-2

Can we convert an UIImage to uint8 byte array?

What Ia m trying to do here is -- I have an image which I want to convert in to 8 bit byte array. I further need this for AES 256 encryption.

Actually I am totally new to this part of iOS, so need basic help.

Shailesh
  • 3,072
  • 3
  • 24
  • 33
  • What are you trying to do exactly? You can turn a `UIImage` into `NSData`. – nhgrif Jun 29 '14 at 18:25
  • Possible duplicate of http://stackoverflow.com/questions/9061800/how-do-i-autocrop-a-uiimage/13922413#13922413 – dalton_c Jun 29 '14 at 18:30
  • This question is probably what you are looking for: http://stackoverflow.com/questions/448125/how-to-get-pixel-data-from-a-uiimage-cocoa-touch-or-cgimage-core-graphics – Jack Jun 29 '14 at 18:38
  • [This answer](http://stackoverflow.com/a/6064453/581994) shows how to access the data in an image and manipulate it on a bit-by-bit basis. You use CGDataProviderCopyData(CGImageGetDataProvider(sourceUIImage.GCImage)) to get an NSData image of the actual bytes. I think there are a couple of other ways. – Hot Licks Jun 29 '14 at 19:53

1 Answers1

1

This shows how to access the image and create a new image (in this case half size) based on the original:

- (UIImage*) halveImage:(UIImage*)sourceImage {

    // Compute the target size
    CGSize sourceSize = sourceImage.size;
    CGSize targetSize;
    targetSize.width = (int) (sourceSize.width / 2);
    targetSize.height = (int) (sourceSize.height / 2);

    // Access the source data bytes
    NSData* sourceData = (NSData*) CGDataProviderCopyData(CGImageGetDataProvider(sourceImage.CGImage));
    unsigned char* sourceBytes = (unsigned char *)[sourceData bytes];

    // Some info we'll need later
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(sourceImage.CGImage);
    int bitsPerComponent = CGImageGetBitsPerComponent(sourceImage.CGImage);
    int bitsPerPixel = CGImageGetBitsPerPixel(sourceImage.CGImage);
    int __attribute__((unused)) bytesPerPixel = bitsPerPixel / 8;
    int sourceBytesPerRow = CGImageGetBytesPerRow(sourceImage.CGImage);
    CGColorSpaceRef colorSpace = CGImageGetColorSpace(sourceImage.CGImage);

    assert(bytesPerPixel == 4);
    assert(bitsPerComponent == 8);

    // Bytes per row is (apparently) rounded to some boundary
    assert(sourceBytesPerRow >= ((int) sourceSize.width) * 4);
    assert([sourceData length] == ((int) sourceSize.height) * sourceBytesPerRow);

    // Allocate target data bytes
    int targetBytesPerRow = ((int) targetSize.width) * 4;
    // Algorigthm happier if bytes/row a multiple of 16
    targetBytesPerRow = (targetBytesPerRow + 15) & 0xFFFFFFF0;
    int targetBytesSize = ((int) targetSize.height) * targetBytesPerRow;
    unsigned char* targetBytes = (unsigned char*) malloc(targetBytesSize);
    UIImage* targetImage = nil;

    // Copy source to target, averaging 4 pixels into 1
    for (int row = 0; row < targetSize.height; row++) {
        unsigned char* sourceRowStart = sourceBytes + (2 * row * sourceBytesPerRow);
        unsigned char* targetRowStart = targetBytes + (row * targetBytesPerRow);
        for (int column = 0; column < targetSize.width; column++) {

            int sourceColumnOffset = 2 * column * 4;
            int targetColumnOffset = column * 4;

            unsigned char* sourcePixel = sourceRowStart + sourceColumnOffset;
            unsigned char* nextRowSourcePixel = sourcePixel + sourceBytesPerRow;
            unsigned char* targetPixel = targetRowStart + targetColumnOffset;

            uint32_t* sourceWord = (uint32_t*) sourcePixel;
            uint32_t* nextRowSourceWord = (uint32_t*) nextRowSourcePixel;
            uint32_t* targetWord = (uint32_t*) targetPixel;

            uint32_t sourceWord0 = sourceWord[0];
            uint32_t sourceWord1 = sourceWord[1];
            uint32_t sourceWord2 = nextRowSourceWord[0];
            uint32_t sourceWord3 = nextRowSourceWord[1];

            // This apparently bizarre sequence scales the data bytes by 4 so that when added together we'll get an average.  We do lose the least significant bits this way, and thus about half a bit of resolution.
            sourceWord0 = (sourceWord0 & 0xFCFCFCFC) >> 2;
            sourceWord1 = (sourceWord1 & 0xFCFCFCFC) >> 2;
            sourceWord2 = (sourceWord2 & 0xFCFCFCFC) >> 2;
            sourceWord3 = (sourceWord3 & 0xFCFCFCFC) >> 2;

            uint32_t resultWord = sourceWord0 + sourceWord1 + sourceWord2 + sourceWord3;
            targetWord[0] = resultWord;
        }
    }

    // Convert the bits to an image.  Supposedly CGCreateImage will dispose of the target bytes buffer.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, targetBytes, targetBytesSize, NULL);
    CGImageRef targetRef = CGImageCreate(targetSize.width, targetSize.height, bitsPerComponent, bitsPerPixel, targetBytesPerRow, colorSpace, bitmapInfo, provider, NULL, FALSE, kCGRenderingIntentDefault);
    targetImage = [UIImage imageWithCGImage:targetRef];

    // Clean up
    CGColorSpaceRelease(colorSpace);

    // Return result
    return targetImage;
}
Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • I am sorry to be a noob here, But I am not sure what exactly this code is doing :( Would you please explain it for me here ? – Shailesh Jun 30 '14 at 09:21
  • Given HotLicks's reputation, I can only assume it's doing exactly what you've asked in your question. – nhgrif Jun 30 '14 at 11:36
  • @Shailesh - You don't need to understand the "allocate target data bytes" and "copy source to target" part as it's doing a transformation that you're likely not interested in. I included them mainly to demonstrate accessing the data. The actual data extraction occurs in the "access the source data bytes" section. – Hot Licks Jun 30 '14 at 11:36
  • Ok @HotLicks: I get it.Any chance we can convert it into NSData ? – Shailesh Jun 30 '14 at 13:03
  • If you look closely it *is* producing an NSData object: `NSData* sourceData = (NSData*) CGDataProviderCopyData(CGImageGetDataProvider(sourceImage.CGImage));` – Hot Licks Jun 30 '14 at 14:15
  • Thats it @HotLicks ? Thats all we need to do convert an image to uint8 array ? – Shailesh Jul 01 '14 at 11:05
  • @Shailesh - Yep. But note that converting the data back to an image requires all the other info and is a fair bit more complex. – Hot Licks Jul 01 '14 at 11:37
  • @HotLicks: Yep -- I will be needing that too.. sometime in coming few days. – Shailesh Jul 01 '14 at 12:01
  • Also @HotLicks: is Base64 encoding and converting into uint8 array same ? – Shailesh Jul 01 '14 at 16:52
  • @Shailesh - No, [Base64](http://en.wikipedia.org/wiki/Base64) encoding is a way to convert binary data into character data that may be transmitted as if it were ordinary text. – Hot Licks Jul 01 '14 at 17:01