Using CGImageCreate to create an image in PureBasic

Mac OSX specific forum
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Using CGImageCreate to create an image in PureBasic

Post by TI-994A »

This Objective-C code obtains some raw bitmap information from the given data object, and then creates a CGImage from it, which is then converted to an NSImage:

Code: Select all

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);
As can be seen from the code, the CGImage is created using the following properties, which looks somewhat similar to Windows' BITMAPINFOHEADER:
- dataSize
- dataBuffer
- bitsPerPixel
- bytesPerRow
- pixelDataType
- fullImageWidth
- fullImageHeight
- bitsPerComponent


There was a similar example by wilbert, in this post, which created a PureBasic-usable image from an NSImage which was created from a CGImage, but in that example, the source image was returned from a screen capture function instead of being created from raw data.

:?: Would it be possible to duplicate the above code in PureBasic, and to create a PureBasic-usable image from the raw data?

:?: Or better still, would it be possible to use the raw data with PureBasic's native image functions to create an image?


Thanks in advance. :D
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Using CGImageCreate to create an image in PureBasic

Post by wilbert »

What kind of raw data ?
Is it pixel data or something like tiff encoded ?
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Using CGImageCreate to create an image in PureBasic

Post by TI-994A »

wilbert wrote:What kind of raw data ?
Is it pixel data or something like tiff encoded ?
Hi wilbert; thanks for your quick reply. :D

This is related to the scanner code that we were working on in the other thread. The raw image data is returned by the didScanToBandData() method, and presumably it could be the format that was set under the documentUTI property; public.png as you had recommended in that example.

However, since this didScanToBandData() method is only called when scanning in memory transfer mode, it might not comply with the documentUTI property, which is used only in file transfer mode.

Couldn't it just be raw image data to be built upon the given properties? (dataSize, dataBuffer, bitsPerPixel, bytesPerRow, pixelDataType, etc.) :?
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Using CGImageCreate to create an image in PureBasic

Post by wilbert »

I think you have two options.
One is to create a CGImage like the code from your first post and draw that onto a PB created image.
The other one is to decode the raw pixel data yourself.
Especially if you always use the same bit depth that shouldn't be overly complicated I think.
How do you select if the scan should be color or b/w and the bit depth (1, 8 or 16) ?
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Using CGImageCreate to create an image in PureBasic

Post by TI-994A »

wilbert wrote:One is to create a CGImage like the code from your first post and draw that onto a PB created image.
Hi wilbert. Is it possible to convert that Objective-C CGImageCreate code into PureBasic? The main point would be to obtain and display an image from the given image data object.
wilbert wrote:The other one is to decode the raw pixel data yourself.
Especially if you always use the same bit depth that shouldn't be overly complicated I think.
How do you select if the scan should be color or b/w and the bit depth (1, 8 or 16) ?
The bit depths (1, 8, 16 bits), and the pixel data types (BW, Gray, RGB, Palette, CMY, CMYK, YUV, YUVK, CIEXYZ), are selectable/obtainable through the scanner unit properties.

Would these be required in order to build the image?
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Using CGImageCreate to create an image in PureBasic

Post by wilbert »

TI-994A wrote:Is it possible to convert that Objective-C CGImageCreate code into PureBasic? The main point would be to obtain and display an image from the given image data object.
Yes, CGImageCreate can be used if you import the function using ImportC.
TI-994A wrote:Would these be required in order to build the image?
Only if you want to decode the dataBuffer yourself.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Using CGImageCreate to create an image in PureBasic

Post by TI-994A »

wilbert wrote:Yes, CGImageCreate can be used if you import the function using ImportC.
Trying to decode the raw data may be a little overkill for this simple requirement.

When importing these functions, could all the parameters be substituted with integers?

Code: Select all

CFDataCreate(allocator.i, bytes.i, length.i)
CGDataProviderCreateWithCFData(data.i)
CGImageCreate(width.i, height.i, bitsPerComponent.i, bitsPerPixel.i, bytesPerRow.i, colorspace.i, bitmapInfo.i, provider.i, decode.i, shouldInterpolate.i, intent.i)
There seems to be some unique data types, like CGColorSpace!, CGBitmapInfo, CGDataProvider!, UnsafePointer<CGFloat>, and CGColorRenderingIntent. :shock:
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Using CGImageCreate to create an image in PureBasic

Post by wilbert »

I can't convert the whole thing since I can't test it (no recognized scanner) but here's something that might help you

Code: Select all

#kCGBitmapByteOrderDefault = 0
#kCGImageAlphaNone = 0
#kCGRenderingIntentDefault = 0

ImportC ""
  CFDataCreate(allocator, *bytes, length)
  CFRelease(cf)
  CGColorSpaceCreateDeviceGray()
  CGColorSpaceCreateDeviceRGB()
  CGColorSpaceRelease(colorspace)
  CGDataProviderCreateWithCFData(cfdata)
  CGDataProviderRelease(provider)
  CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, space, bitmapInfo, provider, *decode, shouldInterpolate, intent)
  CGImageRelease(image)
EndImport



; create raw grayscale data

Dim GrayScaleData.a(99, 99)
RandomSeed(0)
RandomData(@GrayScaleData(), 100 * 100)

; create cgimage

color = CGColorSpaceCreateDeviceGray()

cfdata = CFDataCreate(#Null, @GrayScaleData(), 100 * 100) 
provider = CGDataProviderCreateWithCFData(cfdata)

image = CGImageCreate(100, 100, 8, 8, 100, color, #kCGBitmapByteOrderDefault|#kCGImageAlphaNone, provider, #Null, #False, #kCGRenderingIntentDefault)

; create purebasic image

size.NSSize\width = 100
size\height = 100

nsimage = CocoaMessage(0, CocoaMessage(0, 0, "NSImage alloc"), "initWithCGImage:", image, "size:@", @size)
CreateImage(0, 100, 100)
StartDrawing(ImageOutput(0))
DrawImage(nsimage, 0, 0)
CocoaMessage(0, nsimage, "release")
StopDrawing()

; release some things

CGDataProviderRelease(provider)
CFRelease(cfdata)
CGColorSpaceRelease(color)

; show result

If OpenWindow(0, 0, 0, 100, 100, "Image test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ImageGadget(0, 0, 0, 100, 100, ImageID(0))
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Using CGImageCreate to create an image in PureBasic

Post by TI-994A »

wilbert wrote:

Code: Select all

color = CGColorSpaceCreateDeviceGray()
cfdata = CFDataCreate(#Null, @GrayScaleData(), 100 * 100) 
provider = CGDataProviderCreateWithCFData(cfdata)
image = CGImageCreate(100, 100, 8, 8, 100, color, #kCGBitmapByteOrderDefault|#kCGImageAlphaNone, provider, #Null, #False, #kCGRenderingIntentDefault)
Thanks wilbert! That's precisely what I was looking for. :D

It's funny how all those fancy NS object types can just be substituted with simple integer references. :lol:
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Re: Using CGImageCreate to create an image in PureBasic

Post by coder14 »

wilbert wrote:I can't convert the whole thing since I can't test it (no recognized scanner) but here's something that might help you

Code: Select all

#kCGBitmapByteOrderDefault = 0
#kCGImageAlphaNone = 0
#kCGRenderingIntentDefault = 0

ImportC ""
  CFDataCreate(allocator, *bytes, length)
  CFRelease(cf)
  CGColorSpaceCreateDeviceGray()
  CGColorSpaceCreateDeviceRGB()
  CGColorSpaceRelease(colorspace)
  CGDataProviderCreateWithCFData(cfdata)
  CGDataProviderRelease(provider)
  CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, space, bitmapInfo, provider, *decode, shouldInterpolate, intent)
  CGImageRelease(image)
EndImport



; create raw grayscale data

Dim GrayScaleData.a(99, 99)
RandomSeed(0)
RandomData(@GrayScaleData(), 100 * 100)

; create cgimage

color = CGColorSpaceCreateDeviceGray()

cfdata = CFDataCreate(#Null, @GrayScaleData(), 100 * 100) 
provider = CGDataProviderCreateWithCFData(cfdata)

image = CGImageCreate(100, 100, 8, 8, 100, color, #kCGBitmapByteOrderDefault|#kCGImageAlphaNone, provider, #Null, #False, #kCGRenderingIntentDefault)

; create purebasic image

size.NSSize\width = 100
size\height = 100

nsimage = CocoaMessage(0, CocoaMessage(0, 0, "NSImage alloc"), "initWithCGImage:", image, "size:@", @size)
CreateImage(0, 100, 100)
StartDrawing(ImageOutput(0))
DrawImage(nsimage, 0, 0)
CocoaMessage(0, nsimage, "release")
StopDrawing()

; release some things

CGDataProviderRelease(provider)
CFRelease(cfdata)
CGColorSpaceRelease(color)

; show result

If OpenWindow(0, 0, 0, 100, 100, "Image test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ImageGadget(0, 0, 0, 100, 100, ImageID(0))
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
Hi wilbert. Do you know why this is not working on newer versions of PB? It works on 5.1 and 5.2 but not on 5.4 and above?

Thanks!
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Using CGImageCreate to create an image in PureBasic

Post by wilbert »

coder14 wrote:Do you know why this is not working on newer versions of PB? It works on 5.1 and 5.2 but not on 5.4 and above?
I don't know why it isn't working.
For some reason drawing the image using the vector library does seem to work.

Code: Select all

nsimage = CocoaMessage(0, CocoaMessage(0, 0, "NSImage alloc"), "initWithCGImage:", image, "size:@", @size)
CreateImage(0, 100, 100)
StartVectorDrawing(ImageVectorOutput(0))
DrawVectorImage(nsimage)
CocoaMessage(0, nsimage, "release")
StopVectorDrawing()
Windows (x64)
Raspberry Pi OS (Arm64)
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Re: Using CGImageCreate to create an image in PureBasic

Post by coder14 »

wilbert wrote:
coder14 wrote:Do you know why this is not working on newer versions of PB? It works on 5.1 and 5.2 but not on 5.4 and above?
I don't know why it isn't working.
For some reason drawing the image using the vector library does seem to work.

Code: Select all

nsimage = CocoaMessage(0, CocoaMessage(0, 0, "NSImage alloc"), "initWithCGImage:", image, "size:@", @size)
CreateImage(0, 100, 100)
StartVectorDrawing(ImageVectorOutput(0))
DrawVectorImage(nsimage)
CocoaMessage(0, nsimage, "release")
StopVectorDrawing()
That works! Thank you wilbert! :D

Getting weary weeding out this stuff. But some of the new stuff is great too! :cry: :)
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Using CGImageCreate to create an image in PureBasic

Post by wilbert »

coder14 wrote:That works! Thank you wilbert! :D
This alternative might also work

Code: Select all

#kCGBitmapByteOrderDefault = 0
#kCGImageAlphaNone = 0
#kCGRenderingIntentDefault = 0

ImportC ""
  CFDataCreate(allocator, *bytes, length)
  CFRelease(cf)
  CGColorSpaceCreateDeviceGray()
  CGColorSpaceCreateDeviceRGB()
  CGColorSpaceRelease(colorspace)
  CGDataProviderCreateWithCFData(cfdata)
  CGDataProviderRelease(provider)
  CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, space, bitmapInfo, provider, *decode, shouldInterpolate, intent)
  CGImageRelease(image)
EndImport



; create raw grayscale data

Dim GrayScaleData.a(99, 99)
RandomSeed(0)
RandomData(@GrayScaleData(), 100 * 100)

; create cgimage

color = CGColorSpaceCreateDeviceGray()

cfdata = CFDataCreate(#Null, @GrayScaleData(), 100 * 100) 
provider = CGDataProviderCreateWithCFData(cfdata)

image = CGImageCreate(100, 100, 8, 8, 100, color, #kCGBitmapByteOrderDefault|#kCGImageAlphaNone, provider, #Null, #False, #kCGRenderingIntentDefault)

; create purebasic image

rect.NSRect\size\width = 100
rect\size\height = 100

nsimage = CocoaMessage(0, CocoaMessage(0, 0, "NSImage alloc"), "initWithCGImage:", image, "size:@", @rect\size)
CreateImage(0, 100, 100)
StartDrawing(ImageOutput(0))
CocoaMessage(0, nsimage, "drawInRect:@", @rect)
CocoaMessage(0, nsimage, "release")
StopDrawing()

; release some things

CGDataProviderRelease(provider)
CFRelease(cfdata)
CGColorSpaceRelease(color)

; show result

If OpenWindow(0, 0, 0, 100, 100, "Image test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ImageGadget(0, 0, 0, 100, 100, ImageID(0))
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
It uses CocoaMessage(0, nsimage, "drawInRect:@", @rect) to draw the image.
Windows (x64)
Raspberry Pi OS (Arm64)
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Re: Using CGImageCreate to create an image in PureBasic

Post by coder14 »

wilbert wrote:It uses CocoaMessage(0, nsimage, "drawInRect:@", @rect) to draw the image.
This does not work on 10.7 but works on 10.11. I get an error that the object does not support drawInRect.

Anyway I am happy that vector drawing works. Any "drawbacks" for using it? :P
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Using CGImageCreate to create an image in PureBasic

Post by wilbert »

coder14 wrote:Anyway I am happy that vector drawing works. Any "drawbacks" for using it? :P
Not that I know of. :)
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply