Home > Mobile >  How to convert a CGImageRef to a QPixmap in Qt 6?
How to convert a CGImageRef to a QPixmap in Qt 6?

Time:12-12

In Qt 5, converting a CGImageRef to a QPixmap was easy using their QtMacExtras module and the QtMac::fromCGImageRef function.

In Qt 6, QtMacExtras has been removed. Most of the functions there have explicit replacements, except for QtMac::fromCGImageRef which was removed "due to lack of known clients of the API".

Well it turns out I was a client of that API, just not a known one. Nonetheless, now I need to convert a CGImageRef to a QPixmap in Qt 6.

I looked at the source code for QtMac::fromCGImageRef in Qt 5.15.2, which lead me to a Qt internal function named qt_mac_toQImage. However, it makes use of a ton of internal functions and classes that I don't have access to in Qt 5, much less Qt 6, so that doesn't help.

How can I go about doing this conversion?

CodePudding user response:

It turns out that a lot of the private Qt stuff used in the Qt 5.15 implementation of qt_mac_toQImage applied to situations other than attempting to do CoreGraphics rendering to a QImage. Once I pulled all of those parts out and simplified, the method for converting a CGImageRef to a QImage or QPixmap is fairly straight forward:

CGBitmapInfo CGBitmapInfoForQImage(const QImage &image)
{
    CGBitmapInfo bitmapInfo = kCGImageAlphaNone;
    
    switch (image.format()) {
        case QImage::Format_ARGB32:
            bitmapInfo = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
            break;
        case QImage::Format_RGB32:
            bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
            break;
        case QImage::Format_RGBA8888_Premultiplied:
            bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
            break;
        case QImage::Format_RGBA8888:
            bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrder32Big;
            break;
        case QImage::Format_RGBX8888:
            bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big;
            break;
        case QImage::Format_ARGB32_Premultiplied:
            bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
            break;
        default:
            break;
    }
    
    return bitmapInfo;
}

QImage CGImageToQImage(CGImageRef cgImage)
{
    const size_t width = CGImageGetWidth(cgImage);
    const size_t height = CGImageGetHeight(cgImage);
    QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
    image.fill(Qt::transparent);
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
    CGContextRef context = CGBitmapContextCreate((void *)image.bits(), image.width(), image.height(), 8,
                                                 image.bytesPerLine(), colorSpace, CGBitmapInfoForQImage(image));

    // Scale the context so that painting happens in device-independent pixels
    const qreal devicePixelRatio = image.devicePixelRatio();
    CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
    
    CGRect rect = CGRectMake(0, 0, width, height);
    CGContextDrawImage(context, rect, cgImage);
    
    CFRelease(colorSpace);
    CFRelease(context);
    
    return image;
}

Once you've converted a CGImageRef to a QImage, it's simple converting that to a QPixmap using QPixmap::convertFromImage.

  • Related