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

Hello all,

I’ve run into a bit of a snag when trying to crop a captured photo at full resolution. My initial code tried using a bounding rectangle to be the capture bounds of the crop and use display.captureBounds(), but this function will only capture what is visible on the screen. If you are trying to crop a photo that has a higher resolution than the screen with a crop bounding box that is also higher resolution than the screen then the crop won’t work correctly.

 local tempGroup = display.newGroup() tempGroup:insert(myPhoto) -- This object will be used as screen capture boundaries object local cropArea = display.newRect(cropX, cropY, cropWidth, cropHeight) cropArea.alpha = 0.0 tempGroup:insert(cropArea) -- Now capture the crop area which the user image will be underneath local myCaptureImage = display.captureBounds(cropArea.contentBounds) display.save(myCaptureImage, { filename=self.filePath .. self.fileName, baseDir=self.baseDir, isFullResolution=true, backgroundColor={0, 0, 0, 0} })

How can I crop an image with a resolution higher than the screen with a crop bounding box that is also larger than the screen?

For example:

Device: iPhone 5

Device resolution: 640x1136

Photo resolution: 2448x3264 

Crop bounding box: { x = 200, y = 200, width = 2048, height = 2864 }  This is a box that is 200 pixels smaller on all sides from the original

 

Thanks!

Try with display.newSnapshot(w,h) and you should be able to do what you want.

Is there anyway to do this without the snapshot api? I don’t really feel like paying $600 a year (Pro subscription) for one feature :frowning:

You get a few more features than just one.  

Rob

Yes of course, but I mean the only one I need in the feature set from PRO.

Have you guys found any other way to do this?

I have been searching everywhere but the only answers I find will only allow me to crop within the screen size of the current device.

Here’s what I’ve tried so far: display.save (with and without fullresolution), by making a imageSheet, masks and newSnapshot.

What I want is basically take a large image from the camera (say 2048x2048), crop it at a specific x,y with w/h 600x600 and save it to a file.

Any suggestions?

Thanks.

Image processing with Corona is not some very simple to do… Even with the snapshot feature I don’t know if it would work as you want…

The only solution today is to upload the image to a server, do the image processing there and then download the image back. It is not a good solution but it what you can do with Corona (unless you go Enterprise).

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. 

Try with display.newSnapshot(w,h) and you should be able to do what you want.

Is there anyway to do this without the snapshot api? I don’t really feel like paying $600 a year (Pro subscription) for one feature :frowning:

You get a few more features than just one.  

Rob

Yes of course, but I mean the only one I need in the feature set from PRO.

Have you guys found any other way to do this?

I have been searching everywhere but the only answers I find will only allow me to crop within the screen size of the current device.

Here’s what I’ve tried so far: display.save (with and without fullresolution), by making a imageSheet, masks and newSnapshot.

What I want is basically take a large image from the camera (say 2048x2048), crop it at a specific x,y with w/h 600x600 and save it to a file.

Any suggestions?

Thanks.

Image processing with Corona is not some very simple to do… Even with the snapshot feature I don’t know if it would work as you want…

The only solution today is to upload the image to a server, do the image processing there and then download the image back. It is not a good solution but it what you can do with Corona (unless you go Enterprise).