New feature: black and white color mode - #229
toolicious wants to merge 1 commit into
Conversation
|
Thanks a lot for your PR! |
|
I just received an email with an error:
Looks like this has been pending for a month and expired now. Is this still on your radar? |
|
It is on my radar, but I didn't manage to work on it so far. I'm sorry for that. |
|
Thanks again for this pull request! Here are my thoughts:
About the "two things unrelated to the feature":
I don't see that. Did I miss something?
Yes, but it's minor (25ms per page), so we can handle it separately. I started a new branch based on your code to:
It's not ready to be merged:
Would you like to have a look at it and tell me whether this could be a good starting point for further discussion? No rush. And sorry for the time it took me. |
|
Thanks for the review, and yes, I'd continue on your branch. Binarizing once at capture and storing it lossless is simpler than my export path and the export is fast. The dpi budget can go, your 4x gives about the same resolution at the balanced setting. I'd like to hear your reasoning on the JPEG hint. Without it, someone who exports to JPEG picks black and white for a small, crisp file and gets the opposite, with nothing telling them why. In your branch that JPEG is the 8 MP image at q75, 775 kB for a text page against about 250 kB in grayscale. Maybe you have a better solution. Side note: I find it difficult to switch between the output format as it is currently a global setting rather than an export setting for the current file. I saw that there are already open issues for that. Maybe this could somehow be solved together. If the export page allows to directly change the output format, then it could be automatically adjusted and forced to PDF when B&W is selected. Just a thought. The bolder look comes from the 2 MP step. Your branch shrinks the capture to 2 MP and interpolates it back up 4x, the PR binarized the real pixels. The threshold sits much closer to paper than to ink, so softer edges mean more ink. On a rendered 300 dpi page the strokes come out 6 to 20 % wider. With the dataset photos you won't see it, at 1024x768 nothing gets shrunk. The fix is to resize the warp to The disappearing dots at 8 pt come from the despeckle step. It drops ink below 12 px at 300 dpi, and an 8 pt period or i-dot is 7 to 10 px. If specks are only removed when there is no other ink close by, all the dots survive in my test. It takes one more connectedComponents call and on old, stained paper more specks get through. "Fetched twice": Sorry, that was my mistake. A few things I noticed in the branch:
If you want, I can push the resolution fix and the despeckle change onto your branch. |
|
Thanks for your answer. I can see that you have in mind a lot of implications for this PR. On the JPEG hint. Both black&white and JPEG are non-default choices, so I expect almost only advanced users to use such a combination and to know what they are doing. I also assume that some people may use the black&white filter for the contrast it gives, not for the reduced file size: in that case, if they actually need JPEG, the hint may be annoying. I don't have a strong opinion, though. I think you can go ahead with your PR: take what you want in my commits and add what you think makes sense. Thank you very much for your work on this topic, it's impressive! |
|
Hi, First thing: I discovered a performance issue in the grayscale processing. I fixed it on the main branch (#236), which also makes the black and white processing faster. I continued working on my branch. Here are the main changes:
Performance seems acceptable: on my test device, Here's an example that we can discuss: Would you be OK if I merged that to the main branch and if we worked on improvements as separate PRs? |
|
With a window of I don't really see why the 8 MP image would be a serious problem for preview and OCR:
|
|
The 7 seconds are the elliptical kernel. With a rectangle the fill step takes about 300 ms at 8 MP on a current phone. PR against your branch: #238. Dark rectangle and reflection fixed, dots of light print stay, your 12 pt box stays clean, text pages unchanged. A global cutoff does the same on these pages, I checked on your flattened image, and it's simpler and costs no time. What it doesn't do is close small glare specks inside a fill when they're brighter than the cutoff, like the ones at the right end of your first box. If that isn't worth 300 ms to you, take the cutoff. Preview at 8 MP: fair enough. For OCR, decoding at 2 MP for the OCR run only would be a few lines, if you want it. |
|
@toolicious I just merged #243. Huge thanks for your help on this topic, your suggestions and your patience. I will probably release it in the coming days, after doing some more testing. The most important thing I need from you now is to know how you would like to be credited in the GitHub release notes and in the announcement on Mastodon. Thank you! |
|
Just my username is fine, with a link to my GitHub profile if you like. I keep this account completely separate from my other (commercial) projects. I'd like to give something back to the open source community, with a few new FOSS projects of my own and with contributions like this one. I'm really glad projects like FairScan exist, and if I can help in an area I know a bit about and deal with anyway, for myself and for people around me, that's good for everyone. Thanks for taking this feature on and getting it into the app! |



Implements the black and white mode from #150. Measurements are in the issue comment.
Adds
ColorMode.BLACK_AND_WHITE, selectable per page and as a default in the settings. The binarization runs on the output of the existing grayscale pipeline and adds a Sauvola threshold. PDF export embeds these pages as 1 bit per pixel with CCITT group 4, rebuilt from the original capture. Automatic detection never selects the new mode, page geometry and the other two modes are untouched, and there is no new dependency.Three things you may want to decide differently:
While measuring I also noticed two things unrelated to the feature: during export the page image was fetched twice per page, and the OCR bitmap was decoded even when no OCR language is enabled. Both are fixed in this branch, since they distorted my numbers. I can split them into a separate PR if you prefer.
Tested on a device and with
./gradlew clean license check assembleRelease.