MATHEMA-GmbH / privacyblur

Obfuscate sensitive data in your pictures before sharing them online.
https://privacyblur.app/
MIT License
144 stars 15 forks source link

Loss of picture quality, even well outside of blurred areas #79

Open nicolas-raoul opened 2 years ago

nicolas-raoul commented 2 years ago

I took a picture, and want to upload it onto a Wikipedia article. Before uploading it, I need to erase one passer-by's tiny face on the right. PrivacyBlur seems perfect for that task: Screenshot_20211208-210919 I press Save. Now only the tiny part I blurred (and the few blocks that surround it) should have changed, right? Unfortunately, comparing with the original, we can see that the actually most pixels have changed color, only the low-frequency sky has a few remaining original pixels: 57afbe10f1d2c59527c9f96cae105c99 vRAJa4hMe1x1ftNQ3oeTknkwhcFUOgvr The original picture for reference (GitHub might modify it so feel free to email me asking for the original): dense4

JPEG supports several lossless operations, for instance cropping can be lossless if made along the blocks. Changing a few blocks (8x8 or 16x16) around a face should trigger losses only in these blocks.

Some might consider this nitpicking but:

By the way here are the most egregious changes, as you can see some areas have changed almost as much as the blurred face: 57afbe10f1d2c59527c9f96cae105c99 Pbe2uisZj93nVVs1X7Be8HrmhTuTXT6Q

tkuenneth commented 2 years ago

Thanks for sharing this. While JPEG itself is very flexible, many libraries may not use it to its full potential. Frankly, I need to look at which lib the team has been using first. Then we can see if/how we can influence the bahivor of it regarding decoding/enconding. Let my stress that we really appreciate your effort here. Thanks.

tkuenneth commented 2 years ago

Adding one thought... Maybe we should add the option to save in a lossless file format, for example PNG?

nicolas-raoul commented 2 years ago

@tkuenneth That could indeed be a good solution until the perfect solution is found. The disadvantages (compared to lossless edition) being bigger file size and a more crowded UI. In case you actually implement it, I just want to point out that JPG is lossless if set at maximum quality. At https://github.com/MATHEMA-GmbH/privacyblur/blob/main/lib/src/screens/image/utils/image_tools.dart#L72 you could use the optional quality parameter documented at https://pub.dev/documentation/image/latest/image/encodeJpg.html.

Using lossless transformation would avoid quality loss without bumping file sizes, and help maintain a clean&friendly UI, though. :-) The alternative Flutter library https://pub.dev/packages/jpegtran_ffi implements several lossless operations such as lossless crop. Since it is a port of jpegtran it might also have lossless JPEG join, or could have it added without too much effort. Lossless crop and join are all that is needed to implement the perfect solution:

  1. Use lossless crop to split the picture into elementary JPEG blocks.
  2. Overwrite the blocks where blurring was applied using data from imageBytes (these blocks will obviously not be lossless).
  3. Use lossless join ("de-crop" then drop) to put back the blocks together into a full picture and save it.

It is not trivial (especially if you have to port lossless join to jpegtran_ffi) but not super-hard either :-) Thanks a lot for caring!