I've taken a screenshot of a certain part of my window, then scaled it down and merged with an image also scaled down. The problem is that when I go to its path, there's a PNG file saved with 0KB, so the image isn't saved. Any idea? Thanks!
Here's my current code:
//Save images
- (void) saveimages {
//Save small one (mini)
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIGraphicsBeginImageContextWithOptions((myImageView.bounds.size), NO, 0.5);
[myImageView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *mini = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
float miniVW = VView.image.size.width / 2;
float miniVH = VView.image.size.height / 2;
UIImage *miniV = [self imageWithImage:certain.image convertToSize:CGSizeMake(miniVW, miniVH)];
UIImage *miniTotal = [self mergeIMG:miniV:mini];
NSString *pngFilePath = [NSString stringWithFormat:#"%#/mini%i.png",docDir,number];
NSData *data = [NSData dataWithData:UIImagePNGRepresentation(miniTotal)];
[data writeToFile:pngFilePath atomically:YES];
}
//Merge two images in one
- (UIImage *) mergeIMG:(UIImage *)VextImg:(UIImage *)VintImg {
//Create a new image from two
CGSize newSize = CGSizeMake(VintImg.size.width, VintImg.size.width);
[VintImg drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
[VextImg drawInRect:CGRectMake(0, 0, newSize.width, newSize.height) blendMode:kCGBlendModeNormal alpha:1.0];
UIImage *finalIMG = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return finalIMG;
}
//Scale image
- (UIImage *) imageWithImage:(UIImage *)image convertToSize:(CGSize)size {
//Change size
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *destImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return destImage;
}
mergeImage does not call UIGraphicsBeginImageContextWithOptions
Related
I am trying to send an image through sockets to a server, but the image doesn't appear well on the server side.
I am using this code, what can be the problem? I am sending text to the server and it works, but the image appears unformatted.
UIImage *imageResized=[self resizeImage:editedImage newSize:CGSizeMake(64,32)];
NSData *imageData = UIImageJPEGRepresentation(imageResized, 1.0f);
NSString *encodedString = [imageData base64EncodedStringWithOptions:nil];
NSString *finalStr= [NSString stringWithFormat:#"image:%#",encodedString];
NSData* data = [finalStr dataUsingEncoding:NSASCIIStringEncoding];
[tcpsocket initNetworkCommunication:[tcpSocket linkWebserviceInet1] porta:[tcpSocket linkWebport]];
[tcpsocket sendNSData:data];
- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
CGImageRef imageRef = image.CGImage;
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
// Set the quality level to use when rescaling
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);
CGContextConcatCTM(context, flipVertical);
// Draw into the context; this scales the image
CGContextDrawImage(context, newRect, imageRef);
// Get the resized image from the context and a UIImage
CGImageRef newImageRef = CGBitmapContextCreateImage(context);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
CGImageRelease(newImageRef);
UIGraphicsEndImageContext();
return newImage;
}
Problem:
Cropping with the image zoomed out is fine.
Cropping with the image zoomed in is showing the image above what is should be.
The yOffset I have in there is because the crop square I want starts below where the scrollview does.
Code:
CGRect rect;
float yOffset = 84;
rect.origin.x = floorf([scrollView contentOffset].x * zoomScale);
rect.origin.y = floorf(([scrollView contentOffset].y + yOffset) * zoomScale);
rect.size.width = floorf([scrollView bounds].size.width * zoomScale);
rect.size.height = floorf((320 * zoomScale));
if (rect.size.width > 320) {
rect.size.width = 320;
}
if (rect.size.height > 320) {
rect.size.height = 320;
}
CGImageRef cr = CGImageCreateWithImageInRect([[imageView image] CGImage], rect);
UIImage *img = imageView.image; //[UIImage imageWithCGImage:cr];
UIGraphicsBeginImageContext(rect.size);
// translated rectangle for drawing sub image
CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, 320.0f, 320.0f);
NSLog(#"drawRect: %#", NSStringFromCGRect(drawRect));
NSLog(#"rect: %#", NSStringFromCGRect(rect));
// draw image
[img drawInRect:drawRect];
// grab image
UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRelease(cr);
[self.delegate imageCropper:self didFinishCroppingWithImage:cropped];
What am I doing that is causing the image to get the wrong height when zooming?
UIImage* imageFromView(UIImage* srcImage, CGRect* rect)
{
CGImageRef cr = CGImageCreateWithImageInRect(srcImage.CGImage, *rect);
UIImage* cropped = [UIImage imageWithCGImage:cr];
CGImageRelease(cr);
return cropped;
}
-(void) doneEditing
{
//Calculate the required area from the scrollview
CGRect visibleRect;
float scale = 1.0f/scrollView.zoomScale;
visibleRect.origin.x = scrollView.contentOffset.x * scale;
visibleRect.origin.y = scrollView.contentOffset.y * scale;
visibleRect.size.width = scrollView.bounds.size.width * scale;
visibleRect.size.height = scrollView.bounds.size.height * scale;
FinalOutputView* outputView = [[FinalOutputView alloc] initWithNibName:#"FinalOutputView" bundle:[NSBundle mainBundle]];
outputView.image = imageFromView(imageView.image, &visibleRect);
[self.navigationController pushViewController:outputView animated:YES];
[outputView release];
}
Loading Orginal Image:
Zooming Image:
Finally Capturing the Image
If you want to take screenshot from the whole view of scrollView (after zooming) you can do this:
UIImage* image = nil;
UIGraphicsBeginImageContext(self.scrollView.contentSize);
{
//save previous frames
CGPoint savedContentOffset = self.scrollView.contentOffset;
CGRect savedFrame = self.scrollView.frame;
CGRect imgFrame = self.imageView.frame;
//set the frames with current content size
self.scrollView.contentOffset = CGPointZero;
self.scrollView.frame = CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.contentSize.height);
self.imageView.frame = self.scrollView.frame;
//render image now :)
[self.scrollView.layer renderInContext: UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
//now set the frames again with old ones :)
self.scrollView.contentOffset = savedContentOffset;
self.scrollView.frame = savedFrame;
self.imageView.frame = imgFrame;
[self viewForZoomingInScrollView:self.scrollView];
}
UIGraphicsEndImageContext();
//get the documents path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//save file as savedImage.png
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
//get the png data from image
NSData *imageData = UIImagePNGRepresentation(image);
//write it now
[imageData writeToFile:savedImagePath atomically:NO];
I'm using an AVCaptureVideoDataOutput along with its delegate method to manipulate video frames. In the delegate method, I am using the sampleBuffer to create a CIImage, and from here I crop the CIImage, convert it to a UIImage and display it. Unfortunately, I need to determine the file-size of this new UIImage, but it's returning 0. The code works, the image is cropped beautifully, everything. I just don't see why it has no data!
Why might this be? Relevant code follows:
//In delegate method, given sampleBuffer...
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault,
sampleBuffer, kCMAttachmentMode_ShouldPropagate);
CIImage *ciImage = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer
options:(NSDictionary *)attachments];
...
dispatch_async(dispatch_get_main_queue(), ^(void) {
CGRect rect = [self drawFaceBoxesForFeatures:features forVideoBox:clap
orientation:curDeviceOrientation];
CIImage *cropped = [ciImage imageByCroppingToRect:rect];
UIImage *image = [[UIImage alloc] initWithCIImage:cropped];
NSData *data = UIImageJPEGRepresentation(image, 1);
NSLog(#"Image size is %d", data.length); //returns 0???
[imageView setImage:image];
[image release];
});
I had the same Problem, but with simple filtered images.
I stumbled upon this and it solved the issue. After this, I was able to save my image.
CGSize size = self.originalImage.size;
CGRect rect;
rect.origin = CGPointZero;
rect.size = size;
UIGraphicsBeginImageContext(size);
[[UIImage imageWithCIImage:self.filteredImage] drawInRect:rect];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * jpegData = UIImageJPEGRepresentation(image, 1.0);
But I only needed this two lines in the "ImageContext"
I have an NSImageView which I get an image for from an NSOpenPanel. That works great.
Now, how can I take that NSImage, half its size and save it as the same format in the same directory as the original as well?
If you can help at all with anything I'd appreciate it, thanks.
Check the ImageCrop sample project from Matt Gemmell:
http://mattgemmell.com/source/
Nice example how to resize / crop images.
Finally you can use something like this to save the result (dirty sample):
// Write to TIF
[[resultImg TIFFRepresentation] writeToFile:#"/Users/Anne/Desktop/Result.tif" atomically:YES];
// Write to JPG
NSData *imageData = [resultImg TIFFRepresentation];
NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.9] forKey:NSImageCompressionFactor];
imageData = [imageRep representationUsingType:NSJPEGFileType properties:imageProps];
[imageData writeToFile:#"/Users/Anne/Desktop/Result.jpg" atomically:NO];
Since NSImage objects are immutable you will have to:
Create a Core Graphics context the size of the new image.
Draw the NSImage into the CGContext. It should automatically scale it for you.
Create an NSImage from that context
Write out the new NSImage
Don't forget to release any temporary objects you allocated.
There are definitely other options, but this is the first one that came to mind.
+(NSImage*) resize:(NSImage*)aImage scale:(CGFloat)aScale
{
NSImageView* kView = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, aImage.size.width * aScale, aImage.size.height* aScale)];
[kView setImageScaling:NSImageScaleProportionallyUpOrDown];
[kView setImage:aImage];
NSRect kRect = kView.frame;
NSBitmapImageRep* kRep = [kView bitmapImageRepForCachingDisplayInRect:kRect];
[kView cacheDisplayInRect:kRect toBitmapImageRep:kRep];
NSData* kData = [kRep representationUsingType:NSJPEGFileType properties:nil];
return [[NSImage alloc] initWithData:kData];
}
Here is a specific implementation
-(NSImage*)resizeImage:(NSImage*)input by:(CGFloat)factor
{
NSSize size = NSZeroSize;
size.width = input.size.width*factor;
size.height = input.size.height*factor;
NSImage *ret = [[NSImage alloc] initWithSize:size];
[ret lockFocus];
NSAffineTransform *transform = [NSAffineTransform transform];
[transform scaleBy:factor];
[transform concat];
[input drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
[ret unlockFocus];
return [ret autorelease];
}
Keep in mind that this is pixel based, with HiDPI the scaling must be taken into account, it is simple to obtain :
-(CGFloat)pixelScaling
{
NSRect pixelBounds = [self convertRectToBacking:self.bounds];
return pixelBounds.size.width/self.bounds.size.width;
}
Apple has source code for downscaling and saving images found here
http://developer.apple.com/library/mac/#samplecode/Reducer/Introduction/Intro.html
Here is some code that makes a more extensive use of Core Graphics than other answers. It's made according to hints in Mark Thalman's answer to this question.
This code downscales an NSImage based on a target image width. It's somewhat nasty, but still useful as an extra sample for documenting how to draw an NSImage in a CGContext, and how to write contents of CGBitmapContext and CGImage into a file.
You may want to add extra error checking. I didn't need it for my use case.
- (void)generateThumbnailForImage:(NSImage*)image atPath:(NSString*)newFilePath forWidth:(int)width
{
CGSize size = CGSizeMake(width, image.size.height * (float)width / (float)image.size.width);
CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, size.width * 4, rgbColorspace, bitmapInfo);
NSGraphicsContext * graphicsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO];
[NSGraphicsContext setCurrentContext:graphicsContext];
[image drawInRect:NSMakeRect(0, 0, size.width, size.height) fromRect:NSMakeRect(0, 0, image.size.width, image.size.height) operation:NSCompositeCopy fraction:1.0];
CGImageRef outImage = CGBitmapContextCreateImage(context);
CFURLRef outURL = (CFURLRef)[NSURL fileURLWithPath:newFilePath];
CGImageDestinationRef outDestination = CGImageDestinationCreateWithURL(outURL, kUTTypeJPEG, 1, NULL);
CGImageDestinationAddImage(outDestination, outImage, NULL);
if(!CGImageDestinationFinalize(outDestination))
{
NSLog(#"Failed to write image to %#", newFilePath);
}
CFRelease(outDestination);
CGImageRelease(outImage);
CGContextRelease(context);
CGColorSpaceRelease(rgbColorspace);
}
To resize image
- (NSImage *)scaleImage:(NSImage *)anImage newSize:(NSSize)newSize
{
NSImage *sourceImage = anImage;
if ([sourceImage isValid])
{
if (anImage.size.width == newSize.width && anImage.size.height == newSize.height && newSize.width <= 0 && newSize.height <= 0) {
return anImage;
}
NSRect oldRect = NSMakeRect(0.0, 0.0, anImage.size.width, anImage.size.height);
NSRect newRect = NSMakeRect(0,0,newSize.width,newSize.height);
NSImage *newImage = [[NSImage alloc] initWithSize:newSize];
[newImage lockFocus];
[sourceImage drawInRect:newRect fromRect:oldRect operation:NSCompositeCopy fraction:1.0];
[newImage unlockFocus];
return newImage;
}
}
I'm trying to save a multiple masked image to disk.
The code below explains How I do it. The maskImagewithStroke masks 2 times a picture : first time to provide an irregular stroke to a texture then I'm remasking it with a bigger mask to get a stroke from it. It's the bast way I found to get an irregular stroke around my texture.
Now, for the sake of the iPhone and its performance, I'd like to generate all masked textures and save them to disk. I'll use thos files in another app to load premasked textures. the masking process is perfect on screen but when saving file i'm have a black image with the irregular stroke BUT without texture in it ... How may I change that ?
I'm calling the method masImageWihStrokandSaveToFile to launch the maskin + saving process..
-(void)masImageWihStrokandSaveToFile:(UIImage *)image withMask:(UIImage *)maskImage imageIndex:(NSInteger)i{
//mask image with stroke
//[self maskImageWithStroke:image withMask:maskImage];
//save masked image to disk
// Create paths to output images
NSString *pngPath = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"Documents/Test_%d.png",i]];
NSString *jpgPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Test.jpg"];
// Write a UIImage to JPEG with minimum compression (best quality)
// The value 'image' must be a UIImage object
// The value '1.0' represents image compression quality as value from 0.0 to 1.0
[UIImageJPEGRepresentation([self maskImageWithStroke:image withMask:maskImage], 1.0) writeToFile:jpgPath atomically:YES];
// Write image to PNG
[UIImagePNGRepresentation([self maskImageWithStroke:image withMask:maskImage]) writeToFile:pngPath atomically:YES];
// Let's check to see if files were successfully written...
// Create file manager
NSError *error;
NSFileManager *fileMgr = [NSFileManager defaultManager];
// Point to Document directory
NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
// Write out the contents of home directory to console
NSLog(#"Documents directory: %#", [fileMgr contentsOfDirectoryAtPath:documentsDirectory error:&error]);
}
- (UIImage *) maskImageWithStroke:(UIImage *)image withMask:(UIImage *)maskImage{
UIImage* maskedImage = [self maskImage:image withMask:maskImage];
//****** Add a Stroke - Begin *******//
//grow the actual mask
UIImage* biggerMaskImage = [maskImage scaleToSize:CGSizeMake(310,310)];
//now add a stroke to the image.
//UIImage *bottomImage = [UIImage imageNamed:#"bottom.png"];
//UIImage *image = [UIImage imageNamed:#"top.png"];
CGSize newSize = CGSizeMake(310, 310);
UIGraphicsBeginImageContext( newSize );
// Use existing opacity as is
//[biggerMaskImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
//[biggerMaskImage drawInRect:CGRectMake(0,0,410,410)];
[maskImage drawInRect:CGRectMake(0,0,310,310)];
// Apply supplied opacity
//[retImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height) blendMode:kCGBlendModeNormal alpha:0.8];
[maskedImage drawInRect:CGRectMake(0,0,300,300) blendMode:kCGBlendModeNormal alpha:1];
UIImage *maskedStrokedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//****** Add a Stroke - End *******//
//****** Remask - Begin ******//
maskedStrokedImage = [self maskImage:maskedStrokedImage withMask:biggerMaskImage];
//****** Remask - End ******//
return maskedStrokedImage;
}
/*************Mask Images ***************/
CGImageRef CopyImageAndAddAlphaChannel(CGImageRef sourceImage) {
CGImageRef retVal = NULL;
size_t width = CGImageGetWidth(sourceImage);
size_t height = CGImageGetHeight(sourceImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef offscreenContext = CGBitmapContextCreate(NULL, width, height,
8, 0, colorSpace, kCGImageAlphaPremultipliedFirst);
if (offscreenContext != NULL) {
CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), sourceImage);
retVal = CGBitmapContextCreateImage(offscreenContext);
CGContextRelease(offscreenContext);
}
CGColorSpaceRelease(colorSpace);
return retVal;
}
// masker method
- (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
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];
//UIImage* retImage = [UIImage imageWithCGImage:maskedTransparent];
CGImageRelease(masked);
return retImage;
}