i want to draw 12 images in a circle representing the watch numbers, i have read all topics on stackoverflow regarding images with transparent border but it's not working in my case
-(UIImage *)addImageNumber_:(UIImage *)img {
int w = img.size.width;
int h = img.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);
CGContextSetShouldAntialias(context,YES);
CGContextSetAllowsAntialiasing( context ,YES );
CGAffineTransform transform;
for (int x=0; x<=11; x++) {
UIImage *timg1 = [UIImage imageNamed:#"2.png"];
CGRect imageRect = CGRectMake(0, 0, timg1.size.width+2, timg1.size.height+2);
UIGraphicsBeginImageContext(imageRect.size);
[timg1 drawInRect:CGRectMake(1,1,timg1.size.width,timg1.size.height)];
timg1 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
transform = CGAffineTransformIdentity;
CGContextDrawImage(context, CGRectMake((w-26)/2, 0, 26, 30), timg1.CGImage);
transform = CGAffineTransformConcat(transform, CGAffineTransformMakeTranslation(-w/2, -w/2));
transform = CGAffineTransformConcat(transform, CGAffineTransformMakeRotation(radians(30)));
transform = CGAffineTransformConcat(transform, CGAffineTransformMakeTranslation(w/2, w/2));
CGContextConcatCTM(context, transform);
}
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return [UIImage imageWithCGImage:imageMasked];
}
UIViewEdgeAntialiasing = YES;
UIImage *img = [UIImage imageNamed:#"test.png"];
UIImage *img2 = [self addImageNumber_:img ];
R1.image = img2;
[self.view addSubview:R1];
test img is the background of the watch , 2.png is a transparent png with transparent borders
numbers at 12'o clock and 6'o clock looks ok because they are not rotated the rest are jaggy
Never say UIGraphicsBeginImageContext(imageRect.size). Say UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, 0). That way, on a double-resolution screen, you'll get a double-resolution graphics context.
You could even try a resolution value of 4 to increase the resolution even further.
Of course, the fact that you're starting with a pre-drawn image of a "2" might limit your resolution; you can't make a silk purse out of a sow's ear. You could be a lot better off drawing the "2" from scratch as a string.
try
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
Swift 3:
context!.interpolationQuality = .high
Related
I'm trying to add a text to an UIImage and I'm getting a pixelated drawing.
I have tried some other answers with no success:
Drawing on the retina display using CoreGraphics - Image pixelated
Retina display core graphics font quality
Drawing with Core Graphics looks chunky on Retina display
My code:
-(UIImage *)addText:(UIImage *)imgV text:(NSString *)text1
{
int w = self.frame.size.width * 2;
int h = self.frame.size.height * 2;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate
(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), imgV.CGImage);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);
char* text = (char *)[text1 cStringUsingEncoding:NSASCIIStringEncoding];
CGContextSelectFont(context, "Arial", 24, kCGEncodingMacRoman);
// Adjust text;
CGContextSetTextDrawingMode(context, kCGTextInvisible);
CGContextShowTextAtPoint(context, 0, 0, text, strlen(text));
CGPoint pt = CGContextGetTextPosition(context);
float posx = (w/2 - pt.x)/2.0;
float posy = 54.0;
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 255, 255, 255, 1.0);
CGContextShowTextAtPoint(context, posx, posy, text, strlen(text));
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return [UIImage imageWithCGImage:imageMasked];
}
Like Peter said, use UIGraphicsBeginImageContextWithOptions. You might want to pass image.scale to the scale attribute (where image.scale is the scale of one of the images you're drawing), or simply use [UIScreen mainScreen].scale.
This code can be made simpler overall. Try something like:
// Create the image context
UIGraphicsBeginImageContextWithOptions(_baseImage.size, NO, _baseImage.scale);
// Draw the image
CGRect rect = CGRectMake(0, 0, _baseImage.size.width, _baseImage.size.height);
[_baseImage drawInRect:rect];
// Get a vertically centered rect for the text drawing
rect.origin.y = (rect.size.height - FONT_SIZE) / 2 - 2;
rect = CGRectIntegral(rect);
rect.size.height = FONT_SIZE;
// Draw the text
UIFont *font = [UIFont boldSystemFontOfSize:FONT_SIZE];
[[UIColor whiteColor] set];
[text drawInRect:rect withFont:font lineBreakMode:NSLineBreakByClipping alignment:NSTextAlignmentCenter];
// Get and return the new image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
Where text is an NSString object.
I was facing the exact same problem and posted a question last night to which no-one replied. I have combined fnf's suggested changes with Clif Viegas's answer in the following question:
CGContextDrawImage draws image upside down when passed UIImage.CGImage
to come up with the solution. My addText method is slightly different from yours:
+(UIImage *)addTextToImage:(UIImage *)img text:(NSString *)text1{
int w = img.size.width;
int h = img.size.height;
CGSize size = CGSizeMake(w, h);
if (UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
} else {
UIGraphicsBeginImageContext(size);
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0,h);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);
char* text = (char *)[text1 cStringUsingEncoding:NSASCIIStringEncoding];// \"05/05/09\";
CGContextSelectFont(context, "Times New Roman", 14, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 0, 0, 0, 1);
//rotate text
CGContextSetTextMatrix(context, CGAffineTransformMakeRotation( -M_PI/8 ));
CGContextShowTextAtPoint(context, 70, 88, text, strlen(text));
CGColorSpaceRelease(colorSpace);
UIGraphicsEndImageContext();
return newImg;
}
In summary, what I have done is add
if (UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
} else {
UIGraphicsBeginImageContext(size);
}
Remove
// CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
and put
CGContextRef context = UIGraphicsGetCurrentContext();
instead. But this causes the image to be upside down. Hence I put
CGContextTranslateCTM(context, 0,h);
CGContextScaleCTM(context, 1.0, -1.0);
just before
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
This way you can use CG functions instead of using drawInRect etc.
Don't forget
UIGraphicsEndImageContext
at the end. Hope this helps.
I'm creating an image by combining two other images, using CGContext. Even if I have the #2x images, I can't succeed to create an retina image.
Here's my code. Could you please help ?
-(UIImage*)makePinImageWithImage:(UIImage*)icon {
UIImage * pin = [UIImage imageNamed:#"defaultPin.png"]; // I have the #2x one.
int w = pin.size.width;
int h = pin.size.height;
CGRect iconRect = CGRectMake(16, 47, 24, 26); // the frame where mix icon in pin
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 8 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
// Drawing pin in context
CGContextDrawImage(context, CGRectMake(0, 0, w, h), pin.CGImage);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);
// Drawing icon in context
CGContextDrawImage(context, iconRect, icon.CGImage);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);
// Getting back the final image
CGImageRef imageCG = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIImage * createdImage = [UIImage imageWithCGImage:imageCG];
CGImageRelease(imageCG);
return createdImage;
}
Thanks
This code is done in a text window, should more or less do what you want.
(UIImage*)makePinImageWithImage:(UIImage*)icon // this code assumes this image is #2x if the device is
{
UIImage *pin = [UIImage imageNamed:#"defaultPin.png"]; // I have the #2x one.
CGFloat w = rintf(pin.size.width);
CGFloat h = rintf(pin.size.height);
UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), YES, 0); // 0 means let iOS deal with scale for you
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, h);
CGContextConcatCTM(context, flipVertical);
CGRect iconRect = CGRectMake(16, 47, 24, 26); // the frame where mix icon in pin
// Drawing pin in context
CGContextDrawImage(context, CGRectMake(0, 0, w, h), [pin CGImage]); // CGImage is a method, not a property
//CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1); // this does not do anything does it? You never do a FillRect...
// Drawing icon in context
CGContextDrawImage(context, iconRect, [icon CGImage]);
//CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1); // this does not do anything does it? You never do a FillRect...
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image; // will be either normally sized or retina sized depending on environment
}
I try to speed up the scrolling of my UITableView. I do this by do the drawing of the cells by myself instead of adding subviews.
One of the things I want to draw is an image. The image should have rounded edges. When I drew the cell using subviews I altered the layer of the UIImageView to have round corners.
Now I draw the UIImage directly and does not have a layer to modify. How can I draw the image with round edges?
I'm pretty sure I got this code from stackoverflow.
- (UIImage*)maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef sourceImage = [image CGImage];
CGImageRef imageWithAlpha = sourceImage;
//add alpha channel for images that don't have one (ie GIF, JPEG, etc...)
//this however has a computational cost
// needed to comment out this check. Some images were reporting that they
// had an alpha channel when they didn't! So we always create the channel.
// It isn't expected that the wheelin application will be doing this a lot so
// the computational cost isn't onerous.
//if (CGImageGetAlphaInfo(sourceImage) == kCGImageAlphaNone) {
imageWithAlpha = CopyImageAndAddAlphaChannel(sourceImage);
//}
CGImageRef masked = CGImageCreateWithMask(imageWithAlpha, mask);
CGImageRelease(mask);
//release imageWithAlpha if it was created by CopyImageAndAddAlphaChannel
if (sourceImage != imageWithAlpha) {
CGImageRelease(imageWithAlpha);
}
UIImage* retImage = [UIImage imageWithCGImage:masked];
CGImageRelease(masked);
return retImage;
}
and I call it with:
customImage = [customImage maskImage:customImage withMask:[UIImage imageNamed:#"CircularMask.png"]];
[customImageView setImage:customImage];
Hope that helps!
It sounds like you simply want to remove the corners from a rectangular image: Create a new image via CGImage APIs -- you will apply a mask your input image.
Do you use caching for the images?
If so I'd recommend that you apply this to the UIImage before you cache it so once it's been drawn with rounded corners you can reuse that image.
Here's a category on UIImage that you can use to get a rounded UIImage.
I might have found this code somewhere so I apologize in advance to the original author for not giving him/her a credit.
#import <Foundation/Foundation.h>
#interface UIImage (DPRounded)
- (UIImage *)imageWithCornerRadius:(CGFloat)radius;
#end
#implementation UIImage (DPRounded)
static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight)
{
float fw, fh;
if (ovalWidth == 0 || ovalHeight == 0) {
CGContextAddRect(context, rect);
return;
}
CGContextSaveGState(context);
CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextScaleCTM (context, ovalWidth, ovalHeight);
fw = CGRectGetWidth (rect) / ovalWidth;
fh = CGRectGetHeight (rect) / ovalHeight;
CGContextMoveToPoint(context, fw, fh/2);
CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
CGContextClosePath(context);
CGContextRestoreGState(context);
}
- (UIImage *)imageWithCornerRadius:(CGFloat)radius
{
UIImage * newImage = nil;
if(self != nil)
{
int w = self.size.width;
int h = self.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextBeginPath(context);
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
addRoundedRectToPath(context, rect, radius, radius);
CGContextClosePath(context);
CGContextClip(context);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), self.CGImage);
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
newImage = [[UIImage imageWithCGImage:imageMasked] retain];
CGImageRelease(imageMasked);
}
return [newImage autorelease];
}
#end
(Before you embark on this, please check that you're dequeueing table view cells correctly. This will do a lot to improve performance.)
Draw the image yourself with rounded corners and have the background of the cell be transparent, say.
If your cells are of variable height,
Use resizableImageWithCapInsets: (iOS5.0 and up), or the deprecated stretchableImageWithLeftCapWidth:topCapHeight: for earlier iOSes, to return an image that will expand by repeating a central block of your image. This will also protect the curvature of the corners when autoresizing is carried out. Or,
Cut up your image into pieces and have separate UIImageView instances for each piece and set autoresizing appropriately for each piece. This is best option as far as performance goes, but you might end up with as many as nine outlets.
I developing the simple UIApplication in which i want to crop the UIImage (in .jpg format) with help of CGContext. The developed code till now as follows,
CGImageRef graphicOriginalImage = [originalImage.image CGImage];
UIGraphicsBeginImageContext(originalImage.image.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGBitmapContextCreateImage(graphicOriginalImage);
CGFloat fltW = originalImage.image.size.width;
CGFloat fltH = originalImage.image.size.height;
CGFloat X = round(fltW/4);
CGFloat Y =round(fltH/4);
CGFloat width = round(X + (fltW/2));
CGFloat height = round(Y + (fltH/2));
CGContextTranslateCTM(ctx, 0, image.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGRect rect = CGRectMake(X,Y ,width ,height);
CGContextDrawImage(ctx, rect, graphicOriginalImage);
croppedImage = UIGraphicsGetImageFromCurrentImageContext();
return croppedImage;
}
The above code is worked fine but it can't crop image.
The original image memory and cropped image memory i will got same(equal to original image memory).
The above code is right for cropping the image??????????????????
Here is a good way to crop an image to a CGRect:
- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect
{
//create a context to do our clipping in
UIGraphicsBeginImageContext(rect.size);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
//create a rect with the size we want to crop the image to
//the X and Y here are zero so we start at the beginning of our
//newly created context
CGRect clippedRect = CGRectMake(0, 0, rect.size.width, rect.size.height);
CGContextClipToRect( currentContext, clippedRect);
//create a rect equivalent to the full size of the image
//offset the rect by the X and Y we want to start the crop
//from in order to cut off anything before them
CGRect drawRect = CGRectMake(rect.origin.x * -1,
rect.origin.y * -1,
imageToCrop.size.width,
imageToCrop.size.height);
//draw the image to our clipped context using our offset rect
CGContextDrawImage(currentContext, drawRect, imageToCrop.CGImage);
//pull the image from our cropped context
UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();
//pop the context to get back to the default
UIGraphicsEndImageContext();
//Note: this is autoreleased
return cropped;
}
Or another way:
- (UIImage *)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect
{
CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], rect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return cropped;
}
From http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/.
The context you create to draw the image has the same size that the original image. That's why they have the same size.
If you don't want to re-invent the wheel, take a look at the TouchCode project on Google Code. You will find UIImage categories that do the job (see UIImage_ThumbnailExtensions.m).
We have an issue with transparency. While writing an image to Context with gradient, transparency (which is unwanted) is getting applied. We are not sure why this has been getting applied. We need the context to be "ONLY" with Gradient but not with "TRANSPARENCY".
Attaching the snippet of the code for your reference.
- (UIImage *)ReflectImage:(CGFloat)refFract {
int reflectionHeight = self.size.height * refFract;
CGImageRef gradientMaskImage = NULL;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef gradientBitmapContext = CGBitmapContextCreate(nil, 1, reflectionHeight,
8, 0, colorSpace, kCGImageAlphaNone);
CGFloat colors[] = {0.0, 1.0, 1.0, 1.0};
CGGradientRef grayScaleGradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
CGColorSpaceRelease(colorSpace);
CGPoint gradientStartPoint = CGPointMake(0, reflectionHeight);
CGPoint gradientEndPoint = CGPointZero;
CGContextDrawLinearGradient(gradientBitmapContext, grayScaleGradient, gradientStartPoint,
gradientEndPoint, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(grayScaleGradient);
CGContextSetGrayFillColor(gradientBitmapContext, 0.0, 0.5);
CGContextFillRect(gradientBitmapContext, CGRectMake(0, 0, 1, reflectionHeight));
gradientMaskImage = CGBitmapContextCreateImage(gradientBitmapContext);
CGContextRelease(gradientBitmapContext);
CGImageRef reflectionImage = CGImageCreateWithMask(self.CGImage, gradientMaskImage);
CGImageRelease(gradientMaskImage);
CGSize size = CGSizeMake(self.size.width, self.size.height + reflectionHeight);
UIGraphicsBeginImageContext(size);
[self drawAtPoint:CGPointZero];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, self.size.height, self.size.width, reflectionHeight), reflectionImage);
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRelease(reflectionImage);
return result;
}
So, can someone please let me know why this is so? It would be of great help if this issue gets resolved.
Thanks!!
I didn't try running any of this, but you do seem to be passing an alpha value to CGContextSetGrayFillColor.
Also, the use of "device gray" has been generally discouraged. You might want to double check to make sure that the color space you're getting back has the same number of components as you expect it to.