Tachiyomi: Auto detect page border

Created on 15 Mar 2016  Â·  15Comments  Â·  Source: tachiyomiorg/tachiyomi

I found out about this feature from an app known as Perfect Viewer and its a game changer for reading downloaded manga or comics. There is an option in the settings called "Auto detect page border" which is useful for making the most of a screen by zooming into the inked part of the image.
http://imgur.com/08lxmNn

So basically the empty white spaces from the sides of a manga will be gone and the actual content will fill the whole screen. I would really appreciate this feature to be added as its difficult to go back to reading with white spaces after I got used to a feature like this.

Also, I just wanted to know 1 more thing. In the Scale Type option, what is the difference between fit screen and smart fit? I first thought smart fit was similar to auto detect page border but it was the same as fit screen/fit width

feature

Most helpful comment

Good news. I was able to implement this and it should be available shortly. I still need to figure out a few things and cleanup the implementation.

All 15 comments

Smart fit fits width if page's height is more than it's width. If it's width is bigger, it fits height. Useful when 2 pages are scanned as one page.
https://github.com/inorichi/tachiyomi/blob/a3ec0573847e5cd1ee176c8219f24914f0989009/libs/SubsamplingScaleImageView/src/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java#L2038

j2ghz, thanks for clarifying that. Now I understand the functionality of smart fit, really glad it was implemented. I just hope this feature, auto detect page border, is also added in the next update. It just makes reading so much better because it utilizes all of the screens real estate

I'm sorry to tell you this won't be available soon, or at least by me, unless there's an open source implementation out there already. That's not an easy task, and it probably involves using C/C++ (and I'm bad with these) to process the images, or you would have a slow/laggy reader.

Hey no problem, its fine. Your app is already far superior to pretty much ever other manga reader app out there so kudos for the amazing work. Very much appreciated.

Here you have a C++ snippet with a test application included.

https://gist.github.com/ntrrgc/f1381f0cc8d7ae88cc7381bfe840aedb

ntrrgc, how do I apply this to the app? That would be so amazing if it works!

The snippet contains an algorithm that tries to find where the actual content of a image starts, asuming it's a drawing on white background, which is the case for manga.

In the main() function you can find a test application that uses it. You can compile it e.g. creating a new Qt project in QtCreator and pasting the entire file as main.cpp.

Basically you load an image and call functions like findBorderTop() for each side. Then you can use the returned values to crop the image, adjust the viewport to hide the borders or whatever you want.

Please note the positions returned are inclusive. That is, if you get left = 10, right = 90, x = 10 is the first pixel with content and x = 90 is the last. In total you have 91 pixels wide of content.

The algorithm is written in C++. You can integrate it either by using Android NDK (be sure to build the final version with optimizations enabled, otherwise it will be very slow), or by rewriting it in Java — since the algorithm is actually quite simple, as long as the Java optimizer is not too dumb, it should perform well.

Regardless of the language of implementation, you potentially need your own code for two things:

  • You need an efficient way of reading image pixels.

This usually means getting the base pointer of the bitmap in C++ (e.g. using AndroidBitmap_lockPixels) or a byte array in Java (e.g. using Bitmap.getPixels()).

The former is preferable since it does not require copying the image in memory and may return a more tightly packed bitmap format, whilst the later requires 32 bit integers per pixel in any case.

If you go the getPixels() way with Java, you can asume RGBA8888, packed as a Java int per pixel.

You need to modify getPixelColorValue() in order to find the correct byte for the pixel for the correct format and return a value that tells how much clear is that pixel. If it's less than filledValue (by default 127), it will be assumed as black (with content), otherwise it will be treated as clear (void of content).

The algorithm works by reading for each line how many pixels are _void_ (white) vs how many pixels are _full_ (black). If it exceeds a certain threshold (filledRatioLimit, 0.25% of the length of the line), the search ends and that line is considered the start of content.

Be aware that bitmaps take quite a chunk of memory, which is quite scarce in mobile devices, so try to avoid having too many copies of them at a given time. Also, should you use AndroidBitmap_lockPixels, remember to call AndroidBitmap_unlockPixels so the JVM can reclaim that memory.

Thanks for breaking it down. It makes sense now how it works fo achieve this. However, I'm not familiar with adding this sort of function to an app, so if Inorichi can integrate it with his app I would very much appreciate it since I don't have any expertise working with scripts or programming.

If this is already implemented, it's not working for me.

It's not implemented

Good news. I was able to implement this and it should be available shortly. I still need to figure out a few things and cleanup the implementation.

It's now available.

I tried to be as memory efficient as possible (reusing the same bitmap instead of allocating memory for an almost identical copy) to avoid OutOfMemory exceptions and this led me to do some nasty things in native code (unsafely modifying memory).

It's possible this crashes on some specific ROMs/APIs when the setting is enabled due to the things explained before. I've tested and got it working with the stock API images 16, 18, 19, 21, 22, 23 and 25. Also in my Xiaomi Mi4i (API 21) and Nexus 7 2013 (API 23).

There's also a possibility of weird artifacts in certain big images (when subsampling). I haven't seen any though.

Please note this feature only works with white backgrounds. When the edges are black the algorithm won't crop anything.

Edit: Also note the webtoon reader ignores this setting, since pages are next to each other it could have undesired effects.

Edit2: After some real reading with this feature, I can say I'm very happy with its results after 3 days of hard work. Thank @ntrrgc for the provided snippet and poking/helping me to implement this.

Ever since I posted the thread for this request, I've been checking back to see if it would be achieved one day and had hope. After almost a year I gave up and then recently saw that you would implement this! Finally tried it and its just as I always wanted!!! Thank you so much!!!!!

I know this feature is closed, but will it be possible to tweak it a little?
I love this feature but I would hope for the border to be minimized, rather than completely removed, as it is somewhat inelegant in its current form. If it would leave a tiny bit of breathing room, or let me specify the amount of pixels to not cut out, it would be perfect. This is basically equal to shrinking the image by x% on a white background.

Seconding @sayaendo's comment. Perfect Viewer does it a little nicer by still leaving a minimum white border.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

arkon picture arkon  Â·  3Comments

ElerTheMagnanimous picture ElerTheMagnanimous  Â·  3Comments

K1LL3RR0N1N picture K1LL3RR0N1N  Â·  3Comments

nataliejean2412 picture nataliejean2412  Â·  4Comments

NoodleMage picture NoodleMage  Â·  3Comments