I'm trying to get the display scaling setting for the current screen so that I can correctly scale inside my OpenGL and/or Vulkan window to match the setting that the OS has. The documentation says to use
float dpi = [window backingScaleFactor];
However this will return 1.0f for no scaling at all, and 2.0f for some scaling.
float dpi = [[window screen] backingScaleFactor];
does the same.
NSRect resolution = [[window screen] frame];
will give you the virtual resolution of the current screen. In System Preferences -> Display -> Scaled, this is the "Looks like" value. For a 3840x2160 screen I have, the possible values are 1920x1080, 2560x1440, 3008x1692, 3360x1890, 3830x2160, depending on the Scaled setting you have chosen. On my MBP's built in screen, which has a native resolution of 2880x1440, the "Looks Like" values can be 1024x640, 1280x800, 1440x900, 1680x1050, 1920x1200. the docs say to use
NSRect test = {0, 0, 1000, 1000};
NSRect dpi = [NSView convertRectToBacking:test];
However this just multiplies the supplied NSRect by the backingScaleFactor.
This is someone trying to get the real resolution of the screen.
So, I want either the real backingScaleFactor, or the native screen resolution for a given NSScreen. Any ideas?
The -backingScaleFactor is giving you the real backing scale factor. The backing store is not the same size as the physical pixel dimensions. Your app renders to the backing store and that is displayed to screen, but that often involves another scaling operation. The right thing for an OpenGL or Vulkan app to do is to render to the backing store resolution, not the physical pixel resolution.
Related
In Interface Builder I have a simple view that contains a UIImageView and am trying to constrain the image view's width and height. I have added constraints several ways but whenever I run in the Simulator the image view does not display correctly but always adopts the dimensions of the PNG image, whose dimensions are smaller than the simulator's device. The Content Mode for the image view is Scale to Fill. I am loading the xib like this:
VCMain *vc = [[VCMain alloc] initWithNibName:#"Main" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:vc];
navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
navControllermodalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:navController animated:YES completion:nil];
I have tried constraining the image view to the superview, and constraining it to the Safe Area, but nothing changes. Regardless of which I choose console printing reveals that the Safe Area always takes on the dimensions of the image view (which oddly takes on the dimensions of the png file, even though the setting is Scale to Fill).
I also tested assigning an image larger than the Simulator's dimensions (using iPhone Xs btw) and smaller. You can see in the pics below that the image view does not conform to the constraints.
What am I doing wrong? And why is the Safe Area conforming rather to the image size? Below are pics of IB that show settings, and then pics showing how the Simulator renders things.
When I use an image smaller than the Simulator device dimensions I get this:
and though you can't see, the Safe Area dimensions are {{0, 0}, {320, 480}}, exactly the size of the PNG.
When I use a version of the image much larger than the Simulator device's dims I get:
and again the Safe Area dimensions are exactly the size of the PNG, in this case {{0, 0}, {2133, 2789}}, even though the main view there has dims of {{0, 0}, {375, 812}}
designer give me picture like this
But when I use drawInRect API draw the picture in context, the picture is like this
The size of the rect is just the size of the image.And the image is #1x and #2x.
the difference is very clear, the picture is blurry and there is a gray line in the right of image, and My imac is retina resolution.
================================================
I have found the reason,
[self.headLeftImage drawInRect:NSMakeRect(100,
100,
self.headLeftImage.size.width,
self.headLeftImage.size.height)];
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextSaveGState(context);
CGContextTranslateCTM(context, self.center.x , self.center.y);
[self.headLeftImage drawInRect:NSMakeRect(100,
100,
self.headLeftImage.size.width,
self.headLeftImage.size.height)];
CGContextRestoreGState(context);
And in the first draw the image will not blur, but after translate the image is blurry. Just like the picture:
The problem is that you're translating the context to a non-integral pixel location. Then, the draw is honoring your request to put the image at a non-integral position, which causes it to be anti-aliased and color in some pixels partially.
You should convert the center point to device space, integral-ize it (e.g. by using floor()), and then convert it back. Use CGContextConvertPointToDeviceSpace() and CGContextConvertPointToUserSpace() to do the conversions. That does the right thing for Retina and non-Retina displays.
I am trying to export a plot generated by my program in the form of a bitmap. No problem with creating a bitmap in memory (with CreateDIBSection) and saving it on the disk (using GDI+). To draw I have to use device context, and the only one that is easily available is compatible with the screen. So I create a compatible dc, select the bitmap I already created into this device context and I am ready to draw and print into the bitmap. And it works - but it gives me no control over the size of the plot (note: size of the plot, not size of the bitmap). If I understand correctly what is happening mapping modes follow DPI of the screen DC which in turn means size of the plot (and text I put on the plot) is different on different computers.
Is there any way of changing the DPI resolution for the device context? Or perhaps there exist a better way of doing what I am trying to do? Perfect solution would be to ask user for the pixel bitmap size and be able to draw a plot that nicely fits the bitmap.
You don't have to use device context to draw now that you already use Gdiplus over GDI. You just associate your Gdiplus::Graphics object with a Gdiplus::Bitmap instead of HDC. Units and transformations let alone bitmap size are all independent of the device. Hope that helps.
Gdiplus::Bitmap bitmap( L"miranda_kerr.png" ); // draw over existing
Gdiplus::Graphics graphics( &bitmap );
Gdiplus::Pen pen( Gdiplus::Color(255,0,0));
Gdiplus::Status status = graphics.DrawLine( &pen, 20, 20, 100, 500 );
//...
My main NSWindow contains UI restricted to some size range, otherwise it can get corrupt. I restrict the window to a size-range using
[myWindow setContentsMaxSize:maxSize]
[myWindow setContentsMinSize:minSize]
This works fine for user dragging of the edges or size-box.
When the user presses "fullscreen" button, Lion starts an animation that will
Shrink the window below its current size,
in several steps, increase its size until it reaches the full-screen representation size.
If the window started in its minimal size, this animation will shrink it BELOW the defined minimal size, and will corrupt my UI beyond repair (user needs to relaunch the app). My views are receiving setFrameSize: with unsupported size.
My questions
Can this be considered a Cocoa bug?
Am I doing something wrong in my view hierarchy?
Can I somehow prevent the corruption, without replacing the OS standard animation for full-screen?
Why doesn't the standard animation base on a "snapshot" of the window contents, instead of
live-resizing of the whole view-hierarchy throughout the animation? This is surely not efficient.
Is there a simple way to apply another standard transition that will
be non-destructive for me?
Can someone "spare" a few lines of code that will do a simple linear resizing animation that will NOT go below minimum?
Thanks.!
I've also investigated fullscreen animation behaviour and here is how it works:
It is also based on taking snapshots of window's content, but with some improvements. It takes several snapshots on some control points: 512, 1024, 2048 and so on.
In my case to enter full screen 2560x1440, my 400 pixels wide window took 512 pixels snapshot, then 1024 and then 2560 wide snapshot. I don't know whether this behaviour is default for all cases, but this is the result of my own investigation.
On the issue with setting min/max window size:
Minimal window size set up in Interface Builder works for me, but max constraints not. I'm currently working on it and this documented method should work for you:
Place this code into your window delegate.
static const NSSize kWindowMinSize = {100, 100};
static const NSSize kWindowMaxSize = {100500, 100500};
...
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
{
frameSize.width = MAX(kWindowMinSize.width, MIN(kWindowMaxSize.width, frameSize.width));
frameSize.height = MAX(kWindowMinSize.height, MIN(kWindowMaxSize.height, frameSize.height));
return frameSize;
}
Hope this will help you!
This is very simple code, but I do not know why Cocos2D continues to scale my background image up by x2?
I'm using the Cocos2d Hello World template. I haven't done anything to the code except delete everything inside of - (id) init
I then added this:
//ADD BACKGROUND
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *background = [CCSprite spriteWithFile:#"justAbackground.png"];
background.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:background];
When I build and run it is double the size then what the image is supposed to be.
If I add:
background.scale = .5;
It is the exact size it's supposed to be.
The images pixel dimensions are exactly the same as the iPhone.
What am I missing here?
Thanks in advance.
Maybe you're confused by point vs pixel coordinates?
On a regular iPhone the point & pixel dimensions are equal and both amount to 480x320 pixels/points. On a Retina device the point coordinates remain 480x320 but the pixel coordinates are doubled to 960x640.
Now if you want to display a regular image using pixel coordinates on a Retina device, you must have Retina display mode disabled. Otherwise cocos2d will scale up any image without the -hd suffix to point dimensions.
The alternative is to have Retina display mode enabled and save your image with the -hd suffix (justAbackground-hd.png) with double the resolution.