How to change screen size from user input value - objective-c

I have one requirement to display image into imageview with aspect ratio from user input dimension. If the user enter the width = 2000, height =500, but my image size is 350x199. How can i fit the aspect ratio of the image into user input. If user enters the 2000 then i need to keep the iPad screen width is 2000 then only i can keep aspect ratio. How can i do this?
imgView=[[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 350, 199)];

This code should help you:
//input data
CGSize screenSize;
CGSize enteredRoomSize;
CGSize originalImageSize;
//ratio calculation
CGFloat widthRatio = screenSize.width / enteredRoomSize.width;
CGFloat heightRatio = screenSize.height / enteredRoomSize.height;
CGFloat minRatio = MIN(widthRatio, heightRatio);
//results calculation
CGSize roomViewSize = CGSizeMake(enteredRoomSize.width * minRatio, enteredRoomSize.height * minRatio);
CGSize imageSize = CGSizeMake(originalImageSize.width * minRatio, originalImageSize.height * minRatio);
If you want to use different ratios for width and height use the following code:
//input data
CGSize screenSize;
CGSize enteredRoomSize;
CGSize originalImageSize;
//ratio calculation
CGFloat widthRatio = screenSize.width / enteredRoomSize.width;
CGFloat heightRatio = screenSize.height / enteredRoomSize.height;
//results calculation
CGSize imageSize = CGSizeMake(originalImageSize.width * widthRatio, originalImageSize.height * heightRatio);

Related

In iOS, how to convert a web image into a less-quality one?

The app downloads images from the web and shows them in a table view as thumbnails. However, the quality of these image are "too good". They are HD quality and if there are too many images in a table view, it might slow down the UI a bit.
Before I set the image to a cell, how to make it "less quality"? (occupying less memory & requiring less processing power to show them)
I tried something like this:
let smallerImage = UIImage(CGImage: image.CGImage!, scale: 0.2, orientation: image.imageOrientation)
but it's not working as expected. What's the right way to do it?
Here is my working code from an old project from before the Swift era. An extra parameter maxLength passes the maximum height and width to use (for portrait it's max height, for landscape it's max width). Hope you know how to translate from Ojbective-C to Swift:
- (UIImage *) scaleImage: (UIImage *) image toMax: (float) maxLength
{
//scale down image to fit withing square of maxLength x maxLength
CGSize size = image.size;
printf("scaleImage source size: %f, %f\n", size.width, size.height);
float scaleX = size.width / maxLength;
float scaleY = size.height / maxLength;
float scale = scaleX > scaleY ? scaleX : scaleY;
int newWidth = round(size.width / scale);
int newHeight = round(size.height / scale);
CGSize newSize = CGSizeMake(size.width / scale, size.height / scale);
printf("scaleImage new size: %d, %d\n", newWidth, newHeight);
UIGraphicsBeginImageContext( newSize );// a CGSize that has the size you want
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
//image is the original UIImage
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Applying such scaling does indeed limit the total memory consumed by the thumbnails.

Rotate around the center of a CCLabelTTF as achnor point

I want to rotate a CCLabelTTF around it's center.
But it doesn't look like it. It does look more like a rotation at the bottom of the CCLabelTTF.
Code:
CCLabelTTF *aLabel ... init/addChild and so on
CCRotateBy *rotateLabelA = [[CCRotateBy alloc] initWithDuration:0.5f angle:-60.0f];
aLabel.string = #"0";
aLabel.anchorPoint = ccp(0.5f, 0.5f);
[aLabel runAction:rotateLabelA];
How to rotate a letter around its visible center, if it is a CCLabelTTF?
I was able to make the boundary box of a CCLabelTTF visible:
As seen in the image, the bounding box is much bigger. But there isn't a formula to determine the middle of the letter.
If you set anchorPoint = cpp(0.5f,0.5f) to some ccNode object, it will rotate around its center, which is calculated using boundingBox property.
The problem is the label's boundingBox.size.height differs with it's actual height. That is why it rotates not around the center.
I am not sure in such a manual solution, but it worked for me someday.
CCLabelTTF *label = [CCLabelTTF labelWithString:#"0" fontName:#"Marker Felt"fontSize:24];
label.position = ccp(winSize.width /2.0f, winSize.height / 2.0f);
float fontSize = label.fontSize; // actual Font size
float labelHeight = label.contentSize.height; // actual label height ( the same as boundingBox.size.height
float offset = (labelHeight - fontSize - (labelHeight - fontSize) / 2.0f) / labelHeight / 2.0f;
label.anchorPoint = ccp(0.5f, 0.5f + offset);
[layer addChild:label];
[label runAction:[CCRotateBy actionWithDuration:10.0f angle:-360]];
I found out how to find the middle point of an CCLabelTTF:
float fontSize = bLabel.fontSize; // actual Font size in pixels
float labelHeight = bLabel.contentSize.height; // actual label height ( the same as boundingBox.size.height )
float offset = labelHeight - fontSize; // the free room under the font
float halfFontSize = fontSize / 2;
float percentMiddleOfFont = (halfFontSize + offset) / labelHeight;
bLabel.anchorPoint = ccp(0.5f, percentMiddleOfFont);

UIImage resize and crop to fit frame

I know this question has been asked several times, but their answers make my images loose quality. They all become pixelated. So even though it crops and resizes correctly it looses quality.
Just so you can check it, this is the algorithm which is in every post:
- (UIImage*)scaleAndCropImage:(UIImage *)aImage forSize:(CGSize)targetSize
{
UIImage *sourceImage = aImage;
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
if (CGSizeEqualToSize(imageSize, targetSize) == NO)
{
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if (widthFactor > heightFactor)
{
scaleFactor = widthFactor; // scale to fit height
}
else
{
scaleFactor = heightFactor; // scale to fit width
}
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if (widthFactor > heightFactor)
{
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
}
else
{
if (widthFactor < heightFactor)
{
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
}
UIGraphicsBeginImageContext(targetSize); // this will crop
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
if(newImage == nil)
{
NSLog(#"could not scale image");
}
//pop the context to get back to the default
UIGraphicsEndImageContext();
return newImage;
}
On the line where your begin the UIGraphicsImageContext, use UIGraphicsBeginImageContextWithOptions instead of UIGraphicsBeginImageContext. Try something like this:
UIGraphicsBeginImageContextWithOptions(targetSize, NO, 0.0)
Notice the three parameters passed above, I'll go through them in order:
targetSize is the size of the image measured in points (not pixels)
NO is a BOOL value (could be YES or NO) that indicates whether the image is 100% opaque or not. Setting this to NO will preserve transparency and create an alpha channel to handle transparency.
The most important part of the above code is the final parameter, 0.0. This is the image scale factor that will be applied. Specifying the value to 0.0 sets the scale factor of the current device's screen. This means that the quality will be preserved, and look especially good on Retina Displays.
Here's the Apple Documentation on UIGraphicsBeginImageContextWithOptions.
You should use UIGraphicsBeginImageContextWithOptions(targetSize, false, 0.0) instead of UIGraphicsBeginImageContext(targetSize) so the correct scale factor gets applied to the bitmap.
Specifying 0.0 as scale factor, sets the scale factor to that from the device's main screen.
Calling only UIGraphicsBeginImageContext() is the same as calling
UIGraphicsBeginImageContextWithOptions(..) with a scale factor of 1.0
for more details take a look at: http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/Reference/reference.html#//apple_ref/c/func/UIGraphicsBeginImageContextWithOptions

Attach UILabel to image thumbnail bottom (varying heights)

I have a view with image view and Label. Image view displays images of varying sizes and it is fixed to the top(see image) I want to dynamically glue text label to the bottom of every image without any space between image thumbnail and UILabel.
You can do that programically. I assume that you have UILabel attached to "label" and the image to "imageView" variables.
CGRect labelFrame = label.frame;
labelFrame.origin.y = imageView.frame.origin.y + imageView.frame.size.height + any_space_you_want_between_image_and_label;
label.frame = labelFrame;
That will change the position of label just bellow the imageView. I hope this helps.
Because as you mentioned you use UIViewContentModeScaleAspectFit for the content mode the solution is a bit harder.
You have to actually calculate the final height of the image (the actual size of the image inside the UIImageView):
//UIImage *img = ...; UIImageView *imgView = ....
CGFloat imageWidth = img.size.width;
CGFloat imageHeight = img.size.height;
CGFloat viewWidth = imgView.frame.size.width;
CGFloat viewHeight = imgView.frame.size.height;
float actualHeight = imageHeight * viewWidth / imageWidth;
// this is the actual height of the UIImage inside the UIImageView
CGRect labelFrame = label.frame;
labelFrame.origin.y = imageView.frame.origin.y + actualHeight + any_space_you_want_between_image_and_label;
label.frame = labelFrame;

CGRect changes width when device rotated

I want to draw a XoY coordinate axis... The axis are CGRects .. the thing is they change width when the device is rotated ... I would want them to maintain their with in all rotations. Does width 5.0 mean different things when the device is in portrait rather than landscape?
Here is the code:
CGContextSaveGState(ctx);
CGContextSetFillColorWithColor(ctx, [[UIColor whiteColor] CGColor]);
// the axis is a rect ...
//axis start point
CGFloat axisStartX = viewBounds.size.width * LEFT_EXCLUSION_LENGTH_PERCENT;
CGFloat axisStartY = viewBounds.size.height * UNDER_EXCLUSION_LENGTH_PERCENT;
CGFloat axisLength = viewBounds .size.height - (viewBounds.size.height * OVER_EXCLUSION_LENGTH_PERCENT) - viewBounds.size.height * UNDER_EXCLUSION_LENGTH_PERCENT;
CGContextAddRect(ctx, CGRectMake(axisStartX, axisStartY, AXIS_LINE_WIDTH, axisLength));
CGContextFillPath(ctx);
CGContextRestoreGState(ctx);
I would not know what you are up to with this calculation, but viewBounds.size.height may change on rotation, depending on what it represents. But if its height varies for different orientations then the axisLength will vary too. And axisLength is the height of your rect.
If you want you rect to be of same size in every orientation than do this!
CGContextSaveGState(ctx);
CGContextSetFillColorWithColor(ctx, [[UIColor whiteColor] CGColor]);
// the axis is a rect ...
//axis start point
CGFloat boxSize = MIN(viewBounds.size.width, viewBounds.size.height);
CGFloat axisStartX = boxSize * LEFT_EXCLUSION_LENGTH_PERCENT;
CGFloat axisStartY = boxSize * UNDER_EXCLUSION_LENGTH_PERCENT;
CGFloat axisLength = boxSize - (boxSize * OVER_EXCLUSION_LENGTH_PERCENT) - boxSize * UNDER_EXCLUSION_LENGTH_PERCENT;
CGContextAddRect(ctx, CGRectMake(axisStartX, axisStartY, AXIS_LINE_WIDTH, axisLength));
CGContextFillPath(ctx);
CGContextRestoreGState(ctx);
The idea here is that whatever the orientation is, the size remains same and visible on screen.
hope that helps!