lnln1111 / android-apktool

Automatically exported from code.google.com/p/android-apktool
Other
0 stars 0 forks source link

Grayscale PNG conversion increase brightness #326

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Decode apk containing grayscale 9patch png
2.
3.

What is the expected output? What do you see instead?
The png has same brightness, instead the resulting png is brighter.

What version of the product are you using? On what operating system?
I think this is actually java problem.

Please provide any additional information below.

I fixed the problem using this snippet (note: messy code, I'm not a java 
programmer) in method decode in Res9patchStreamDecoder class:

BufferedImage im2 = new BufferedImage(w + 2, h + 2, 
BufferedImage.TYPE_4BYTE_ABGR);
Raster src = im.getRaster();
WritableRaster dst = im2.getRaster();
int nbands = im.getSampleModel().getNumBands();
int[] bands = new int[4];
if (nbands == 2) {
    bands[0] = bands[1] = bands[2] = 0;
    bands[3] = 1;
} else {
    bands[0] = 0; bands[1] = 1; bands[2] = 2; bands[3] = 3;
}
int[] band = null;
for (int y = 0; y < h; y++) {
    for (int bi = 0; bi < 4; bi++) {
        band = src.getSamples(0, y, w, 1, bands[bi], band);
        dst.setSamples(1, y + 1, w, 1, bi, band);
    }
}

Original issue reported on code.google.com by peac...@gmail.com on 27 Apr 2012 at 6:35

GoogleCodeExporter commented 9 years ago
I try the patch and it do work well
-------------------------
What`s more, the code "
NinePatch np = getNinePatch(data);
" just after the patch, need to be move up to before the patch for fixing  
ArrayIndexOutOfBoundsException when getSamples if "cant find 9patch chunk in 
file"

Original comment by yyjdel...@gmail.com on 16 May 2012 at 5:53

GoogleCodeExporter commented 9 years ago
I have tested this code personally in Apktool v1.4.7 and it had to be reverted 
on Apktool v1.4.8 due to Index OutOfBounds frequent errors (probably with bad 
PNGs). Will need to re-work fix.

Original comment by connor.tumbleson on 16 Nov 2012 at 1:19

GoogleCodeExporter commented 9 years ago
Issue 432 has been merged into this issue.

Original comment by connor.tumbleson on 20 Mar 2013 at 11:27

GoogleCodeExporter commented 9 years ago
this is a jdk bug, here the bug report 
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5051418.

is there a method to avoid the problem? 

Original comment by hackerm...@gmail.com on 20 Mar 2013 at 12:08

GoogleCodeExporter commented 9 years ago
The JDK website has been down a lot, so I'm copying information here.

================== 
A TYPE_CUSTOM BufferedImage with the same SampleModel, ColorModel and pixel 
data as a TYPE_BYTE_GRAY BufferedImage is rendered differently (it shows up a 
lighter gray). A test case that demonstrates this is attached.

The Java Advanced Imaging API (JAI) uses a custom subclass of WritableRaster in 
some instances, which when converted to a BufferedImage, results in a 
TYPE_CUSTOM BufferedImage, causing lighter rendering to be noticed by 
customers. This issue was reported by a JAI customer:

http://archives.java.sun.com/cgi-bin/wa?A2=ind0405&L=jai-interest&F=&S=&P=1121

=======================
EVALUATION

The root of problem can be reduced to he question
"What kind of data is supposed to be stored in data buffer?
Is it always sRGB or native representation for used color space?"

There are three ways to access image pixel data (data buffer):

  a) use setRGB/getRGB
  b) use optimized blits
  c) direct access to the data buffer.

The difference between these approaches shows up when image uses color
model based on non-sRGB color space (e.g. grayscale images).

At the moment our implementation is following:
  - In a) case colors are actually converted from sRGB to image color
     space and vice versa.
  - In case b) results depend on implementation of the blit.
     Generic blits (e.g. AnyToIntArgb and IntArgbToAny) are implemented using
     setRGB/getRGB and therefore colors are stored in "native" form.
     However, other blits (e.g. ByteGrayToIntArgb and IntArgbToByteGray)
     do not perform any conversion and therefore we may have sRGB data in
     the buffer.
  - In case of c) no convertion is performed and raw data is used.

Note that if pixel data are used by paired methods only (e.g. setRGB/getRGB
or set with blit and get with blit) we end up with same output as input.
However, if blit without conversion is used to set data and then data 
are accessed with getRGB() result is different from original data.

Fortunately this inconsistency has limited impact because it is 
applicable to non sRGB color spaces only.
Still it is easy to reproduce with grayscale images. E.g.

 - create TYPE_BYTE_GRAY and corresponding custom image.
 - fill the data buffer directly with same data.
 - draw image to some sRGB destination.

As the result the custom image will be look brighter then 
TYPE_BYTE_GRAY. It is because the TYPE_BYTE_GRAY is drawn by optimized
blits (without "gamma correction") whereas custom image is draw by using 
getRGB method (with "gamma correction").

Note that similar problem theoretically may happen with other color 
spaces like linear RGB.
It is not easily reproducible now because we have no predefined image 
types based on linear RGB color space.

Also note that generic blits use setRGB/getRGB so for custom images 
results are always consistent.

It seems that solution is to add conversion logic to blits (because it 
seems reasonable to expect that raw data buffer contains converted data).
It certainly will have performance hit and have to be done carefully.

For instance at the moment it seems we only have to worry about "gamma 
correction"  and can probably use something similar to LUT-based
approach that was added to ComponentColorModel in 1.3.x.

Original comment by connor.tumbleson on 26 Mar 2013 at 3:25

GoogleCodeExporter commented 9 years ago
Hi, I ran into this problem when customizing a ROM, after some puzzling I found 
a solution which gives good results as far as I could test.

Solution is to use the ImageTypeSpecifier class, with this class a new 
BufferedImage with the same parameters as the original can be created, even if 
the returned type is unknown!
In this way we can keep the new image always in the same format as the original 
and have no conversion issues giving the increase in brightness.
Checked on a ZTE ROM but needs more testing, not verified on phone yet but 
resulting image files look good. Thought it would be good to share; just 
included the complete file, not too big.

Original comment by christia...@hccnet.nl on 7 Jul 2013 at 7:30

Attachments:

GoogleCodeExporter commented 9 years ago
Thank you :)

It passed all my testing so far and seems to work great. I will run a few more 
tests and pass it to some testers and then merge it in.

I see no color changes on multiple decodes and rebuilds.

Thanks again.

Original comment by connor.tumbleson on 8 Jul 2013 at 4:19

GoogleCodeExporter commented 9 years ago

Original comment by connor.tumbleson on 8 Jul 2013 at 4:19

GoogleCodeExporter commented 9 years ago
No problem; glad I could help to improve such a great tool! Keep it up!

Original comment by christia...@hccnet.nl on 8 Jul 2013 at 7:22

GoogleCodeExporter commented 9 years ago
Fixed in commit: 63b0dd1edb626c8e4482955d0ab36752b7ee13df

Original comment by connor.tumbleson on 8 Jul 2013 at 9:11