I wrote a small function to zoom by 2x. But it is giving EXC_BAD_ACCESS error while I run it. Below is the code
- (CGImageRef)CGImageScale2x:(CGImageRef)imgRef
{
CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);
CGRect imgRect = CGRectMake(0, 0, width, height);
CGAffineTransform transform = CGAffineTransformMakeScale(2.0, 2.0);
CGRect scaledRect = CGRectApplyAffineTransform(imgRect, transform);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bmContext = CGBitmapContextCreate(NULL,
scaledRect.size.width,
scaledRect.size.height,
8,
0,
colorSpace,
kCGImageAlphaPremultipliedFirst);
CGContextSetAllowsAntialiasing(bmContext, FALSE);
CGContextSetInterpolationQuality(bmContext, kCGInterpolationNone);
CGColorSpaceRelease(colorSpace);
CGContextScaleCTM(bmContext, 2.0, 2.0);
CGContextDrawImage(bmContext, CGRectMake(0, 0,
scaledRect.size.width,
scaledRect.size.height),
imgRef);
CGImageRef scaledImage = CGBitmapContextCreateImage(bmContext);
CFRelease(bmContext);
[(id)scaledImage autorelease];
return scaledImage;
}
I am new to iOS. Please help.
Thanks
CGImageRef can't be autoreleased, it's Core Foundation type. Try to use CGImageRelease(scaledImage) instead.
Related
I have this code that renders a custom slidebar handle with a dynamic text inside.
The problem is that I cannot get it to scale to retina resolution. It draws right on all devices and has the right size, but the resolution is low on retina.
How do I change this code to double the end image resolution?
-(UIImage *)addText:(UIImage *)img{
int w = img.size.width;
int h = img.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 0, colorSpace,kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
char* text= (char *)[[NSString stringWithFormat:#"$%d", (int)betSlider.value * 5] cStringUsingEncoding:NSASCIIStringEncoding];
CGContextSetShouldAntialias(context, true);
CGContextSelectFont(context, "TimesNewRomanPS-BoldMT",mainFrame.size.width/22, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context,255,255,255, 1);
CGContextShowTextAtPoint(context,(img.size.width-(strlen(text)*strlen(text)*(img.size.width/27)))/2.5,img.size.width/2.5,text, strlen(text));
CGImageRef imgCombined = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIImage *retImage = [UIImage imageWithCGImage:imgCombined];
CGImageRelease(imgCombined);
return retImage;
}
Change creating context like this:
CGFloat scale = [[UIScreen mainScreen] scale]
CGContextRef context = CGBitmapContextCreate(NULL, w * scale, h * scale, 8, 0, colorSpace,kCGImageAlphaPremultipliedFirst);
You can get Retina Image from current context using screen's scale.
Here is solution for Swift.
Swift 3
func getImageFromContext() -> UIImage{
UIGraphicsBeginImageContextWithOptions(self.frame.size, false, UIScreen.main.scale)
self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
In this code
CGRect contextRect = self.bounds;
will refer which bound? rectangle, imageRect, or whole iOS view.
I am trying to manipulate image using quartz2D, i created this code by looking different examples, and code written between // is from Apple Quartz2D guide draw text.
Thanks in advance,
Regards.
- (void)drawRect:(CGRect)rect
{
CGSize cgs = CGSizeMake(250.0, 400.0);
UIGraphicsBeginImageContext(cgs);
CGRect rectangle = CGRectMake(0,0,cgs.width,cgs.height);
CGRect imageRect = CGRectInset(rectangle, 5.4, 5.4);
imageRect.size.height -= 100;
UIImage *myImage = [UIImage imageNamed:#"pumpkin.jpg"];
[myImage drawInRect:imageRect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 10.0);
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0);
CGContextStrokeRect(context, rectangle);
//
CGRect contextRect = self.bounds;
CGContextTranslateCTM(context, 0, contextRect.size.height);
CGContextScaleCTM(context, 1, -1);
float w, h;
w = contextRect.size.width;
h = contextRect.size.height;
CGAffineTransform myTextTransform;
CGContextSelectFont (context, "Helvetica-Bold", h/10, kCGEncodingMacRoman);
CGContextSetCharacterSpacing (context, 10);
CGContextSetTextDrawingMode (context, kCGTextFillStroke);
CGContextSetRGBFillColor(context, 0, 1, 0, .5);
CGContextSetRGBStrokeColor(context, 0, 0, 1, 1);
myTextTransform = CGAffineTransformMakeRotation(0);
CGContextSetTextMatrix(context, myTextTransform);
CGContextShowTextAtPoint(context, 0, 50, "Quartz 2D", 9);
//
UIImage *testImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[testImg drawAtPoint:CGPointMake(35, 10)];
}
self.frame indicates the coords and size of the view in its parent view coordinate system.
self.bounds indicates the coords and size of the view in its own coordinate system. So it always has the same width and height as self.frame, but it has x and y equal to 0.
self.bounds is equal to CGRectMake(0, 0, self.frame.size.width, self.frame.size.height).
So your code:
CGRect contextRect = self.bounds;
is the same as:
CGRect contextRect = rect;
I'm working on an Augmented Reality app for a client. The OpenGL and EAGL part has been done in Unity 3D, and implemented into a View in my application.
What i need now, is a button that snaps a screenshot of the OpenGL content, which is the backmost view.
I tried writing it myself, but when i click a button with the assigned IBAction, it only saves 1/4 of the screen (the lower left corner) - though it does save it to the camera roll.
So basically, how can i make it save the entire screensize, instead of just one fourth?
here's my code for the method:
-(IBAction)tagBillede:(id)sender
{
UIImage *outputImage = nil;
CGRect s = CGRectMake(0, 0, 320, 480);
uint8_t *buffer = (uint8_t *) malloc(s.size.width * s.size.height * 4);
if (!buffer) goto error;
glReadPixels(0, 0, s.size.width, s.size.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, buffer, s.size.width * s.size.height * 4, NULL);
if (!ref) goto error;
CGImageRef iref = CGImageCreate(s.size.width, s.size.height, 8, 32, s.size.width * 4, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault, ref, NULL, true, kCGRenderingIntentDefault);
if (!iref) goto error;
size_t width = CGImageGetWidth(iref);
size_t height = CGImageGetHeight(iref);
size_t length = width * height * 4;
uint32_t *pixels = (uint32_t *)malloc(length);
if (!pixels) goto error;
CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * 4,
CGImageGetColorSpace(iref), kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big);
if (!context) goto error;
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeTranslation(0.0f, height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref);
CGImageRef outputRef = CGBitmapContextCreateImage(context);
if (!outputRef) goto error;
outputImage = [UIImage imageWithCGImage: outputRef];
if (!outputImage) goto error;
CGDataProviderRelease(ref);
CGImageRelease(iref);
CGContextRelease(context);
CGImageRelease(outputRef);
free(pixels);
free(buffer);
UIImageWriteToSavedPhotosAlbum(outputImage, self, #selector(image: didFinishSavingWithError: contextInfo:), nil);
}
I suspect you are using a device with a Retina display, which is 640x960. You need to take the screen scale into account; it is 1.0 on non-Retina displays and 2.0 on Retina displays. Try initializing s like this:
CGFloat scale = UIScreen.mainScreen.scale;
CGRect s = CGRectMake(0, 0, 320 * scale, 480 * scale);
If the device is a retina device, you need to scale the opengl stuff yourself. You're actually specifying that you want the lower-left corner by only capturing half the width and half the height.
You need to double both your width and height for the retina screens, but realistically, you should be multiplying it by the screen's scale:
CGFloat scale = [[UIScreen mainScreen] scale];
CGRect s = CGRectMake(0, 0, 320.0f * scale, 480.0f * scale);
Thought i'd chime and, and at the same time, throw some gratitude :)
I got it working like a charm now, here's the cleaned up code:
UIImage *outputImage = nil;
CGFloat scale = [[UIScreen mainScreen] scale];
CGRect s = CGRectMake(0, 0, 320.0f * scale, 480.0f * scale);
uint8_t *buffer = (uint8_t *) malloc(s.size.width * s.size.height * 4);
glReadPixels(0, 0, s.size.width, s.size.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, buffer, s.size.width * s.size.height * 4, NULL);
CGImageRef iref = CGImageCreate(s.size.width, s.size.height, 8, 32, s.size.width * 4, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault, ref, NULL, true, kCGRenderingIntentDefault);
size_t width = CGImageGetWidth(iref);
size_t height = CGImageGetHeight(iref);
size_t length = width * height * 4;
uint32_t *pixels = (uint32_t *)malloc(length);
CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * 4,
CGImageGetColorSpace(iref), kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big);
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeTranslation(0.0f, height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref);
CGImageRef outputRef = CGBitmapContextCreateImage(context);
outputImage = [UIImage imageWithCGImage: outputRef];
CGDataProviderRelease(ref);
CGImageRelease(iref);
CGContextRelease(context);
CGImageRelease(outputRef);
free(pixels);
free(buffer);
UIImageWriteToSavedPhotosAlbum(outputImage, nil, nil, nil);
I know it is possible to have rounded corners on objects like a UIImageView (I have done it before). But in this case, I need to have my square UIImage to have rounded corners. I know it is more difficult than just doing it to an object but I need this specifically for the UIImage.
Can anyone share a method that is not static and can be implemented in a class that I already made?
I have to do this to a UIImage unless it is possible to add rounded edges to a CCSprite.
Thanks!
Edit2:
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 *)makeRoundCornerImage : (UIImage*) img : (int) cornerWidth : (int) cornerHeight
{
UIImage * newImage = nil;
if( nil != img)
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int w = img.size.width;
int h = img.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextBeginPath(context);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
addRoundedRectToPath(context, rect, cornerWidth, cornerHeight);
CGContextClosePath(context);
CGContextClip(context);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
[img release];
newImage = [[UIImage imageWithCGImage:imageMasked] retain];
CGImageRelease(imageMasked);
[pool release];
}
return newImage;
}
Use https://stackoverflow.com/a/8125604/412916 to clip with a UIBezierPath instead. It's simpler.
Using the code posted above from http://blog.sallarp.com/iphone-uiimage-round-corners/
// rounded corner 10x10
UIImage *original = [UIImage imageNamed:#"original.png"];
UIImage *rounded = [self makeRoundCornerImage:original :10 :10];
I am trying to resize an image on the basis of value selected on picker by user.
To this aim, I currently use following code:
- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize {
CGRect frame;
UIImage * newImage;
newImage = image;
frame = frontImageView.frame;
frame.size.width = targetSize.width;
frame.size.height = targetSize.height;
frontImageView.frame = frame;
// the pixels will be painted to this array
CGImageRef imageRef = [newImage CGImage]; (APP crash at this point)
CGFloat height = targetSize.height;
CGFloat Width = targetSize.width;
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
pixels = (uint32_t *) malloc(targetSize.width * targetSize.height * sizeof(uint32_t));
// clear the pixels so any transparency is preserved
memset(pixels, 0, Width * height * sizeof(uint32_t));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
alphaInfo = kCGImageAlphaNoneSkipLast;
CGContextRef bitmap = CGBitmapContextCreate(pixels, Width, height, 8, Width * sizeof(uint32_t), colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
CGContextDrawImage(bitmap, CGRectMake(0, 0, Width, height), imageRef);
CGImageRef ref = CGBitmapContextCreateImage(bitmap);
UIImage *result = [UIImage imageWithCGImage:ref];
CGContextRelease(bitmap);
CGImageRelease(ref);
CGImageRelease(newImage);
return result;
}
If I resize an image, the first time (by 25 % for instance) there is no crash. But afterwards, a crash occurs with the error "exec_BAD_Access".
How can I solve this?