UIImage stretch only a portion - iphone

So, lets say i have this sprite:
mbm
bcb
mbm
where each letter is a portion. (m: margin; b: border, c:center)
and I want a class that is able to repeat the b's and c as long as it needs to complete the view so i get something like this:
mbbbbbbbbbbbbbm
bcccccccccccccb
bcccccccccccccb
bcccccccccccccb
mbbbbbbbbbbbbbm
Is there something that can do this already?
If it doesn't exist, any ideas on how to implement it?

Could you not achieve this with this method ?
-(UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight
(see Apple UIImage Class Reference )

We can stretch the image using the below code :- Here we need the m..m must be in same size so we stretch the middle portion
UIImage *image = [UIImage imageNamed:#"img_loginButton.png"];
UIEdgeInsets edgeInsets;
edgeInsets.left = 3.0f; //Assume it is the pixel for starting 'm'
edgeInsets.top = 0.0f;
edgeInsets.right = 3.0f; //Assume it is the pixel for Ending 'm'
edgeInsets.bottom = 0.0f;
image = [image resizableImageWithCapInsets:edgeInsets];
//Use this image as your controls image

Related

divide image into two parts using divider

I'm working on one app where I need to divide a image into two part using a red line.
left part for labels
right part for prices
Question 1.
How can I draw a red line on image?
Question 2.
How can I divide image to two parts using red line ?( red line position is not fixed. user can move the position wherever it want)
Question 3.
How can I get line current position and how can I use that position two divide image
Thanks in advance
I would approach this in somewhat the same manner as koray was suggesting:
1) I am assuming that your above image/view is going to be managed by a view controller, which I will call ImageSeperatorViewController from here on.
Inside of ImageSeperatorViewController, insert koray's code in the -(void) viewDidLoad{} method. Make sure you change the imageToSplit variable to be an UIImageView instead of a plain UIView.
2) Next, I assume that you know how to detect user gestures. You will detect these gestures, and determine if the user has selected the view (i.e. bar in koray's code). Once you have determined if the user has selected bar, just update its origin's X position with the touch position.
CGRect barFrame = bar.frame;
barFrame.origin.x = *X location of the users touch*
bar.frame = barFrame;
3) For cropping, I would not use github.com/bilalmughal/NLImageCropper, it will not do what you need to do.
Try this on for size:
Header:
#interface UIImage (ImageDivider)
- (UIImage*)imageWithDividerAt:(CGFloat)position width:(CGFloat)width color:(UIColor*)color;
- (UIImage*)imageWithDividerAt:(CGFloat)position patternImage:(UIImage*)patternImage;
- (NSArray*)imagesBySlicingAt:(CGFloat)position;
#end
Implementation:
#implementation UIImage (ImageDivider)
- (UIImage*)imageWithDividerAt:(CGFloat)position patternImage:(UIImage*)patternImage
{
//pattern image
UIColor *patternColor = [UIColor colorWithPatternImage:patternImage];
CGFloat width = patternImage.size.width;
//set up context
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
//draw the existing image into the context
[self drawAtPoint:CGPointZero];
//set the fill color from the pattern image color
CGContextSetFillColorWithColor(context, patternColor.CGColor);
//this is your divider's area
CGRect dividerRect = CGRectMake(position - (width / 2.0f), 0, width, self.size.height);
//the joy of image color patterns being based on 0,0 origin! must set phase
CGContextSetPatternPhase(context, CGSizeMake(dividerRect.origin.x, 0));
//fill the divider rect with the repeating pattern from the image
CGContextFillRect(context, dividerRect);
//get your new image and viola!
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
- (UIImage*)imageWithDividerAt:(CGFloat)position width:(CGFloat)width color:(UIColor *)color
{
//set up context
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
//draw the existing image into the context
[self drawAtPoint:CGPointZero];
//set the fill color for your divider
CGContextSetFillColorWithColor(context, color.CGColor);
//this is your divider's area
CGRect dividerRect = CGRectMake(position - (width / 2.0f), 0, width, self.size.height);
//fill the divider's rect with the provided color
CGContextFillRect(context, dividerRect);
//get your new image and viola!
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
- (NSArray*)imagesBySlicingAt:(CGFloat)position
{
NSMutableArray *slices = [NSMutableArray array];
//first image
{
//context!
UIGraphicsBeginImageContext(CGSizeMake(position, self.size.height));
//draw the existing image into the context
[self drawAtPoint:CGPointZero];
//get your new image and viola!
[slices addObject:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
}
//second
{
//context!
UIGraphicsBeginImageContext(CGSizeMake(self.size.width - position, self.size.height));
//draw the existing image into the context
[self drawAtPoint:CGPointMake(-position, 0)];
//get your new image and viola!
[slices addObject:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
}
return slices;
}
The concept is simple - you want an image with the divider drawn over it. You could just overlay a view, or override drawRect:, or any number of any solutions. I'd rather give you this category. It just uses some quick Core Graphics calls to generate an image with your desired divider, be it pattern image or color, at the specified position. If you want support for horizontal dividers as well, it is rather trivial to modify this as such. Bonus: You can use a tiled image as your divider!
Now to answer your primary question. Using the category is rather self explanatory - just call one of the two methods on your source background to generate one with the divider, and then apply that image rather than the original source image.
Now, the second question is simple - when the divider has been moved, regenerate the image based on the new divider position. This is actually a relatively inefficient way of doing it, but this ought to be lightweight enough for your purposes as well as only being an issue when moving the divider. Premature optimization is just as much a sin.
Third question is also simple - call imagesBySlicingAt: - it will return an array of two images, as generated by slicing through the image at the provided position. Use them as you wish.
This code has been tested to be functional. I strongly suggest that you fiddle around with it, not for any purpose of utility, but to better understand the mechanisms used so that next time, you can be on the answering side of things
For Crop you can try this,
UIImage *image = [UIImage imageNamed:#"yourImage.png"];
CGImageRef tmpImgRef = image.CGImage;
CGImageRef topImgRef = CGImageCreateWithImageInRect(tmpImgRef, CGRectMake(0, 0, image.size.width, image.size.height / 2.0));
UIImage *topImage = [UIImage imageWithCGImage:topImgRef];
CGImageRelease(topImgRef);
CGImageRef bottomImgRef = CGImageCreateWithImageInRect(tmpImgRef, CGRectMake(0, image.size.height / 2.0, image.size.width, image.size.height / 2.0));
UIImage *bottomImage = [UIImage imageWithCGImage:bottomImgRef];
CGImageRelease(bottomImgRef);
hope this can help you, :)
if you want to draw a line you could just use a UIView with red background and make the height the size of your image and the width around 5 pixels.
UIView *imageToSplit; //the image im trying to split using a red bar
CGRect i = imageToSplit.frame;
int x = i.origin.x + i.size.width/2;
int y = i.origin.y;
int width = 5;
int height = i.size.height;
UIView *bar = [[[UIView alloc] initWithFrame:CGRectMake(x, y, width, height)] autorelease];
bar.backgroundColor = [UIColor redColor];
[self.view addSubview:bar];

Get Specific Rect of UIImage

Need to fit a UIImage for its frame(which is also a UIImage in own), as frame's thickness is unknown. Images are attached .
How can we detect the rect of same UIColor in UIImage ?
For getting the frame of ain image is as easy as this:
CGRect myFrame = myUIImageView.frame;
Is this what you are asking for?
UIImage *img=[UIImage imageNamed:#"yourimagename.png(any)"];
You can make use of it to set frame as image frames,
CGRect imageFrame=CGRectMake(x,y,img.size.width,img.size.height);
Note:
img.size.width gives you the width of your image and img.size.height gives you the height of your image
You could check the color at pixel (0,0). This would be the color of the frame. Then
you'd go 1px down and 1px left until you get different color - that's how you find
frame thickness.
Like so:
self.yourImage = [UIImage imageNamed:#"painting-with-border.png"];
NSLog(#"original size: %#", NSStringFromCGSize(self.yourImage.size));
BOOL success = NO;
CGFloat x_frame = 1.0;
CGFloat y_frame = 1.0;
CGFloat x_max = self.yourImage.size.width/2.0;
CGFloat y_max = self.yourImage.size.height/2.0;
UIColor *frameColor = [self.yourImage colorAtPixel: CGPointMake (1.0,1.0)];
NSString *hexFrameColor = [frameColor hexStringFromColor];
NSLog (#"frame color: %#", hexFrameColor);
UIColor *testPixelColor;
NSString *hexTestPixelColor;
while ((!success) && (x_frame < x_max) && (y_frame < y_max)) {
x_frame = x_frame + 1.0;
y_frame = y_frame + 1.0;
testPixelColor = [self.yourImage colorAtPixel: CGPointMake (x_frame,y_frame)];
hexTestPixelColor = [testPixelColor hexStringFromColor];
NSLog(#"color at pixel (%.0f,%.0f): %#", x_frame,y_frame,hexTestPixelColor);
if (![hexFrameColor isEqualToString: hexTestPixelColor]) {
success = YES;
NSLog (#"found frame border at (%.0f,%.0f)", x_frame,y_frame);
}
}
CGRect newFrame;
if (success) {
newFrame = CGRectMake(x_frame,y_frame,self.yourImage.size.width-x_frame,self.yourImage.size.height-y_frame);
NSLog(#"To crop image inside frame use: %#", NSStringFromCGRect(newFrame));
} else {
NSLog (#"couldn't define frame width");
}
This method would check the picture for it's frame to the middle of the picture.
Note:
ColorAtPixel is not a part of UIKit. You can get it in Ole Begemann's OBShapedButton.
hexStringFromColor is not a part of UIKit. It's a category you can find at uicolor-utilities.
For cropping UIImage you can then find many ways here on SO but that's not part of your question.
This code was tested with image:
Output was:
original size: {314, 451}
frame color: 980C0C
color at pixel (2,2): 980C0C
color at pixel (3,3): 980C0C
color at pixel (4,4): 980C0C
color at pixel (5,5): 980C0C
color at pixel (6,6): 414429
found frame border at (6,6)
To crop image inside frame use: {{6, 6}, {308, 445}}
NOTE: this method will work only if border is made out of exactly the same color. Some borders in (compressed) .jpg images might have borders where color slightly variates. For that you should use an algorithm that checks color similarity - but that's completely another topic.
Also this code is written for images with frame of the same thickness at all sides. I'm sure you'll be able to modify the code for cases where thickness of the frame on top/bottom differs from thickness on left/right.

Stretching an UIImage while preserving the corners

I'm trying to stretch a navigation arrow image while preserving the edges so that the middle stretches and the ends are fixed.
Here is the image that I'm trying to stretch:
The following iOS 5 code allows the image when resized to stretch the center portions of the image defined by the UIEdgeInsets.
[[UIImage imageNamed:#"arrow.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 7, 15, 15)];
This results in an image that looks like this (if the image's frame is set to 70 pixels wide):
This is actually what I want but resizableImageWithCapInsets is only supported on iOS 5 and later.
Prior to iOS 5 the only similar method is stretchableImageWithLeftCapWidth:topCapHeight but you can only specify the top and left insets which means the image has to have equal shaped edges.
Is there an iOS 4 way of resizing the image the same as iOS 5's resizableImageWithCapInsets method, or another way of doing this?
Your assumption here is wrong:
Prior to iOS 5 the only similar method is stretchableImageWithLeftCapWidth:topCapHeight but you can only specify the top and left insets which means the image has to have equal shaped edges.
The caps are figured out as follows - I'll step through the left cap, but the same principle applies to the top cap.
Say your image is 20px wide.
Left cap width - this is the part on the left hand side of the image that cannot be stretched. In the stretchableImage method you send a value of 10 for this.
Stretchable part - this is assumed to be one pixel in width, so it will be the pixels in column "11", for want of a better description
This means there is an implied right cap of the remaining 9px of your image - this will also not be distorted.
This is taken from the documentation
leftCapWidth
End caps specify the portion of an image that should not be resized when an image is stretched. This technique is used to implement buttons and other resizable image-based interface elements. When a button with end caps is resized, the resizing occurs only in the middle of the button, in the region between the end caps. The end caps themselves keep their original size and appearance.
This property specifies the size of the left end cap. The middle (stretchable) portion is assumed to be 1 pixel wide. The right end cap is therefore computed by adding the size of the left end cap and the middle portion together and then subtracting that value from the width of the image:
rightCapWidth = image.size.width - (image.leftCapWidth + 1);
UIImage *image = [UIImage imageNamed:#"img_loginButton.png"];
UIEdgeInsets edgeInsets;
edgeInsets.left = 0.0f;
edgeInsets.top = 0.0f;
edgeInsets.right = 5.0f; //Assume 5px will be the constant portion in your image
edgeInsets.bottom = 0.0f;
image = [image resizableImageWithCapInsets:edgeInsets];
//Use this image as your controls image
Your example is perfectly possible using stretchableImageWithLeftCapWidth:topCapHeight: with a left cap of 15 (apparently, from reading your code). That will horizontally stretch the button by repeating the middle column.
You can extend UIImage to allow stretching an image with custom edge protection (thereby stretching the interior of the image, instead of tiling it):
UIImage+utils.h:
#import <UIKit/UIKit.h>
#interface UIImage(util_extensions)
//extract a portion of an UIImage instance
-(UIImage *) cutout: (CGRect) coords;
//create a stretchable rendition of an UIImage instance, protecting edges as specified in cornerCaps
-(UIImage *) stretchImageWithCapInsets: (UIEdgeInsets) cornerCaps toSize: (CGSize) size;
#end
UIImage+utils.m:
#import "UIImage+utils.h"
#implementation UIImage(util_extensions)
-(UIImage *) cutout: (CGRect) coords {
UIGraphicsBeginImageContext(coords.size);
[self drawAtPoint: CGPointMake(-coords.origin.x, -coords.origin.y)];
UIImage *rslt = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return rslt;
}
-(UIImage *) stretchImageWithCapInsets: (UIEdgeInsets) cornerCaps toSize: (CGSize) size {
UIGraphicsBeginImageContext(size);
[[self cutout: CGRectMake(0,0,cornerCaps.left,cornerCaps.top)] drawAtPoint: CGPointMake(0,0)]; //topleft
[[self cutout: CGRectMake(self.size.width-cornerCaps.right,0,cornerCaps.right,cornerCaps.top)] drawAtPoint: CGPointMake(size.width-cornerCaps.right,0)]; //topright
[[self cutout: CGRectMake(0,self.size.height-cornerCaps.bottom,cornerCaps.left,cornerCaps.bottom)] drawAtPoint: CGPointMake(0,size.height-cornerCaps.bottom)]; //bottomleft
[[self cutout: CGRectMake(self.size.width-cornerCaps.right,self.size.height-cornerCaps.bottom,cornerCaps.right,cornerCaps.bottom)] drawAtPoint: CGPointMake(size.width-cornerCaps.right,size.height-cornerCaps.bottom)]; //bottomright
[[self cutout: CGRectMake(cornerCaps.left,0,self.size.width-cornerCaps.left-cornerCaps.right,cornerCaps.top)]
drawInRect: CGRectMake(cornerCaps.left,0,size.width-cornerCaps.left-cornerCaps.right,cornerCaps.top)]; //top
[[self cutout: CGRectMake(0,cornerCaps.top,cornerCaps.left,self.size.height-cornerCaps.top-cornerCaps.bottom)]
drawInRect: CGRectMake(0,cornerCaps.top,cornerCaps.left,size.height-cornerCaps.top-cornerCaps.bottom)]; //left
[[self cutout: CGRectMake(cornerCaps.left,self.size.height-cornerCaps.bottom,self.size.width-cornerCaps.left-cornerCaps.right,cornerCaps.bottom)]
drawInRect: CGRectMake(cornerCaps.left,size.height-cornerCaps.bottom,size.width-cornerCaps.left-cornerCaps.right,cornerCaps.bottom)]; //bottom
[[self cutout: CGRectMake(self.size.width-cornerCaps.right,cornerCaps.top,cornerCaps.right,self.size.height-cornerCaps.top-cornerCaps.bottom)]
drawInRect: CGRectMake(size.width-cornerCaps.right,cornerCaps.top,cornerCaps.right,size.height-cornerCaps.top-cornerCaps.bottom)]; //right
[[self cutout: CGRectMake(cornerCaps.left,cornerCaps.top,self.size.width-cornerCaps.left-cornerCaps.right,self.size.height-cornerCaps.top-cornerCaps.bottom)]
drawInRect: CGRectMake(cornerCaps.left,cornerCaps.top,size.width-cornerCaps.left-cornerCaps.right,size.height-cornerCaps.top-cornerCaps.bottom)]; //interior
UIImage *rslt = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return [rslt resizableImageWithCapInsets: cornerCaps];
}
#end
Swift 3.0 version of Vicky's answer.
var imageInset:UIEdgeInsets = UIEdgeInsets()
imageInset.left = 10.0
imageInset.top = 10.0
imageInset.bottom = 10.0
imageInset.right = 10.0
self.myImageView.image = myimage.resizableImage(withCapInsets: imageInset)

Retina display of images-iPhone 3 to 4

I have developed an application of tile game for iPhone 3.
In which I took an image from my resource and divided it into number of tiles using CGImageCreateWithImageInRect ( originalImage.CGImage, frame ); function.
It works great on all iPhones but now I want it to work on Retina Displays also.
So as per this link I have taken anothe image with its size double the current images size and rename it by adding suffix #2x. But the problem is it takes the upper half part of the retina display image only. I think thats because of the frame I have set while using CGImageCreateWithImageInRect. So What shall be done in respect to make this work.
Any kind of help will be really appreciated.
Thanks in advance...
The problem is likely that the #2x image scale is only automatically set up properly for certain initializers of UIImage... Try loading your UIImages using code like this from Tasty Pixel. The entry at that link talks more about this issue.
Using the UIImage+TPAdditions category from the link, you'll implement it like so (after making sure that the images and their #2x counterparts are in your project):
NSString *baseImagePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *myImagePath = [baseImagePath stringByAppendingPathComponent:#"myImage.png"]; // note no need to add #2x.png here
UIImage *myImage = [UIImage imageWithContentsOfResolutionIndependentFile:myImagePath];
Then you should be able to use CGImageCreateWithImageInRect(myImage.CGImage, frame);
Here's how I got it to work in an app I did:
//this is a method that takes a UIImage and slices it into 16 tiles (GridSize * GridSize)
#define GridSize 4
- (void) sliceImage:(UIImage *)image {
CGSize imageSize = [image size];
CGSize square = CGSizeMake(imageSize.width/GridSize, imageSize.height/GridSize);
CGFloat scaleMultiplier = [image scale];
square.width *= scaleMultiplier;
square.height *= scaleMultiplier;
CGFloat scale = ([self frame].size.width/GridSize)/square.width;
CGImageRef source = [image CGImage];
if (source != NULL) {
for (int r = 0; r < GridSize; ++r) {
for (int c = 0; c < GridSize; ++c) {
CGRect slice = CGRectMake(c*square.width, r*square.height, square.width, square.height);
CGImageRef sliceImage = CGImageCreateWithImageInRect(source, slice);
if (sliceImage) {
//we have a tile (as a CGImageRef) from the source image
//do something with it
CFRelease(sliceImage);
}
}
}
}
}
The trick is using the -[UIImage scale] property to figure out how big of a rect you should be slicing.

How do achieve a frame around image

I like the way this (http://shakeitphoto.com/) application puts a border around the image.. i would like to do something similar in my application but not sure how should I go about doing it.
Any ideas on how given a UIImage can I wrap a frame around it?
From that website, it appears you want a border with a shadow. There's 2 reasonable options, 3 if you don't care about the shadow.
If you don't care about the shadow, you can just do something like
#import <QuartzCore/QuartzCore.h> // this should be at the top
// inside your view layout code
myImageView.layer.borderColor = [UIColor whiteColor].CGColor
myImageView.layer.borderWidth = 5;
This will give you a 5-pixel white border inset into the view, layered on top of the view's contents (e.g. the image). What it won't give you is a shadow. If you want the shadow, there's 2 other options.
You could just create an image that includes the border and the shadow, and nothing else. Just make everything else alpha-transparent. Then you can simply layer this image on top of the one you want to display (either with 2 imageviews, or by creating a third image out of the 2). This should work fine, but it won't scale to different image sizes. In the case of the linked app, the image size is always the same so they could be using this.
The other option is to simply draw the border and shadow on top of your image in a new image. Here's a bit of sample code that will do this - it creates a new image the same size as your original, but with a white, shadowed border:
- (UIImage *)borderedImage:(UIImage *)image {
// the following NO means the new image has an alpha channel
// If you know the source image is fully-opaque, you may want to set that to YES
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
[image drawAtPoint:CGPointZero];
CGContextRef ctx = UIGraphicsGetCurrentContext();
const CGFloat shadowRadius = 5;
CGContextSetShadowWithColor(ctx, 0, shadowRadius, [UIColor blackColor].CGColor);
[[UIColor whiteColor] set];
CGRect rect = (CGRect){CGPointZero, image.size};
const CGFloat frameWidth = 5;
rect = CGRectInset(rect, frameWidth / 2.0f, frameWidth / 2.0f);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:rect];
path.lineWidth = frameWidth;
[path stroke];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// note: getting the new image this way throws away the orientation data from the original
// You could create a third image by doing something like
// newImage = [UIImage imageWithCGImage:newImage.CGImage scale:newImage.scale orientation:image.orientation]
// but I am unsure as to how orientation actually affects rendering (if at all)
UIGraphicsEndImageContext();
return newImage;
}
(note: this code has not been compiled and could contain bugs)