Photo Editing and Corona: how can I crop a photo at full resolution?

Thanks for your suggestion.

The cropping of the image is one the main features of the app I’m developing and I don’t think users would be very pleased to depend on an internet connection in order to use the app.

BTW if I was to choose between Enterprise and native for this project then I’d rather go 100% native.

It’s not the first time I’m unable to carry on with an app because of Corona limitations and will probably have to give up on it once again.

Cheers.

@lpalmieri, try this code, it should work for your case of taking a photo. You can definitile crop it, scale it, regardless of the screen size. It works for us for an app that we are building for a customer like a charm with the PRO version of Corona.

local function cropImage(photo, newFileName, cropW, cropH)          -- adjust width and height of the resulting image     local endWidth  = cropW \* display.contentScaleX     local endHeight = cropH \* display.contentScaleY          -- set the masking container     local tempGroup = display.newSnapshot(endWidth, endHeight )     tempGroup.x = 0     tempGroup.y = 0     tempGroup.anchorX = 0     tempGroup.anchorY = 0          -- Define a solid color background, in case the final image is     -- smaller than the cropping output     local whiteRc = display.newRect( 0, 0, endWidth, endHeight )     tempGroup.group:insert(whiteRc)     whiteRc.anchorX = 0.5     whiteRc.anchorY = 0.5     whiteRc:setFillColor( 1,1,1 )          -- insert the photo     tempGroup.group:insert(photo)          -- scale the photo to your need.     local scale = math.max(endWidth / photo.width, endHeight / photo.height)      photo:scale(scale, scale)          -- center the photo inside the container or position it     -- the way you want inside the container area. In our case     -- we center it.     photo.x = 0     photo.y = 0     photo.anchorX = 0.5     photo.anchorY = 0.5     -- save the cropped image     display.save( tempGroup, { filename = newFileName, baseDir = system.TemporaryDirectory, isFullResolution = true } )     -- clean up the mess     tempGroup:removeSelf()     tempGroup = nil end

The problem doing image manipulation (including crop) with Corona today are the following:

  1. You need to load the image on screen, so, your image will be capped to 2048x2048 pixels. Since smartphone cameras have now a higher resolution than that, you cannot keep the original photo resolution for example.

  2. All “image manipulation” needs to be done within the screen, so your final image will also be capped by your screen resolution

  3. Related to #2, when you do your image manipulation in the visible screen, the user may see it (like, you showing a new image, positioning at x,y, cropping, and then removing the image), impacting the user experience. (@nmichaud, don’t you have this problem?)

These are problems that I already faced when having to crop images or manipulate them (like adding a overlay image) while trying to keep the real full resolution of the image. If you guys found ways to overcome these problems (or I am wrong with any of these issues), please let me know.

I do not understand  when you say : “so your final image will also be capped by your screen resolution”.  In our app, the size of the image is not capped by the screen resolution, it is capped by the maximum size of the openGL buffer allocated by the snapshot. 

Also, you can do all of those manipulation when dealing with snapshot without showing anything on screen, therefore the user never knows what is happening in the background.

I have quickly coded a test project for you, so you can run it on the simulator but also on your device. On your device, the media.save API is called, therefore each generated image is directly saved in your photo library so you can copy them back to your computer to take a look at them. I have also quickly added another image to be overlay on the main one. This is quick code to show you what you can do. 

Project : imgTesting.zip 

I hope this help. In our case this is good enough for what we need and the most important thing to remember is that you are not tight to screen  resolution, but the frame buffer size witch I imagine can change depending of the device (especially cheap android devices).

Thanks @nmichaud, I will test and post the results back here.

From what I know and my previous experience, media.save only saves what is visible on screen, so you cannot do your image manipulation outside of screen.

That fact is also written here in the manual: http://docs.coronalabs.com/api/library/display/save.html

The object to be saved must be on the screen and fully within the screen boundaries.

Yes, we saw that,  when we were doing our first test regarding some of the restriction of display.save (not media.save which into your photolib a file).

But in the same help page, it is mention that isFullResolution (optional) is true,  the image is not scaled to the size of the screen of the device. Therefore by setting this flag and dealing with a snapshot buffer, the magic can happen.

I have been experimenting with this for awhile now and this is what I have found:

I have a picture that I load in. It has a resolution of 1200x1800.

I add it to a display group because I overlay some things on it.

I then save it with this: 

local photoGroup = display.newGroup() local photo = display.newImage("original.jpg", system.DocumentsDirectory, display.contentCenterX, display.contentCenterY, true) photoGroup:insert(photo) -- Add other display objects because I want some things overlayed on it (not shown here) -- Save it display.save(photoGroup, { filename="myPic.jpg", baseDir=system.TemporaryDirectory, isFullResolution=true, backgroundColor={0, 0, 0, 0}, jpegQuality=1 })

Results:

Column1 = saved photo resolution

Column2 = config.lua width and height

Column3 = Hardware device width and height

563x750 @ 640x960 on 640x960

406x540 @ 320x480 on 640x960

203x270 @ 320x480 on 320x480

282x375 @ 640x960 on 320x480

If I don’t add the photo to a display group and just save it back out after I load it in, then I get different results:

1200x1600 @ 640x960 on 640x960

2400x3200 @ 320x480 on 640x960
1200x1600 @ 320x480 on 320x480

600x800     @ 640x960 on 320x480

As you can see it multiplies the resolution by the scale factor used by corona’s dynamic scaling.

This behavior seems pretty erratic. 

Hi Corona Staff,

Could we please have a look at this issue… if you use @nmichaud sample project above you will see some strange behavior:

  1. Run the project on the corona simulator with hardware set to iPhone 4

  2. Look at the output images, specifically crop3000x3000.jpg

  3. Run the same project on the corona simulator again but this time with hardware set to iPhone 6 Plus

  4. Look at the output images again, specifically crop3000x3000.jpg. You will notice that they are not the same! The image saved with the iPhone 6 Plus is zoomed in further.

I think there is a bug happening here in the saving code. It doesn’t output the same result regardless of device resolution. Please help!

iPhone 4 Result:

[media] EBRN6eG.jpg[/media]

iPhone 6 Result:

[media] wdPZoLE.jpg[/media]

What does your config.lua look like?

config.lua

    

application =     {                          launchPad = false,              content =         {             width =  320, --320             height = 480, --480             scale = "letterbox",                xAlign = "center",             yAlign = "center",                imageSuffix =             {                 ["@2x"] = 2, --2             },          }, }

What happens when you test on device?

Rob

I tried this on my iPhone 4 device and it only saved one real image. The other 4 images it produces are black. Here is the log output:

Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateSourceDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Source width/height is below minimum of 16: sourceWidth=12, sourceHeight=170 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateDestDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Destination width/height is below minimum of 4: destWidth=43, destHeight=3 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: transformGeneral failed (0xe00002c2). Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateSourceDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Source width/height is below minimum of 16: sourceWidth=12, sourceHeight=94 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateDestDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Destination width/height is below minimum of 4: destWidth=24, destHeight=3 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: transformGeneral failed (0xe00002c2). Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateSourceDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Source width/height is below minimum of 16: sourceWidth=12, sourceHeight=94 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateDestDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Destination width/height is below minimum of 4: destWidth=24, destHeight=3 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: transformGeneral failed (0xe00002c2). Mar &nbsp;7 14:29:16 My-iPhone SpringBoard[34] \<Warning\>: LICreateIconForImage passed NULL CGImageRef image

Hi Corona Staff,

Could we please have a look at this issue… if you use @nmichaud sample project above you will see some strange behavior:

  1. Run the project on the corona simulator with hardware set to iPhone 4

  2. Look at the output images, specifically crop3000x3000.jpg

  3. Run the same project on the corona simulator again but this time with hardware set to iPhone 6 Plus

  4. Look at the output images again, specifically crop3000x3000.jpg. You will notice that they are not the same! The image saved with the iPhone 6 Plus is zoomed in further.

I think there is a bug happening here in the saving code. It doesn’t output the same result regardless of device resolution. Please help!

iPhone 4 Result:

[media] EBRN6eG.jpg[/media]

iPhone 6 Result:

[media] wdPZoLE.jpg[/media]

What does your config.lua look like?

config.lua

    

application = &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; launchPad = false, &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content = &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; width = &nbsp;320, --320 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; height = 480, --480 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; scale = "letterbox", &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; xAlign = "center", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yAlign = "center", &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; imageSuffix = &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ["@2x"] = 2, --2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}, }

What happens when you test on device?

Rob

I tried this on my iPhone 4 device and it only saved one real image. The other 4 images it produces are black. Here is the log output:

Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateSourceDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Source width/height is below minimum of 16: sourceWidth=12, sourceHeight=170 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateDestDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Destination width/height is below minimum of 4: destWidth=43, destHeight=3 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: transformGeneral failed (0xe00002c2). Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateSourceDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Source width/height is below minimum of 16: sourceWidth=12, sourceHeight=94 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateDestDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Destination width/height is below minimum of 4: destWidth=24, destHeight=3 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: transformGeneral failed (0xe00002c2). Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateSourceDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Source width/height is below minimum of 16: sourceWidth=12, sourceHeight=94 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: virtual IOReturn AppleM2ScalerCSCHalSamsung::validateDestDimensions(M2ScalerCSCRequest \*, transformData \*, IOReturn) const, Destination width/height is below minimum of 4: destWidth=24, destHeight=3 Mar &nbsp;7 14:28:55 My-iPhone kernel[0] \<Debug\>: transformGeneral failed (0xe00002c2). Mar &nbsp;7 14:29:16 My-iPhone SpringBoard[34] \<Warning\>: LICreateIconForImage passed NULL CGImageRef image