0

I followed along with this tutorial (http://www.bit-101.com/blog/?p=1861) and noticed that upon saving the same image multiple times, the quality slowly degraded.

Aside from the memory leaks, what's going wrong here? It should be pulling 4 bytes (rgba) for each pixel. Where's the loss if each pixel is accounted for?

----------------- EDIT -----------------

I'm saving a new image from the pixel data each time there's a vertex position transformation, then load this altered image into my texture buffer, and reset the vertex/index buffers. That way I can keep my changes persistent and ultimately make a less choppy warp. See my other SO question: OpenGL ES 2.0 Vertex Transformation Algorithms


----------------- EDIT -----------------

Before

Before multiple saves

After

enter image description here


Here's the code from the tutorial:

-(UIImage *) glToUIImage {
    NSInteger myDataLength = 320 * 480 * 4;

    // allocate array and read pixels into it.
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, 320, 480, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

    // gl renders "upside down" so swap top to bottom into new array.
    // there's gotta be a better way, but this works.
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
    for(int y = 0; y < 480; y++)
    {
        for(int x = 0; x < 320 * 4; x++)
        {
            buffer2[(479 - y) * 320 * 4 + x] = buffer[y * 4 * 320 + x];
        }
    }

    // make data provider with data.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);

    // prep the ingredients
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * 320;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    // make the cgimage
    CGImageRef imageRef = CGImageCreate(320, 480, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

    // then make the uiimage from that
    UIImage *myImage = [UIImage imageWithCGImage:imageRef];
    return myImage;
}

-(void)captureToPhotoAlbum {
    UIImage *image = [self glToUIImage];
    UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);
}
Community
  • 1
  • 1
Matisse VerDuyn
  • 1,148
  • 15
  • 40
  • When you say “multiple times”, do you mean running this code more than once on the same image, or loading the image from the album and then saving it again? If the latter, then I would guess you are seeing JPEG compression (I'm not familiar with iOS, so I can't say for sure that the image is being written as JPEG). – Kevin Reid Mar 20 '12 at 17:31
  • I'm saving a new image from the pixel data each time there's a vertex position transformation, then load this altered image into my texture buffer, and reset the vertex/index buffers. That way I can keep my changes persistent and ultimately make a less choppy warp. See my other SO question: http://stackoverflow.com/questions/9777393/opengl-es-2-0-vertex-transformation-algorithms – Matisse VerDuyn Mar 20 '12 at 17:42
  • That is key information — you should add it to your question. – Kevin Reid Mar 20 '12 at 17:49
  • Also, it would be very useful to include before/after images demonstrating the loss of quality — seeing the problem will help us recognize and understand it. – Kevin Reid Mar 20 '12 at 17:53

1 Answers1

1

Every time you render the altered image, it is (necessartly) being resampled — that is, converted to a bitmap where the original pixels (texels) align with the screen grid other than on a 1:1 basis. This is necessarily lossy, in that you have lost some of the detail of the original image, so you will get worse results if you distort that image again, compared to transforming the original image with different parameters.

Kevin Reid
  • 37,492
  • 13
  • 80
  • 108
  • Sorry... Here's my comment from above: "I'm saving a new image from the pixel data each time there's a vertex position transformation, then load this altered image into my texture buffer, and reset the vertex/index buffers. That way I can keep my changes persistent and ultimately make a less choppy warp." ... My application of the principles in that code is not to save the image to the library – Matisse VerDuyn Mar 20 '12 at 18:14
  • 1
    I've updated my answer to clarify a bit. The resampling is not an artifact of *saving*, as I incorrectly stated, but of drawing the image at all. You will always lose quality if you transform a transformed image rather than starting with the original image again. – Kevin Reid Mar 20 '12 at 18:23