0x0 Background
Well known (?), most (?) Unity3d for the engine. To further compress the resource size, the mapping resource is often compressed in ETC1 format on the Android platform to reduce volume. The egg hurts is that ETC1 does not support alpha channel ....
Program apes choose to split the original image, using a map to record alpha information separately. This brings inconvenience to the subsequent dismantling (stealing) (≧▽≦) (no face). Merge back on the line! righteously
0x1 implementation
The public ... An RGBA image contains three color channels and an alpha channel, which, after splitting, becomes an RGB parameter of the original image record, and an image only records the Alpha parameter.
If the collapse of the unpacking diagram:
So if you want to merge back, you just need to get the RGB values in a graph, get the alpha value in the two graph, and then merge the graphs that generate one by one RGBA messages together to save them.
The language used in this article is C #, first written in an easy-to-understand getpixel () method ~
0x2 Core code-Get pixel method
1 PrivateBitmap mergeimageold (Bitmap rgbtexture,bitmap alphatexture)2 {3Texturewithalpha =NewBitmap (Rgbtexture.width, Rgbtexture.height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);//Create a new bitmap with RGB resolution4 Try5 {6 for(inti =0; i < rgbtexture.width; i++)7 {8 for(intj =0; J < Rgbtexture.height; J + +)9 {TenColor Withalpha =Color.FromArgb (Alphatexture.getpixel (i, J). R, Rgbtexture.getpixel (i, J)); One Texturewithalpha.setpixel (i, J, Withalpha); A}//Internal for End -}//For End - the returnTexturewithalpha; - } - Catch(Exception ex) - { + Console.WriteLine (ex. Message); - returnTexturewithalpha; + } A}//Mergeimageold ()
Where 6-13 rows are critical code for loop-by-line pixel-wise processing
The overloads used here in line tenth are:
Color Color.FromArgb (int alpha,color basecolor);
The first parameter is the alpha value, the second parameter is the color, alphatexture.getpixel (i, J). R means to get the red component in the alphatexture of line I, J pixels, Rgbtexture.getpixel (i, J) means to get the color in Rgbtexture
Alpha value got, color also got, direct setpixel () just fine ~
0X3 Advanced Code-pointer method
One of the biggest problems with running the above code is ... The chicken is slow .... itself GetPixel () as slow as a snail we also have to getpixel in two pictures () .....
It takes about 2.4 seconds to process a 1.21M 1024*1024-sized picture on my computer.
After flipping through the predecessors ' data, I decided to use the pointer method instead of acquiring pixels
The use of pointers must be checked in the project settings to allow unsafe code and the code that involves the pointer operation must be placed in the unsafe {...} area otherwise not compiled ~
The code is as follows:
1 Public unsafeBitmap mergeimage (Bitmap rgbtexture,bitmap alphatexture)2 {3 intwidth =Rgbtexture.width;4 intHeight =Rgbtexture.height;5 6 Try7 {8BitmapData Texturewithalphadata = Rgbtexture.lockbits (NewRectangle (0,0, width, height), imagelockmode.readwrite, Pixelformat.format32bppargb);//lock an image into memory for Operation9BitmapData Alphatexturedata = Alphatexture.lockbits (NewRectangle (0,0, width, height), imagelockmode.readwrite, Pixelformat.format32bppargb);Ten One byte* RESULTP = (byte*) Texturewithalphadata.scan0;//gets the first address in the memory A byte* Alphap = (byte*) Alphatexturedata.scan0; - - for(intj =0; J < height; J + +) the { - for(inti =0; I < width; i++) - { -resultp[3] = alphap[2];//arbg is stored in memory in the order Gbra so resultp[3] is the alpha component Resultp[2] is the red component +RESULTP + =4;//Move down 4 positions to process the next pixel information -Alphap + =4; + } A } at -Rgbtexture.unlockbits (Texturewithalphadata);//Unlock - alphatexture.unlockbits (alphatexturedata); - - returnrgbtexture; - } in Catch - { to returnrgbtexture; + } -}//mergeimage ()
The 8th line is to note that the second parameter is set to read-write or write-only (imagelockmode.writeonly), and the third parameter is set to 32 bits because it requires a ARGB format with transparent channels AGRB
The 9th line can be set to read-only (imagelockmode.readonly) and because the picture itself is read without an alpha channel, it can be formatted as Pixelformat.format32bpprgb
Line 18th Note that the order of the 32-bit ARGB format bitmap in memory is [g,b,r,a] so the alpha component is actually in the fourth position
Also must pay attention to the release of resources the author put it outside this method or handle the amount of a minute memory explosion
1 rgbtexture.dispose (); 2 alphatexture.dispose (); 3 texturewithalpha.dispose ();
0x4 pointer Method Supplement
The example of this article requires an alpha channel, so the direct use of the 32-bit ARGB format, 32-bit bitmap in four bytes per pixel, the length of each row of data must be a multiple of 4, so do not consider the alignment
The other very common 24-bit graphs each pixel occupies 24/8 = 3, when the length of the data per row is not necessarily a multiple of 4
For a chestnut: a 10 * 10 24-bit picture each row has a data length of 3 * 10 = 30 bytes This will automatically be added to 0 bytes with "32", altogether supplementing 32-30 = 2 bytes
Then if you use pointers in this case to read the data, you must skip the bytes of those bits per row to get the actual number of bytes in the BitmapData class as an attribute bitmapdata.stride
So to process a 24-bit picture, you need to be at the end of the first-level for loop (that is, skip the placeholder bytes at the end of each line as the chestnut above will jump 2 bytes)
The code below can be compared with 0x3
1 byte* RESULTP = (byte*) Texturewithalphadata.scan0;//gets the first address in the memory2 byte* Alphap = (byte*) Alphatexturedata.scan0;3 4 intResultoffset = Texturewithalphadata.stride-width *3;//subtract the length of an effective pixel in a picture by the actual occupied length this line of code is valid only for 24-bit graphs5 intAlphaoffset = Texturewithalphadata.stride-width *3;6 7 for(intj =0; J < height; J + +)8 {9 for(inti =0; I < width; i++)Ten { Oneresultp[2] = alphap[2];//RBG in memory order for GBR Here's just a handy comparison of chestnuts. This line of code will set the red component of the 2 graph to the 1 graph after running . ARESULTP + =3;//Move down 3 positions to process the next pixel information -Alphap + =3; - } theRESULTP + = Resultoffset;//because the width of the picture is used above, the pointer stops at the front of the placeholder byte, so it needs to skip too many bytes . -Alphap + =Alphaoffset; -}
0x5 End
Code Address: Https://github.com/yyuueexxiinngg/HSoD2TextureMerge
Extraction tool used: Https://github.com/Perfare/UnityStudio
Time-consuming comparisons in two ways: (Right-click new tab Open)
Disintegration of the school Park 2 and most of the ETC1 compression format of the Unity3d game Package diagram processing