Much better MacOSLib/NSImage Picture conversion quality

One thing that really disturbed me when using MacOSLib was the image conversion quality of a Xojo Picture to a NSImage. Especially when rescaled afterwards the images looked ugly, so I ended up creating different prescaled images to have a somewhat satisfying result, but they looked never as sharp as the System icons.

A scaled Image for a NSStatusItem looked a bit rough anyway, no matter what I tried:

I found the reason for this to be the image conversion via CGImage.
If you modify the NSImage Constructor for a aPicture as Picture by

dim mb as MemoryBlock = aPicture.GetData (Picture.FormatPNG) dim mydata as New NSData (mb)

and pass this NSData to the NSImage constructor from NSData, the result is that much better I wonder if holding differently scaled images is really that necessary:

(This is a different picture but with the same original size and basically just different colors):

It takes a bit longer, but in my eyes the delay is worth the time.

This is technically odd, considering that a CGImage is just bitmap data and all the conversion mechanism should be doing is creating a NSBitmapImageRep and then drawing that bitmap data.

I would take a look into the NSImage meta data, to see what the images’s rep sizes are and the scaling options.

Ideally you shouldn’t be scaling down, you should have representations at the correct sizes (to avoid such issues). I believe that the StatusItem icon is 19 x 19.

[quote=132715:@Ulrich Bogun]One thing that really disturbed me when using MacOSLib was the image conversion quality of a Xojo Picture to a NSImage. Especially when rescaled afterwards the images looked ugly, so I ended up creating different prescaled images to have a somewhat satisfying result, but they looked never as sharp as the System icons.

A scaled Image for a NSStatusItem looked a bit rough anyway, no matter what I tried:

I found the reason for this to be the image conversion via CGImage.
If you modify the NSImage Constructor for a aPicture as Picture by

dim mb as MemoryBlock = aPicture.GetData (Picture.FormatPNG) dim mydata as New NSData (mb)

and pass this NSData to the NSImage constructor from NSData, the result is that much better I wonder if holding differently scaled images is really that necessary:

(This is a different picture but with the same original size and basically just different colors):

It takes a bit longer, but in my eyes the delay is worth the time.[/quote]

I don’t know what macoslib is doing, but it ought to be able to take the CGImage the Xojo framework gives back from Picture.CopyOSHandle and create an NSImage from it via NSImage’s initWithWithCGImage:size: initializer.

Ahhh… I recall I ran into some issues with this function, (although can’t recall exactly), I found I had better results when using

[NSImage initWithSize] [NSImage addRepresentation: [NSBitImageRep initWithCGImage]]

If I can recall exactly why I went with the above method, I’ll list it here for future reference.

Thanks for your answers!

Sam, I didn‘t mean to say the scaling would be different. I have not rechecked this but I have the feeling that the method MacOSLib uses for Xojo Picture conversion (creating a CGIImage via Carbon calls) adds some kind of anti-aliasing even when there is no resize involved (but I‘m not sure about that, will check it soon).

I scaled my images to the needed size before but they did not look that crisp like they are when using the OSHandle. And the excellent scaling methods of NSImage seem to make it unnecessary to hold different images for Retina and standard displays, at least for me. In fact the StatusItem image I posted was scaled down inside the app from a 512 x 512 Application icon.

And thanks for the hint on initWithCGIImage, Joe! Looks like I could skip the NSData conversion then too.

BTW: Sam, do you have any hint on where to get some useful information on ImageReps and CALayers? I looked into the examples from Apple dev but most of them don‘t run on Os X 10.9 – and I find the documentation a bit weak on that part.

Joe, I tried your proposal, and it brings the same result as MacOSLib.

Here is a Picture I imported to a NSImage cast on a NSImageView with scale proportionally – first via the workaround with GetData and NSData:

and the same one via CGIHandle:

The CGI way is a lot faster, but I really prefer the first result.
Differences are visible for unscaled images too.
Any idea why it behaves this way?

To me that looks like a premultiplied-with-alpha problem. Does the original picture have an alpha channel or is it masked?

What are you trying to do? I might be able to give you some tips, but it’s a vast framework and you kinda really need to understand it to use it.

If it’s masked, simply draw it into a new Xojo picture first, although I seem to recall that there is a convenience method (just can’t recall what).

Ulrich : Stupid question if you are interested mostly in declares, but have you tried the code you created from Dr. Gerard Hammond method ? This issue seems exactly like the kind of problem it would solve, and since the size of the picture is real small, speed should be no problem.
https://forum.xojo.com/9403-scale-quality-of-canvas-control?search=Gerard+Hammond

I think the problem is that it’s an alpha channel picture, a masked picture is what you’d want. That’s why GetData(Picture.FormatPNG) “fixes” it because PNG doesn’t do premultiplied, so it must be unmultiplying it in the conversion. Can’t be sure though because all ways of creating a picture produce a masked version except for “new Picture(w, h)”.

Thanks all, expecially for the hint to the reason: Yes, it‘s a PNG with Transparency I‘m using.
First creating a Xojo picture would be something worth a try; right now I‘m opening it from an imported file.

Michel: Thanks, but I wouldn‘t know why to use that method. NSImages use really good scaling routines, the scaled images look a lot like being treated by Photoshop. There’s even optimizations for pure black & white images (Templates). It‘s more the question how to get the image file fast and convenient into a property (and a viewer)

Sam: In the long run, become a Mac OS Guru :wink:
This is partly purely academic and partly because I want to get rid of MacOSLib and have a more lightweight solution – the currently more than 450 warnings make it almost impossible to refine my own code – simply because I don‘t find my warnings in the compiler list.
Current question for me: I have managed to give the CALayer of a Xojo Rectangle (a NSView subclass) a clipping mask (by setting the corner radius). But once I resize the window, it‘s back to normal. To formulate it as a question: “How do I make changes to layers stick; how do I set up & use them as multiple layers?”

At some time surely animation and filter possibilities will become interesting, but I feel that‘s a bit over my head right now.