display.capture adds a 1 pixel white line on right and bottom edge

Urgent Issue with display.capture saving to the Photo Library!

When I use display.capture to save a group object to the Photo Library it adds a 1 pixel white line on right and bottom edge instead of the color that is supposed to be there. Next to the white line is about 50% grayed color pixel line. Also it only exports JPGs but the documentation says it can do PNG but there is no info on how to set that parameter.

I need to save without any anti-aliasing so PNG format would probably work best.

I have an app I need to release but I can’t until the issues are fixed!

Since the implementation of Graphics 2.0 (many years ago), Solar2D no longer does anti-aliasing, that’s why Circles doesn’t look smooth.

As for the issue you’re experiencing, not sure whether it’s related but I have encountered similar issues a few times in the past, something related to scaling and/or size of the display object and its position (fractional positions to be precise)

If you’re still having this issue, would you mind posting a code that can replicate exactly the output of your screenshot?

I have attached example code to replicate the issue.

I need to be able to capture and save to the photo library as a 24 bit PNG because currently there JPG artifacts in the colors even though I have jpegQuality=1. The jpegQuality parameter may not be working. The documentation says it can do PNG but there is no info on how to set that parameter.

I was able to get rid of the lines on the edge by moving the object by two pixels. Even though the lines go away by moving the object this worries me that it could still happen on some devices. See example and test with line 10 verses line 12. You will need to build and test on a device. To most easily see the issues open in photoshop.

Capture.zip (261.1 KB)

According to the code, you just need to have “.png”, “.PNG”, or whatever as the end of the filename.

@StarCrunch
For some reason using the filename parameter does not work when saving to the photo library. Does it work for you?

I don’t see a way to specify the image format when using display.capture() to save the file, it only saves as png for me.

On the other hand, display.save() does have parameters to provide a file name and file extension, and it does reflect the file format by the file extension used; png, jpg, and bmp are all valid (I checked the file headers), and I can see the artifact issue when saving to jpg.

If you can find a way to save the files to the photo library while using display.save then you can try using bmp as the file format, otherwise, you can also use display.captureBounds() instead.

Of course, all these are just workarounds, I got weird results when saving the files; the image resolution was set at an odd number depending on the scaling used in config.lua, sometimes it was only on the width and others at both, width and height. For this reason, if you can use display.captureBounds() then you can be certain to always use even numbers for the screenBounds as maybe those extra lines are the faded ones.

Just additional info per source code, saving as png can result in 24 or 32 bit; it’s saving as 32 for me, while jpg’s are saving as 24 bit. BMP’s are also saving as 32bit and without artifact issues, but I don’t know if you’ll encounter any issues in iOS.

@vlads Update Needed to display.capture

Please add functionality to display.capture to export a 32 bit PNG to the photo library. The documentation (see image below) says it should already do this but does not give info on how. I hope this functionality will be quick and easy to implement since it is already available in the display.save function for saving to a base directory.

I have an app I need to release but I can’t until I can export a 32 bit PNG to the photo library so I hope this is something that you can do very soon.

capture1

Like @Siu pointed out, and this is purely a guess from my part, but those white lines are likely an issue caused by incorrectly rounding up values.

It’s likely that the captured image is 199.8 by 200.3 pixels in Solar2D, and then for some reason, Solar2D captures the display object as 199x200, but saves it to file as 200x200, for instance, and since it doesn’t have content for that 1 pixel line, it fills the area with white.

@Mike_Hempfling

It’s a bit crazy chasing this all around, but I think I see what’s going on with the saving.

If not using display.save(), where the saving goes to the photo library, it calls this logic on Mac, which just searches for the first free image of form “X.jpg”, where X is an integer. So obviously, no PNG. The documentation addresses that in the Gotchas, but confuses things by saying “PNG file” in what you cited. :slight_smile:

With save() you go through something that respects the filename. (Are you able to use this?)

It doesn’t look like JPEG quality gets used anywhere on the Mac simulator. Is this where you’re testing?

Also, I agree it’s probably a rounding issue causing the edge problem.

@StarCrunch
I am testing on mobile devices and that is where I need to be able export a PNG to the devices photo library.

If the issue with the white lines is a rounding issue is that something that can be accounted for when the images are being created so it does not happen?

I just noticed something suspicious.

When preparing the capture rect in screen coordinates, we first round the dimensions up. So far so good.

That in turn goes through this to apply any scaling, where it rounds up AGAIN.

This would definitely be in line with the problem you’re seeing.

Part of the problem is that ContentToScreen() takes integers. I expect this is more about the output than the input. It doesn’t seem to be called in many places, so maybe those could be switched to float instead (or rather, another overload added for this case), then just not do the first rounding up.

On the other hand, other uses seem to first be flooring the values instead. That might mitigate this issue, but maybe we’d get “it’s too short!” instead. :smiley:

This is a follow-up to the last post.

In the meantime, I’ve been able to implement something different, but along similar lines:

  • create a new “capture”-type resource, with graphics.newTexture()
  • make proxy objects to capture the screen
  • feed the results back into paints

@Mike_Hempfling These aren’t your use case, but I’m getting minor—probably single-pixel—wobble when capturing and re-displaying in the same position. I’m hoping to mitigate that, which looks like it will involve some of the same code from screen captures. If so, I could see if it handles that problem spot. (Any chance you have a basic test to replicate the case above on desktop?)

Maybe I can push a PR within a week or so.

EDIT: Whoops, somebody pointed out that you included a project. :smiley:

@StarCrunch
@Scott_Harrison

Any updates on fixing the white lines and being able to export PNG to photo library?

@Mike_Hempfling I made the aforementioned PR and added the non-rounding conversion routines along the way. I’ll see if I can try them out on this in the days ahead.

Is it only on mobile where you see the issue? (And if so, only on specific devices? Or is it rather common / everywhere?) I didn’t see the issue just running the project in the simulator.

@StarCrunch
The issue happened on 3 different iOS devices (which was all the devices I tested on) that I tested it on but not on the simulator. Thank you for working on this.

@StarCrunch
@Scott_Harrison

I tested on 2 Android devices:

On android 4.4.2 it creates a PNG which is what I need.

On android 10 it does not create anything.

I just submitted an update for display.capture to saveToPhotoLibrary as a PNG on iOS, will be added to next release (i.e 3667+)

1 Like

@Scott_Harrison
Awesome!
Did you also fix the issue I found on android 10 where it does not create anything? I don’t know if this issue affects other android version but it worked on my android 4.4.2 device.

@Scott_Harrison
The new release 3667 now exports PNG but the line issue on right and bottom edge is still occurring.
Also I still don’t get a PNG created on my android 10 device. Below is the error that I think has to do with the issue. I checked and the app has storage listed under Permissions.

04-20 10:44:42.564 18801 18826 W System.err: java.io.FileNotFoundException: /storage/emulated/0/Pictures/App Name Picture 1.png: open failed: EACCES (Permission denied)

I just tired your code on two Android 11 device (Pixel 2 and Samsung phone) and was able to save photo to camera roll after adding this to your sample project

splashScreen =
    {
        enable = false,
        --image = "mySplashScreen.png"
    },
   android =
    {
        usesPermissions =
        {
            "android.permission.WRITE_EXTERNAL_STORAGE",
        },
    },

^ I assume you have already added this to your build.settings and hit allow?

Will see if I can find an Android 10 device