Qt源码分析--QImage(5)

1.QImage createAlphaMask(Qt::ImageConversionFlags flags = Qt::AutoColor) const;

/*!
    Builds and returns a 1-bpp mask from the alpha buffer in this
    image. Returns a null image if the image's format is
    QImage::Format_RGB32.
    The \a flags argument is a bitwise-OR of the
    Qt::ImageConversionFlags, and controls the conversion
    process. Passing 0 for flags sets all the default options.
    The returned image has little-endian bit order (i.e. the image's
    format is QImage::Format_MonoLSB), which you can convert to
    big-endian (QImage::Format_Mono) using the convertToFormat()
    function.
    \sa createHeuristicMask(), {QImage#Image Transformations}{Image
    Transformations}
*/
QImage QImage::createAlphaMask(Qt::ImageConversionFlags flags) const
{
    if (!d || d->format == QImage::Format_RGB32)
        return QImage();
    if (d->depth == 1) {
        // A monochrome pixmap, with alpha channels on those two colors.
        // Pretty unlikely, so use less efficient solution.
        return convertToFormat(Format_Indexed8, flags).createAlphaMask(flags);
    }
    QImage mask(d->width, d->height, Format_MonoLSB);
    if (!mask.isNull()) {
        dither_to_Mono(mask.d, d, flags, true);
        copyPhysicalMetadata(mask.d, d);
    }
    return mask;
}

void dither_to_Mono(QImageData *dst, const QImageData *src,
                           Qt::ImageConversionFlags flags, bool fromalpha)
{
    Q_ASSERT(src->width == dst->width);
    Q_ASSERT(src->height == dst->height);
    Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
    dst->colortable.clear();
    dst->colortable.append(0xffffffff);
    dst->colortable.append(0xff000000);
    enum { Threshold, Ordered, Diffuse } dithermode;
    if (fromalpha) {
        if ((flags & Qt::AlphaDither_Mask) == Qt::DiffuseAlphaDither)
            dithermode = Diffuse;
        else if ((flags & Qt::AlphaDither_Mask) == Qt::OrderedAlphaDither)
            dithermode = Ordered;
        else
            dithermode = Threshold;
    } else {
        if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither)
            dithermode = Threshold;
        else if ((flags & Qt::Dither_Mask) == Qt::OrderedDither)
            dithermode = Ordered;
        else
            dithermode = Diffuse;
    }
    int          w = src->width;
    int          h = src->height;
    int          d = src->depth;
    uchar gray[256];                                // gray map for 8 bit images
    bool  use_gray = (d == 8);
    if (use_gray) {                                // make gray map
        if (fromalpha) {
            // Alpha 0x00 -> 0 pixels (white)
            // Alpha 0xFF -> 1 pixels (black)
            for (int i = 0; i < src->colortable.size(); i++)
                gray[i] = (255 - (src->colortable.at(i) >> 24));
        } else {
            // Pixel 0x00 -> 1 pixels (black)
            // Pixel 0xFF -> 0 pixels (white)
            for (int i = 0; i < src->colortable.size(); i++)
                gray[i] = qGray(src->colortable.at(i));
        }
    }
    uchar *dst_data = dst->data;
    qsizetype dst_bpl = dst->bytes_per_line;
    const uchar *src_data = src->data;
    qsizetype src_bpl = src->bytes_per_line;
    switch (dithermode) {
    case Diffuse: {
        QScopedArrayPointer lineBuffer(new int[w * 2]);
        int *line1 = lineBuffer.data();
        int *line2 = lineBuffer.data() + w;
        int bmwidth = (w+7)/8;
        int *b1, *b2;
        int wbytes = w * (d/8);
        const uchar *p = src->data;
        const uchar *end = p + wbytes;
        b2 = line2;
        if (use_gray) {                        // 8 bit image
            while (p < end)
                *b2++ = gray[*p++];
        } else {                                // 32 bit image
            if (fromalpha) {
                while (p < end) {
                    *b2++ = 255 - (*(const uint*)p >> 24);
                    p += 4;
                }
            } else {
                while (p < end) {
                    *b2++ = qGray(*(const uint*)p);
                    p += 4;
                }
            }
        }
        for (int y=0; ydata + (y+1)*src->bytes_per_line;
                end = p + wbytes;
                b2 = line2;
                if (use_gray) {                // 8 bit image
                    while (p < end)
                        *b2++ = gray[*p++];
                } else {                        // 24 bit image
                    if (fromalpha) {
                        while (p < end) {
                            *b2++ = 255 - (*(const uint*)p >> 24);
                            p += 4;
                        }
                    } else {
                        while (p < end) {
                            *b2++ = qGray(*(const uint*)p);
                            p += 4;
                        }
                    }
                }
            }
            int err;
            uchar *p = dst->data + y*dst->bytes_per_line;
            memset(p, 0, bmwidth);
            b1 = line1;
            b2 = line2;
            int bit = 7;
            for (int x=1; x<=w; x++) {
                if (*b1 < 128) {                // black pixel
                    err = *b1++;
                    *p |= 1 << bit;
                } else {                        // white pixel
                    err = *b1++ - 255;
                }
                if (bit == 0) {
                    p++;
                    bit = 7;
                } else {
                    bit--;
                }
                const int e7 = ((err * 7) + 8) >> 4;
                const int e5 = ((err * 5) + 8) >> 4;
                const int e3 = ((err * 3) + 8) >> 4;
                const int e1 = err - (e7 + e5 + e3);
                if (x < w)
                    *b1 += e7;                  // spread error to right pixel
                if (not_last_line) {
                    b2[0] += e5;                // pixel below
                    if (x > 1)
                        b2[-1] += e3;           // pixel below left
                    if (x < w)
                        b2[1] += e1;            // pixel below right
                }
                b2++;
            }
        }
    } break;
    case Ordered: {
        memset(dst->data, 0, dst->nbytes);
        if (d == 32) {
            for (int i=0; i> 24) >= qt_bayer_matrix[j++&15][i&15])
                            *m |= 1 << bit;
                        if (bit == 0) {
                            m++;
                            bit = 7;
                        } else {
                            bit--;
                        }
                    }
                } else {
                    while (p < end) {
                        if ((uint)qGray(*p++) < qt_bayer_matrix[j++&15][i&15])
                            *m |= 1 << bit;
                        if (bit == 0) {
                            m++;
                            bit = 7;
                        } else {
                            bit--;
                        }
                    }
                }
                dst_data += dst_bpl;
                src_data += src_bpl;
            }
        } else if (d == 8) {
            for (int i=0; idata, 0, dst->nbytes);
        if (d == 32) {
            for (int i=0; i> 24) >= 128)
                            *m |= 1 << bit;        // Set mask "on"
                        if (bit == 0) {
                            m++;
                            bit = 7;
                        } else {
                            bit--;
                        }
                    }
                } else {
                    while (p < end) {
                        if (qGray(*p++) < 128)
                            *m |= 1 << bit;        // Set pixel "black"
                        if (bit == 0) {
                            m++;
                            bit = 7;
                        } else {
                            bit--;
                        }
                    }
                }
                dst_data += dst_bpl;
                src_data += src_bpl;
            }
        } else
            if (d == 8) {
                for (int i=0; iformat == QImage::Format_MonoLSB) {
        // need to swap bit order
        uchar *sl = dst->data;
        int bpl = (dst->width + 7) * dst->depth / 8;
        int pad = dst->bytes_per_line - bpl;
        for (int y=0; yheight; ++y) {
            for (int x=0; xdpmx = src->dpmx;
    dst->dpmy = src->dpmy;
    dst->devicePixelRatio = src->devicePixelRatio;
}

主要是通过dither_to_Mono 这个函数对图像数据进行处理。

2. QImage createHeuristicMask(bool clipTight = true) const;

/*!
    Creates and returns a 1-bpp heuristic mask for this image.
    The function works by selecting a color from one of the corners,
    then chipping away pixels of that color starting at all the edges.
    The four corners vote for which color is to be masked away. In
    case of a draw (this generally means that this function is not
    applicable to the image), the result is arbitrary.
    The returned image has little-endian bit order (i.e. the image's
    format is QImage::Format_MonoLSB), which you can convert to
    big-endian (QImage::Format_Mono) using the convertToFormat()
    function.
    If \a clipTight is true (the default) the mask is just large
    enough to cover the pixels; otherwise, the mask is larger than the
    data pixels.
    Note that this function disregards the alpha buffer.
    \sa createAlphaMask(), {QImage#Image Transformations}{Image
    Transformations}
*/
QImage QImage::createHeuristicMask(bool clipTight) const
{
    if (!d)
        return QImage();
    if (d->depth != 32) {
        QImage img32 = convertToFormat(Format_RGB32);
        return img32.createHeuristicMask(clipTight);
    }
#define PIX(x,y)  (*((const QRgb*)scanLine(y)+x) & 0x00ffffff)
    int w = width();
    int h = height();
    QImage m(w, h, Format_MonoLSB);
    QIMAGE_SANITYCHECK_MEMORY(m);
    m.setColorCount(2);
    m.setColor(0, QColor(Qt::color0).rgba());
    m.setColor(1, QColor(Qt::color1).rgba());
    m.fill(0xff);
    QRgb background = PIX(0,0);
    if (background != PIX(w-1,0) &&
         background != PIX(0,h-1) &&
         background != PIX(w-1,h-1)) {
        background = PIX(w-1,0);
        if (background != PIX(w-1,h-1) &&
             background != PIX(0,h-1) &&
             PIX(0,h-1) == PIX(w-1,h-1)) {
            background = PIX(w-1,h-1);
        }
    }
    int x,y;
    bool done = false;
    uchar *ypp, *ypc, *ypn;
    while(!done) {
        done = true;
        ypn = m.scanLine(0);
        ypc = nullptr;
        for (y = 0; y < h; y++) {
            ypp = ypc;
            ypc = ypn;
            ypn = (y == h-1) ? nullptr : m.scanLine(y+1);
            const QRgb *p = (const QRgb *)scanLine(y);
            for (x = 0; x < w; x++) {
                // slowness here - it's possible to do six of these tests
                // together in one go. oh well.
                if ((x == 0 || y == 0 || x == w-1 || y == h-1 ||
                       !(*(ypc + ((x-1) >> 3)) & (1 << ((x-1) & 7))) ||
                       !(*(ypc + ((x+1) >> 3)) & (1 << ((x+1) & 7))) ||
                       !(*(ypp + (x     >> 3)) & (1 << (x     & 7))) ||
                       !(*(ypn + (x     >> 3)) & (1 << (x     & 7)))) &&
                     (       (*(ypc + (x     >> 3)) & (1 << (x     & 7)))) &&
                     ((*p & 0x00ffffff) == background)) {
                    done = false;
                    *(ypc + (x >> 3)) &= ~(1 << (x & 7));
                }
                p++;
            }
        }
    }
    if (!clipTight) {
        ypn = m.scanLine(0);
        ypc = nullptr;
        for (y = 0; y < h; y++) {
            ypp = ypc;
            ypc = ypn;
            ypn = (y == h-1) ? nullptr : m.scanLine(y+1);
            const QRgb *p = (const QRgb *)scanLine(y);
            for (x = 0; x < w; x++) {
                if ((*p & 0x00ffffff) != background) {
                    if (x > 0)
                        *(ypc + ((x-1) >> 3)) |= (1 << ((x-1) & 7));
                    if (x < w-1)
                        *(ypc + ((x+1) >> 3)) |= (1 << ((x+1) & 7));
                    if (y > 0)
                        *(ypp + (x >> 3)) |= (1 << (x & 7));
                    if (y < h-1)
                        *(ypn + (x >> 3)) |= (1 << (x & 7));
                }
                p++;
            }
        }
    }
#undef PIX
    copyPhysicalMetadata(m.d, d);
    return m;
}

3. mirrored()

QImage mirrored(bool horizontally = false, bool vertically = true) const &
    { return mirrored_helper(horizontally, vertically); }

QImage QImage::mirrored_helper(bool horizontal, bool vertical) const
{
    if (!d)
        return QImage();
    if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
        return *this;
    // Create result image, copy colormap
    QImage result(d->width, d->height, d->format);
    QIMAGE_SANITYCHECK_MEMORY(result);
    // check if we ran out of of memory..
    if (!result.d)
        return QImage();
    result.d->colortable = d->colortable;
    result.d->has_alpha_clut = d->has_alpha_clut;
    copyMetadata(result.d, d);
    do_mirror(result.d, d, horizontal, vertical);
    return result;
}

inline void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool vertical)
{
    Q_ASSERT(src->width == dst->width && src->height == dst->height && src->depth == dst->depth);
    int w = src->width;
    int h = src->height;
    int depth = src->depth;
    if (src->depth == 1) {
        w = (w + 7) / 8; // byte aligned width
        depth = 8;
    }
    if (vertical && !horizontal) {
        // This one is simple and common, so do it a little more optimized
        do_flip(dst, src, w, h, depth);
        return;
    }
    int dstX0 = 0, dstXIncr = 1;
    int dstY0 = 0, dstYIncr = 1;
    if (horizontal) {
        // 0 -> w-1, 1 -> w-2, 2 -> w-3, ...
        dstX0 = w - 1;
        dstXIncr = -1;
    }
    if (vertical) {
        // 0 -> h-1, 1 -> h-2, 2 -> h-3, ...
        dstY0 = h - 1;
        dstYIncr = -1;
    }
    switch (depth) {
    case 64:
        do_mirror_data(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
        break;
    case 32:
        do_mirror_data(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
        break;
    case 24:
        do_mirror_data(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
        break;
    case 16:
        do_mirror_data(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
        break;
    case 8:
        do_mirror_data(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
        break;
    default:
        Q_ASSERT(false);
        break;
    }
    // The bytes are now all in the correct place. In addition, the bits in the individual
    // bytes have to be flipped too when horizontally mirroring a 1 bit-per-pixel image.
    if (horizontal && dst->depth == 1) {
        Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
        const int shift = 8 - (dst->width % 8);
        const uchar *bitflip = qt_get_bitflip_array();
        for (int y = 0; y < h; ++y) {
            uchar *begin = dst->data + y * dst->bytes_per_line;
            uchar *end = begin + dst->bytes_per_line;
            for (uchar *p = begin; p < end; ++p) {
                *p = bitflip[*p];
                // When the data is non-byte aligned, an extra bit shift (of the number of
                // unused bits at the end) is needed for the entire scanline.
                if (shift != 8 && p != begin) {
                    if (dst->format == QImage::Format_Mono) {
                        for (int i = 0; i < shift; ++i) {
                            p[-1] <<= 1;
                            p[-1] |= (*p & (128 >> i)) >> (7 - i);
                        }
                    } else {
                        for (int i = 0; i < shift; ++i) {
                            p[-1] >>= 1;
                            p[-1] |= (*p & (1 << i)) << (7 - i);
                        }
                    }
                }
            }
            if (shift != 8) {
                if (dst->format == QImage::Format_Mono)
                    end[-1] <<= shift;
                else
                    end[-1] >>= shift;
            }
        }
    }
}

你可以看到, 通过do_mirror函数进行了镜像操作。

你可能感兴趣的:(Qt,源码分析,C++,qt,开发语言,c++)