Re: Image classes (Re: How to detect a Retina Mac)
FYI, I went into this question in some detail in this talk from WWDC 2009: Session 111: NSImage in Snow Leopardhttps://deimos.apple.com/WebObjects/Core.woa/BrowsePrivately/adc.apple.com.2233538716.02233538722.2238039498?i=1820509221 The last part of the talk is a discussion of the differences between the different APIs available, and when you'd use what. Can result in odd behavior, for example scaling the the cached bitmap instead of re-rasterizing the PDF or even using the cached bitmap when printing (yikes!). Marcel, you shouldn't have seen this since 10.6. :-) -ken On Wed, Aug 21, 2013 at 1:49 AM, Marcel Weiher marcel.wei...@gmail.comwrote: On Aug 20, 2013, at 18:02 , Uli Kusterer witness.of.teacht...@gmx.net wrote: On Aug 20, 2013, at 12:36 PM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: Well that much I know. And I also know that many NS/UI-things (which use Objective-C) often have a CF-counterpart, which uses plain C and often these are toll-free bridged. The latter kind is typically used when one needs more options or finer control. (E.g. NSDictionary / CFDictionary). But what is the story behind NS/UIView relative to CIImage, CGImage? When to use what? What are the relevant advantages? I would really like to get some link to some documentation, which explains these questions. NSImage/UIImage: Highest-level image abstraction, usually independent of pixels (e.g. may hold vector graphics, values are measured in Points, not pixels) CGImage: Highest-level pixel-based representation of an image, mostly measured in actual pixels, you have to do all Retina-work yourself. CIImage: Abstraction on top of textures on a graphics card for use as images. Useful if you want to quickly apply effects (CIFilter, transitions etc.) to an image, because the image is kept in GPU memory instead of RAM, so for applying several filters you save repeated up/downloads, and the filters run on many cores on the GPU, instead of blocking the few CPU cores your phone has. Note that the abstraction is transparent. E.g. for bitmap images, NSImage these days uses a CGImageRef under the hood. Also, CGImageRefs try to be smart about keeping image data on the GPU if they can (so conceptually use CIImage, if not actually). NSImage: a container format for multiple representations of an image for optimized display. Can contain different image representations (NSImageReps), for example a PDF and bitmaps at multiple resolutions, and will create additional cached representation(s) if the display and the available representations don’t match, for example rasterizing a PDF for you and then using that rasterized representation for you. Can result in odd behavior, for example scaling the the cached bitmap instead of re-rasterizing the PDF or even using the cached bitmap when printing (yikes!). If you want control, don’t use this (devs have been learning this lesson over and over since early NeXTStep days). I think of it as the NSIcon class. (Note: since 10.6 there has been some access to the selection mechanism with bestRepresentationForRect:context:hints:) UIImage / NSBitmapImageRep / CGImage: a bitmap in UIKit, AppKit and CoreGraphics, respectively Both UIImage and NSBitmapImageRep wrap a CGImage(Ref) (UIImage always did, with NSBitmapImageRep this happened a while ago, I think in Leopard). To the best of my knowledge, UIImage is equivalent to NSBitmapImageRep, not NSImage, because it does not allow vector data. Due to the history of NSBitmapImageRep, it does have methods for direct access to the bitmap data, but because it is now a wrapper for CGImageRef, using those tends to be somewhat inefficient, requiring sending the bitmap data back and forth between graphics card and main memory. IIRC, the recommended way of getting the color at a pixel is to create a context and draw the image into the context with appropriate clipping. That way, the extraction can be done on the graphics card and only the result shipped back to the CPU. In UIImage, they dropped support for the direct access methods. CIImage: for CoreImage, a virtual image Although a CIImage object has image data associated with it, it is not an image. You can think of a CIImageobject as an image “recipe.” A CIImage object has all the information necessary to produce an image, but Core Image doesn’t actually render an image until it is told to do so. This “lazy evaluation” method allows Core Image to operate as efficiently as possible.” The recipe is executed if you draw the CIImage on a context or initialize another type of image with it. I personally know very little about CIImage, have only used it a couple of times. Are there interesting uses for this outside of CoreImage? Marcel ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list.
Image classes (Re: How to detect a Retina Mac)
On Aug 20, 2013, at 18:02 , Uli Kusterer witness.of.teacht...@gmx.net wrote: On Aug 20, 2013, at 12:36 PM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: Well that much I know. And I also know that many NS/UI-things (which use Objective-C) often have a CF-counterpart, which uses plain C and often these are toll-free bridged. The latter kind is typically used when one needs more options or finer control. (E.g. NSDictionary / CFDictionary). But what is the story behind NS/UIView relative to CIImage, CGImage? When to use what? What are the relevant advantages? I would really like to get some link to some documentation, which explains these questions. NSImage/UIImage: Highest-level image abstraction, usually independent of pixels (e.g. may hold vector graphics, values are measured in Points, not pixels) CGImage: Highest-level pixel-based representation of an image, mostly measured in actual pixels, you have to do all Retina-work yourself. CIImage: Abstraction on top of textures on a graphics card for use as images. Useful if you want to quickly apply effects (CIFilter, transitions etc.) to an image, because the image is kept in GPU memory instead of RAM, so for applying several filters you save repeated up/downloads, and the filters run on many cores on the GPU, instead of blocking the few CPU cores your phone has. Note that the abstraction is transparent. E.g. for bitmap images, NSImage these days uses a CGImageRef under the hood. Also, CGImageRefs try to be smart about keeping image data on the GPU if they can (so conceptually use CIImage, if not actually). NSImage: a container format for multiple representations of an image for optimized display. Can contain different image representations (NSImageReps), for example a PDF and bitmaps at multiple resolutions, and will create additional cached representation(s) if the display and the available representations don’t match, for example rasterizing a PDF for you and then using that rasterized representation for you. Can result in odd behavior, for example scaling the the cached bitmap instead of re-rasterizing the PDF or even using the cached bitmap when printing (yikes!). If you want control, don’t use this (devs have been learning this lesson over and over since early NeXTStep days). I think of it as the NSIcon class. (Note: since 10.6 there has been some access to the selection mechanism with bestRepresentationForRect:context:hints:) UIImage / NSBitmapImageRep / CGImage: a bitmap in UIKit, AppKit and CoreGraphics, respectively Both UIImage and NSBitmapImageRep wrap a CGImage(Ref) (UIImage always did, with NSBitmapImageRep this happened a while ago, I think in Leopard). To the best of my knowledge, UIImage is equivalent to NSBitmapImageRep, not NSImage, because it does not allow vector data. Due to the history of NSBitmapImageRep, it does have methods for direct access to the bitmap data, but because it is now a wrapper for CGImageRef, using those tends to be somewhat inefficient, requiring sending the bitmap data back and forth between graphics card and main memory. IIRC, the recommended way of getting the color at a pixel is to create a context and draw the image into the context with appropriate clipping. That way, the extraction can be done on the graphics card and only the result shipped back to the CPU. In UIImage, they dropped support for the direct access methods. CIImage: for CoreImage, a virtual image Although a CIImage object has image data associated with it, it is not an image. You can think of a CIImageobject as an image “recipe.” A CIImage object has all the information necessary to produce an image, but Core Image doesn’t actually render an image until it is told to do so. This “lazy evaluation” method allows Core Image to operate as efficiently as possible.” The recipe is executed if you draw the CIImage on a context or initialize another type of image with it. I personally know very little about CIImage, have only used it a couple of times. Are there interesting uses for this outside of CoreImage? Marcel ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 19 Aug 2013, at 19:18, Alex Zavatone z...@mac.com wrote: Sent from my iPad On Aug 18, 2013, at 11:16 AM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: But I do not understand it. CIImage, CGImage, NSImage I know it's not much, but CI = Core Image, CG = Core Graphics and NS = Next Step (Mac). UI Image would be for iOS, if I'm not mistaken. Well that much I know. And I also know that many NS/UI-things (which use Objective-C) often have a CF-counterpart, which uses plain C and often these are toll-free bridged. The latter kind is typically used when one needs more options or finer control. (E.g. NSDictionary / CFDictionary). But what is the story behind NS/UIView relative to CIImage, CGImage? When to use what? What are the relevant advantages? I would really like to get some link to some documentation, which explains these questions. Kind regards, Gerriet. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On Aug 20, 2013, at 12:36 PM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: On 19 Aug 2013, at 19:18, Alex Zavatone z...@mac.com wrote: Sent from my iPad On Aug 18, 2013, at 11:16 AM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: But I do not understand it. CIImage, CGImage, NSImage I know it's not much, but CI = Core Image, CG = Core Graphics and NS = Next Step (Mac). UI Image would be for iOS, if I'm not mistaken. Well that much I know. And I also know that many NS/UI-things (which use Objective-C) often have a CF-counterpart, which uses plain C and often these are toll-free bridged. The latter kind is typically used when one needs more options or finer control. (E.g. NSDictionary / CFDictionary). But what is the story behind NS/UIView relative to CIImage, CGImage? When to use what? What are the relevant advantages? I would really like to get some link to some documentation, which explains these questions. NSImage/UIImage: Highest-level image abstraction, usually independent of pixels (e.g. may hold vector graphics, values are measured in Points, not pixels) CGImage: Highest-level pixel-based representation of an image, mostly measured in actual pixels, you have to do all Retina-work yourself. CIImage: Abstraction on top of textures on a graphics card for use as images. Useful if you want to quickly apply effects (CIFilter, transitions etc.) to an image, because the image is kept in GPU memory instead of RAM, so for applying several filters you save repeated up/downloads, and the filters run on many cores on the GPU, instead of blocking the few CPU cores your phone has. Note that the abstraction is transparent. E.g. for bitmap images, NSImage these days uses a CGImageRef under the hood. Also, CGImageRefs try to be smart about keeping image data on the GPU if they can (so conceptually use CIImage, if not actually). Cheers, -- Uli Kusterer The Witnesses of TeachText are everywhere... http://www.zathras.de ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On Aug 20, 2013, at 12:36 PM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: Well that much I know. And I also know that many NS/UI-things (which use Objective-C) often have a CF-counterpart, which uses plain C and often these are toll-free bridged. The latter kind is typically used when one needs more options or finer control. (E.g. NSDictionary / CFDictionary). But what is the story behind NS/UIView relative to CIImage, CGImage? When to use what? What are the relevant advantages? One more note (I presume you're aware of that, but since you're not 100% clear about that in your phrasing above): CGImage and NSImage are not toll-free bridged. CGImageRef is more of an equivalent to NSBitmapImageRep than NSImage. Cheers, -- Uli Kusterer The Witnesses of TeachText are everywhere... http://www.zathras.de ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 19 Aug 2013, at 06:41, Marcel Weiher marcel.wei...@gmail.com wrote: My problem is: ... some drawing here ... seems to assume a locked NSImage in place. It looks like: NSUInteger graphicIndex = [graphics count]; while (graphicIndex-- 0) { SKTGraphic *graphic = graphics[graphicIndex]; [currentContext saveGraphicsState]; // next line uses current graphics context [NSBezierPath clipRect:[graphic drawingBounds]]; // next line will do e.g. NSBezierPath stroke and drawGlyphsForGlyphRange:atPoint: // for the latter: focus must already be locked on the destination view or image [graphic drawContentsInView:nil isBeingCreateOrEdited:NO]; [currentContext restoreGraphicsState]; }; so drawing directly via CGContext... stuff is not really an option. I tried: NSImage *image = [[NSImage alloc] initWithSize: sizE]; NSBitmapImageRep *imageRep =[ [ NSBitmapImageRep alloc ] initWithBitmapDataPlanes:... [ image addRepresentation: imageRep ]; [image lockFocus]; ... some drawing here ... (see above) [image unlockFocus]; At this point my image has a representation: NSCGImageSnapshotRep:0x100675b60 cgImage=CGImage 0x100675a80 but my carefully crafted NSBitmapImageRep has been ignored and removed. I also tried (before [image lockFocus]: NSGraphicsContext *bitmapContext = [ NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep ]; [NSGraphicsContext setCurrentContext: bitmapContext ]; But after [image lockFocus] the currentContext changes to: NSSnapshotBitmapGraphicsContext. I seem to need a way to tell NSImage NOT to double the pixels for me, but I don't see any way to do this. Like: [ image setBackingScaleFactor: 1 ] but no such method seems to exist. So hardcoding the retina-ness of my current computer seems to be the only solution. Kind regards, Gerriet. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
Il giorno 19/ago/2013, alle ore 09:01, Gerriet M. Denkmann gerr...@mdenkmann.de ha scritto: On 19 Aug 2013, at 06:41, Marcel Weiher marcel.wei...@gmail.com wrote: [...] I also tried (before [image lockFocus]: NSGraphicsContext *bitmapContext = [ NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep ]; [NSGraphicsContext setCurrentContext: bitmapContext ]; But after [image lockFocus] the currentContext changes to: NSSnapshotBitmapGraphicsContext. in this case, you should not use -lockFocus: since you have already created and set the new context, you just need to start drawing -- Simone Tellini http://tellini.info ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
I seem to need a way to tell NSImage NOT to double the pixels for me, but I don't see any way to do this. Have you tried my sample code? This part seems to be what you're looking for: NSBitmapImageRep *bmpImageRep = [NSBitmapImageRep imageRepWith32bitBuffer:NULL pixelsWide:size.width * scale pixelsHigh:size.height * scale bitmapFormat:0 bytesPerRow:0]; // Setting the user size communicates the dpi. [bmpImageRep setSize:size]; return bmpImageRep; ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 19/08/2013, at 9:01 AM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: I seem to need a way to tell NSImage NOT to double the pixels for me, but I don't see any way to do this. Like: [ image setBackingScaleFactor: 1 ] but no such method seems to exist. So hardcoding the retina-ness of my current computer seems to be the only solution. Of course it isn't. Marcel's answer looks correct to me - forget NSImage, use NSBitmapImageRep instead (without adding it to an NSImage). Instead of -lockFocus, etc, just create a context using the bitmap rep and set it as the current context. Then you can draw using either high-level stuff that uses the current context or lower level CG... functions. The problem you're running into is that NSImage is trying to be too darn smart. Don't give it the chance, by not using it AT ALL. --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 19 Aug 2013, at 14:17, Lee Ann Rucker lruc...@vmware.com wrote: I seem to need a way to tell NSImage NOT to double the pixels for me, but I don't see any way to do this. Have you tried my sample code? This part seems to be what you're looking for: NSBitmapImageRep *bmpImageRep = [NSBitmapImageRep imageRepWith32bitBuffer:NULL pixelsWide:size.width * scale pixelsHigh:size.height * scale bitmapFormat:0 bytesPerRow:0]; // Setting the user size communicates the dpi. [bmpImageRep setSize:size]; return bmpImageRep; Yes, I did try this. But at that point I was still using NSImage, which, as Graham pointed out, is NOT really a good idea. Thanks for your help! Kind regards, Gerriet. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 19 Aug 2013, at 14:17, Graham Cox appt...@me.com wrote: On 19/08/2013, at 9:01 AM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: I seem to need a way to tell NSImage NOT to double the pixels for me, but I don't see any way to do this. Like: [ image setBackingScaleFactor: 1 ] but no such method seems to exist. So hardcoding the retina-ness of my current computer seems to be the only solution. Of course it isn't. Marcel's answer looks correct to me - forget NSImage, use NSBitmapImageRep instead (without adding it to an NSImage). Instead of -lockFocus, etc, just create a context using the bitmap rep and set it as the current context. Then you can draw using either high-level stuff that uses the current context or lower level CG... functions. The problem you're running into is that NSImage is trying to be too darn smart. Don't give it the chance, by not using it AT ALL. Yes, this really the crux of the matter. Once I eliminated NSImage, everything started working. Here is the final code (if there is anything wrong or not quite right, please feel free to critizise it): #define USE_IMAGEx // Off. Works, but has Retina hard-coded. #ifdef USE_IMAGE finalWidth /= 2;// hardcoded Retina Fix #endif CGFloat scaleFactor = finalWidth / bounds.size.width; NSSize sizE = NSMakeSize( finalWidth, bounds.size.height * scaleFactor ); #ifdef USE_IMAGE NSImage *image = [[NSImage alloc] initWithSize: sizE]; [image setFlipped:YES]; [image lockFocus]; #else // USE_BITMAP NSInteger width = (NSInteger)sizE.width; NSInteger height = (NSInteger)sizE.height; NSInteger bps = 8; NSInteger spp = 4;//RGBA NSBitmapImageRep *imageRep =[ [ NSBitmapImageRep alloc ] initWithBitmapDataPlanes: NULL pixelsWide: width pixelsHigh: height bitsPerSample: bps samplesPerPixel: spp hasAlpha: YES isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0 ]; NSGraphicsContext *bitmapContext1 = [ NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep ]; void *graphicsPort = [ bitmapContext1 graphicsPort ]; NSGraphicsContext *bitmapContext2 = [ NSGraphicsContext graphicsContextWithGraphicsPort:graphicsPort flipped: YES ]; [NSGraphicsContext setCurrentContext: bitmapContext2 ]; #endif // USE_IMAGE or BITMAP NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; NSLog(@%s currentContext: %@,__FUNCTION__, currentContext);//NSSnapshotBitmapGraphicsContext: 0x1018c1e40 NSAffineTransform *transform = [NSAffineTransform transform]; #ifdef USE_IMAGE [transform scaleXBy: scaleFactor yBy: +scaleFactor ]; [transform translateXBy: -NSMinX(bounds) yBy: -NSMinY(bounds) ]; #else // USE_BITMAP // no idea why these have to be different: [transform scaleXBy: scaleFactor yBy: -scaleFactor ]; [transform translateXBy: -NSMinX(bounds) yBy: -NSMaxY(bounds) ]; #endif //
Re: How to detect a Retina Mac
On 19/08/2013, at 12:05 PM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: Here is the final code (if there is anything wrong or not quite right, please feel free to critizise it): [NSGraphicsContext setCurrentContext: bitmapContext2 ]; You might want to save and restore the current graphics context around the whole thing so that you don't leave it set to your bitmap. It may well be harmless, but always better to play nice. --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 19 Aug 2013, at 17:35, Graham Cox graham@bigpond.com wrote: On 19/08/2013, at 12:05 PM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: Here is the final code (if there is anything wrong or not quite right, please feel free to critizise it): [NSGraphicsContext setCurrentContext: bitmapContext2 ]; You might want to save and restore the current graphics context around the whole thing so that you don't leave it set to your bitmap. It may well be harmless, but always better to play nice. Good idea. I added: NSGraphicsContext *originalContext = [NSGraphicsContext currentContext]; ... do stuff ... [NSGraphicsContext setCurrentContext: originalContext ]; I had indeed some (non-reproducible) error messages, which may very well be the result of this omission: [...]: _initWithWindowNumber: error creating graphics ctxt object for ctxt:0x30917, window:0x Thanks a lot for pointing this out! Kind regards, Gerriet. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 19/08/2013, at 12:56 PM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: NSGraphicsContext *originalContext = [NSGraphicsContext currentContext]; ... do stuff ... [NSGraphicsContext setCurrentContext: originalContext ]; or more simply: [NSGraphicsContext saveGraphicsState]; ... do stuff ... [NSGraphicsContext restoreGraphicsState]; this saves the current context as well as its state --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
Sent from my iPad On Aug 18, 2013, at 11:16 AM, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: But I do not understand it. CIImage, CGImage, NSImage I know it's not much, but CI = Core Image, CG = Core Graphics and NS = Next Step (Mac). UI Image would be for iOS, if I'm not mistaken. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
How to detect a Retina Mac
I just noticed that the program I use to create Png files creates files with twice the number of pixels in each dimension. Obviously because since I last used it, I have switched to a Retina Mac Book. Ok, so I have to fix this program. But: how do I detect that the programm is running on a computer where each pixel is really four pixels? Both NSScreen and NSWindow have a backingScaleFactor property, which seems to be right. But my code does neither involves a screen nor a window: finalWidth = 50;because I want a Png 50 pixels wide finalWidth /= 2;← this fixes my Retina problem, but hardcoding this looks simply wrong CGFloat scaleFactor = finalWidth / bounds.size.width; NSSize sizE = NSMakeSize( finalWidth, bounds.size.height * scaleFactor ); NSImage *image = [[NSImage alloc] initWithSize: sizE]; [image setFlipped:YES]; [image lockFocus]; NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; NSAffineTransform *transform = [NSAffineTransform transform]; [transform scaleXBy: scaleFactor yBy: scaleFactor ]; [transform translateXBy: -bounds.origin.x yBy: -bounds.origin.y ]; [transform concat]; ... do some drawing [image unlockFocus]; NSRect recct = NSMakeRect(0, 0, sizE.width, sizE.height ); [image lockFocus]; NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: recct ]; [image unlockFocus]; NSData *data = [ bitmapImageRep representationUsingType: NSPNGFileType properties: nil ]; ... write data to file So where do I get my backingScaleFactor from? What if there are two screens, one Retina, one not? Kind regards, Gerriet. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 18 Aug 2013, at 15:03, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: I just noticed that the program I use to create Png files creates files with twice the number of pixels in each dimension. Obviously because since I last used it, I have switched to a Retina Mac Book. Ok, so I have to fix this program. The correct way to fix this problem is to create an image via CGContextCreate and CGContextCreateImage. When doing this you specify pixel rather than point dimensions, and do not have the issue you’re experiencing. You detect a retina device by testing scaleFactor as you suggested, it’s just unnecessary here. Tom Davie ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 18 Aug 2013, at 20:09, Tom Davie tom.da...@gmail.com wrote: On 18 Aug 2013, at 15:03, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: I just noticed that the program I use to create Png files creates files with twice the number of pixels in each dimension. Obviously because since I last used it, I have switched to a Retina Mac Book. Ok, so I have to fix this program. The correct way to fix this problem is to create an image via CGContextCreate and CGContextCreateImage. When doing this you specify pixel rather than point dimensions, and do not have the issue you’re experiencing. You detect a retina device by testing scaleFactor as you suggested, it’s just unnecessary here. I just asked Xcode about CGContextCreate and it told me that there is absolutely no information available. Could anybody help me with some link to some documentation? Kind regards, Gerriet. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 18 Aug 2013, at 15:56, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: On 18 Aug 2013, at 20:09, Tom Davie tom.da...@gmail.com wrote: On 18 Aug 2013, at 15:03, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: I just noticed that the program I use to create Png files creates files with twice the number of pixels in each dimension. Obviously because since I last used it, I have switched to a Retina Mac Book. Ok, so I have to fix this program. The correct way to fix this problem is to create an image via CGContextCreate and CGContextCreateImage. When doing this you specify pixel rather than point dimensions, and do not have the issue you’re experiencing. You detect a retina device by testing scaleFactor as you suggested, it’s just unnecessary here. I just asked Xcode about CGContextCreate and it told me that there is absolutely no information available. Could anybody help me with some link to some documentation? Uhh sorry, my bad, I meant CG*Bitmap*ContextCreate… http://developer.apple.com/library/ios/documentation/graphicsimaging/Reference/CGBitmapContext/Reference/reference.html Tom Davie ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
Il giorno 18/ago/2013, alle ore 15:03, Gerriet M. Denkmann gerr...@mdenkmann.de ha scritto: I just noticed that the program I use to create Png files creates files with twice the number of pixels in each dimension. Obviously because since I last used it, I have switched to a Retina Mac Book. Ok, so I have to fix this program. you can do something like this: NSSize size = ...; NSBitmapImageRep*bitmapRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: size.width pixelsHigh: size.height bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bitmapFormat: NSAlphaFirstBitmapFormat bytesPerRow: 0 bitsPerPixel: 0]; NSGraphicsContext *bmCtx; NSAffineTransform *transform = [NSAffineTransform transform]; [bitmapRep setSize: size]; bmCtx = [NSGraphicsContext graphicsContextWithBitmapImageRep: bitmapRep]; bmCtx = [NSGraphicsContext graphicsContextWithGraphicsPort: [bmCtx graphicsPort] flipped: YES]; [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext: bmCtx]; [transform translateXBy: 0 yBy: size.height]; [transform scaleXBy: 1 yBy: -1]; [transform set]; ...do some drawing... [NSGraphicsContext restoreGraphicsState]; data = [bitmapRep representationUsingType: NSPNGFileType properties: nil]; [bitmapRep release]; -- Simone Tellini http://tellini.info ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 18 Aug 2013, at 16:27, Simone Tellini cocoa-...@tellini.info wrote: Il giorno 18/ago/2013, alle ore 15:03, Gerriet M. Denkmann gerr...@mdenkmann.de ha scritto: I just noticed that the program I use to create Png files creates files with twice the number of pixels in each dimension. Obviously because since I last used it, I have switched to a Retina Mac Book. Ok, so I have to fix this program. you can do something like this: NSSize size = ...; NSBitmapImageRep*bitmapRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: size.width pixelsHigh: size.height bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bitmapFormat: NSAlphaFirstBitmapFormat bytesPerRow: 0 bitsPerPixel: 0]; NSGraphicsContext *bmCtx; NSAffineTransform *transform = [NSAffineTransform transform]; [bitmapRep setSize: size]; bmCtx = [NSGraphicsContext graphicsContextWithBitmapImageRep: bitmapRep]; bmCtx = [NSGraphicsContext graphicsContextWithGraphicsPort: [bmCtx graphicsPort] flipped: YES]; [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext: bmCtx]; [transform translateXBy: 0 yBy: size.height]; [transform scaleXBy: 1 yBy: -1]; [transform set]; ...do some drawing... [NSGraphicsContext restoreGraphicsState]; data = [bitmapRep representationUsingType: NSPNGFileType properties: nil]; [bitmapRep release]; No need for the complex cocoa to CG manoeuvrings there, this will do fine: NSSize size = …; CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef ctx = CGBitmapContextCreate(NULL, size.width, size.height, 8, 8 * 4 * size.width, rgbColorSpace, kCGBitmapAlphaInfoMask kCGAlphaLast); CFRelease(rgbColorSpace); … do some drawing … CGImageRef img = CGBitmapContextCreateImage(ctx); CGContextRelease(ctx); return [[[NSImage alloc] initWithCGImage:img size:size] autorelease]; Thanks Tom Davie ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
On 18 Aug 2013, at 21:03, Tom Davie tom.da...@gmail.com wrote: On 18 Aug 2013, at 15:56, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: On 18 Aug 2013, at 20:09, Tom Davie tom.da...@gmail.com wrote: On 18 Aug 2013, at 15:03, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: I just noticed that the program I use to create Png files creates files with twice the number of pixels in each dimension. Obviously because since I last used it, I have switched to a Retina Mac Book. Ok, so I have to fix this program. The correct way to fix this problem is to create an image via CGContextCreate and CGContextCreateImage. When doing this you specify pixel rather than point dimensions, and do not have the issue you’re experiencing. You detect a retina device by testing scaleFactor as you suggested, it’s just unnecessary here. I just asked Xcode about CGContextCreate and it told me that there is absolutely no information available. Could anybody help me with some link to some documentation? Uhh sorry, my bad, I meant CG*Bitmap*ContextCreate… http://developer.apple.com/library/ios/documentation/graphicsimaging/Reference/CGBitmapContext/Reference/reference.html Ah, now I found lots of info! But I do not understand it. CIImage, CGImage, NSImage, UIImage... This is just too much for my small brain. I removed: finalWidth /= 2;// Retina Fix 18.Aug. 2013 and replaced: NSImage *image = [[NSImage alloc] initWithSize: sizE]; by: size_t pixelsWide = (size_t)sizE.width; size_t pixelsHigh = (size_t)sizE.height; size_t bitmapBytesPerRow = pixelsWide * 4; CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); CGContextRef c = CGBitmapContextCreate ( NULL, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast); CGImageRef cgImage = CGBitmapContextCreateImage ( c ); NSImage *image = [[NSImage alloc] initWithCGImage: cgImage size: NSZeroSize ]; (ignoring leaks for the time being) ... and then continued with my old code. The png is still 100 pixels wide. You see, I am rather clueless. Kind regards, Gerriet. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: How to detect a Retina Mac
Adapted from things I picked up at WWDC, this creates an NSImage with normal and Retina representations @implementation NSBitmapImageRep (NSAppKitAdditions) + (NSBitmapImageRep *)imageRepWith32bitBuffer: (unsigned char *)bitmapBuffer // IN/OPT pixelsWide: (int)pixelsWide // IN pixelsHigh: (int)pixelsHigh // IN bitmapFormat: (NSBitmapFormat)bitmapFormat // IN bytesPerRow: (int)bytesPerRow // IN { NSBitmapFormat supportedFormatsMask = NSAlphaNonpremultipliedBitmapFormat | NSAlphaFirstBitmapFormat; NSBitmapImageRep *result = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:bitmapBuffer pixelsWide:pixelsWide pixelsHigh:pixelsHigh bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bitmapFormat:bitmapFormat bytesPerRow:bytesPerRow bitsPerPixel:32] autorelease]; if (!result) { return nil; } /* * If a new buffer has been allocated (not passed in), clear the contents * to prevent garbage data from showing up in unused areas. */ if (!bitmapBuffer [result bitmapData]) { bzero([result bitmapData], [result bytesPerRow] * [result pixelsHigh]); } return result; } + (NSBitmapImageRep *)imageRepWithSize: (NSSize)size // IN scale: (NSUInteger)scale // IN { NSBitmapImageRep *bmpImageRep = [NSBitmapImageRep imageRepWith32bitBuffer:NULL pixelsWide:size.width * scale pixelsHigh:size.height * scale bitmapFormat:0 bytesPerRow:0]; // Setting the user size communicates the dpi. [bmpImageRep setSize:size]; return bmpImageRep; } @end @implementation NSImage (NSAppKitAdditions) /* * Creates an image with high and low DPI representations. * Both representations will be set to the same size. */ + (NSImage *)imageWithSize: (NSSize)size // IN rep1: (NSImageRep *)rep1 // IN rep2: (NSImageRep *)rep2 // IN { if (rep1 == nil || rep2 == nil) { return nil; } NSImage *result = [[[NSImage alloc] initWithSize:size] autorelease]; [rep1 setSize:size]; [rep2 setSize:size]; [result addRepresentation:rep1]; [result addRepresentation:rep2]; return result; } /* * Calls the drawingBlock to generate high and low dpi images. */ + (NSImage *)imageWithSize: (NSSize)size// IN drawingBlock: (NSImageAdditions_DrawingBlock)drawingBlock // IN { NSBitmapImageRep *bitmap1x = [NSBitmapImageRep imageRepWithSize:size scale:1]; NSBitmapImageRep *bitmap2x = [NSBitmapImageRep imageRepWithSize:size scale:2]; [NSGraphicsContext saveGraphicsState]; NSGraphicsContext *bitmapContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap1x]; [NSGraphicsContext setCurrentContext:bitmapContext]; drawingBlock(); bitmapContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap2x]; [NSGraphicsContext setCurrentContext:bitmapContext]; drawingBlock(); [NSGraphicsContext restoreGraphicsState]; return [self imageWithSize:size rep1:bitmap1x rep2:bitmap2x]; } @end - Original Message - From: Gerriet M. Denkmann gerr...@mdenkmann.de To: Tom Davie tom.da...@gmail.com Cc: Cocoa Dev List cocoa-dev@lists.apple.com Sent: Sunday, August 18, 2013 8:16:47 AM Subject: Re: How to detect a Retina Mac On 18 Aug 2013, at 21:03, Tom Davie tom.da...@gmail.com wrote: On 18 Aug 2013, at 15:56, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: On 18 Aug 2013, at 20:09, Tom Davie tom.da...@gmail.com wrote: On 18 Aug 2013, at 15:03, Gerriet M. Denkmann gerr...@mdenkmann.de wrote: I just noticed that the program I use to create Png files creates files with twice the number of pixels in each dimension. Obviously because since I last used it, I have switched to a Retina Mac Book. Ok, so I have to fix this program. The correct way to fix this problem is to create an image via CGContextCreate and CGContextCreateImage. When doing this you specify pixel rather than point dimensions, and do not have the issue you’re experiencing. You detect a retina device by testing scaleFactor as you
Re: How to detect a Retina Mac
Hi Gerriet, On Aug 18, 2013, at 17:16 , Gerriet M. Denkmann gerr...@mdenkmann.de wrote: [Tom Davie] Uhh sorry, my bad, I meant CG*Bitmap*ContextCreate… http://developer.apple.com/library/ios/documentation/graphicsimaging/Reference/CGBitmapContext/Reference/reference.html Ah, now I found lots of info! But I do not understand it. CIImage, CGImage, NSImage, UIImage... This is just too much for my small brain. […] NSImage *image = [[NSImage alloc] initWithCGImage: cgImage size: NSZeroSize ]; (ignoring leaks for the time being) ... and then continued with my old code. The png is still 100 pixels wide. I think the problem may be that you are keeping the NSImage. NSImage is specifically made to deal with images (icons in particular) that you want to display on screen, and my reading of the docs and various forums suggest that NSImage may be doing the doubling for you to be “helpful” (for example: it may be caching your original size image into a representation for the screen, which will have twice the pixels on a Retina display, and then using the “best” representation later on when you want to save, which will be the pixel-doubled one). If you want control over what is happening, my experience is that it's best to avoid NSImage and stick to something like NSBitmapImageRep, for example: NSBitmapImageRep *image = [[[NSBitmapImageRep alloc] initWithCGImage:cgImage] autorelease]; […] Now if all that CG low-level stuff seems a bit verbose, you might want to try MPWDrawingContext: bitmapContext = [MPWCGDrawingContext rgbBitmapContext:NSMakeSize( 50, 50 )]; [… drawing code here …] image = [bitmapContext image];// UIImage on iOS, NSBitmapImageRep on OSX On Github: https://github.com/mpw/MPWDrawingContext Cheers, Marcel ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com