Rainbow effect on grays on Kindle Colorsoft after converting with KCC
I've noticed that some grays have a rainbow effect on the Kindle Colorsoft. This doesn't ruin the experience, but it can be distracting.
I compared the same frame to a version from Amazon's official release and the rainbow effect on the Amazon version isn't as prominent. This issue happens with all compression settings (JPEG/PNG/mozJpeg)
Is there something wrong with my settings, or is this caused by something in the conversion process?
Here are my settings (6.2.1):
KCC version:
Amazon version:
Pictures taken with iPhone 16 Pro.
Thanks again.
You may want to bring this up in a forum where more people can comment like MobileRead or Reddit since I don't have a CS12.
But it could be anything. Color eink has limitations with grayscales and screentones.
I've also heard that kindle cs12 has different color modes like "vivid" that I'm unsure are available for mobi manga. Amazon manga is KFX.
what does it look like if you deactivate color mode in the kcc settings?
Even with color mode deactivated, the grays have the rainbow effect. It is possibly just a limitation of the CS? Maybe I got one of the bad ones...
@oncpnda is there a rendering mode toggle for vivid mode anywhere in the menu or Aa menu or control center via swipe from top of screen in book?
Rainbow sheen happens since color eink is just a normal bw panel behind a bunch of small red/blue/green stickers.
Yes, I forgot to mention in the initial post that it happens with both vivid and standard mode on low and high brightness.
It's pretty much a property of color eink.
- https://github.com/koreader/koreader/issues/11877
Interesting solutions discussed their. Blurring the image, using a profile with a smaller resolution, etc. I wonder if pw11 or scribe profile fixes it. @oncpnda
Maybe png would help? But png has a bug where it converts really slow rn.
- #533
It is not a bug but another kindlegen limitation. If image file is too big or use format not supported by it then it is converted again and in general break everything KCC do.
There are good reasons why JPEG is default output. Every time when kindlegen is working too long on EPUB created by KCC mean that input was faulty.
@utopiafallen looks like koreader from above post found a solution better than blurring using Fourier transform in case you are interested
@utopiafallen looks like koreader from above post found a solution better than blurring using Fourier transform in case you are interested
Hi, thanks for quoting my work :).
Sadly I do not have the knowledge nor the time to port my C code to python, but I'm sure it is doable with pyFFTW. I prefer an "on-the-fly" fix for the rainbow effect but for those who don't use Koreader and prefer fixing it when converting through KCC, this could be a starting point: https://github.com/Its-my-right/pocketbook_cfa_interference_breaker
@axu2 Transforming into frequency domain and removing peaks would be low-pass filtering, and in the spatial domain, that would be a blur. The referenced method is equivalent to blurring the whole image in a way that reduces global and local contrast (the Pantheon article eliminates the peaks along the center horizontal and vertical axis which correspond to average image contrast in the horizontal and vertical axes), and you can see commenters explicitly having to fix that global contrast reduction by “re-normalizing” the resulting image.
All of this strikes me as a bit odd because the proposed solution to avoid blurring the image is….to the blur the image. If someone wants to implement this alternative blur, have at it, but I’d rather not pay the extra processing time in KCC that I already spent a significant effort in improving 😂
@axu2 Transforming into frequency domain and removing peaks would be low-pass filtering, and in the spatial domain, that would be a blur. The referenced method is equivalent to blurring the whole image in a way that reduces global and local contrast (the Pantheon article eliminates the peaks along the center horizontal and vertical axis which correspond to average image contrast in the horizontal and vertical axes), and you can see commenters explicitly having to fix that global contrast reduction by “re-normalizing” the resulting image.
All of this strikes me as a bit odd because the proposed solution to avoid blurring the image is….to the blur the image. If someone wants to implement this alternative blur, have at it, but I’d rather not pay the extra processing time in KCC that I already spent a significant effort in improving 😂
Please see for yourself:
Vanilla Picture
KCC 7.6.0 Blurred picture:
Fourier Picture:
Both methods involve some form of blur, yes.
But the drawings and text are sharper with the Fourier transform method. Furthermore, in this example, the settings are particularly aggressive (pushed to cover more than just rainbow effect removal: they also include the "smoothing" of certain patterns). With settings limited to rainbow effect removal, the image would have a sharpness closer to the original image.
I completely understand that you don't want to rewrite a feature that you consider sufficient as it stands. I myself don't really have the time or the expertise to contribute to an open-source project. But I wanted to share my work here because I thought it might be of interest to some users bothered by blur.
However, I remain convinced that "fixing" the rainbow effect by altering the image isn't the best option: source images shouldn't suffer a loss of quality just to compensate for a hardware problem due to the screen. I prefer the on-the-fly patch method that doesn't alter the original images, which is why I also presented this work on the koreader GitHub. But I imagine that some users use their e-reader's internal reader and not koreader, and for them, altering the source images is the only option.
At the risk of overfitting for a specific test case, you can more or less recreate the Fourier transform results by tweaking the parameters currently used by KCC to apply the rainbow reduction:
def optimizeForDisplay(self):
# Reduce rainbow artifacts for grayscale images by breaking up dither patterns that cause Moire interference with color filter array
if (self.opt.displayType == DisplayType.KALEIDO3_COLOR and not self.color):
unsharpFilter = ImageFilter.UnsharpMask(radius=1, percent=25)
self.image = self.image.filter(unsharpFilter)
self.image = self.image.filter(ImageFilter.BoxBlur(0.25))
self.image = self.image.filter(unsharpFilter)
And here is the result:
(I disabled resizing and auto-contrast in KCC since that makes the visual comparison more difficult.)
As a bonus, this avoids some of the aliasing artifacts introduced by the Fourier transform (you can see it as noise inside the white text) that I'm guessing is happening because globally rejecting frequency peaks means that some signals will be undersampled and can't be correctly represented anymore when transformed back (e.g. clean vertical and horizontal edges). This aliasing noise still ends up being aesthetically pleasing because it's perceived as detail, similar to film grain, which also enhances the perception of sharpness.
Anyway, this was mostly an academic exercise to prove to myself my own intuition that there isn't something inherently unique to blurring in the frequency domain that couldn't be represented in the spatial domain. I'm happy there are multiple solutions out there for hiding the rainbow artifacts on these Kaleido 3 screens.
At the risk of overfitting for a specific test case, you can more or less recreate the Fourier transform results by tweaking the parameters currently used by KCC to apply the rainbow reduction:
def optimizeForDisplay(self): # Reduce rainbow artifacts for grayscale images by breaking up dither patterns that cause Moire interference with color filter array if (self.opt.displayType == DisplayType.KALEIDO3_COLOR and not self.color): unsharpFilter = ImageFilter.UnsharpMask(radius=1, percent=25) self.image = self.image.filter(unsharpFilter) self.image = self.image.filter(ImageFilter.BoxBlur(0.25)) self.image = self.image.filter(unsharpFilter) And here is the result:
(I disabled resizing and auto-contrast in KCC since that makes the visual comparison more difficult.)
As a bonus, this avoids some of the aliasing artifacts introduced by the Fourier transform (you can see it as noise inside the white text) that I'm guessing is happening because globally rejecting frequency peaks means that some signals will be undersampled and can't be correctly represented anymore when transformed back (e.g. clean vertical and horizontal edges). This aliasing noise still ends up being aesthetically pleasing because it's perceived as detail, similar to film grain, which also enhances the perception of sharpness.
Anyway, this was mostly an academic exercise to prove to myself my own intuition that there isn't something inherently unique to blurring in the frequency domain that couldn't be represented in the spatial domain. I'm happy there are multiple solutions out there for hiding the rainbow artifacts on these Kaleido 3 screens.
Which color e-reader do you have? And have you tried displaying your latest image on it? Because when I display that image on my InkPad Color 3, which has the same resolution as the image, the rainbow effect is still visible (less than in the original image, of course, but still distracting).
Regarding the comparison of methods, you're right when you say that everything that can be done in the frequency domain can also be done in the spatial domain. This is mathematically true according to the convolution theorem.
However, for this specific use case, since the interferences causing the rainbow effect appear as localized peaks in the Fourier domain, acting precisely on those peaks is a more "surgical" and less "global" way to remove the root cause—and only that. In theory, this makes it possible to eliminate only the unwanted frequencies while preserving the rest of the image. It's easier to isolate frequency peaks in the frequency domain than in the spatial domain.
That said, my localized frequency suppression algorithm is far from optimal and could be significantly improved. It works in its current state and produces results that I find very satisfying, but there is still plenty of room for improvement.
Thanks to our exchanges, I’ve decided to modify my frequency suppression algorithm to specifically match the spatial frequency of the Kaleido 3 CFA. Since this frequency may vary slightly from one unit to another, it will require a preliminary test: displaying calibration patterns tuned to different frequencies to determine at which cycles-per-pixel value the patterns cause rainbow artifacts. That value could then be entered as a parameter in the algorithm, which will then target that specific frequency range for attenuation, instead of simply removing all frequency "peaks". The result should be precise and tailored to each individual screen—suppressing only the problematic parts specific to that display while keeping the rest of the image untouched.
I'm also glad that there are several ways to tackle this problem. I always find it cool when users work to fix issues that manufacturers haven’t managed to solve. I hope someone will eventually find an even better way to eliminate the rainbow effect—whether in the spatial or frequency domain :)
Just to jump in with my own anecdote: I implemented the modified optimizeForDisplay function and while there was still some rainbow effect on grays when viewed on my Colorsoft, compared to the function that ships in the compiled version it was a much better compromise in regards to how blurry the text gets. Thank you @utopiafallen.
Sure, happy to help! And I would suggest keep playing with different strengths for the unsharp mask and different radius value for the box blur since you're still getting the rainbow artifacts. I suspect that the box blur radius probably needs to go up to 0.5 or 0.75, in which case you'll want to make the second unsharp stronger to restore some of the sharpness.
On Tue, Jul 1, 2025 at 4:59 PM Michael Gardiner @.***> wrote:
gardinermichael left a comment (ciromattia/kcc#771) https://github.com/ciromattia/kcc/issues/771#issuecomment-3025878271
Just to jump in with my own anecdote: I implemented the modified optimizeForDisplay function and while there was still some rainbow effect on grays when viewed on my Colorsoft, compared to the function that ships in compiled version it was a much better compromise in regards to how blurry the text gets. Thank you @utopiafallen https://github.com/utopiafallen.
— Reply to this email directly, view it on GitHub https://github.com/ciromattia/kcc/issues/771#issuecomment-3025878271, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOT7JKOASIKZDRAABT46UT3GMOHPAVCNFSM6AAAAABRFTJBPSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTAMRVHA3TQMRXGE . You are receiving this because you were mentioned.Message ID: @.***>
OK, I've finished refining my rainbow effect frequency removal algorithm! By displaying many different patterns on Kaleido 3, it appears that the CFA is oriented at approximately 135° and that several frequencies, particularly around 0.16, 0.32, and 0.40->0.50 cycles/pixel, interfere with the CFA, creating rainbow effect artifacts.
Rather than removing high frequencies in all directions, I modified the algorithm to strongly attenuate the magnitude of key frequencies (within a tolerance interval), oriented around 135° (also within a tolerance interval), leaving all other frequencies/directions untouched.
The result is images without rainbow artifacts, and with much better sharpness than in my first version.
Additionally, I've also adapted my code so that it no longer reconstructs the Hermitian symmetry of the spectrum after the FFT, which improves processing time to around 300 ms :)
Here's the result for the same image after applying this new method:
Awesome, now that actually sounds like an improvement over a global blur!
On Sun, Jul 6, 2025, 2:17 AM Its-my-right @.***> wrote:
Its-my-right left a comment (ciromattia/kcc#771) https://github.com/ciromattia/kcc/issues/771#issuecomment-3041236260
OK, I've finished refining my rainbow effect frequency removal algorithm! By displaying many different patterns on Kaleido 3, it appears that the CFA is oriented at approximately 135° and that several frequencies, particularly around 0.16, 0.32, and 0.40->0.50 cycles/pixel, interfere with the CFA, creating rainbow effect artifacts.
Rather than removing high frequencies in all directions, I modified the algorithm to strongly attenuate the magnitude of key frequencies (within a tolerance interval), oriented around 135° (also within a tolerance interval).
The result is images without rainbow artifacts, and with much better sharpness than in my first version.
Additionally, I've also adapted my code so that it no longer reconstructs the Hermitian symmetry of the spectrum after the FFT, which improves processing time to around 300 ms :)
Here's the result for the same image after applying this new method: 04.-.fourier_new_2.png (view on web) https://github.com/user-attachments/assets/251d8ce6-0e2a-4d59-939f-07101e6ad137
— Reply to this email directly, view it on GitHub https://github.com/ciromattia/kcc/issues/771#issuecomment-3041236260, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOT7JPDGMMSLHZ5ZRP3UYD3HDSSFAVCNFSM6AAAAABRFTJBPSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTANBRGIZTMMRWGA . You are receiving this because you were mentioned.Message ID: @.***>
I made my first ever pull request, covering this :) https://github.com/ciromattia/kcc/pull/1027
@Its-my-right now that's cool. Btw, is this algorithm modifiable to handle normal b/w moire on bw eink?
@Its-my-right now that's cool. Btw, is this algorithm modifiable to handle normal b/w moire on bw eink?
I think it could be. For B/W moiré the solution would probably be to attenuate high frequencies as well (>= 0.3 cycles/pixel). For the rainbow effect, targeting high frequencies in the 135° direction (with a margin) is effective because the CFA is oriented at 135° on Kaleido 3. Now for the B/W moiré, we would need to check if it occurs more often in particular directions (I don't know manga tones well) and target those directions. If no particular direction is identifiable, we can still attenuate high frequencies in all directions, but this would be roughly equivalent to utopiafallen's solution (with a slightly longer processing time).
Just in case it's useful, I found this paper on moire reduction:
http://hdl.handle.net/10919/30304
I may need to open a new issue since b/w moire is separate but related issue.
I think the important part is:
Chapter 9 Prevention of Moire Patterns When Sampling a Halftone
An aliasing moire pattern in a sampled halftone image is due to insufficient low-pass filtering prior to sampling. If we can perform proper low-pass filtering, we can prevent aliasing moire altogether.
The partial inverse Fourier transform method converts an image of M ×N pixels to a lower resolution image of m×n pixels, m≤M, n≤N.
By inverse transforming only the center portion of the Fourier transform of the input image, a uniform subsampling preceded by an ideal low-pass filtering is implicitly performed on the input image. No aliasing occurs in the output image.
Just in case it's useful, I found this paper on moire reduction:
http://hdl.handle.net/10919/30304
I may need to open a new issue since b/w moire is separate but related issue.
I think the important part is:
Chapter 9 Prevention of Moire Patterns When Sampling a Halftone
An aliasing moire pattern in a sampled halftone image is due to insufficient low-pass filtering prior to sampling. If we can perform proper low-pass filtering, we can prevent aliasing moire altogether.
The partial inverse Fourier transform method converts an image of M ×N pixels to a lower resolution image of m×n pixels, m≤M, n≤N.
By inverse transforming only the center portion of the Fourier transform of the input image, a uniform subsampling preceded by an ideal low-pass filtering is implicitly performed on the input image. No aliasing occurs in the output image.
That seems to be indeed an (old but) interesting source. As you said I think moire pattern reduction is indeed a related but distinct issue. Do you have source files and pictures of how they display on a reader ? I may dig into this sometime, could be a good starting point
I am looking for volunteers to test the new rainbow effect removing algorithm on their e-reader.
I have noticed at least two different CFA orientations on two e-reader models (135° on Pocketbook Inkpad Color 3 with Kaleido 3 7.8" screen and 45° on Kobo Libra Color with Kaleido 3 7" screen).
The idea is to gather data to determine the precise CFA orientation depending on the e-reader model (it is possible that all Kaleido 3 of the same size have the same CFA orientation because they are all produced by the same company, but production methods may have changed over time or according to which e-reader manufacturers it goes).
This would then make the algorithm more accurate.
Two test builds are available in my repo:
(Edited - axu2) https://github.com/axu2/kcc/releases/tag/v8.0.4-major https://github.com/axu2/kcc/releases/tag/v8.0.4-minor
Testing is simple: Choose a manga that displays a rainbow effect on your e-reader after being converted with KCC, and convert it with the 8.0.4+ build. If the converted manga still displays a rainbow effect on your e-reader, follow the same process but with the 8.0.4+b build.
Then, please just share your results here:
- Which of the two builds removes the rainbow effect (don't bother the angle thing, the name of the build 8.0.4+ / 8.0.4+b is enough ;))
- Which e-reader you tested this on
Thank you!
I am looking for volunteers to test the new rainbow effect removing algorithm on their e-reader.
Then, please share your results here:
- Which of the two builds removes the rainbow effect
- Your e-reader's reference
Thank you!
I would be happy to help with a Kindle Colorsoft, but how I would be able to find the CFA degree/reference?
You just tell us which build fixes the problem and that will tell us the angle. @gardinermichael
I think by reference he just means tell us which device model you have.
Yeah sorry my English is rusty ! I updated my comment, it should be clearer
Turns out those test builds don't run, I rebuilt them with fixed imports
https://github.com/axu2/kcc/releases/tag/v8.0.4-major https://github.com/axu2/kcc/releases/tag/v8.0.4-minor
Disabled:
New method:
Old method:
Kindle Colorsoft running 5.18.3
No Rainbow Blur
Old Rainbow Blur
Major
Minor
Apologies for the warm tone, forgot to turn that off, but it's made a huge difference! Great work 👏! I'm not sure how easy it is to tell from the pictures but the Major/8.0.4+ branch has got rid of the rainbow effect entirely while maintaining most of the text crispness. The Minor/8.0.4+b branch seems to still have the rainbow effect. I would be happy to take more zoomed in pictures or retake the pictures without the warm tone if you would like.
@oncpnda @KeePach @lovesewerrats @SUM1-UNO @nodscrim @Treishpel @
In case you want to test the new sharper rainbow eraser algorithm.