[GUIDE][TOOL][v1.2]-=Solved=-The Google Splash Sceen & Bootloader Graphics

Search This thread

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
Note 3
n900w8_mj1_0034_zps75afe135.jpg~original

n900w8_mj1_0036_zpsd34da51e.jpg~original

n900w8_mj1_0033_zpsf115d96c.jpg~original

n900w8_mj1_0035_zpsb90716ab.jpg~original

n900w8_mj1_0032_zpsf574dc12.jpg~original

n900w8_mj1_0029_zps15ed52f7.jpg~original

n900w8_mj1_0031_zpsb086dc02.jpg~original

n900w8_mj1_0025_zps582facc7.jpg~original

n900w8_mj1_0030_zps6844388b.jpg~original

n900w8_mj1_0026_zpsc3199afd.jpg~original

n900w8_mj1_0022_zpsdda3eef0.jpg~original

n900w8_mj1_0027_zps956627f9.jpg~original

n900w8_mj1_0028_zps0e15c189.jpg~original

n900w8_mj1_0024_zpsbcfa5f07.jpg~original

n900w8_mj1_0020_zps1e6daa94.jpg~original

n900w8_mj1_0021_zps90cc2cc6.jpg~original

n900w8_mj1_0023_zps9c6729e9.jpg~original

n900w8_mj1_0019_zpse7efeaf3.jpg~original

n900w8_mj1_0017_zps473ee8e0.jpg~original

n900w8_mj1_0018_zpsf8a10c44.jpg~original

n900w8_mj1_0016_zps227a0b38.jpg~original

n900w8_mj1_0010_zps1814313a.jpg~original

n900w8_mj1_0009_zps01b57231.jpg~original

n900w8_mj1_0015_zpsb13405a4.jpg~original

n900w8_mj1_0014_zps7075dc80.jpg~original

n900w8_mj1_0011_zps43acd2f7.jpg~original

n900w8_mj1_0012_zps78bf6a3b.jpg~original

n900w8_mj1_0013_zpsfc727d73.jpg~original

n900w8_mj1_0005_zps1735bd87.jpg~original

n900w8_mj1_0007_zpsd24a7148.jpg~original

n900w8_mj1_0002_zpsdf1803be.jpg~original

n900w8_mj1_0008_zpsec5e7a4b.jpg~original

n900w8_mj1_0006_zps3e9257b6.jpg~original

n900w8_mj1_0001_zps1e5dbaef.jpg~original

n900w8_mj1_0004_zps1aaf225a.jpg~original

n900w8_mj1_0003_zps6e1cad4c.jpg~original

Samsung Tab 2 7.0 & 10.1
tab2_0016_zps81070fb2.jpg~original

tab2_0009_zps9dabfd1e.jpg~original

tab2_0010_zps381520e6.jpg~original

tab2_0011_zps3b2bbb80.jpg~original

tab2_0014_zps3104f8ae.jpg~original

tab2_0015_zpsd1716bdf.jpg~original

tab2_0013_zps551895b9.jpg~original

tab2_0012_zps02972946.jpg~original

tab2_0004_zps0cfce002.jpg~original

tab2_0005_zps1e30c368.jpg~original

tab2_0007_zpse13dcfcf.jpg~original

tab2_0003_zpsef5b7aab.jpg~original

tab2_0002_zpsc86e6945.jpg~original

tab2_0001_zpseeae9602.jpg~original

tab2_0006_zps2236d6cc.jpg~original

tab2_0008_zps8d3ea7e8.jpg~original
 

E:V:A

Inactive Recognized Developer
Dec 6, 2011
1,447
2,222
-∇ϕ
@makers_mark : Hi, we found something called Qmage. Apparently all images in Samsung 4.4.4+ firmware are in this proprietary qmg format, so no more PNGs.
They mention RGB565 and we're wondering if this is the same stuff as you've been working with?
If so, perhaps your tool can be extended to deal with these?
 

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
@makers_mark : Hi, we found something called Qmage. Apparently all images in Samsung 4.4.4+ firmware are in this proprietary qmg format, so no more PNGs.
They mention RGB565 and we're wondering if this is the same stuff as you've been working with?
If so, perhaps your tool can be extended to deal with these?

Thanks, that is very interesting. I've looked at qmgs before, and can see a repetition pattern in them, but the compression was unintelligible. I will definitely take another look at them though!
[edit]
I've never seen rgb5658. That is something, I'll have to keep an eye out for. That extra byte means so much when you're looking for an image encoding, especially with rgb565, as it is hard as hell to interperet two plain bytes as pixel data when you look at a whole image. ARGB8888 provides you with a static barrier of 1's between pixels (usually, unless the image actually takes advantage of the alpha channel)

I'll get back with you, with this new found knowledge, thanks again!
 
Last edited:

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
Just for thread completion, alireza7991 also has some png2rle in his GitHub.

I am all for thread completion and internet history, and think that it is vital (among lots of other things) as to trying to stay advanced with technology and also with perceived avenues of future technology.

I have to say though, that I have seen the source, and the thread. It involves the same two programs I gave credit to in the OP, but is sans credit. That's okay with me, as long as everyone else is okay as well, but the important thing to note is that, it only involves the run length encoding of rgb565; two byte count, two byte color. And if that is all you are focused on, you may as well call it a file extension. But, my thread is more about the concept of run length encoding. It is not an extension to me and I've seen different variations that make it a compression method, and not your typical file type. Since I wrote the original post, I've actually seen some kernel source that uses the 4 byte method.Here is one example But I still haven't found any kernel code utilizing the 1 byte count 3 byte color that is used in the Nexus 5 bootloader.

I am trying to infer that what they use in the bootloader may potentially be used in kernels, somewhere down the road. I don't know and don't care, but I can't go wrong in documenting and making a conversion tool, just in case.

I know you are not talking directly to me, but I am on the same page as you, and believe that all things should be documented. And I think that your drive is the same as mine.:good:
 
Last edited:
  • Like
Reactions: osm0sis and E:V:A

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
Last week they came out with the HTC Nexus 9. I was awkwardly eager to see the bootloader, to see how it was structured and what not. Google released the factory images, with `bootloader-flounder-3.43.0.0114.img` included. At first I didn't see anything that looked like images, but I did see a lot of `PK` headers. Which is "almost" always a zip file. I changed the `.img` extension to `.zip` and it worked.
1_ss_zpsc60cc2cc.png~original


So in true HTC fashion, they have allowed access to the partition which is the splash screen, given you're bootloader is not locked. The second file down is sp1.nb0, which is a non rle image in rgb565 pixel format. It resides in mmcblk0p9 on the device, and the image only takes up ~2/5 ths of the partition. I don't think the extra space is of any significant value, just a 1024*1024*1024.... space thing.

I haven't had a lot of time to see what other images are in the different files, but I did find some run length encoded images; like the 3 android skateboarders, and the htc logo with the reflection.

Now that I have a n9, it took me mere decaminutes to change the splash screen. It is as simple as `fastboot flash spash1 raw.rgb565.file.name.on.your.computer` I must say thank you XDA, I've never owned an HTC device, but reading through all the threads regarding HTC splash screens; in between the time I got the bootloader until the time I got home to the new device (I was out of town). It made my work easier. If anyone has a HTC Nexus 9 and would like to change it, here is my thread.
@E:V:A
I haven't had time to test some of the QMG source, yet.. I did however learn that they are pretty complex, two stages of decompression with a dozen algorithms. I found some source for a program named `wave remaker` right here on XDA and a couple of threads that are very interesting. Most of the interesting stuff came from two different people and neither one of them use the forums anymore, or if they do, they use a different account. But one of them did briefly post that qmgs right now are different than they use to be. And I have no idea how they got the source that they used, it was probably some sort of corporate liscense or something of that nature. I will start testing whether that statement is true or not in a couple of months.
 

E:V:A

Inactive Recognized Developer
Dec 6, 2011
1,447
2,222
-∇ϕ
The second file down is sp1.nb0, which is a non rle image in rgb565 pixel format. It resides in mmcblk0p9 on the device, and the image only takes up ~2/5 ths of the partition.

Interesting, that is actually a Qualcomm Tegra (?) binary blob, that could be part of the boot loader itself, or the modem firmware, depending on what your partition table says about P9 content. Those type of files are flashed by emmc loader... Do have a look in my threads related to Qualcomm...

EDIT: Nope, I may be wrong, that file seem to be the (Bootloader) Splash Screen, so yes, it's probably an image. I'm just wondering why it need to be 6MB?

Also, please link to those other threads, relating to QMG. I bet they got the code from either the Code Aurora or the Android Sources repo's.
 
Last edited:
  • Like
Reactions: makers_mark

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
@E:V:A
Sorry for bad wording, but yes, the Google splash screen is in a straight rgb565 (two bytes per pixel) format in the bootloader.img from google. If you change the .img file extension to .zip, that is when you see the screenshot up above. The splash screen is stored in the sp1.nb0 file. It is 6 megabytes exactly because the width x height x bytes per pixel yields 6,291,456 bytes. (1536*2048=3145728 >> 3145728*2=6291456)
However if the image was run length encoded, it would only be 20288 bytes.
On the device side it resides in mmcblk0p9, a 16.0 MB partition, here is the partition list by-name; it's name is SP1:
lrwxrwxrwx root root 2014-11-11 17:13 APP -> /dev/block/mmcblk0p29
lrwxrwxrwx root root 2014-11-11 17:13 CAC -> /dev/block/mmcblk0p30
lrwxrwxrwx root root 2014-11-11 17:13 CDR -> /dev/block/mmcblk0p23
lrwxrwxrwx root root 2014-11-11 17:13 DIA -> /dev/block/mmcblk0p20
lrwxrwxrwx root root 2014-11-11 17:13 DTB -> /dev/block/mmcblk0p5
lrwxrwxrwx root root 2014-11-11 17:13 EF1 -> /dev/block/mmcblk0p21
lrwxrwxrwx root root 2014-11-11 17:13 EF2 -> /dev/block/mmcblk0p22
lrwxrwxrwx root root 2014-11-11 17:13 EKS -> /dev/block/mmcblk0p3
lrwxrwxrwx root root 2014-11-11 17:13 EXT -> /dev/block/mmcblk0p11
lrwxrwxrwx root root 2014-11-11 17:13 FST -> /dev/block/mmcblk0p12
lrwxrwxrwx root root 2014-11-11 17:13 GPT -> /dev/block/mmcblk0p33
lrwxrwxrwx root root 2014-11-11 17:13 KEY -> /dev/block/mmcblk0p1
lrwxrwxrwx root root 2014-11-11 17:13 LNX -> /dev/block/mmcblk0p16
lrwxrwxrwx root root 2014-11-11 17:13 MD1 -> /dev/block/mmcblk0p25
lrwxrwxrwx root root 2014-11-11 17:13 MD2 -> /dev/block/mmcblk0p26
lrwxrwxrwx root root 2014-11-11 17:13 MFG -> /dev/block/mmcblk0p18
lrwxrwxrwx root root 2014-11-11 17:13 MSC -> /dev/block/mmcblk0p17
lrwxrwxrwx root root 2014-11-11 17:13 NCT -> /dev/block/mmcblk0p10
lrwxrwxrwx root root 2014-11-11 17:13 OTA -> /dev/block/mmcblk0p28
lrwxrwxrwx root root 2014-11-11 17:13 PG1 -> /dev/block/mmcblk0p14
lrwxrwxrwx root root 2014-11-11 17:13 PST -> /dev/block/mmcblk0p27
lrwxrwxrwx root root 2014-11-11 17:13 RCA -> /dev/block/mmcblk0p8
lrwxrwxrwx root root 2014-11-11 17:13 RV1 -> /dev/block/mmcblk0p6
lrwxrwxrwx root root 2014-11-11 17:13 RV2 -> /dev/block/mmcblk0p13
lrwxrwxrwx root root 2014-11-11 17:13 RV3 -> /dev/block/mmcblk0p32
lrwxrwxrwx root root 2014-11-11 17:13 SER -> /dev/block/mmcblk0p19
lrwxrwxrwx root root 2014-11-11 17:13 SOS -> /dev/block/mmcblk0p15
lrwxrwxrwx root root 2014-11-11 17:13 SP1 -> /dev/block/mmcblk0p9
lrwxrwxrwx root root 2014-11-11 17:13 TOS -> /dev/block/mmcblk0p2
lrwxrwxrwx root root 2014-11-11 17:13 UDA -> /dev/block/mmcblk0p31
lrwxrwxrwx root root 2014-11-11 17:13 VNR -> /dev/block/mmcblk0p24
lrwxrwxrwx root root 2014-11-11 17:13 WB0 -> /dev/block/mmcblk0p4
lrwxrwxrwx root root 2014-11-11 17:13 WDM -> /dev/block/mmcblk0p7​

Links for QMG read-up:
This is the thread for Wave Remaker, it could susposedly decode qmg files, although in my short tests I couldn't get it to work. Other users in this thread did though. This is where the source for the program was released:
http://xdaforums.com/showthread.php?t=1028714
This is a really good one, where a user took the source from the above program and continued the development where the original user stopped, after releasing the source. I read the whole thing, but what I referenced up above can be found in posts 58-63http://xdaforums.com/showthread.php?t=2028845
 
  • Like
Reactions: E:V:A

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
Nexus 6 with MotoRun

The other day Google released the factory image for the Nexus 6, and a couple of things have changed in the way of run length encoding formats. They brought out a new one that I wasn't sure if I'd be able to figure it out, but I finally got it. I will post the images in the next post. I made the decoder but haven't made an encoder yet, but I will. This new format is setup like a file format, it has a header that is 12 bytes long. The first 7 bytes is "MotoRun" followed by a "0" then a 16-bit unsigned integer representing the width of the image, then another 16-bit value representing the height.

Then it goes right into the data part. Parts of this resembles the three byte rle method, and the image is actually encoded in the bgr24 pixel format (in the Nexus 6 at least). Here is how the run length encoding works. You have two count bytes and three color bytes. If the last bit is set in the first count byte, you drop it and essentially have a 15 bit unsigned integer. It is flagged as having a run multiplier, or actually using all the bits (minus the flag bit). (You can look at it that way, or you can simply multiply the value of the first count byte by 256, after dropping the flag bit of course, and add the second byte to it.) That is how you count, then your next three bytes are the color bytes that are going to be repeated how ever many times the count calls for.

If the flag bit is not set, then the count is not going to be a run of the following three bytes. You have to get the count from the second byte, but this count is the number of pixels you are getting ready to copy in a row. If your count bytes is (0,5) then the next 15 bytes will be read directly. It is 15 in this format because we are dealing with a 3 byte pixel format, and 5*3=15.

The file is complete when 255 (aka 11111111) goes into the count.

The height and width encoded in the header is for a purpose. No runs shall carry over to the next line down! This means the height and width is just for encoding the image.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#define BIT_SET 0x80
#define IS_BIT_SET(x) (x & BIT_SET)

unsigned int _CRT_fmode = _O_BINARY;

void motoDecode(char *inputFile, char *outputfile)
{
	FILE *outStream;
	FILE *inStream;
	unsigned short repeats;
    unsigned char data[5];
	unsigned char color[3];
	unsigned short counttotal = 0;
	
	if ((inStream = fopen(inputFile, "rb")) == NULL){
		fclose(inStream);
		fprintf(stderr, "\n%s\nCould not be opened.", inputFile);
		return;
	}

	if ((outStream = fopen(outputfile, "wb")) == NULL){
		fclose(outStream);
		fclose(inStream);
		fprintf(stderr, "\n%s\nCould not be opened.", outputfile);
		return;
	}
	int inNumber = fileno(inStream);
	int outNumber = fileno(outStream);

    while(read(inNumber, data, 5) == 5){
		counttotal = 0;
		color[0] = data[2];
		color[1] = data[3];
		color[2] = data[4];

		if (IS_BIT_SET(data[0])){
			data[0] &= ~0x80;
			counttotal = (((data[0] * 256)) + data[1]);
			for (repeats = 0;repeats < counttotal; repeats++){
				write(outNumber, &color, 3);
			}
			continue;
		} else {
			counttotal = (data[1]);
			write(outNumber, &color, 3);
			for (repeats = 0; repeats < counttotal -1; repeats++){
				read(inNumber, color, 3);
				write(outNumber, &color, 3);
			}
			continue;
		}

	}
}


int main(int argc, char **argv)
{
	char *inputFile;
	char *outputfile;
	
	int c;

	while ((c = getopt (argc, argv, "i:o:")) != -1)
		switch(c)
			{

			case 'i':
				inputFile = optarg;
				break;
			case 'o':
				outputfile = optarg;
				break;

			}

	motoDecode(inputFile, outputfile);
	
return(1);
}
 
  • Like
Reactions: osm0sis

Iceman_jkh

Senior Member
Aug 10, 2010
242
32
Hi Makers_Mark.
I've tried to follow along with your commentary here so that I could mod my N7-2013 Deb boot screen. (It uses the bootloader-deb-flo-04.04.img)
Firstly, even though I haven't been able to follow it to conduct the mod, thanks for the informative write up - I managed to get the gist of it :)

My Nexus 7-2013 is mounted in the dash of my car, in a reverse landscape orientation.
All I'd like to change for the splash screen is to remove the Google text (just replace it with black) and to turn the padlock 90 degrees (so it's upright when the tablet is in reverse landscape). Fairly simple (I think).
Is there any chance you can do a very quick write up for me on this so I can do the mod?

I just haven't managed to connect the dots between your commentary and what I'm trying to do.

Thanks in advance :)
 

osm0sis

Senior Recognized Developer / Contributor
Mar 14, 2012
16,767
40,432
Halifax
GT-i9250
Google Nexus 4
Since the Nexus 2013 is now EOL for OTA updates, here are the highlights I just found for our final bootloader:

bootloader-flo-flo-04.08.img
4 byte pp
bgr0
(offsets are in decimal)

logo:
search string 9C030000 00000000 01000000 09090900
size 518x179
length 43768

offset 1187772 (311688 in aboot)
offset 3270044 (2393960 in aboot)
offset 3955364 (3079280 in aboot)
offset - (3167460 in aboot only)

lock:
search string 1C000000 00000000 01000000 24242400
size 72x94
length 4616

offset 1127848 (251764 in aboot)
offset 1267360 (391276 in aboot)
offset 3102124 (2226040 in aboot)

Worth restating that the corresponding partition on-device containing the images, mmcblk0p12 (as mentioned several times by @makers_mark), is named aboot. When the device is locked, abootb (mmcblk0p19) is a byte-for-byte copy of aboot with the exception of the bootloader's lockstate storage area located near 5242368 with another "ANDROID-BOOT!". When unlocked this is also the case, and the only further change is at the lockstate offset in aboot.

Also.. *cough*

Now.. to generate a replacement image and see about hacking it in... ;)
 
Last edited:
  • Like
Reactions: makers_mark

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
Since the Nexus 2013 is now EOL for OTA updates, here are the highlights I just found for our final bootloader:

bootloader-flo-flo-04.08.img
4 byte pp
bgr0

logo:
search string 9C030000 00000000 01000000 09090900
size 518x179
length 43768

offset 1187772 (311688 in aboot)
offset 3270044 (2393960 in aboot)
offset 3955364 (3079280 in aboot)
offset - (3167460 in aboot only)

lock:
search string 1C000000 00000000 01000000 24242400
size 72x94
length 4616

offset 1127848 (251764 in aboot)
offset 1267360 (391276 in aboot)
offset 3102124 (2226040 in aboot)

Worth restating that the corresponding partition on-device containing the images, mmcblk0p12 (as mentioned several times by @makers_mark), is named aboot. When the device is locked, abootb (mmcblk0p19) is a byte-for-byte copy of aboot with the exception of the bootloader's lockstate storage area located near 5242368 with another "ANDROID-BOOT!". When unlocked this is also the case, and the only further change is at the lockstate offset.

Also.. *cough*

Now.. to generate a replacement image and see about hacking it in... ;)
I will make a lock image that has a long white line ,corresponding to their oblivious pixel, and replace it in all three spots. It will contain no more and no less data (no padding in testing scenarios). If you want to "dd" it to the partition or use otherwise "cough" mentions, then feel free. Very nice find there. I used a popular internet archive to get the source (thread) that I was referring to. The cough seems about the same caliber as far as knowledge and insight.

Let me know if you want me to make a 4.08 bootloader for you. I will not go off of your offsets, I will re-verify all that and quintuple check everything. You can do the same as well if you want to be extra sure. If that was the case we would have bianrily exact files. When I wrote this thread, the N7 was the only (and first) android that I owned. Hence it was not sacrificial to me, but an enjoyment that I couldn't just test like that. It is dead now (probably just the battery) and getting ready to set sail on an equitable distribution-end of life garbage cycle, or straight to the data recovery center for cheating wives who want to find any dirt they can to make themselves look better :laugh:

:)
 
  • Like
Reactions: osm0sis

osm0sis

Senior Recognized Developer / Contributor
Mar 14, 2012
16,767
40,432
Halifax
GT-i9250
Google Nexus 4
I will make a lock image that has a long white line ,corresponding to their oblivious pixel, and replace it in all three spots. It will contain no more and no less data (no padding in testing scenarios). If you want to "dd" it to the partition or use otherwise "cough" mentions, then feel free. Very nice find there. I used a popular internet archive to get the source (thread) that I was referring to. The cough seems about the same caliber as far as knowledge and insight.

Let me know if you want me to make a 4.08 bootloader for you. I will not go off of your offsets, I will re-verify all that and quintuple check everything. You can do the same as well if you want to be extra sure. If that was the case we would have bianrily exact files. When I wrote this thread, the N7 was the only (and first) android that I owned. Hence it was not sacrificial to me, but an enjoyment that I couldn't just test like that. It is dead now (probably just the battery) and getting ready to set sail on an equitable distribution-end of life garbage cycle, or straight to the data recovery center for cheating wives who want to find any dirt they can to make themselves look better :laugh:

:)

Hmm, I'll have to check out the popular internet archives since perhaps the pictures, etc. would still be intact in their coughs.. :highfive:

I tried hacking the bootloader.img already and fastboot throws a "signature failed!" error, so it seems aboot is the only way to go.

I decided to get crazy with it so I already tried replacing the lock image with the new version in all 3 places in aboot and flashing it and it hard bricked my device. But not so hard that I couldn't recover it myself with some more poking around. ;)

So it seems your original assessment may have been correct, or perhaps I was just a bit cavalier since the new lock image was shorter in data length than the old and required some minor 00 padding. Since I can reliably recover my device (tried it again by fully zeroing aboot), I'm definitely up for some more testing, and agree that a more methodic/scientific approach where the data is the same length (perhaps just changing a single pixel or something to start with) would probably be the best approach. :laugh::cowboy:
 
Last edited:
  • Like
Reactions: makers_mark

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
Hmm, I'll have to check out the popular internet archives since perhaps the pictures, etc. would still be intact in their coughs.. :highfive:

I tried hacking the bootloader.img already and fastboot throws a "signature failed!" error, so it seems aboot is the only way to go.

I decided to get crazy with it so I already tried replacing the lock image with the new version in all 3 places in aboot and flashing it and it hard bricked my device. But not so hard that I couldn't recover it myself with some more poking around. ;)

So it seems your original assessment may have been correct, or perhaps I was just a bit cavalier since the new lock image was shorter in data length than the old and required some minor 00 padding. Since I can reliably recover my device (tried it again by fully zeroing aboot), I'm definitely up for some more testing, and agree that a more methodic/scientific approach where the data is the same length (perhaps just changing a single pixel or something to start with) would probably be the best approach. :laugh::cowboy:

Attached is my aboot.img backup for you to modify and generate your tests. :good:
You have done your research on the bootloader in question, and maximized efficiency in a recovery of a failed attempt. Good job!
One of the good things about RLE (pertaining to this particular scenario) is that you don't have to alter just one pixel to make the image size the same. That is actually really difficult based on the image. I was simply putting out there the random white dot at the bottom right of the lock as a "shove it" move, whereas the ideal way would be to move some pixels that do not go from a white/grey to another white/grey (or black/grey vice versa). The solution was obvious (after the fact):

72x94_zpsemnjqv5a.png~original
. It is the exact same size and doesn't have to mess with any of the grey areas, and should not be hard to recognize if it takes and boots. I just made a black line white by changing 000 at byte 2884 (in the cut out image, not the complete bootloader) to ÿÿÿ. Here is the data for it.
 

Attachments

  • lock.zip
    4.6 KB · Views: 42
  • Like
Reactions: osm0sis

osm0sis

Senior Recognized Developer / Contributor
Mar 14, 2012
16,767
40,432
Halifax
GT-i9250
Google Nexus 4
You have done your research on the bootloader in question, and maximized efficiency in a recovery of a failed attempt. Good job!
One of the good things about RLE (pertaining to this particular scenario) is that you don't have to alter just one pixel to make the image size the same. That is actually really difficult based on the image. I was simply putting out there the random white dot at the bottom right of the lock as a "shove it" move, whereas the ideal way would be to move some pixels that do not go from a white/grey to another white/grey (or black/grey vice versa). The solution was obvious (after the fact):
72x94_zpsemnjqv5a.png~original

It is the exact same size and doesn't have to mess with any of the grey areas, and should not be hard to recognize if it takes and boots. I just made a black line white by changing 000 at byte 2884 (in the cut out image, not the complete bootloader) to ÿÿÿ. Here is the data for it.

No luck. Tried it in all 3 locations, tried it in only last 2 and last 1 just to see, and still nothing. Then returned to untouched manually by changing the bytes back and flashing that, and that unbricked with no issue (just to rule out something weird with the editing/flashing process).

I guess our only hope would be to figure out where/how the signature is stored and update it (probably trustzone/tz?), but the same could be said for a whole bootloader.img and that might be a safer prospect mediated by fastboot. And of course figuring out the signing procedure/key might be next to impossible. No new logo for us. :(;)
 
Last edited:
  • Like
Reactions: makers_mark

L.F.B.

Senior Member
Feb 29, 2012
818
356
Thats a bummer.... I thought it was easy to chaange splash screen like on nexus 5...


Ii just wanted the new Google logo updated on splash screen...
 
  • Like
Reactions: osm0sis

Top Liked Posts

  • There are no posts matching your filters.
  • 15
    Attempting to modify your bootloader may brick your device!!
    Updated to v1.2: August 23rd, 2014
    -Embedded a solid jpeg extractor in rlimager1.2.c (java is no longer needed)
    -Added a zero byte function to fix the encoding of rgb0, bgr0, 0bgr, & 0rgb pixel formats
    A while back I wanted to make a boot animation for my Nexus 7 2013, that utilized the Google splash screen in the first part of the bootanimation. I started searching Google and XDA, and found that it was embedded in the bootloader somewhere, but nobody had a clue how to retrieve it. I could see the battery charging icons with a hex editor and use FFmpeg to convert them from their encoded rgb24 pixel format into usable images. That was easy, but I couldn't find what I was looking for. I then figured they were in some odd pixel format, maybe even proprietary. I made loops going through every conceivable pixel format at different widths, generating 1000's of images, still nothing. The last thing I tried was making an image where every bit in the bootloader was translated into a pixel, either on or off, still nothing. I pretty much gave up, until I came across this thread. I had heard of run length encoding, but didn't know it was used in Android. I soon found that Google and some manufacturers were using it for the graphics in their bootloaders.

    Hit the button below to see the splash screen for the Nexus 7 2013, this is a pixel for pixel exact image, with the Google logo and Unlock Icon in their un-encoded form as seen on the devices screen. (unfortunately the splash screen wasn't encoded as a complete image, the text was encoded one place and the lock icon in another, so I did have to use photoshop to make a 1200x1920 black background and place the Google logo and the lock icon in the right position.)
    Google_line_up_zps04806259.png~original

    The complete Google splash screen in full 1200x1920 can be downloaded as an attachment at the bottom of this post. It is a PSD with a black background layer and the 518 pixel "Google" and the 72 pixel "unlock" all on separate layers.

    The "Tool":

    This is a Windows batch script I wrote to find images in any type of file. Included in the zip at the bottom of this post is: a modified run length encoder/decoder, rlimager1.2.c, that does the encoding/decoding and the extraction of jpegs from any type of file.

    Rlimager1.2.c is based off of the original to565.c put out by the AOSP several years ago. To565 was made to convert an rgb24 image into a rgb565 run length encoded file which could then be named initlogo.rle, and packed into the boot image for a kernel splash screen. Of course having the ability to encode images in this format left users the want to decode them as well (to make sure it worked before they flashed it to their device). XDA user @zebarbu in this thread, made a program to decode rgb565 rle as well. I must credit both of these authors, as rlimager1.2.c is based off of both these programs.:good: I have added additional decoding/encoding of some newer formats; as mentioned below; as well as a jpeg extractor and a function to write 0's where ffmpeg will put 1's in the case of certain pixel formats.

    The executable rlimager1.2.exe was compiled with mingw32-gcc 4.8.1 on a 64-bit Intel running Windows 7, and has been tested on Windows 7 Home Premium and Windows 8. The batch script, RUN_length_imager_v1.2.bat, will not work with obsolete versions of Windows. The source file for rlimager1.2.exe and RUN_length_imager_v1.2 batch script are available in the second post, as well as in the `src\` folder of the download. FFmpeg is also in the download, and the source can be found here, while the included pre-compiled version was downloaded at Zeranoe.

    Googles ADB is also included in the download, which is located at the bottom of this post.

    "Run_length_imager_v1.2.zip", should be unzipped into a new directory.
    Click the button below for instructions on how to use rlimager1.2 by itself. Rlimager1.2 is a standalone command line program.

    Usage:

    rlimager1.2.exe ([-e] [2-4] | [-d] [2-4] [-m] [max run] [-o] [offset]) < input_file > output_file

    Mandatory, one or the other

    -d (2-4)Run Length Decode input_file from 2, 3, or 4 byte color pattern
    -e (2-4) Run Length Encode input_file to 2, 3, or 4 byte color pattern
    -j (output root name) Extract Jpegs from file. Output name can include a full path.
    -z (skip) -o (offset) Zero every (skip) bytes, starting with (offset)

    Optional for [-d] decoding only:

    -m (max run) Maximum pixel run to decode. Default is 0, which defaults to the maximum allowable for each color pattern
    -o (offset) Offset (in bytes) to start decoding. Default is 0


    Examples:

    rlimager1.2 -d 4 -m 8064 < "C:\example_file.rle" > "C:\output\rle_decoded\example_file.rgb0"
    rlimager1.2 -j root_name < "C:\users\downloads\system.img"

    Notice with the jpeg extractor example above you have to use: < "inputfile"

    rlimager1.2 -z 8 -o 5 -i "C:\output\example_file.rle" -e 4 < "C:\example_file.rgb0" > "C:\output\example_file.rle"

    The above example run length encodes the input file, then takes the output file and zeros every eighth byte starting at 5
    You can also zero byte any file without doing it all on one line, like:

    rlimager1.2 -z 5 -o 8 -i "C:\file_to_be_zeroed_every_5th_byte_strarting_with_the_8th.raw"
    To load a file into RUN_length_imager_v1.2.bat, you have two options:
    -Drag and drop the file you wish to use onto the "RUN_length_imager_v1.2.bat" file.
    -Run the program and choose option 4 at the menu. This will pull whichever partition you choose, from your device to your computer.

    Note:
    The second method requires you to have your ADB drivers for your device installed on your computer. You must also have busybox installed on your device. If for some reason ADB will not start and you end up with a blank partition list, simply close the program and open it back up and it should work. If it still doesn't work your ADB is probably not functioning correctly.​

    First and foremost before you get too much into searching for run length encoded images, you should check for jpegs first, especially if you have a Samsung device. It is really fast, and all you have to do is drag the file onto the RUN_length_imager_v1.2.bat file and select option 8 at the main menu. In five seconds or less, if there are jpegs in the file, you will have all of them in their entirety.

    What is run length encoding?

    RLE is a method of encoding an image with the intentions of having a smaller filesize. If you have 1000 pixels of the exact same color, you can save memory, by instead of encoding (R,G,B) 1000 times; you can add a count before the pixel description, 1000 (R,G,B). This works real efficiently for images that have lots of pixel runs, but an image where every pixel is different actually will take more memory than your conventional method of storage.

    The Run Length Patterns:

    I have found three different run length patterns so far. The first is the original one mentioned up above, rgb565, or as I call it 2 byte. This format can be used to encode any pixel format that uses two bytes per pixel. It works like this, the first 2 bytes is the count and the next 2 bytes is the color. The M8 uses this encoding for its bootloader graphics.
    Note:
    When I say "can be used to encode any pixel format that uses two bytes per pixel", I really mean pixel formats with sequential pixels. Some pixel formats use the YUV colorspace. Not all formats stored in the YUV colorspace store the pixels sequentially. For instance some YUV pixel formats will take 6 bytes of data for 4 pixels, but the first 3 bytes are not just for the first 2 pixels.
    In the RGB colorspace there are BAYER pixel formats which don't encode sequential pixels either, the colors are split onto different lines in this method. Neither of the previous examples are candidates for this type of run length encoding.​

    The Nexus 5 and 4 use this next one, what I call 3 byte, because it can be used to encode any pixel format that uses...3 bytes per pixel. This encoding uses a 1 byte count and 3 byte color. This is easily the slowest method, for obvious reasons.

    The last one, up to this point, is what I will reference as 4 byte. It works with four byte per pixel pixel formats, and uses 4 bytes for the count and 4 bytes for color. Both Nexus 7's use this format.

    There may be more patterns, but it is hard to find partition dumps to download off the internet. I have found several though, and found run length encoded images in almost all of them. If anyone wants to upload a bootloader, I will gratefully add it to my collection and see what is in it.

    This program will take any file, and decode it using whatever pixel format you choose, and if you have run length decoding turned on it will automatically associate the proper run length method to make a usable image, if there is one. Another important thing when dealing with raw image files, besides the pixel format, is the line length (width). This width is encoded in regular image files like bmp, jpg, and pngs. But raw images are nothing but pixel data. To get the correct image, if there is one, you have to specify when to go to the next line. I have built loops into the windows script that will let you specify multiple pixel formats to run, with an embedded loop that goes through all of the different widths you choose.

    You may want to load a whole bootloader file to see if there are any images in it. To do so just drag and drop the file onto "RUN_length_imager.bat" Since the file contains different types of code and possibly images, you will want to set the maximum pixel count down to around 1000. This will limit the maximum number of a pixel run. This is necessary because not all of the data going through the decoder is meant to be run length decoded obviously, so FF FF FF FF 01 01 0A F0 in a 4 byte rle scheme will decode to over 16 gigabytes if you don't have your maximum pixel run set down to halt this.
    Note:
    You can stop the program at any time. I designed the program to save your settings before running and after changing anything. So if you accidentally don't set your max run and it seems like it is taking forever, and you are watching the output file size growing and growing, you can simply x out of it, or close it. Restart it and adjust whatever you have to.​
    Another variable is the byte offset. Since the very first count byte has to go into the decoder as the very first count byte, you may have to offset the whole file up to a certain number of bytes as specified below.
    For 4 byte rle patterns offsets to be tried are 0,1,2,3,4,5,6,7.
    For 3 byte rle patterns offsets to be tried are 0,1,2,3
    For 2 byte rle patterns offsets to be tried are 0,1,2,3

    The last variable is the width. Hitting 2 in the program will allow you to set a range, or specific widths. Example: My Nexus 7 2013 bootloader has the Google logo as a 518 pixel wide image, the android as 712, the buttons as 1090, and some other things at 600 and 960. I would enter:
    Code:
    518 712 1090 600 960
    You simply separate the different widths with spaces. You can't mess up, you can put whatever width (in any order) you want to in and it will make an image.
    The second method is an exploratory method, where you enter the starting width, skips, ending width. All separated by commas.
    Example:
    Code:
    712, 1, 1200
    This will run through every width, incrementing by 1, from 712 pixels to 1200 pixels.
    Note:
    The height is automatically calculated based on the width, filesize, bytes per pixel. This happens at the core of the loops.​
    Click the button below to see what the entire Nexus 5 bootloader screen looks like when the bootloader "file" is loaded with these settings used: pixel format rgb24, max run 1080, offset 0, line length 1080. The image is really big, because the whole file is run length decoded.
    After you click the button, scroll down and you will see the bootloader screen towards the bottom of the image.
    1080x22331_zps2cbe5d2c.png~original

    This is the Nexus 4, whole bootloader, pixel format rgb24, max run 1080, offset 0, line length 720
    After you click the button, scroll down and you will see the bootloader screen towards the bottom of the image.

    720x43213_zpsb556e3ef.png~original

    You've Identified there are images, but how do you extract just the images?

    You need a good hex editor, don't worry though because you don't have to look at any hex. I prefer 010 Editor by SweetScape Software. You get a free 30 day trial. Download it. Load your bootloader file into it by right clicking on the file and selecting "010 editor". If you don't have your bootloader file you can use option 4 in RUN_length_imager.bat and pull the partition from your device. If you don't know what partition you are looking for or how to do it manually, here is an excellent guide. If you use my script, the partition will be saved in the "__partitions__" folder.
    Go up to View:
    Set Left Area to Char
    Set Right Area to Binary
    Change Line Width to Custom Width
    Choose a value where the characters on your left pane almost fill up your screen so that when you start scrolling over, your right pane (binary) is right there. The right binary pane is a lot wider, that's why I prefer it on the right. Also choose a width that is evenly divisible by 8, I set mine at 224, using a small 1366x768 laptop.​

    A real handy shortcut in 010 editor is Ctrl + and Ctrl - to enlarge or shrink the font.​
    The 4 byte run length encoding is the easiest to identify because there is 4 bytes for the count, and the biggest number you can store into a 4 byte address is over 4 billion. The 3rd and 4th bytes are usually nothing but zeros. The only 4 byte pixel format I've seen used so far is, bgr0, which also has the fourth byte as nothing but 8 zeros. Here is what a typical looking 4 byte rle image looks like.
    SS-4byte_zps0148dcdb.jpg


    Notice how the count value, mostly, show up as just four periods ....
    Sometimes the first byte (period) will be a different character representing a higher value for a run of same colored pixels. Also notice that there is a lot of black and white (gray) shades in the color values. All colors on a grey scale, represented in rgb, are equal values. A value of 255,255,255 is white 200,200,200 is a light shade of grey, and 0,0,0 is black. The rgb values will always be identical to be an exact shade of grey. This image is part of the Google logo which is mostly black and white.

    SS-4bytebinary_zpsf43e64aa.jpg


    Any area that you highlight in the "char" pane will also be highlighted in the "binary" pane when you scroll over, you'll find this extremely handy. These 8 bytes is one complete encoded run, which represents 15 pixels pure white. You can see exactly how the four count bytes sit beside the bgr0 color bytes. Byte 1 is 00001111, binarys equivalent to decimal 15. Bytes 2, 3, and 4 are 0; then the color bytes 5, 6, 7, 8. Blue is represented with the 5th byte, green the 6th, red the 7th, and the 8th byte is not used in this pixel format. Don't get confused about the pixel format, because this method of encoding will cover all 4 byte per pixel formats, some could use the 4th color byte (or alpha), and the order they're in is not that important right now. Unless you know exactly what you are looking for, like the infamous green android laying on its back, you may be trying to pay more attention to the green column when trying to find where the image starts or stops.
    712x552_zpscdd0776c.png~original

    (This is the binary copy of the android image you see if you have a Nexus 7 2013)

    518x184_brg0_zpsd5765196.png~original

    (from Nexus 7 2013 bootloader)
    This part can be kind of tricky, I actually surprised myself at how good I was at "getting lucky" and finding the correct beginning and ending of an image in the bootloader files. So that probably means that it really isn't that hard, it is just not something you encounter every day. Being aware of how your image should be encoded helps a lot. If you know there are 100's of black pixels at the start and/or end of an image, keep that in your mind when looking at the characters.
    An image will never start or end with the count byte(s) as 00000000!!! But, often times they DO start or end after some zeros, or before some zeros at the end. Take for example: This is the beginning of one of the lock images. (notice how it is right after the text ANDROID BOOT, hmm)
    (Keep in mind that this is a 4 byte pattern run length encoding, which actually will consume 8 bytes total per run. Four bytes for the count and four bytes for the color. The other two patterns look as you would think: 3 byte .### 2 byte ..##)
    binartstart_zpsa51cb7e9.jpg

    charstart_zps135f49da.jpg


    Notice how the count bytes before what I have highlighted in blue is all zeros. So you won't start there, move right and see what that is. And that is your image start, it is a run of 28 solid black pixels (0,0,0,0) Once you have identified the start, and hopefully selected it as I have in the screenshot, write down the number after "Start:" Which is 3097596.
    charend_zpsbda03020.jpg

    binaryend_zps38e16175.jpg

    This is the end of the lock. Notice the characters all of the sudden changing, this is an indication of a color change. I visually scanned line by line and found this spot that separated all the ÿÿÿ and ÀÀÀ's up above to the newer assortment of characters like ## and 33Ì

    Now you need to isolate just that image. With those last 8 bytes selected, go up to Edit - Select Range, and down at the bottom of the screen, enter in the start byte you wrote down earlier. Hit enter and the encoded image will be selected. Copy this by hitting Ctrl-C or going up to Edit - Copy.
    Go to File - New - New Hex File
    Hit Ctrl-V to paste, or go to Edit - Paste
    Now save that file somewhere, and drag and drop it onto "RUN_length_imager.bat"
    I already knew the width of the image before writing this, but here is the output with the Line length set at 60,1,80 and pixel format bgr0
    lock_zps4b39d74c.jpg


    Notes:

    You can also encode jpg, bmp, and png files into whatever 2, 3 or 4 byte pixel format you choose. The run length encoding will be automatically adjusted according to which pixel format you choose. When encoding images into the pixel format rgb0, bgr0, 0rgb ...
    Any of those 4 byte formats. FFmpeg will put 11111111 in place of the zero in the zero byte position. I'm not sure why it doesn't put 00000000 like it should, but I know how to fix it, but it involves another option, and I haven't gotten to it yet. If you were to try writing this to your device, I have no idea how Android would treat this 11111111 in the null spot, because as far as I know rgb0 (and cousins) is a made up definition by the writers of FFmpeg to describe rgb24 as rgb32 with 8 bits per color, and 8 padding bits.


    Nexus 5 & 4 use the pixel format rgb24. The whole bootloader screen is encoded in one pass, as opposed to drawing several images at different spots on the screen.

    The Nexus 7 1 & 2 use the pixel format bgr0. It's kind of ironic that at first when I was looking for the Google logo, I thought it was entirely made up of black and white pixels and stored in an 1 = white 0 = black, binary format (that would account for no one being able to find it, unless you do like I did and use the monow or monob pixel format in FFmpeg), but in actuality the format that it is stored in can potentially contain billions of colors. (4 byte color)

    The Nexus 7 2013 Unlock Icon has an extra white pixel at the bottom right that you can clearly see on the device, now that I told you it's there. Does it mean something, or is it just poor editing by the people at Google?

    The Nexus 7 2013 has the Google logo encoded in 3 different places in the Bootloader. They are binary copies of each other, so that leads me to believe that the reason for this is to discourage people from trying to edit the images. Maybe you'd brick if you just changed one and not all three? I don't know, but can't think of any other reason why they would do this. There is also two unlock icons, not counting the big one on the bootloader screen that asks you if you're sure you want to unlock it.

    The Nexus 7 2013 has the only bootloader, that I've encountered, that not only stores images in a 4 byte run length manner, but there are also non-encoded 3 byte rgb24 images for the battery icon, and charging icons. Even the older Nexus 7 has all of the images run length encoded.

    Samsung bootloaders use jpegs, although I did find the Linux penguin, non-encoded in the Note 3. I also found the "font mask" that uses bits to make some different fonts stored as bit masks. You can see it, using the monow or monob pixel format and setting your width at 16 32.

    The HTC M8 uses the pixel format rgb565. The only device I own is the second generation Nexus 7, and it is the only one where I have been through the bootloader with a purpose. Since I don't own a M8 I really kind of just glanced at it in the hex editor and found the exclamation triangle, the htc silver logo, and the android laying on its back; all run length encoded. It also has the bit mask font embedded in it for the text, as I mentioned about the Note 3.
    I take no responsibility to any damage that is done to your device or computer with this program.
    The source file and batch script can be found in the following post AND in the download!
    Download Run Length Imager v1.2

    Changelog:

    Current version 1.2
    -Embedded a solid jpeg extractor (java is no longer needed)
    -Added a zero byte function to fix the encoding of rgb0, bgr0, 0bgr, & 0rgb pixel formats
    -Added and Output folder to contain made images
    -Several other code modifications

    v1.1
    -Added a java jpeg extractor
    -Click the button below to view the additional credits related to version 1.1
    The java jpegextractor.java I found here! It was written back in 2002 by Marco Schmidt. I have slightly modified it by putting in a polarity counter that takes care of embedded jpegs, that otherwise will destroy the jpeg extraction process.

    v1.0
    -initial upload

    More images:

    Nexus 5
    517x183_rgb24_zps1691e224.png~original


    1080x3750_rgb24_zps251c0ffb.png~original

    HTC M8
    229x124_zps3428955e.png~original

    25x25_rgb565_zpsb06e5d58.png~original

    300x297_zps50742e90.png~original

    2013 Nexus 7 where you can see all three logos
    m1000o4518x4116_zpsee699794.png

    3
    RUN_length_imager_v1.2.bat
    Code:
    @echo off
    setlocal enabledelayedexpansion
    	color 0b
    	set "vers=1.2"
    	title Run Length Imager v%vers%
    	set "device_dir=sdcard"
    	set "partitionfind=mmc"
    	set autozero=sure
    	set outfiletype=png
    	set autoopen=sure
    	set "outfilefolder=output"
    	set "loglevel=-loglevel debug"
    	set "hidebanner=-hide_banner"
    	set "adblog=>>"%~dp0sys\adb_log.txt" 2>&1"
    	set "ffmlog=>>"%~dp0sys\ffmpeg_log.txt" 2>&1"
    	IF "%~1"=="-d" (
    		set ffmlog=
    		set adblog=
    		set "loglevel=-loglevel debug"
    		set hidebanner=	
    		mode con:cols=1000 lines=4000
    		color 07
    		shift
    	)
    	cd /d "%~dp0"
    	if not exist "%~dp0%outfilefolder%\" mkdir "%~dp0%outfilefolder%"
    	if exist "%~dp0sys\adb_log.txt" del /q "%~dp0sys\adb_log.txt"
    	if exist "%~dp0sys\ffmpeg_log.txt" del /q "%~dp0sys\ffmpeg_log.txt"
    	if exist "%~dp0sys\rli_log.txt" del /q "%~dp0sys\rli_log.txt"
    	if exist "%~dp0sys\needfiles" del /q "%~dp0sys\needfiles"
    	if not exist "%~dp0bin\ffmpeg.exe" echo.FFMPEG Program "%~dp0bin\ffmpeg.exe">>"%~dp0sys\needfiles"
    	if not exist "%~dp0bin\rlimager1.2.exe" echo.rlimager1.2.exe "%~dp0bin\rlimager1.2.exe">>"%~dp0sys\needfiles"
    	if exist "%~dp0sys\needfiles" goto :help
    	if not exist "%~dp0sys\definitions" call :make_definitions_file
    	if "[%~1]" neq "[]" if exist "%~1" echo.%1>"%~dp0sys\last_file"
    	if exist "%~dp0sys\settings" (call :load_settings) else (
    			set "maxcount=0"
    			set "offset=0"
    			set /a "bpp=4"
    			set "pixel_format=bgr0"
    			set "line_length=50,1,180"
    			set "rldecode_on=1"
    			call :save_settings
    		)
    	if exist "%~dp0sys\last_file" call :load_last_file
    	goto :menu
    	
    :help
    	echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
    	echo.The following necessary file^(s^) are not found in their proper location:
    	echo.&echo.
    	type "%~dp0sys\needfiles"
    	echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
    	pause>nul
    goto :egress
    
    :make_definitions_file
    	cls&echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
    	if not exist "%~dp0sys\" mkdir "%~dp0sys"
    	echo.Building FFmpeg Pixel Format List..
    	echo.This should only take a minute...&echo.
    	if exist "%~dp0sys\definitions" del /q "%~dp0sys\definitions"
    	echo.rgb565 2 >>"%~dp0sys\definitions"
    	echo.bgr565 2 >>"%~dp0sys\definitions"
    	for /f "skip=1 tokens=2" %%p in ('bin\ffmpeg -pix_fmts 2^>^&1^|findstr /rxic:"^I.*"') do (
    		%ffmlog%"%~dp0bin\ffmpeg.exe" -f rawvideo -s 1x1 -pix_fmt rgba -i "%~dp0sys\getres" -f rawvideo -s 1x1 -pix_fmt %%p -y "%~dp0sys\%%p"
    		for %%? in ("%~dp0sys\%%p") do if not "%%~z?"=="0" set /a bval=%%~z?/3&echo.%%~n? !bval!>>"%~dp0sys\definitions"
    		del /q "%~dp0sys\%%p"
    	)
    	echo.Finished!&call :load_settings
    goto :eof
    	
    :make_images
    	call :drawhead
    	call :drawsettings
    	if defined list (set "for_type=for /l") else (set "for_type=for")
    	for %%p in (%pixel_format%) do (
    		call :setbpp %%p
    	    if "!rldecode_on!"=="1" (	
    			set "out_file=decoded_raw_!bpp!_byte_%in_filename%"
    			set "out_path=%~dp0%outfilefolder%\%in_filename%_max_%maxcount%_offset_%offset%"
    			if not exist "!out_path!\" mkdir "!out_path!"
    			if not exist "!out_path!\!out_file!" (echo.Decoding !bpp! byte rle)&("%~dp0bin\rlimager1.2.exe" -d !bpp! -m %maxcount% -o %offset% < %file% > "!out_path!\!out_file!")||(call :rli_help&goto :menu)
    			for %%? in ("!out_path!\!out_file!") do set /a "out_filesize=%%~z?"
    			if not exist "!out_path!\%%p\" mkdir "!out_path!\%%p" 
    			if defined autoopen start "" "!out_path!\%%p\"
    			%for_type% %%R in (%line_length%) do (
    				set /a height=!out_filesize!/%%R/!bpp!
    				echo.Using ffmpeg to generate %%Rx!height! image from %%p pixel format.
    				if !height! NEQ 0 %ffmlog%"%~dp0bin\ffmpeg.exe" %hidebanner% %loglevel% -f rawvideo -vcodec rawvideo -pix_fmt %%p -s %%Rx!height! -i "!out_path!\!out_file!" -vframes 1 -y "!out_path!\%%p\%%Rx!height!.%outfiletype%"
    			)
    		) else (
    			set "out_path=%~dp0%outfilefolder%\%in_filename%_no_rldecode\%%p"
    			if not exist "!out_path!\" mkdir "!out_path!"
    			if defined autoopen start "" "!out_path!\"
    			%for_type% %%R in (%line_length%) do (
    				set /a height=!in_filesize!/%%R/!bpp!
    				if /i "%%p"=="monow" set /a height*=8
    				if /i "%%p"=="monob" set /a height*=8
    				echo.Using ffmpeg to generate %%Rx!height! image from %%p pixel format.
    				if !height! NEQ 0 %ffmlog%"%~dp0bin\ffmpeg.exe" %hidebanner% %loglevel% -f rawvideo -vcodec rawvideo -pix_fmt %%p -s %%Rx!height! -i %file% -vframes 1 -y "!out_path!\%%Rx!height!.%outfiletype%"
    			)
    		)
    		if "!auto_turn_back_on!"=="1" (set "rldecode_on=1"&set auto_turn_back_on=)
    	)
    goto :eof
    
    :rle_image
    	set "out_path=%outfilefolder%\Run Length Encoded_%in_filename%"
    	for %%p in (%pixel_format%) do (
    		call :setbpp %%p
    		if "%%p"=="rgb0" (set "zoffset=8"&set "zero=8")
    		if "%%p"=="0rgb" (set "zoffset=5"&set "zero=8")
    		if "%%p"=="bgr0" (set "zoffset=8"&set "zero=8")
    		if "%%p"=="0bgr" (set "zoffset=5"&set "zero=8")
    		set "out_file=encoded_raw_!bpp!_byte_%in_filename%"
    		if not exist "%~dp0!out_path!\" mkdir "%~dp0!out_path!\"
    		%ffmlog%"%~dp0bin\ffmpeg.exe" %hidebanner% %loglevel% -i %file% -f rawvideo -vcodec rawvideo -pix_fmt %%p -y "%~dp0!out_path!\raw_%%p"
    		if defined autozero (echo.Encoding !bpp! byte rle&"%~dp0bin\rlimager1.2.exe" -z 8 -o !zoffset! -i "%~dp0!out_path!\%in_filename%_rl_encoded_with_!bpp!_byte_pattern_and_%%p_pixel_format" -e !bpp! < "%~dp0!out_path!\raw_%%p" > "%~dp0!out_path!\%in_filename%_rl_encoded_with_!bpp!_byte_pattern_and_%%p_pixel_format"||(call :rli_help&goto :menu)
    			) else (echo.Encoding !bpp! byte rle&"%~dp0bin\rlimager1.2.exe" -e !bpp! < "%~dp0!out_path!\raw_%%p" > "%~dp0!out_path!\%in_filename%_rl_encoded_with_!bpp!_byte_pattern_and_%%p_pixel_format"||(call :rli_help&goto :menu))
    		set zoffset=&set zero=
    		)
    	if defined autoopen start "" "%~dp0!out_path!\"	
    goto :eof
    
    :rli_help
    	echo.There was a problem encoding^/decoding the file:&echo.%file%
    	echo.Bpp is: %bpp%&echo.Pixel format is: %pixel_format%&echo.Offset is: %offset%
    	echo.Max run is: %maxcount%&echo.Width is: %line_length%&echo.Working file name is: %in_filename%&echo.&pause >nul
    goto :eof
    
    :load_last_file
    	set "encode="
    	set /p file=<"%~dp0sys\last_file"
    	for %%? in (%file%) do set /a "in_filesize=%%~z?" &set "in_filename=%%~n?" &set "ext=%%~x?"
    	if [%ext%]==[] goto :eof
    	if "%ext%"==".jpg" set "encode=true"
    	if "%ext%"==".png" set "encode=true"
    	if "%ext%"==".bmp" set "encode=true"
    	if "%ext%"==".jpeg" set "encode=true"
    goto :eof
    
    :load_settings
    	<"%~dp0sys\settings" (
    		set /p pixel_format=
    		set /p bpp=
    		set /p offset=
    		set /p maxcount=
    		set /p line_length=
    		set /p rldecode_on=
    		)
    	set /a bpp
    	echo.%line_length%|findstr ".*,.*,"&&set "list=1"||set list=
    goto :eof
    	
    :save_settings
    	>"%~dp0sys\settings" (
    		echo.%pixel_format%
    		echo.%bpp%
    		echo.%offset%
    		echo.%maxcount%
    		echo.%line_length%
    		echo.%rldecode_on%
    		)
    goto :eof
    	
    :menu
    	set auto_turn_back_on=&call :load_last_file&call :drawhead&call :drawsettings
    	echo.&echo.&echo.1 - Make Image(s)
    	echo.&echo.2 - Change Output Line Length ^(width^)
    	echo.&echo.3 - Change Pixel Format 
    	echo.&echo.4 - Use ADB To List/Pull A Partition
    	echo.&if defined rldecode_on (echo.5 - Turn Off Run Length Decoding) else (echo.5 - Turn On Run Length Decoding)
    	echo.&if defined rldecode_on (echo.6 - Change Offset) else (echo.	- - Change Offset ^(run length decoding is off^))
    	echo.&if defined rldecode_on (echo.7 - Change Max Run Length) else (echo.	- - Change Max Run Length ^(run length decoding is off^))
    	echo.&if defined encode (echo.8 - Encode image) else (echo.8 - Extract Jpgs From File)
    	echo.&echo.9 - Exit&echo.
    	choice /n /m "Select A Menu Number:" /C:123456789
    	if errorlevel 1 set k=1
    	if errorlevel 2 set k=2
    	if errorlevel 3 set k=3
    	if errorlevel 4 set k=4
    	if errorlevel 5 set k=5
    	if errorlevel 6 set k=6
    	if errorlevel 7 set k=7
    	if errorlevel 8 set k=8
    	if errorlevel 9 set k=9
    	if %k%==1 call :make_images
    	if %k%==8 if "%encode%"=="true" (call :rle_image) else (call :jextract %file%)
    	if %k%==4 call :getpartitions
    	if %k%==3 call :change_pf
    	if %k%==2 call :change_line_length
    	if %k%==5 call :rle_toggle
    	if %k%==6 if defined rldecode_on call :change_offset
    	if %k%==7 if defined rldecode_on call :change_max_run
    	if %k%==9 goto :egress
    goto :menu
    
    :jextract
    	call :drawhead&call :drawsettings
    	set "out_path=%~dp0%outfilefolder%\%in_filename%_extracted_jpgs"
    	if not exist "%out_path%\" mkdir "%out_path%"
    	echo.&echo.Working...
    	"%~dp0bin\rlimager1.2.exe" -o %offset% -j "%out_path%\%in_filename%" <%file%
    	if defined autoopen start "" "%out_path%\"
    	echo.&echo.&echo Press any key to continue to the main menu..
    	pause>nul
    goto :eof
    
    :change_max_run
    	call :drawhead&call :drawsettings
    	echo.over 4 billion times.  With a 3 Bpp rle pattern the highest value 0xFF will repeat the 
    	echo.pixel 255 times maximum.  And with a 2 Bpp rle pattern the value 0xFFFF will repeat 
    	echo.a pixel 65535 times.&echo.
    	echo.When searching this way you need to set the max pixel run count to around ~1000-2000 to avoid
    	echo.unusable image files that can take forever to generate.&echo.
    	echo.Just press enter for a default value of 0 which will let the decoding process run its
    	echo.natural course.&echo.
    	set /p maxcount=Max pixel run:||set "maxcount=0"
    	call :save_settings
    goto :eof
    	
    :change_offset
    	call :drawhead&call :drawsettings
    	echo.Enter the byte offset for the file.&echo.
    	echo.This should always be 0 when dealing with pure rle image files.
    	echo.The reason it is in here is because if you load an entire file with data/images all
    	echo.mixed together; the start of the Pixel count read for an image might just not be in 
    	echo.the right spot, and the count will be read as color data instead of count data, resulting
    	echo.in really long^/short runs and no image. If using a whole partition^/file and a standard
    	echo.0 as the offset at several resolutions isn't generating the image you are looking for,
    	echo.taking the offset up, 1 by 1 until you get to 7 for 4 Bpp raw files, or an offset of
    	echo.3 for 2 ^& 3 Bpp raw files.  It is advised to set your max pixel run count to ^~1000-2000
    	echo.when searching through complete files/partitions like this.&echo.
    	echo.This is the same thing as deleting "x" bytes from the beginning of the file.&echo.
    	echo.If you are using an image that starts with the count byte^(s^) at byte 1 in the file, then
    	echo.you don't have to worry about it.&echo.
    	echo.Just press enter for the default offset of 0.&echo.
    	set /p offset=Offset:||set "offset=0"
    	call :save_settings
    goto :eof
    	
    :egress
    	"%~dp0bin\adb.exe" kill-server>nul 2>&1
    	endlocal&exit
    goto :eof
    
    :rle_toggle
    	if defined rldecode_on (set rldecode_on=) else (set "rldecode_on=1")
    	call :save_settings
    goto :eof
    
    :change_pf
    	:keepitinthecall
    	call :drawhead
    	call :drawsettings
    	echo.Enter the pixel format to use.  The run length decoder will automatically adjust format accordingly.
    	echo.You may enter multiple pixel formats, but of course if will take longer and produce double the 
    	echo.images if you enter two, or triple if you choose three.  If you enter multiple pixel formats
    	echo.seperate them with a space or a comma.  The bytes per pixel number seen at the top of the screen
    	echo.will only reflect the correct value when one pixel format is chosen, this however will have
    	echo.no bearing when you go to make images as the bpp is determined before each set of images is made.&echo.
    	echo.Note that any pixel format over 4 bytes per pixel will probably never be used in Android, for the 
    	echo.purpose of displaying a static image at least.
    	echo.Threre is no run length decoding of those pixel formats over 4 bytes per pixel as of right now.&echo.
    	echo.The ones listed below, grouped by their bytes per pixel, are some of the more common pixel formats.
    	echo.Hit enter to see all input formats available with your FFmpeg build.
    	echo.&echo.Enter pixel formats in LOWER CASE ONLY.&echo.
    	echo.Enter "build" if you have updated your ffmpeg, and would like to update the pixel formats also.&echo.
    	echo.Enter "show" to show available pixel formats with your ffmpeg build.
    	echo.Common 2 Bpp android pixel formats ^[rgb565le, bgr565le^]
    	echo.Common 3 Bpp android pixel formats ^[rgb24, bgr24^]
    	echo.Common 4 Bpp android pixel formats ^[rgb0, 0rgb, 0bgr, bgr0, rgba, argb, abgr, bgra^]&echo.
    	set "old=%pixel_format%"
    	set /p pixel_format=Pixel format^(s^):||goto :eof
    	if /i "%pixel_format%"=="build" (set "pixel_format=%old%"&call :make_definitions_file&goto :keepitinthecall)
    	if /i "%pixel_format%"=="show" (set "pixel_format=%old%"&call :show_pixel_formats&goto :keepitinthecall)
    	call :setbpp %pixel_format%
    	call :save_settings
    goto :eof
    
    :setbpp
    	for /f "tokens=1,2" %%a in ('type "%~dp0sys\definitions"') do if /i "%~1"=="%%a" set /a "bpp=%%b"
    	if %bpp% GEQ 5 if defined rldecode_on (set "auto_turn_back_on=1"&set rldecode_on=)
    	if %bpp% EQU 1 if defined rldecode_on (set "auto_turn_back_on=1"&set rldecode_on=)
    	call :save_settings
    goto :eof
    
    :show_pixel_formats
    	cls&echo.Input pixel formats supported with your FFmpeg build:
    	for /f "skip=1 tokens=2,4" %%A in ('bin\ffmpeg -pix_fmts 2^>^&1^|FINDSTR /rxic:"^I.*"') DO echo.%%A---		%%B ^<^<^<BITS per pixel
    	echo.&echo.Press enter to continue...
    	pause>nul
    goto :eof
    
    :drawsettings
    	echo.Working Name: %in_filename%&echo.File Name: %file%&echo.Size: %in_filesize% bytes
    	echo.__________________________________&echo.______________________________________&echo.
    	echo.Pixel Format: %pixel_format%&echo.Line Length: %line_length%
    	if defined rldecode_on (
    		echo.Rle Format: %bpp% byte pp&echo.Max Run Length: %maxcount% pixels
    		echo.Offset: %offset%) else (echo.&echo.Run Length Decoding Is Turned Off.&echo.)
    	echo.______________________________________&echo.
    goto :eof
    		
    :change_line_length
    	call :drawhead&call :drawsettings
    	echo.Enter the line length ^(width^) that you want to use.  You can enter several, SEPERATED BY SPACES;
    	echo.or you can use a range SEPERATED BY COMMAS, in this format: start resolution, skips, ending resolution.&echo.
    	echo.Example: If you want to use the widths of 150 25 3000 400 98 16. You would enter in any order:
    	echo.150 25 3000 400 16 98&echo.
    	echo.Example: If you want a line length starting at 100 pixels going to 1200 pixels, while skipping to every
    	echo.10th pixel. You would enter: 
    	echo.100,10,1200&echo.
    	set /p "line_length=Line length:"
    	echo.%line_length%|findstr ".*,.*,.*"&&set "list=1"||set list=
    	call :save_settings
    goto :eof
    
    :drawhead
    	cls&echo.&echo.___________________________________-_-
    	echo.__________________________________&echo.&echo.Run Length Imager: v%vers% by makers_mark
    	echo.__________________________________&echo.______________________________________&echo.
    goto :eof
    
    :getpartitions
    	if not exist "%~dp0partitions\" mkdir "%~dp0partitions"
    	call :drawhead&set /a index=1
    	"%~dp0bin\adb.exe" -d start-server
    	if %ERRORLEVEL% GTR 0 call :adb_error&goto :eof
    	for /f "skip=1 tokens=3,4" %%s in ('bin\adb.exe -d shell cat /proc/partitions^|findstr /rxic:".*%partitionfind%.*"') do (
    		if not "%%s"=="" (call set /a "_size[!index!]=%%s"&&call set "_partition[!index!]=%%t") else (set /a index=1)
    		call set /a index+=1
    	)
    	if %ERRORLEVEL% GTR 0 call :adb_error&goto :eof
    	set /a index-=1
    	echo.   Partition		Size&echo.
    	for /l %%c in (1,1,%index%) do (
    		if %%c LSS 10 (echo. %%c.  !_partition[%%c]!		!_size[%%c]!) else (
    						 echo.%%c.  !_partition[%%c]!		!_size[%%c]!)
    	)
    	echo.&echo.If you want to pull one of these partitions from your device, enter the number
    	echo.to the left of it and press enter.  Just press enter to go back to the Main Menu&echo.
    	set /p _pick=:||goto :eof
    	2>nul set /a _pick=%_pick%/1 || GOTO :eof
    	IF %_pick% LSS 1 GOTO :eof
    	if %_pick% GTR %index% goto :eof
    	cls&echo.&echo.&echo.WARNING:	WARNING:	WARNING:	WARNING:	WARNING:&echo.WARNING:	WARNING:	WARNING:	WARNING:	WARNING:
    	echo.WARNING:	WARNING:	WARNING:	WARNING:	WARNING:&echo.WARNING:	WARNING:	WARNING:	WARNING:	WARNING:&echo.&echo.&echo.&echo.&echo.
    	echo.Issuing this command:&echo.
    	call echo.bin^\adb.exe -d shell dd if^=^/dev^/block^/%%_partition[!_pick!]%% of^=^/%device_dir%^/%%_partition[!_pick!]%%
    	echo.&echo.PLEASE READ THIS TWICE....&echo.
    	echo.DD is a VERY powerful tool, and if the output directory^/file; listed after ^"of^=^" is not the 
    	echo.name of the partition you chose to pull, DO NOT CONTINUE. If you are not sure what you are doing; 
    	echo.what this command is, or what you are even looking at. DO NOT CONTINUE.&echo.
    	set "guess=%random%"
    	echo.Enter this number to continue:  %guess%
    	echo.&set /p answer=:||goto :eof
    	if not "%guess%"=="%answer%" goto :eof
    	echo.&echo.Copying data into a file on your device...
    	call echo."%~dp0bin\adb.exe" -d shell "dd if=/dev/block/%%_partition[!_pick!]%% of=/%device_dir%/%%_partition[!_pick!]%%"|cmd /v:on%adblog%&&echo.&&echo.Copying file from your device to your computer...&&call echo."%~dp0bin\adb.exe" -d pull "/%device_dir%/%%_partition[!_pick!]%%" "%~dp0partitions\%%_partition[!_pick!]%%"|cmd /v:on%adblog%&&echo.&&echo.Deleting the file from your device...&&call echo."%~dp0bin\adb.exe" -d shell rm "/%device_dir%/%%_partition[!_pick!]%%"|cmd /v:on%adblog%
    	call echo."%~dp0partitions\%%_partition[!_pick!]%%">"%~dp0sys\last_file"
    	echo.&echo.&echo.Finished.  The partition has been loaded and is saved as:&echo.&call echo."%~dp0partitions\%%_partition[!_pick!]%%"&echo.&echo.Press any key to continue.
    	call :save_settings
    	pause>nul
    goto :eof
    
    :adb_error
    	echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
    	echo.			ADB is not connected, working properly, or you have
    	echo.			more than one device connected.
    	echo.			Try "Safely Removing" your device from your computer.
    	echo.			Then unplug your usb cable, and reinsert it.
    	echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
    	pause>nul
    goto :eof

    rlimager1.2.c
    C:
    /*
     * Copyright (C) 2008 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     *
     &	NOTICE:
     &	 May 5th, 2014
     &
     &	 makers_mark @ xda-developers.com
     &   http://xdaforums.com/showthread.php?t=2764354
     &
     &	 Original source:
     &	 https://android.googlesource.com/platform/build/+/b6c1cf6de79035f58b512f4400db458c8401379a/tools/rgb2565/to565.c
     &	 Based off of the original to565.c program to convert raw rgb888 r=8 g=8 b=8 images
     &	 to, 2 byte count, 2 byte color run length encoded rgb565 r=5 g=6 b=5 files.
     &	 Mainly, if not always to my knowledge, used for creating initlogo.rle files for kernel splash
     &	 screens.
     &
     &	 Added decoding of 2, 3, and 4 byte rgb(x) patterns
     &	 Added encoding of 3 and 4 byte rgb(x) patterns
     &	 Added byte offsets and maximum pixel runs for decoding files not totally
     &	 encoded in a run length manner
     & Version 1.2 added:
     &   Jpeg extractor, to pull jpegs from any file or drive/device image
     &   A zero byte writer, to undo what ffmpeg does to rgb0, 0rgb, bgr0, and 0bgr pixel formats
    
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <fcntl.h>
    
    unsigned int _CRT_fmode = _O_BINARY;
    static char fileName[1024];
    void zeroBytes(long long, long, char *);
    void jpegExtract(char *, unsigned long long);
    void headerToFooter(int);
    int getFilename(char *);
    void decode_rgb16_rle(unsigned int, unsigned long long int);
    void decode_rgb24_rle(unsigned int, unsigned long long int);
    void decode_rgbx32_rle(unsigned long int, unsigned long long int);
    void encode_rgb16_rle(void);
    void encode_rgb24_rle(void);
    void encode_rgbx32_rle(void);
    
    void zeroBytes(long long offset, long z, char *inputFile)
    {
    	int readByte;
    	FILE *zeroStream;
    	FILE *inStream;
    	long long int cursorPosition;
    	char outputFile[1024];
    
    	sprintf(outputFile, "%s.zero", inputFile);
    	if ((inStream = fopen(inputFile, "rb")) == NULL){
    		fclose(inStream);
    		return;
    	}
    	if ((zeroStream = fopen(outputFile, "wb")) == NULL){
    		fclose(inStream);
    		fclose(zeroStream);
    		return;
    	}
    	fprintf(stderr,"\nZeroing every %ld bytes starting at %lld", z, offset);
    	fprintf(stderr,"\nInput file: %s", inputFile);
    	while ((readByte = fgetc(inStream)) != EOF){
    		cursorPosition = ftell(inStream);
    		if (((cursorPosition - offset) % z) == 0 && cursorPosition >= offset){
    			fputc(0,zeroStream);
    		}else{
    			fputc(readByte,zeroStream);
    		}
    	}
    	fclose(inStream);
    	fclose(zeroStream);
    }
    
    void jpegExtract(char outname[1024], unsigned long long o)
    {
    	int readByte;
    	FILE *fileStream;
    	unsigned int header;
    
    	if (o != 0){
    		fseek(stdin, o, SEEK_SET);
    	}
    	while ((readByte = fgetc(stdin)) != EOF){
    		if (readByte == 0xff){
    			readByte = fgetc(stdin);
    			if (readByte == 0xd8){
    				readByte = fgetc(stdin);
    				if (readByte == 0xff){
    					readByte = fgetc(stdin);
    						if (readByte == 0xe0 || readByte == 0xe1){
    							header = 0x00ffd8ff | (readByte << 24);
    							if (!getFilename(outname)){
    								if ((fileStream = fopen(fileName, "wb")) == NULL){
    									fclose(fileStream);
    									return;
    								}
    								int streamNumber = fileno(fileStream);
    								fprintf(stderr, "\n%s", fileName);
    								write(streamNumber, &header, 4);
    								headerToFooter(streamNumber);
    								close(streamNumber);
    								continue;
    							}else{
    								break;
    							}
    						}
    				}
    			}
    		}
    	}
    	fclose(stdin);
    }
    
    void headerToFooter(int streamNumber)
    {
    	short notFinished = 1;
    	int polarity = 1;
    	int readByte;
    
    	while((readByte = fgetc(stdin)) != EOF){
    		if (readByte == 0xff){
    			readByte = fgetc(stdin);
    			if (readByte == EOF){
    				readByte = 0xff;
    				write(streamNumber, &readByte, 1);
    				break;
    			}else if (readByte == 0xd8){
    				polarity += 1;
    				readByte = 0xd8ff;
    				write(streamNumber, &readByte, 2);
    			}else if (readByte == 0xd9){
    				polarity -= 1;
    				readByte = 0xd9ff;
    				write(streamNumber, &readByte, 2);
    				if (polarity == 0){
    					break;
    				}
    			}else{
    				readByte = 0x00ff | (readByte << 8);
    				write(streamNumber, &readByte, 2);
    			}
    		}else{
    			write(streamNumber, &readByte, 1);
    		}
    	}
    }
    
    int getFilename(char outputbase[1024])
    {
    	unsigned int counter;
    	FILE *stream;
    
    	for (counter = 1; counter <= 99999; counter++){
    		sprintf(fileName, "%s_%05d.jpg", outputbase, counter);
    		if ((stream = fopen(fileName, "r+")) != NULL){
    			fclose(stream);
    			continue;
    		} else {
    			fclose(stream);
    			return(0);
    		}
    	}
    	fclose(stream);
    	return(1);
    }
    
    void decode_rgb16_rle(unsigned int m, unsigned long long int o)
    {
        unsigned short data[2], repeats;
    
    	if (o != 0){
    		fseek(stdin, o, SEEK_SET);
    	}
    
        while(read(0,data,4) == 4){
    
    		if (data[0] > m){
    			continue;
    		}
    		for (repeats = 0; repeats < data[0]; repeats++){
    			write(1, &data[1], 2);
    		}
        }
    }
    
    void decode_rgb24_rle(unsigned int m, unsigned long long int o)
    {
    
        unsigned char repeats, data[4];
    	unsigned long color;
    
    	if (o != 0){
    		fseek(stdin, o, SEEK_SET);
    	}
    
        while(read(0, data, 4) == 4){
    
    		if (data[0] > m){
    			continue;
    		}
    		color = ((data[1]) | (data[2] << 8) | (data[3]) << 16);
    		for (repeats = 0;repeats < data[0]; repeats++){
    			write(1, &color, 3);
    		}
        }
    }
    
    void decode_rgbx32_rle(unsigned long int m, unsigned long long int o)
    {
    	unsigned long repeats;
        unsigned long data[2];
    	
    	if (o != 0){
    		fseek(stdin, o, SEEK_SET);
    	}
    
        while(read(0, data, 8) == 8){
    		if (data[0] > m){
    			continue;
    		}
    		for (repeats = 0; repeats < data[0]; repeats++){
    			write(1, &data[1], 4);
    		}
        }
    }
    
    void encode_rgbx32_rle(void)
    {
        unsigned long color, last, count;
        count = 0;
    	while(read(0, &color, 4) == 4){
    	    if (count){
                if ((color == last) && (count != 0xFFFFFFFF)){
                    count++;
                    continue;
                } else {
                    write(1, &count, 4);
                    write(1, &last, 4);
                }
            }
            last = color;
            count = 1;
        }
        if (count){
            write(1, &count, 4);
            write(1, &last, 4);
        }
    }
    
    void encode_rgb16_rle(void)
    {
        unsigned short int last, color, count;
    
        count = 0;
        while(read(0, &color, 2) == 2){
            if (count){
                if ((color == last) && (count != 0xFFFF)){
                    count++;
                    continue;
                } else {
                    write(1, &count, 2);
                    write(1, &last, 2);
                }
            }
            last = color;
            count = 1;
        }
        if (count){
            write(1, &count, 2);
            write(1, &last, 2);
        }
    }
    
    void encode_rgb24_rle(void)
    {
        unsigned char count;
        unsigned long int last, color;
    
    	count = 0;
        while(read(0, &color, 3) == 3){
            if (count){
                if ((color == last) && (count != 0xFF)){
                    count++;
                    continue;
                } else {
                    write(1, &count, 1);
                    write(1, &last, 3);
                }
            }
            last = color;
            count = 1;
        }
        if (count){
            write(1, &count, 1);
            write(1, &last, 3);
        }
    }
    
    int usage(void){
    	fprintf(stderr, "\n\n\nUsage:\n\nrlimager.exe ([-e] [2-4] | [-d] [2-4] [-m] [max run] [-o] [offset]) < input_file > output_file\n\n");
    	fprintf(stderr, "Mandatory, one or the other\n\n");
    	fprintf(stderr, "-d (2-4)		Run Length Decode input_file from 2, 3, or 4 byte color pattern\n");
    	fprintf(stderr, "-e (2-4)		Run Length Encode input_file to 2, 3, or 4 byte color pattern\n");
    	fprintf(stderr, "-j (output root name)	Extract Jpegs from file.  Output name can include a full path.\n");
    	fprintf(stderr, "-z (skip) -o (offset)	Zero every (skip) bytes, starting with (offset)\n\n");
    	fprintf(stderr, "Optional for [-d] decoding only:\n\n");
    	fprintf(stderr, "-m (max run)	Maximum pixel run to decode. Default is 0, which defaults to the maximum allowable for each color pattern\n");
    	fprintf(stderr, "-o (offset)	Offset (in bytes) to start decoding.  Default is 0\n");
    	fprintf(stderr, "\n\nExamples:\n\nrlimager1.2 -d 4 -m 8064 < \"C:\\example_file.rle\" > \"C:\\output\\rle_decoded\\example_file.rgb0\"\n");
    	fprintf(stderr, "rlimager1.2 -j root_name < \"C:\\users\\downloads\\system.img\"\n\n");
    	fprintf(stderr, "Notice with the jpeg extractor example above you have to use: < \"inputfile\"\n\n");
    	fprintf(stderr, "rlimager1.2 -z 8 -o 5 -i \"C:\\output\\example_file.rle\" -e 4 < \"C:\\example_file.rgb0\" > \"C:\\output\\example_file.rle\"\n\n");
    	fprintf(stderr, "The above example rle encodes the input file, then takes the output file and zeros every eighth byte starting at 5\n");
    	fprintf(stderr, "You can also zero byte any file without doing it all on one line, like:\n\n");
    	fprintf(stderr, "rlimager1.2 -z 5 -o 8 -i \"C:\\file_to_be_zeroed_every_5th_byte_strarting_with_the_8th.raw\"\n");
    	return(1);
    }
    
    int main(int argc, char **argv)
    {
    	unsigned int decode_opt = 0, encode_opt = 0;
    	unsigned long long int maxrun = 0;
    	long long int offset = 0;
    	long zeroByte = 0;
    	short jflag = 0;
    	char *d_string, *e_string, *m_string, *o_string, *j_string, *z_string, *inputFile;
    	int c;
    
    	while ((c = getopt (argc, argv, "i:z:j:m:o:e:d:")) != -1)
    		switch(c)
    			{
    
    			case 'i':
    				inputFile = optarg;
    				break;
    
    			case 'z':
    				z_string = optarg;
    				zeroByte = atol(z_string);
    				break;
    
    			case 'j':
    				jflag = 1;
    				j_string = optarg;
    				break;
    
    			case 'm':
    				m_string = optarg;
    				maxrun = atoll(m_string);
    				break;
    
    			case 'o':
    				o_string = optarg;
    				offset = atoll(o_string);
    				break;
    
    			case 'e':
    				e_string = optarg;
    				encode_opt = atoi(e_string);
    				break;
    
    			case 'd':
    				d_string = optarg;
    				decode_opt = atoi(d_string);
    				break;
    	}
    
    	if ((encode_opt > 1) && (encode_opt < 5)){
    
    			if (maxrun != 0 || decode_opt != 0){
    				usage();
    				return(1);
    			}
    
    			if (encode_opt == 2){
    				encode_rgb16_rle();
    				return(0);
    			}
    
    			if (encode_opt == 3){
    				encode_rgb24_rle();
    			}
    
    			if (encode_opt == 4){
    				encode_rgbx32_rle();
    			}
    
    			if (zeroByte){
    				zeroBytes(offset, zeroByte, inputFile);
    			}
    			return(0);
    	} else if (zeroByte){
    			zeroBytes(offset, zeroByte, inputFile);
    			return(0);
    
    	} else if ((decode_opt > 1) && (decode_opt < 5)){
    
    			if (encode_opt != 0){
    				usage();
    				return(1);
    			}
    
    			if (decode_opt == 2){
    					if (maxrun == 0){
    						maxrun = 0xFFFF;
    					}
    				fprintf(stderr, "Maximum pixel run set at %d\n",maxrun);
    				decode_rgb16_rle(maxrun, offset);
    				return(0);
    			}
    
    			if (decode_opt == 3){
    					if (maxrun == 0){
    						maxrun = 0xFF;
    					}
    				fprintf(stderr, "Maximum pixel run set at %d\n",maxrun);
    				decode_rgb24_rle(maxrun, offset);
    				return(0);
    			}
    
    			if (decode_opt == 4){
    					if (maxrun == 0){
    						maxrun = 0xFFFFFFFF;
    					}
    				fprintf(stderr, "Maximun pixel run set at %lld\n",maxrun);
    				decode_rgbx32_rle(maxrun, offset);
    				return(0);
    			}
    
    			return(0);
    	} else if (jflag){
    		jpegExtract(j_string, offset);
    		} else usage();
    
    return(1);
    }
    2
    Came across this, simply because it's for LCD screens but explains the different encoding methods ;)

    http://www.demmel.com/download/ilcd/2d_rle_appnote.pdf

    Bashing away at my HTC Desire C

    The possibilities are endless when it comes to run length encoding. The three different methods that I've found probably aren't the only ones being used. Most people probably confuse rle with the old microsoft file format, but actually rle these days is a method of encoding. So, if you want to have 3 bytes for the count and 3 bytes for the color, you can do it. But if you notice, all three of the methods are 4 or 8 byte reads. No 3, 6, 10.... I wrote an arbitrary decoder for rlimager, but took it out because I don't see them ever using rle that doesn't add up to 4 or 8. Like 2 bytes count 3 bytes color, would be a more efficient way to encode 3 byte color, as opposed to 1 byte count 3 byte color (like they use). But it would be horribly slow. Here is the arbitrary decoder:
    Code:
    void arbitrary(int bytesofcount, int bytesofcolor)
    {
    	unsigned int i, j, k, totalperpixel = bytesofcount+bytesofcolor;
        unsigned long times, count, counttotal;
        unsigned char color, instream[totalperpixel];
    	unsigned char colorbyte[bytesofcolor];
    		
        while(read(0,instream,totalperpixel)){
    		for (i = 0; i<bytesofcount; i++){ 			
    			count = instream[i];
    			if (i > 0) {				
    				counttotal = (count << 8) | counttotal;			
    			} else {			
    				counttotal = count;
    			}
    		}
    		for (j=0; j<bytesofcolor;j++){	
    			color = instream[j+i];
    			colorbyte[j] = color;
    		}
    		for (times=0;times< counttotal;times++) {
    			for (k=0;k<bytesofcolor;k++){
    				write(1, &colorbyte[k], 1);
    			}
    		}
    		count=0;
        }	
    }

    But in the end, there are countless ways to run length encode an image. I've seen vertical encodings, diagonal, and horizontal. I've just simply found 3 used to encode images in some bootloaders...
    2
    If you haven't read it yet, try a search for ARM_ELF.pdf
    If the partition you're reading (like a boot.img) is an ELF file it will give you the offsets for the start of files (that's how I found my systems initial splash image) and the byte size for that file and any other files in that partition ;) ie. Boot code, splash screen, text data.

    Throw a boot.img/recovery.img into a hex editor (I use HxD) and alter the displayed byte count from standard 8/16/32 etc to 320 (or your screens pixel width) and scroll through and you'll see the data layout roughly of your splash screen (really basic way to find it)

    Bashing away at my HTC Desire C
    2
    You've spiked my curiosity now, especially as I've not been able to work at my PC in a while :D

    Is now off to see where it's pointed at from....

    Bashing away at my HTC Desire C

    Here is the mmcblk0p12 from the Nexus 7 2013 and the whole bootloader.img from the factory download. I don't know if it would help you, I imagine you have a device to check, but I have the logo locations already if it would help you out any.

    There are 4 locations of the image (the splashscreen isn't drawn all at once, it places the logo and the lock from different places in the bootloader) in the partition mmcblk0p12 they are all 43768 bytes long:
    307760 o----c 351528
    2390104 o----c 2433872
    3075424 o----c 3119192
    3166732 o----c 3210500​

    In the factory image there are three locations, they are:
    1183172 o----c 1226940
    3265516 o----c 3309284
    3950836 o----c 3994604​

    @E:V:A
    If you were at a bar and you figured out where I got my name from, you'd have to be right!