I have a stupid question. I want to load a JPEG file and do some image processing. In the processing, the image file must be in pixel=by-pixel (unsigned char*), or in the format .bmp. I want to know how can I do this?
After processing, I want to save this file as .bmp or .jpg, how can I do it?
Thanks very much and sorry for my poor English.
The link int the comments is useful but not exactly what I think you want to do. You will have to read up a bit on Quartz, Apple's technology for drawing and image processing. Apple has great documentation on this, but its not a simple one hour type of effort - plan on at least a day maybe more.
Assume you start with a UIImage (I'm guessing, its not all critical):
get a CGImageRef to that image (possibly [UIImage CGImage])
create a CGBitMapContext that is large enough to render that image into (you can ask a CGImage for its width and height, etc).
if you want to ultimately create a PNG with alpha, you will need to create a bitmap context big enough for alpha, even if the JPEG image does not have it. If you want another JPEG your job is a bit easier.
render the image into the bit map context (there is a CGContextDraw... routine for that)
Now your image is contained in a bitmap that you can read and modify. The layout will probably be r-g-b unless you specified alpha, in which case you will have to determine where the alpha byte is.
Once you have the bit map modified, you can create a new CGImage from that bitmap, and with that you can get a UIImage if you want.
PS: you will find much sample code and posting about this if you search, so you will not be totally on your own.
Related
I am doing an upload function to my server from my iOS app. I am right now architecting the best way to do this and thinking that my approach would run into trouble.
I've over 20 pictures that I would like to send in 1 request using AFmultiparFormData in AFNetworking with also text information that is relevant to that picture.
Now... I know how to create the NSDictionary with lots of information inside but never created a NSDictionary with 20 images in NSData format or attempted to upload many pictures at once.
The issue is that I don't know whether the NSData images would take as much memory space as an image. Thus, I could only do 2/3 at the time (if they were full screen images which they are not, but its just an arbitrary point of measurement)
Given What I said and the seudo code below, Could I do that or would I ran out of memory? otherwise I would be left to do 1 by 1.
// for loop that does this 20 times
UIImage* image = [UIImage imageNamed:myExercise.exercisePictureThumb];
NSData * exercisePictureThumb = UIImagePNGRepresentation(image1);
// add to dictionary recursively
You should not put all of your image data into a NSDictionary, as that's likely to cause memory problems.
Instead, create a dictionary or array of the URLs to your files, then make use of AFNetworking's multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock: and the AFMultipartFormData protocol, particularly appendPartWithFileURL:name:fileName:mimeType:error:. This way your image data for all of the images is not all in memory at one time, but is instead streamed from disk. Huge performance increase.
MishieMoo is absolutely right regarding the memory/streaming considerations and the wise counsel to avoid loading all of the images into memory at one time.
I wanted to get back to your UIImage vs NSData question, though. In my mind, there are two considerations:
File size: Unfortunately, there is no simple answer as to whether the original image will be smaller than the UIImage/UIImagePNGRepresentation output. Sometimes, if the original file was a JPEG, the result of round-tripping the image through a UIImage can actually make the file larger (e.g. I just grabbed three images and the PNG roundtrip took them from 4.7mb to 38.9mb). But, if the originals were uncompressed images, then the PNG roundtrip could make them considerably smaller.
Data loss: For me, the more significant issue with round-tripping the image through UIImage is that you'll suffer data loss. You lose meta data. Depending upon the image, you can even lose image data in the translation, too (e.g. if original wasn't in sRGB color space, if bit-depth lowered, etc.).
Now, sometimes it makes perfect sense (e.g., I use a variation of this UIImage round trip technique when creating image thumbnails). But if my intent is to upload images onto a server, I'd be very wary about going through the UIImage conversion, possibly losing data, without a compelling business case.
In background thread, my application needs to read images from disk, downscale them to the size of screen (1024x768 or 2048x1536) and save them back to disk. Original images are mostly from the Camera Roll but some of them may have larger sizes (e.g. 3000x3000).
Later, in a different thread, these images will frequently get downscaled to different sizes around 500x500 and saved to the disk again.
This leads me to wonder: what is the most efficient way to do this in iOS, performance and memory-wise? I have used two different APIs:
using CGImageSource and CGImageSourceCreateThumbnailAtIndex from ImageIO;
drawing to CGBitmapContext and saving results to disk with CGImageDestination.
Both worked for me but I'm wondering if they have any difference in performance and memory usage. And if there are better options, of course.
While I can't definetly say it will help, I think it's worth trying to push the work to the GPU. You can either do that yourself by rendering a textured quad at a given size, or by using GPUImage and its resizing capabilities. While it has some texture size limitations on older devices, it should have much better performance than CPU based solution
With libjpeg-turbo you can use the scale_num and scale_denom fields of jpeg_decompress_struct, and it will decode only needed blocks of an image. It gave me 250 ms decoding+scaling time in background thread on 4S with 3264x2448 original image (from camera, image data placed in memory) to iPhone's display resolution. I guess it's OK for an image that large, but still not great.
(And yes, that is memory efficient. You can decode and store the image almost line by line)
What you said on twitter does not match your question.
If you are having memory spikes, look at Instruments to figure out what is consuming the memory. Just the data alone for your high resolution image is 10 megs, and your resulting images are going to be about 750k, if they contain no alpha channel.
The first issue is keeping the memory usage low, for that, make sure that all of the images that you load are disposed as soon as you are done using them, that will ensure that the underlying C/Objective-C API disposes the memory immediately, instead of waiting for the GC to run, so something like:
using (var img = UIImage.FromFile ("..."){
using (var scaled = Scaler (img)){
scaled.Save (...);
}
}
As for the scaling, there are a variety of ways of scaling the images. The simplest way is to create a context, then draw on it, and then get the image out of the context. This is how MonoTouch's UIImage.Scale method is implemented:
public UIImage Scale (SizeF newSize)
{
UIGraphics.BeginImageContext (newSize);
Draw (new RectangleF (0, 0, newSize.Width, newSize.Height));
var scaledImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return scaledImage;
}
The performance will be governed by the context features that you enable. For example, a higher-quality scaling would require changing the interpolation quality:
context.InterpolationQuality = CGInterpolationQuality.High
The other option is to run your scaling not on the CPU, but on the GPU. To do that, you would use the CoreImage API and use the CIAffineTransform filter.
As to which one is faster, it is something left for someone else to benchmark
CGImage Scale (string file)
{
var ciimage = CIImage.FromCGImage (UIImage.FromFile (file));
// Create an AffineTransform that makes the image 1/5th of the size
var transform = CGAffineTransform.MakeScale (0.5f, 0.5f);
var affineTransform = new CIAffineTransform () {
Image = ciimage,
Transform = transform
};
var output = affineTransform.OutputImage;
var context = CIContext.FromOptions (null);
return context.CreateCGImage (output, output.Extent);
}
If either is more efficient of the two then it'll be the former.
When you create a CGImageSource you create just what the name says — some sort of opaque thing from which an image can be obtained. In your case it'll be a reference to a thing on disk. When you ask ImageIO to create a thumbnail you explicitly tell it "do as much as you need to output this many pixels".
Conversely if you draw to a CGBitmapContext then at some point you explicitly bring the whole image into memory.
So the second approach definitely has the whole image in memory at once at some point. Conversely the former needn't necessarily (in practice there'll no doubt be some sort of guesswork within ImageIO as to the best way to proceed). So across all possible implementations of the OS either the former will be advantageous or there'll be no difference between the two.
I would try using a c-based library like leptonica. I'm not sure whether ios optimizes Core Graphics with the relatively new Accelerate Framework, but CoreGraphics probably has more overhead involved just to re-size an image. Finally... If you want to roll your own implementation try using vImageScale_??format?? backed with some memory mapped files, I can't see anything being faster.
http://developer.apple.com/library/ios/#documentation/Performance/Conceptual/vImage/Introduction/Introduction.html
PS. Also make sure to check the compiler optimization flags.
I think if you want to save the memory you can read the source image from tile to tile and compress the tile and save to the destination tile.
There is an example from apple. It is the implementation of the way.
https://developer.apple.com/library/ios/samplecode/LargeImageDownsizing/Introduction/Intro.html
You can download this project and run it. It is MRC so you can use it very smoothly.
May it help. :)
I have a MIDP application using GameCanvas, and I'm using this sequence to get scaled image as javax.microedition.lcdui.Image for rendering into the canvas:
Bitmap.createBitmapFromBytes(data from file)
bitmap.scaledInto(largerBitmap..)
largerBitmap.getARGB(..)
Image.createRGBImage(..)
The obvious disadvantage of this is that consumes a lot of memory, especially at the moment when pulling RGB data from (large) scaled bitmap to a (large) buffer to create Image from it. Performance is also not very good, either due to memory usage or wrong approach - dont' know.
Is there a more efficient way to do what I want? Thank you!
I'm working on a photo app that needs to save images with user specified properties such as number of inches across the long edge at a specific resolution, say 400dpi or whatever the user specifies. So, I need to write out a CGImage with the ability to set image dimensions, resolution, colorspace, etc. I haven't yet found a way to do this at the CGImage level. I'm currently using the iOS port of ImageMagick and as amazing as it is, I'd like to use methods intrinsic to iOS.
Any help would be greatly appreciated....
CGImage is an immutable, opaque, in memory image representation.
I believe what you are looking for instead is the Image I/O functionalities, located in the aptly titled ImageIO.framework. Create a CGImageDestination, then specify its properties using CGImageDestinationSetProperties.
Is there any good component for Delphi to create a frame like the messenger frame around a photo?
This frame is basically just a bitmap. There seems not to be any function in the Windows API to draw this. Instead, a previous questioner here at SO found that this (or at least a very similar) bitmap is stored as a resource bitmap in explorer.exe, if I recall correctly.
Hence, to write a Delphi component displaying a bitmap inside such a frame would be trivial -- one just have to copy this bitmap. However, I feel this would be wrong (copyvio or at least bad manners). But of course you can draw your own version of a frame /using The GIMP or Photoshop/, and include it as a bitmap.
Also notice that it is very easy to apply bitmap effects, such as hue shifts, to a bitmap during run-time.
Take a look at our MicroPic very small tool.
http://bouchez.info/micropic.html
You've got the source code on the page.
It could be interesting for you, as start for drawing a custom frame to any picture.
I wrote this years ago, just to help my girl friend with her web site, without using photoshop before inserting pictures...