Question

I receive data (NSData) from the scanner that looks something like this when logged with NSLog:

2014-04-07 10:42:07.309 Pantelegraph[488:303] <
4c9d8f4d 9f9849a2 9a4fa79f 46a8984d a9a346aa 9f53aea0 50ad884d aa9354b4
9251b291 54b18f54 b28e47b3 9254b396 49af8d4f b3834fb1 904fb488 59b7874f
b38a4cb2 8551b186 4ab78556 b4884cb1 894eb180 59b17d4e b37b57b2 754fb386
56b98453 b38449b1 794fb37b 49ae8852 b08253ac 8652af80 58b18552 b08850b2
8856b086 51b08a51 ad9656ad 8d4fb091 50ab934c ab9753af 9a4aae9a 54af9c53
ae9c49b0 a451afa5 4faba450 aea54eae aa4db0a3 57b0a24e aea34caf a74eafa2
49b09b51 afa448ae a152b0a1 51aca147 aea44db3 9851b0a3 4ab49d50 b09d49b3
924fb198 49af964e b29553b1 8e50b294 52b6874b b18d50b2 944eb48d 49b28a56
b3844aae 934fb485 53af884d b08356b0 814eac84 52b37754 b08650ae 7d57b081
57ae8752 ac8356a9 9150ae8a 52af7f52 ac8e51ac 8554ad8e 44ae9851 ad9c55af
9d54b095 56ae9a52 afa052ae a150aca4 51aba74c aaa34eac a453aea7 4bafa254
af9c4fac a150b29a 54aea652 af9d4db0 9e4eb195 4eaf9454 af974caf 884eb086
54a98750 ad8d51ad 8249ac85 51ab7750 ad7951ae 8453ab80 4cac8553 …
>

Now I think those are hexadecimal colors, pixel by pixel.

Together with this NSData object I also receive information like the width and height of the image.

My question is how can I create an image (NSImage, CGImageRef, etc…) from this data? I used CGImageCreate but all I got from that is a lot of noise.

Edit

As requested in one of the comments her is the full data of an piece of paper (A8) I scanned with 6 colors on it.

Pastebin of the data and metadata.

At the bottom there is also the other information I received from the scanner.

I scanned the image in rgb with a bit depth of 8 bits and a resolution of 50ppi. Below is an image of the paper I scanned with another application:

enter image description here

When using this code to create a CGImageRef:

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, (__bridge const void *)([data dataBuffer]), [data dataSize], NULL);
    CGImageRef image = CGImageCreate([data fullImageWidth], [data fullImageHeight], [data bitsPerComponent], [data bitsPerPixel], [data bytesPerRow], CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault|kCGImageAlphaNone, provider, NULL, false, kCGRenderingIntentDefault);

I get a lot of noise that looks like this (for the image shown above) :

enter image description here

Edit

As suggested in one of the answers, the size of the data I get is the same as what the metadata says as seen in this picture:

enter image description here

Was it helpful?

Solution 2

With the help of the above answer I managed to make it work, this is the code I used:

- (void)scannerDevice:(ICScannerDevice *)scanner didScanToBandData:(ICScannerBandData *)data {
    CGColorSpaceRef color = CGColorSpaceCreateDeviceGray();
    if ([data pixelDataType] == ICScannerPixelDataTypeRGB) color = CGColorSpaceCreateDeviceRGB();
    CGDataProviderRef provider = CGDataProviderCreateWithCFData(CFDataCreate(NULL, [[data dataBuffer] bytes], [data dataSize]));
    CGImageRef image = CGImageCreate([data fullImageWidth], [data fullImageHeight], [data bitsPerComponent], [data bitsPerPixel], [data bytesPerRow], color, kCGBitmapByteOrderDefault|kCGImageAlphaNone, provider, NULL, false, kCGRenderingIntentDefault);

    NSImage *finImage = [[NSImage alloc] initWithCGImage:image size:NSMakeSize([data fullImageWidth], [data fullImageHeight])];
    CGImageRelease(image);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(color);
}

The problem was that I'm putting the NSData object straight into the data provider. This gives the data provider other data in your memory than the actual raw image data, so that's the noise in the picture.

OTHER TIPS

I made a test bmp of 320*320px, added a Red, Green and Blue area.

enter image description here

Opened it in an text editor and removed meta data at the beginning.

When I used this code

NSString *imagePath = [[NSBundle mainBundle] pathForResource: @"test3" ofType: @"bmp"];

NSData *data = [NSData dataWithContentsOfFile:imagePath];
CGFloat width = 320.0;
CGFloat height = 320.0;

NSUInteger bitPerByte = 8;
NSUInteger bytePerColor = 3;
NSUInteger len = [data length];

Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);


CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,
                                                          byteData,
                                                          width*height*bytePerColor,
                                                          NULL);

CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();

CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;

CGImageRef imageRef = CGImageCreate(width,
                                    height,
                                    bitPerByte,
                                    bytePerColor*bitPerByte,
                                    bytePerColor*width,colorSpaceRef,
                                    bitmapInfo,
                                    provider,NULL,NO,0);

Red and Blue where switched

enter image description here

The data looking like this

<… 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 
ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 
0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00
00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000
ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff
0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00
00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000
ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff
0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ff0000ff 0000ff00 00ff0000 ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff …>

BTW: the groping of 8 bytes has nothing to do with the number of color components in the image. NSData doesn't know which data it contains. this is just the way it's description method displays the data.

One solution would be to create a BGR colorspace, but I did't have this option, as I decided to create an iOS app, as I am not very familiar with Mac Cocoa.

Instead I exchanged red and blue values manually

// on ios i cannot create a BGR colorspace, there for I swap red and blue values
for (NSUInteger i =2; i < len; i+=3) {
    Byte l = byteData[i-2];
    Byte r = byteData[i];
    byteData[i] = l;
    byteData[i-2] = r;
}

giving me following code

NSString *imagePath = [[NSBundle mainBundle] pathForResource: @"test3" ofType: @"bmp"];

NSData *data = [NSData dataWithContentsOfFile:imagePath];
CGFloat width = 320.0;
CGFloat height = 320.0;

NSUInteger bitPerByte = 8;
NSUInteger bytePerColor = 3;
NSUInteger len = [data length];

Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);

// on ios i cannot create a BGR colorspace, there for I swap red and blue values
for (NSUInteger i =2; i < len; i+=3) {
    Byte l = byteData[i-2];
    Byte r = byteData[i];
    byteData[i] = l;
    byteData[i-2] = r;
}

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,
                                                          byteData,
                                                          width*height*bytePerColor,
                                                          NULL);

CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();

CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;

CGImageRef imageRef = CGImageCreate(width,
                                    height,
                                    bitPerByte,
                                    bytePerColor*bitPerByte,
                                    bytePerColor*width,colorSpaceRef,
                                    bitmapInfo,
                                    provider,NULL,NO,0);

and this result:

enter image description here


So as you haven't provided a sample data set yet, you may have to adjust certain things, mainly bitPerByte and bytePerColor. you also have to check, if the scanner adds some meta data.


I don't know why, but that raw data array has exactly twice as much bytes as told by the metada, 89352 istead of 44676.

with this code

NSData *data = [NSData dataWithContentsOfFile:imagePath];
CGFloat width = 146.0;
CGFloat height = 102.0;

NSUInteger bitPerByte = 8;
NSUInteger bytePerColor = 2*3;
NSUInteger len = [data length];

Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);


CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,
                                                          byteData,
                                                          width*height*bytePerColor,
                                                          NULL);

CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();

CGBitmapInfo bitmapInfo = kCGBitmapByteOrder16Big;

CGImageRef imageRef = CGImageCreate(width,
                                    height,
                                    bitPerByte * 2,
                                    bytePerColor*bitPerByte ,
                                    bytePerColor*width ,
                                    colorSpaceRef,
                                    bitmapInfo,
                                    provider,NULL,NO,0);

I am able to display

enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top