Why does my movie from UIImages gets distorted? - iphone

I'm using zoul's solution to export UIImage array as a movie. But my frames all turns out distorted. Here's the original image:
Here's a similar distortion example:
I've read here that it has something to do with aspect ratio, but there's no explanation on how to fix it.

After a lot of experiments with different image sizes, and with the help of this article, I've got to the conclusion that the width of the images must be a multiple of 16.

For those still doing the journey in 2020, and getting distortion in their movies because its not width 16px
change
CGContextRef context = CGBitmapContextCreate(pxdata,
width, height,
8, 4 * width,
rgbColorSpace,
kCGImageAlphaNoneSkipFirst);
to
CGContextRef context = CGBitmapContextCreate(pxdata,
width, height,
8, CVPixelBufferGetBytesPerRow(pxbuffer),
rgbColorSpace,
kCGImageAlphaNoneSkipFirst);
Credit to #Bluedays Output from AVAssetWriter (UIImages written to video) distorted

I'v encountered this problem too, and I found the reason is the image's size is not the multiple of 16, you can change the size and have a try.

Related

converting the coordinates of a 300 dpi image to coordinates of a 72 dpi image

I'm working on a tess4J project and using tess4j, i've gotten the coordinates of words in the image. The only problem is, these are coordinates for a TIFF image. My project involves writing a layer of text overr the image in a pdf document. I take it the resolution of a pdf document is 72dpi. So the coordinates are morphed and too widely placed. If i can bring down the resolution from 300 dpi to 72dpi and THEN pass the image to tessaract, wont i get the coordinates i need? If not, any alternatives? already tried multiplying the coordinates with 300/72. Surprisingly, that doesnt work.
Thanks in advance!
To convert from 300DPI to 72DPI, you need to multiply by 72/300, not the other way round. Do it in floating point or the multiplication first and division then, as in (x * 72) / 300. PDF units are always 1/72 of an inch.
Scaling down the original image is not a good idea, since the loss of information will reduce the output text quality.
-(UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
{
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSLog(#"New image has w=%f, h=%f", newImage.size.width, newImage.size.height);
return newImage;
}
this code to change any image 72 dpi.

In Core Graphics, why is Alpha channel preferred to be most significant? (kCGImageAlphaPremultipliedFirst vs kCGImageAlphaPremultipliedLast)

Most code that creates a bitmap context uses kCGImageAlphaPremultipliedFirst, to create ARGB, instead of kCGImageAlphaPremultipliedLast to create RGBA. Is there a reason ARGB is preferred?
(the usage):
CGBitmapContextCreate(NULL, size.width, size.height, 8, size.width * 4,
colorSpace, kCGImageAlphaPremultipliedFirst);
I think it has got something to do with 'endian-ness' of the CPU used.
The above two constants specify the location of the alpha component and whether the color components are premultiplied. It could be stored in the most or least significant bits of each pixel, other than that both constants perform equally there is no preference over one another in term of performance.
For bitmaps created in iOS 3.2 and later, the drawing environment uses the premultiplied ARGB format to store the bitmap data.
For bitmaps created in iOS 3.1.x and earlier, the drawing environment uses the premultiplied RGBA format to store the bitmap data.

How to convert to 16 bit pixel format for use in OpenGL ES 2.0 when reading frames from a video (AV Foundation)

I'm using OpenGL to do some image processing on each frame of a 1280x720 quicktime video. The frames are then read back and a new video is created from these. The problem is the large amount of data that needs to be transfered to and from OpenGL (using glTexImage2D and glReadPixels), resulting in a very slow process.
Currently, I'm using kCVPixelFormatType_32BGRA as the pixel format for my AVAssetReaderTrackOutput instance. To decrease time consumption, I would like to use a 16 bit pixel format instead. Unfortunately, changing to such a format gives me empty frames when calling AVAssetReaderTrackOutput's copyNextSampleBuffer method. Does anyone have experience with using a 16 bit pixel format in AV Foundation?
If I can't get AV Foundation to change the format for me, I suppose I could convert from 32 bit to 16 bit "manually", maybe using NEON instructions? Any help is appreciated.
A further revision, and this is now community wiki because I've made so many errors in answering this question alone that it makes sense.
Although CoreGraphics would prima facie be able to do a 32bit to 16bit conversion for you using something like the following code, it instead reports that "4 integer bits/component; 16 bits/pixel; 3-component color space; kCGImageAlphaPremultipliedLast" is an unsupported parameter combination. So it seems that CoreGraphics can't internally comprehend 4 bits/channel images.
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, buffer, width*height*4, NULL);
CGImageRef inputImage = CGImageCreate( width, height,
8, 32, width*4,
colourSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big,
dataProvider,
NULL, NO,
kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
unsigned char *outputImage = (unsigned char *)malloc(width*height*2);
CGContextRef targetContext = CGBitmapContextCreate( outputImage,
width, height,
4, width*2,
colourSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextDrawImage(targetContext, CGRectMake(0, 0, width, height), inputImage);
/* uplopad outputImage to OpenGL here! */
CGContextRelease(targetContext);
CGImageRelease(inputImage);
CGColorSpaceRelease(colourSpace);
free(outputImage);
However, per the documentation:
Supported pixel formats are
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
and kCVPixelFormatType_32BGRA, except
on iPhone 3G, where the supported
pixel formats are
kCVPixelFormatType_422YpCbCr8 and
kCVPixelFormatType_32BGRA.
So for reducing the size of what you receive, you could switch to a YCbCr colour space. As the buffers come back biplanar (ie, all y components for the entire image, then all Cb and Cr components as a separate block), you can upload them as two individual textures to OpenGL and recombine in a shader, assuming you're happy limiting yourself to the 3GS and above, and can afford to spend 2 texture units of the 8 that are available on SGX iOS devices.
YCbCr is a colour space that represents colour as brightness (the Y) and colour (the CbCr) separately. It's been shown empirically that the colour channel can be sampled at a lower frequency than the brightness without anybody being able to tell. The '420' part of the pixel format describes how many Cb and Cr components you get for each 4 Y components — essentially it's telling you that you get one sample of Cb and one of Cr for every four samples of Y. Hence you have a total of six bytes to describe four pixels, for 12 bits/pixel rather than 24 bits/pixel in RGB. That saves you 50% of your storage.
For GL purposes you've potentially incurred an extra cost because it's two uploads rather than one. You're also going to need to use three varyings if you want to avoid dependent texture reads, and I think the SGX is limited to eight of those.

Crash when I convert PDF pages to PNG images

I need to convert each page of a PDF document to PNG images. These images are then displayed in a scrollView. I need to create two images per page: one at the screen dimension, and one 2.5 times bigger (it is used when the user zoom in the scrollView).
My problem is that I have sometimes memory warnings and crashes when I create big images.
The way I do it is well-known:
CGRect pageRect = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
float pdfScale = 2.5*self.view.frame.size.height/pageRect.size.height;
pageRect.size = CGSizeMake(pageRect.size.width*pdfScale, pageRect.size.height*pdfScale);
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, pdfScale,-pdfScale);
CGContextDrawPDFPage(context, page);
CGContextRestoreGState(context);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
The problem occurs on iPhone 3G/3GS and iPod Touch.
How can I limit the memory consumption while still having a zoom scale of 2.5 ?
Thanks !
You could consider using a webview to display the PDF, that takes care of the zooming and memory issues. Basically rendering the vector format PDF to a bitmap PNG at a large size is possibly not the most appropriate design decision. Without knowing what your requirements for the PNG are though, it's hard to comment.

CGBitmapContextCreate on the iPhone/iPad

I have a method that needs to parse through a bunch of large PNG images pixel by pixel (the PNGs are 600x600 pixels each). It seems to work great on the Simulator, but on the device (iPad), i get an EXC_BAD_ACCESS in some internal memory copying function. It seems the size is the culprit because if I try it on smaller images, everything seems to work. Here's the memory related meat of method below.
+ (CGRect) getAlphaBoundsForUImage: (UIImage*) image
{
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = malloc(height * width * 4);
memset(rawData,0,height * width * 4);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
/* non-memory related stuff */
free(rawData);
When I run this on a bunch of images, it runs 12 times and then craps out, while on the simulator it runs no problem. Do you guys have any ideas?
Running 12 times and then crashing sounds like a running out of memory problem. It might be that internally the CGContext is creating some large autoreleased structures. Since you're doing this in a loop, they are not getting freed, so you run out of memory and die.
I'm not sure how Core Foundation deals with temporary objects though. I don't think CF objects have the equivalent of autorelease, and a Core Graphics context is almost certainly dealing with CF objects rather than NSObjects.
To reduce the memory churn in your code, I would suggest refactoring it to create an offscreen CGContext once before you start processing, and use it repeatedly to process each image. Then release it when you are done. That is going to be faster in any case (since you aren't allocating huge data structures on each pass through the loop.)
I'll wager that will eliminate your crash problem, and I bet it also makes your code much, much faster. Memory allocation is very slow compared to other operations, and you're slinging around some pretty big data structures to handle 600x600 pixel RGBA images.
Goto Product -> Edit Schemes -> Enable Zombie objects. Put a tick mark before Enable Zombie objects. Now build and run it. It can give you better and to the point description for EXC_BAD_ACCES error.
I was getting a similar crash on my iPad (iPhoneOS 3.2 of course) using CGImageCreate(). Seeing your difficulty gave me a hint. I solved the problem by aligning my bytesPerRow to the next largest power of 2.
size_t bytesPerRowPower2 = (size_t) round( pow( 2.0, trunc( log((double) bytesPerRow) / log(2.0) ) + 1.0 ) );
Let us know if providing power of 2 row alignment also solves your problem. You would need to allocate *rawData with the adjusted size and pass bytesPerRowPower2 to CGBitmapContextCreate()... The height does not seem to need alignment.
Perhaps CGImageGetBytesPerRow (power of two sounds excessive).
I used a power of two aligned row size in an app that was defining the row size directly, as I was creating images programmatically. But I would also recommend toastie to try CGImageGetBytesPerRow before trying my suggestion as well.
Try to Run instruments allocation while you are running the application on device, it cold be' a memory related issue. If you are in a loop, create inside that loop an auto release pool.
Maybe replace
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
with
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGColorSpaceRelease(colorSpace);
as the color space ref might still be needed somehow? Just a random guess...
And maybe even put it behind the release of the context?
// cleanup
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
I solved the problem by making a square context (width=height). I was having a 512x256 texture and it crashing every time I sent the data to OpenGL. Now I allocate a 512x512 buffer BUT STILL render 512x256. Hope this helps.