[SOLVED] How to store a qimage to iOS Camera Roll (Photo Album) ?



  • Hi, i am trying to port an native Objective C iOS App to an QT App.
    The App uses the iPhone/iPad Camera and should create an Image which is saved to the Camera Roll of the Device.

    So here is the Problem: How do I access the Camera Roll or what Path (QStandardPaths::PicturesLocation returns an empty string) I need to use when saving an Image.

    Thanks,



  • Ok it seems no one ever tried this or ever succeeded.

    I found only a dirty way to do it without going too deep in UIImage and QtImage Logic - I didn't have the time so I needed to use already working Algorithm.

    For my "solution" you need the OpenCV Framework in your Qt Project (see my post http://qt-project.org/forums/viewthread/41530/ how to do this). Basically you have to Convert the QImage to an IplImage and then the IplImage to an UIImage.

    To accomplish that you need to use following code in a Qt/Objective C Hybrid mm File (see http://el-tramo.be/blog/mixing-cocoa-and-qt/ for how to mix Objective C and C++ in Qt) :

    @
    #include "cv.h"

    #import <Foundation/NSData.h>
    #import <UIKit/UIKit.h>

    UIImage* GetUIImg(IplImage* iplImage) {
    // NOTE Do not try to include this function in your header, because it will
    // need UIImage and if you add the UIKit Objective C Lib in your header
    // to make the Type visible the Qt Preprocessor will try to Process the
    // UIKit Lib as C++ and will fail
    cv::Mat cvMat = cv::cvarrToMat(iplImage);

    NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()];
    
    CGColorSpaceRef colorSpace;
    
    if (cvMat.elemSize() == 1)
    {
        colorSpace = CGColorSpaceCreateDeviceGray();
    }
    else
    {
        colorSpace = CGColorSpaceCreateDeviceRGB();
    }
    
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
    
    CGImageRef imageRef = CGImageCreate(cvMat.cols,                                     // Width
                                        cvMat.rows,                                     // Height
                                        8,                                              // Bits per component
                                        8 * cvMat.elemSize(),                           // Bits per pixel
                                        cvMat.step[0],                                  // Bytes per row
                                        colorSpace,                                     // Colorspace
                                        kCGImageAlphaNone | kCGBitmapByteOrderDefault,  // Bitmap info flags
                                        provider,                                       // CGDataProviderRef
                                        NULL,                                           // Decode
                                        false,                                          // Should interpolate
                                        kCGRenderingIntentDefault);                     // Intent
    
    UIImage* imgResult = [[UIImage alloc] initWithCGImage:imageRef];
    
    CGImageRelease(imageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);
    
    cvMat.release();
    
    return imgResult;
    

    }

    void ObjCHelpers::saveImgToGallery(QImage qimg4Album) {
    QImage* qImage = &qimg4Album;

    int width = qImage->width();
    int height = qImage->height();
    CvSize Size;
    Size.height = height;
    Size.width = width;
    
    IplImage *ipl4Album = cvCreateImage(Size, IPL_DEPTH_8U, 1);
    char *charTemp = (char *) ipl4Album->imageData;
    
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            int index = y * width + x;
            charTemp[index] = (char) qGray(qImage->pixel(x, y));
        }
    }
    
    UIImage* uiimg4Album = GetUIImg(ipl4Album);
    
    UIImageWriteToSavedPhotosAlbum(uiimg4Album, Nil, Nil, Nil);
    

    }
    @

    Its not a perfect solution but it works for me. If someone knows how an QImage is stored internally and knows the same about an UIImage, he could do the Convertion without using an IplImage but I already use the OpenCV Framework in my Project and had an working Ipl to UI Image Convertion in another Project so it was the simplest way for me.


  • Lifetime Qt Champion

    Hi,

    QImage can be of several "formats":http://qt-project.org/doc/qt-5/qimage.html#image-formats and "here":http://qt-project.org/doc/qt-5/qimage.html#Format-enum

    You should also take a look at QtMacExtras, you have a helper function to get a CGImageRef from a QPixmap.

    Hope it helps



  • Sorry to dig this old topic.
    I also needed to save a picture to the camera roll, and I thought that such a frequent use case would be supported "out of the box" by Qt, unfortunately after almost a complete day of browsing the web I haven't found a ready to use and working solution.
    I liked aqmah solution but I didn't want to add OpenCV dependency to my project just for this.

    Unfortunately QtMacExtras is no longer available on iOS.
    I have thus modified aqmah solution to come up with an acceptable solution without OpenCV.

    I know it is far from perfect but still it could be of some help :

    bool saveImgToGallery(const QImage& qimg4Album) {
        UIImage* uiimg4Album = QImage2UIImmage(qimg4Album);
        if ( uiimg4Album){
            UIImageWriteToSavedPhotosAlbum( uiimg4Album, Nil, Nil, Nil);
            return true;
        }
        return false;
    }
    
    UIImage* QImage2UIImmage(const QImage& img)
    {
        if (img.isNull()) return nullptr;
        CGDataProviderRef provider = CGDataProviderCreateWithData(nullptr, img.bits(), img.byteCount(), nullptr);
        CGColorSpaceRef colorSpace = img.isGrayscale() ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB();
        
    CGImageRef imageRef = CGImageCreate( 
            img.width(),  img.height(), 
            8, img.depth(), img.bytesPerLine(), 
            colorSpace, getFlagsFromImageFormat(img.format()),
            provider, NULL, false, kCGRenderingIntentDefault);
        
        CGImageRelease(imageRef);
        CGDataProviderRelease(provider);
        CGColorSpaceRelease(colorSpace);
    
        return imgResult;
    }
    
    uint getFlagsFromImageFormat(QImage::Format frm)
    {
        uint cgFlags = kCGImageAlphaNone;
        switch (frm) {
        case QImage::Format_ARGB32:
            cgFlags = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
            break;
        case QImage::Format_RGB32:
            cgFlags = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
            break;
        case QImage::Format_RGB888:
            cgFlags = kCGImageAlphaNone | kCGBitmapByteOrder32Big;
            break;
        case QImage::Format_RGBA8888_Premultiplied:
            cgFlags = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
            break;
        case QImage::Format_RGBA8888:
            cgFlags = kCGImageAlphaLast | kCGBitmapByteOrder32Big;
            break;
        case QImage::Format_RGBX8888:
            cgFlags = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big;
            break;
        case QImage::Format_ARGB32_Premultiplied:
            cgFlags = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
            break;
        default:
            cgFlags = kCGImageAlphaNone;
        }
        return cgFlags;
    }
    


  • Hi, and what if I need to download an image and save it in the camera roll?
    I'm using Qt 5.5.1, pictures location seems to be correct and when saving I don't get any error but I can't find the image on the gallery app!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.