[MOD][CM12][COLOROS 2][HYDROGENOS] Splash Screen Image Injector v1.2

Search This thread

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
This is a program that I wrote to decode the newer style "logo.bin" files used in some OPPO, and OnePlus devices. Please read below so you can better understand this type of encoding being used:
What Is A Raw Image?

A raw image, whether it be a file or an image in memory, is simply pixel data. There is no extra information like width, height, name, end of line... Absolutely nothing, just pixel data. If you have an image that is raw and the resolution is 1080x1920 and you are using a typical RGB24 or BGR24 (like the ones used here), then your exact filesize or size in memory will be 1080x1920x3! We use 3 here because there is one byte for the R or red component, one for the G (green), and one for the B(blue).

What Is A Run Length Encoded Image?

A run length image encoding uses a count ;usually a single byte (char), 2 bytes (short int), or 4 bytes (long int); and then the pixel components. So instead of writing out 300 bytes of '0's to make a line of 100 black pixels. Black is RGB(0,0,0). You could encode this as 100, 0, 0, 0. And only use 4 bytes of data to get the exact same image as the 300 byte raw image. All the run length encoding I've found, except the Motorola style which is a little different, use a run length encoding that is pixel-oriented like this.

Now I've figured out this new one and it is a byte-oriented run length encoding. This is for runs of bytes, not pixels. You may think, well whats the big deal? When you add a little area of color, you increase the run length encoded image in you logo.bin immensely! You use 6 bytes per pixel if there aren't any runs of color data. If you had an image that was a 1080x1920 black image with a 25 pixel wide, by 25 pixel high red box in the middle. The encoder would be doing runs of black data efficiently until it reached the red area.
.....0 255 0 255 0 255 0 255 0 255 0 133 /// we've reached the top left corner of the red square /// 13 1 30 1 255 1 // << that was just one red pixel!! in bgr color order (13, 30, 255) <<// And it keeps going through the rest of the red pixels on that line using 6 bytes per pixel, which is the opposite of compression. Before reaching the red square the encoding was decoding to 255 zeros over and over, until finally 133 zeros. 255 zeros is 85 black pixels stored in just 2 bytes!

This type of encoding is only good for grey scale images. It is not good with color, but it still will handle color of course. In grey scale, the Red, Blue, and Green data components are always the same values. All the way from black (0,0,0) to white (255, 255, 255); including every shade of grey in between>>>(1,1,1) (2,2,2) (3,3,3)....(243, 243, 243) (244, 244, 244)<<<

One other difference in this method of run length encoding is that the color byte is before the count, which is backwards from all of the other methods.​

The attachment contains the C source code (which is also in the 2nd post) and the executable that was compiled using mingw32 on a 64 bit Windows 7 pc. The png library that I used is LodePng, the source is in the download.

To use logoinjector:

Decode your logo.bin:
Code:
logoInjector.exe -i logo.bin -d

All the PNG 's will be extracted from logo.bin. Edit the PNGs that you want to change...

Note:
Your original "logo.bin" file is never changed, it is just read. If the file you try to load isn't a logo.bin file, or if it is the older style, then the program will tell you and exit​

Inject the image(s) back in to the logo.bin:
Code:
logoinjector.exe -i logo.bin -j image_name_1 image_name_3
To list whats in your logo file:
Code:
logoinjector.exe -i logo.bin -l
For a more detailed list:
Code:
logoinjector.exe -i logo.bin -L
If the colors are messed up use the "-s" switch while decoding.
Code:
logoinjector.exe -i logo.bin -d -s
If you had to use the "-s" switch to decode properly, you'll have to use it to inject also:
Code:
logoinjector.exe -i logo.bin -j image_name -s
Note:
With version 1.2, you can put as many names after "-j" as you want, and it's not case sensitive. You also don't have to put the whole name. If you just put "-j fhd" every image in the logo.bin that starts with "fhd" will be injected. There has to be a PNG with the name in the directory though​

The size of your modified.logo.bin will displayed along with the original size, if everything went good. Please know the size of you logo partition. I made this program to encompass any device using this format, and there is no set size of the logo partition between devices. Fastboot will just error out if you try to flash data bigger than the partition before it writes anything. But if someone gets brave and trys to "DD" to the logo partition, it could get ugly.:cyclops:

Flash the "modified.logo.bin" file through fastboot.


v1.2
  • made it possible for multiple injections in one command
  • doesn't add png to the decoded png if it was already in the name
  • fixed out of scope with image 26 in OPPO find 7 logo.bin
  • added LodePng source in the download
  • made the default color order BGR
  • displays the modified logo file size as well as the original file size
  • runs the modified.logo.bin back through the list function after injecting
  • checks the number of offsets between the original and modified logo.bin

Use this at your own risk.
Always make backups.
Always.
 
Last edited:

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
Code:
/* 
/* 
 * Logo Injector v1.2
 *
 * Copyright (C) 2015 Joseph Andrew Fornecker
 * makers_mark @ xda-developers.com
 * [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3 of the License, or (at your
 * opinion) any later version. See <http://www.gnu.org/licenses/gpl.html>
 *
 * New in v1.2:
 * 
 * - Fixed out of scope crash involving image #26 in oppo find 7 logo.bin (26 IS BIG) 
 * - Multiple injection names possible after the -j parameter
 * - Injection names are now case insensitive
 * - BGR is the the default color order, instead of RGB
 * - Added more error checks
 * - Show the change in file size of original logo.bin compare to the modified logo.bin
 * - Several small changes dealing with readability
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include "lodepng.h"

#define SWAP32(x) (( x >> 24 )&0xff) | ((x << 8)&0xff0000) | ((x >> 8)&0xff00) | ((x << 24)&0xff000000)
#define BLOCK 512
#define OFFSETSTART 48
#define BYTESPERPIXEL 3
#define MAXOFFSETS 28
#define SIZEOFLONGINT 4
#define TWOTOTHETEN 1024

typedef struct {

	uint8_t header[8];
	uint8_t blank[24];
	uint32_t width;
	uint32_t height;
	uint32_t lengthOfData;
	uint32_t special;
	uint32_t offsets[MAXOFFSETS];
	uint8_t name[64];
	uint8_t metaData[288];

} IMAGEHEAD;

uint16_t Copy(FILE *, IMAGEHEAD *, uint16_t , uint16_t, FILE *);
int32_t InjectNewStyle(FILE *, IMAGEHEAD *, uint16_t , uint8_t *, uint16_t, FILE *, uint32_t * );
int32_t RewriteHeaderZero( uint32_t , uint16_t,  FILE* , int32_t, uint32_t * );
uint32_t Encode(uint8_t*, uint8_t*, uint32_t);
uint32_t GetEncodedSize(uint8_t*, uint32_t);
uint32_t GetWidth(FILE*);
uint32_t GetHeight(FILE*);
uint64_t BlockIt(uint32_t);
uint16_t GetNumberOfOffsets(FILE*);
int32_t DecodeLogoBin(FILE*, IMAGEHEAD *);
int32_t ListFileDetails(FILE*, IMAGEHEAD *);
uint8_t* Decode(FILE*, uint32_t, uint32_t, uint32_t, uint8_t*);
int32_t IsItTheNewStyle(FILE*);
IMAGEHEAD* ParseHeaders(FILE*, uint16_t);
int32_t IsItALogo(FILE*);
void PrintFileSize(uint32_t);
uint32_t GetFileSize(FILE *);

uint16_t badAss = 0;
int16_t rgb2bgr = 1;
uint16_t convertToPNG = 1;
uint8_t HEADER[] = {0x53,0x50,0x4C,0x41,0x53,0x48,0x21,0x21};
	

int32_t IsItALogo(FILE *originalLogoBin){

	uint8_t string[9];
	uint16_t i;

	fread(string, 1, 8, originalLogoBin);

	for (i = 0 ; i < 8 ; i++){

		if (string[i] == HEADER[i]){

			continue;

		} else {

			return 0;

		}

	}

	return 1;
}

int32_t IsItTheNewStyle(FILE *originalLogoBin){

	int32_t newStyle = 0;

	fread(&newStyle, 1, SIZEOFLONGINT, originalLogoBin);

	if (newStyle == 0){

		return 1;

	} else {

		return 0;

	}
}	

IMAGEHEAD *ParseHeaders(FILE *originalLogoBin, uint16_t numberOfOffsets){

	uint8_t i = 0;
	IMAGEHEAD *imageHeaders;

	imageHeaders = malloc(BLOCK * numberOfOffsets);

	memset(imageHeaders, 0, BLOCK * numberOfOffsets);
	fseek(originalLogoBin, 0, SEEK_SET);
	fread(&imageHeaders[i], 1 , BLOCK, originalLogoBin);

	for ( i = 1 ; i < numberOfOffsets ; ++i ){

		fseek(originalLogoBin, imageHeaders[0].offsets[i], SEEK_SET);
		fread(&imageHeaders[i], 1 , BLOCK, originalLogoBin);

	}

	return imageHeaders;
}

uint16_t GetNumberOfOffsets(FILE *originalLogoBin){

		uint16_t i = 0;
		uint32_t readAs = 0;

		fseek(originalLogoBin, OFFSETSTART, SEEK_SET);

		while(i < MAXOFFSETS){

			fread(&readAs, 1, SIZEOFLONGINT, originalLogoBin);

			if ((readAs == 0) && (i != 0)){

				break;

			} else {

				i++;

			}

		}

		return i;
}

uint8_t* Decode(FILE *originalLogoBin, uint32_t start, uint32_t length, uint32_t imageBytes, uint8_t* image){

	uint32_t decodedBytes = 0, i = 0;
	uint8_t* data; 

	fseek(originalLogoBin, start, SEEK_SET);
	data = (uint8_t*)malloc(length);

	if (fread(data, 1, length, originalLogoBin) != length) {

		fprintf(stderr, "Could not read file!!\n");
		exit(0);

	}

	while((i < length) && (decodedBytes < imageBytes)){

		memset(&image[decodedBytes], data[i], (data[i + 1]));
		decodedBytes += (uint8_t)data[i+1];
		i += 2;

		if ((i  < length) && (imageBytes - decodedBytes < (uint8_t)data[i + 1])){

			memset(&image[decodedBytes], data[i], imageBytes - decodedBytes);
			decodedBytes = imageBytes;
			fprintf(stdout, "More information was in encoding than resolution called for.\n");
			break;

		}

    }

	fprintf(stdout, "%ld decoded bytes\n", decodedBytes);
	free(data);

	if( rgb2bgr == 1 ){

		uint8_t old;
		i = 0;

		while( i < imageBytes){

			old = image[i];
			memset(&image[i], image[i + 2], 1);
			memset(&image[i + 2], old, 1);
			i += BYTESPERPIXEL;

		}

	}

	return image;
}

int32_t DecodeLogoBin(FILE *originalLogoBin, IMAGEHEAD *imageHeaders){

	uint32_t size, imageBytes, start;
	uint8_t* image;
	uint8_t name[65];
	uint8_t r = 0;
	uint16_t i , numberOfOffsets = GetNumberOfOffsets(originalLogoBin);

	for ( i = 0 ; i < numberOfOffsets ; i++ ){

		fprintf(stdout,"\n\n\n#%d: Offset:%ld\n", i + 1, imageHeaders[0].offsets[i]);

		if ((imageHeaders[i].width == 0) || (imageHeaders[i].height == 0)){

			fprintf(stdout, "Placeholder for %s\n", imageHeaders[i].metaData);
			continue;

		}

		fprintf(stdout, "Header=%s\nWidth=%ld\nHeight=%ld\nData Length=%ld\nSpecial=%ld\nName=%s\nMetadata=%s\n",
			imageHeaders[i].header, imageHeaders[i].width, imageHeaders[i].height,
			imageHeaders[i].lengthOfData, imageHeaders[i].special, imageHeaders[i].name, imageHeaders[i].metaData);

		if (convertToPNG){

			start = imageHeaders[0].offsets[i] + BLOCK;
			imageBytes = imageHeaders[i].width * (imageHeaders[i].height) * BYTESPERPIXEL;
			image = malloc(imageBytes);
			uint8_t lengthOfName = strlen(imageHeaders[i].name);
			uint8_t *ext;

			ext = strrchr(imageHeaders[i].name, '.');

			if (((ext[1] == 'p') || (ext[1] == 'P')) && 
				((ext[2] == 'n') || (ext[2] == 'N')) &&
				((ext[3] == 'g') || (ext[3] == 'G')) &&
				((ext[0] == '.'))){

				sprintf(name, "%s", imageHeaders[i].name);

			} else {

				sprintf(name, "%s.png", imageHeaders[i].name);

			}

			lodepng_encode24_file(name, Decode(originalLogoBin, (uint32_t)start, (uint32_t)imageHeaders[i].lengthOfData, (uint32_t)imageBytes, image) , (unsigned)imageHeaders[i].width, (unsigned)imageHeaders[i].height);
			free(image);

		}

	}

	return 0;
}

int32_t ListFileDetails(FILE *originalLogoBin, IMAGEHEAD *imageHeaders){

	uint32_t i = 0, j = 0;
	fseek(originalLogoBin, 0, SEEK_SET);
	uint16_t numberOfOffsets = GetNumberOfOffsets(originalLogoBin);

	fprintf(stdout, "Resolution\tOffset\tName\n");
	fprintf(stdout, "-------------------------------------------------------------\n");

	for ( i = 0 ; i < numberOfOffsets ; i++ ){

		if ((imageHeaders[i].width == 0) || (imageHeaders[i].height == 0)){

			fprintf(stdout, "(placeholder) for %s\n", imageHeaders[i].metaData);
			continue;

		}

		fprintf(stdout,"%dx%d\t", imageHeaders[i].width, imageHeaders[i].height);
		if ((imageHeaders[i].width < 1000) && (imageHeaders[i].height <1000)){fprintf(stdout, "\t");}
		fprintf(stdout, "%ld\t%s\n", imageHeaders[0].offsets[i], imageHeaders[i].name );

	}

	return 1;
}

 uint16_t Copy(FILE *originalLogoBin, IMAGEHEAD *imageHeaders, uint16_t numberOfOffsets, uint16_t injectionNumber, FILE *modifiedLogoBin){

		uint8_t *data;
		uint32_t offset, originalOffset;
		uint32_t imageSize = BlockIt(BLOCK + imageHeaders[injectionNumber].lengthOfData);

		if( imageHeaders[injectionNumber].name[0] == 0){

			fprintf(stdout, "Copying \t#%d:(placeholder) %s\n", injectionNumber + 1 , imageHeaders[injectionNumber].metaData);

		} else {

			fprintf(stdout, "Copying \t#%d:%s\n", injectionNumber + 1 , imageHeaders[injectionNumber].name);
			
		}

		data = malloc(imageSize);
		memset(data, 0 , imageSize);
		fread(data, 1, imageSize, originalLogoBin);
		fwrite(data, 1 , imageSize, modifiedLogoBin);
		free(data);
}

int32_t InjectNewStyle(FILE *originalLogoBin, IMAGEHEAD *imageHeaders, uint16_t numberOfOffsets, uint8_t *injectionName, uint16_t injectionNumber, FILE *modifiedLogoBin, uint32_t *ihMainOffsets ){
	
		uint32_t encodedSize = 0, actualWritten = 0, imageSize = 0;
		uint8_t *data, *header;
		int8_t inFileName[69];
		int32_t blockDifference;
		uint32_t offset, originalOffset;
		FILE *pngFile;
		sprintf(inFileName, "%s", injectionName);
		
		if (imageHeaders[injectionNumber].special != 1){

			fprintf(stdout, "ERROR: \"Special\" is not equal to '1' \nThis would not be safe to flash!\nPlease email logo.bin in question to:\[email protected]\n");
			fclose(originalLogoBin);
			fclose(modifiedLogoBin);
			return 0;

		}

		if ((pngFile = fopen(inFileName, "rb")) == NULL){

			sprintf(inFileName, "%s.png", injectionName);

			if ((pngFile = fopen(inFileName, "rb")) == NULL){

				fclose(pngFile);
				fclose(modifiedLogoBin);
				fclose(originalLogoBin);
				fprintf(stderr, "%s could not be read\n", inFileName);
				return 0;

			}
		}

		IMAGEHEAD new;

		memset(new.blank, 0, sizeof(new.blank));
		memset(new.metaData, 0, sizeof(new.metaData));
		memset(new.offsets, 0, SIZEOFLONGINT * MAXOFFSETS);
		strncpy(new.header, HEADER , 8);
		strncpy(new.metaData, imageHeaders[injectionNumber].metaData, sizeof(imageHeaders[injectionNumber].metaData));
		strncpy(new.name, injectionName, 64);
		new.special = 1;

		fprintf(stdout, "Injecting\t#%d:%s\n", injectionNumber + 1 , imageHeaders[injectionNumber].name);

		if (((new.width = GetWidth(pngFile)) != imageHeaders[injectionNumber].width) && (!badAss)){

			fprintf(stderr, "Error: Width of PNG to be injected is %d, it must be %d!\n", new.width, imageHeaders[injectionNumber].width);
			fclose(pngFile);
			fclose(modifiedLogoBin);
			fclose(originalLogoBin);

			return 0;

		}

		if (((new.height = GetHeight(pngFile)) != imageHeaders[injectionNumber].height) && (!badAss)){

			fprintf(stderr, "Error: Height of PNG to be injected is %d, it must be %d!\n", new.height, imageHeaders[injectionNumber].height);
			fclose(pngFile);
			fclose(modifiedLogoBin);
			fclose(originalLogoBin);

			return 0;

		}

		uint32_t rawBytes = new.width * new.height * BYTESPERPIXEL;
		uint8_t *decodedPNG = malloc(rawBytes);

		lodepng_decode24_file(&decodedPNG, (uint32_t*)&new.width, (uint32_t*)&new.height , (const uint8_t*)inFileName);

		if (rgb2bgr == 1){

			uint8_t old;
			uint32_t k = 0;

			while( k < rawBytes ){

				old = decodedPNG[k];
				memset(&decodedPNG[k], decodedPNG[k + 2], 1);
				memset(&decodedPNG[k + 2], old, 1);
				k += BYTESPERPIXEL;

			}
		}

		encodedSize = GetEncodedSize(decodedPNG, (new.width * new.height * BYTESPERPIXEL));
		new.lengthOfData = encodedSize;
		uint8_t *rlEncoded = malloc(BlockIt(encodedSize));
		memset(rlEncoded, 0, BlockIt(encodedSize));
		actualWritten = Encode(decodedPNG, rlEncoded, (new.width * new.height * BYTESPERPIXEL));
		blockDifference = (((BLOCK + BlockIt(actualWritten)) - (BLOCK + BlockIt(imageHeaders[injectionNumber].lengthOfData))) / BLOCK);
		fwrite(&new, 1 , BLOCK, modifiedLogoBin);
		fwrite(rlEncoded, 1 , BlockIt(actualWritten), modifiedLogoBin);
		free(decodedPNG);
		free(rlEncoded);

		RewriteHeaderZero( injectionNumber , numberOfOffsets , modifiedLogoBin , blockDifference, ihMainOffsets);

		fclose(pngFile);

		return 1;
}

int32_t RewriteHeaderZero( uint32_t injectionImageNumber , uint16_t numberOfOffsets, FILE *modifiedLogoBin , int32_t blockDifference, uint32_t *ihMainOffsets){

	uint8_t i, j = injectionImageNumber + 1 ;
	uint32_t filePosition = ftell(modifiedLogoBin);
	uint32_t offset = 0;

	for( ; j < numberOfOffsets; j++){

		fseek(modifiedLogoBin, OFFSETSTART + (SIZEOFLONGINT * j), SEEK_SET);
		offset = ihMainOffsets[j];
		offset += (blockDifference * BLOCK);
		fseek(modifiedLogoBin, OFFSETSTART + (SIZEOFLONGINT * j), SEEK_SET);
		fwrite(&offset, 1 , SIZEOFLONGINT , modifiedLogoBin);
		ihMainOffsets[j] = offset;

	}

	fseek(modifiedLogoBin, filePosition , SEEK_SET);
	
return;
}

uint32_t GetEncodedSize(uint8_t* data, uint32_t size){

	uint32_t pos = 0, ret = 0;
	uint16_t count = 1;

	for( pos = 0 ; pos < size ; ++pos , count = 1){

		while((pos < size - 1) && (count < 0xFF) && ((memcmp(&data[pos], &data[pos+1], 1)) == 0)){

			count++;
			pos++;

		}

		ret += 2;

	}

	return ret;
}

uint32_t Encode(uint8_t* rawRgbReading, uint8_t* rlEncoded, uint32_t rawSize){

	uint32_t writePosition = 0 , readPosition = 0;
	uint16_t count = 1;

	for( readPosition = 0 ; readPosition < rawSize ; ++readPosition , count = 1){

		while((readPosition < rawSize - 1 ) && (count < 0xFF) && ((memcmp(&rawRgbReading[readPosition], &rawRgbReading[readPosition+1], 1)) == 0)){

			count++;
			readPosition++;

		}

		rlEncoded[writePosition] = rawRgbReading[readPosition];
		rlEncoded[writePosition + 1] = count;
		writePosition += 2;

	}

	return writePosition;
}

uint32_t GetWidth(FILE *pngFile){

	uint32_t width;

	fseek(pngFile, 16, SEEK_SET);
	fread(&width, 1, SIZEOFLONGINT, pngFile);

	return(SWAP32(width));

}

uint32_t GetHeight(FILE *pngFile){

	uint32_t height;

	fseek(pngFile, 20, SEEK_SET);
	fread(&height, 1, SIZEOFLONGINT, pngFile);

	return(SWAP32(height));
}

uint64_t BlockIt(uint32_t isize){

	uint32_t blockSize = BLOCK;

	if ((isize % blockSize) == 0){

		return isize;

	}else{

		return isize + (blockSize - (isize % blockSize));

	}
}

void Usage(){

	fprintf(stdout, "Usage: logoinjector -i \"input file\" [-l] | [-L] | [-d [-s]] | [-j \"image to be replaced\" [-b] | [-s]]\n\n");
	fprintf(stdout, "Mandatory Arguments:\n\n");
	fprintf(stdout, "\t-i \"C:\\xda\\logo.bin\"\n");
	fprintf(stdout, "\t   This is the logo.bin file to analyze or inject an image\n\n");
	fprintf(stdout, "Optional Arguments:\n\n");
	fprintf(stdout, "\t-d Decode all images into PNGs, (-s)wap parameter may be needed for proper color.\n");
	fprintf(stdout, "\t-l Lower case 'L' is to display a short list of what is inside the input file.\n");
	fprintf(stdout, "\t-L Upper case 'L' is for a more detailed list of logo.bin image contents.\n");
	fprintf(stdout, "\t-b 'b' is used to tell the program to disregard width or height differences\n");
	fprintf(stdout, "\t   when encoding an image, the program also won't fail if it can't find a name\n");
	fprintf(stdout, "\t   that can't be found on the inject list when encoding images\n");
	fprintf(stdout, "\t-s 's' is used to swap RGB and BGR color order. Can be used on decoding or encoding.\n");
	fprintf(stdout, "\t   NEW IN THIS V1.2: Swap is on by default, meaning the color order will be BGR. Using\n");
	fprintf(stdout, "\t   the \"-s\" switch will result in a RGB color order. Bottom line: If you (-d)ecode the\n");
	fprintf(stdout, "\t   images (that have color) and the colors aren't right, then you should use (-s) to \n");
	fprintf(stdout, "\t   decode and inject images.\n");
	fprintf(stdout, "\t-j \"image(s) to be replaced\"\n");
	fprintf(stdout, "\t   The image(s) name to be replaced as seen in the (-l)ist\n");
	fprintf(stdout, "\t   NEW IN THIS V1.2: Multiple image names may be put after \"-j\"\n");
	fprintf(stdout, "\t   The names simply need to be separated by a space. The names now also are not case\n");
	fprintf(stdout, "\t   sensitive, and it doesn't matter if you put the extension at the end of the name.\n");
	fprintf(stdout, "\t   You actually only need to put the first characters of the name.\nExample:\n");
	fprintf(stdout, "\t   logoinjector -i \"your_logo.bin\" -j FHD \n\n");
	fprintf(stdout, "\t   This will inject a PNG for every name in the logo bin that begins with \"fhd\"\n");

	return;
}

void PrintFileSize(uint32_t bytes){

	float megaBytes = 0, kiloBytes = 0;
	kiloBytes = (float)bytes / (float)TWOTOTHETEN;
	megaBytes = kiloBytes / (float)TWOTOTHETEN;
	
	if (kiloBytes < (float)TWOTOTHETEN){

		fprintf(stdout, "\t%.2f KB\n", kiloBytes);

	} else {

		fprintf(stdout, "\t%.2f MB\n", megaBytes);

	}

return;
}

uint32_t GetFileSize(FILE *temp){

	fseek(temp, 0 , SEEK_END);
	uint32_t fileSizeZ = ftell(temp);

return(fileSizeZ);
}

int32_t main(int32_t argc, int8_t **argv){

	int32_t c;
	int16_t h, i , j , k = 0;
	FILE *originalLogoBin = NULL, *modifiedLogoBin = NULL;
	uint8_t *inputFile = NULL;
	uint8_t *injectNames[MAXOFFSETS];
	int16_t decodeAllOpt = 0;
	int16_t encodeOpt = 0;
	int16_t inject = 0;
	int16_t listFile = 0;
	uint16_t numberOfOffsets = 0, injected = 0;

	for(i = 0; i < MAXOFFSETS; i++){

		injectNames[i] = NULL;

	}

	fprintf(stdout, "__________________________________________________________-_-\n");
	fprintf(stdout, "Logo Injector v1.2\n\nWritten By Makers_Mark @ XDA-DEVELOPERS.COM\n");
	fprintf(stdout, "_____________________________________________________________\n\n");

	while ((c = getopt (argc, (char**)argv, "sSj:J:hHbBdDlLi:I:")) != -1){

		switch(c)
		{
			case 'l':

				listFile = 1;
				break;

			case 'L':

				decodeAllOpt = 1;
				convertToPNG = 0;
				break;

			case 'i':
			case 'I':

				inputFile = optarg;
				break;

			case 'b':
			case 'B':

				badAss = 1;
				break;

			case 'j':
			case 'J':

				h = optind - 1 ;
				uint8_t *nextArg;

				while(h < argc){

					inject = 1;
					nextArg = strdup(argv[h]);
					h++;

					if(nextArg[0] != '-'){

						injectNames[k++] = nextArg;

					} else {

						break;

					}
				}
				optind = h - 1;
				break;

			case 'd':
			case 'D':

				decodeAllOpt = 1 ;
				break;

			case 's':
			case 'S':

				rgb2bgr = -1 ;
				break;

			case 'h':
			case 'H':

				Usage();
				return 0;
				break;

			default:
				Usage();
				return 0;
				break;

		}
	}

	if (inputFile == NULL){

		Usage();
		return 0;

	}

	fprintf(stdout, "FILE: %s\n_____________________________________________________________\n\n", inputFile);

	if (rgb2bgr == 1){

		fprintf(stdout, "BGR is the color order. Use \"-s\" switch to change it to RGB.\n\n");

	} else {

		fprintf(stdout, "RGB is the color order. Use \"-s\" switch to change it to BGR.\n\n");

	}

	if ((originalLogoBin = fopen(inputFile, "rb")) == NULL){

		fprintf(stderr, "%s could not be opened\n", inputFile);
		return 0;

	}

	if (!IsItALogo(originalLogoBin)){

		fprintf(stdout, "\nThis is NOT a valid Logo.bin\n\n");
		fclose(originalLogoBin);
		return 0;

	}

	if (!IsItTheNewStyle(originalLogoBin)){

		fprintf(stdout, "\nThis is the old style logo.bin\n\n");
		fclose(originalLogoBin);
		return 0;

	}

	numberOfOffsets = GetNumberOfOffsets(originalLogoBin);
	IMAGEHEAD *imageHeaders = ParseHeaders(originalLogoBin, numberOfOffsets);

	if (listFile){

		ListFileDetails(originalLogoBin, imageHeaders);
		return 1;

	}

	if(inject){

		uint32_t ihMainOffsets[MAXOFFSETS];
		uint8_t found = 0, exitFlag = 0;

		for (i = 0; i < MAXOFFSETS ; i++){

			ihMainOffsets[i] = 0;

		}

		for (j = 0; j < k ; j++){

			for (i = 0 ;  i < numberOfOffsets ; i++ ){

				if((strcasecmp(imageHeaders[i].name, injectNames[j]) == 0) ||
				   (strncasecmp(imageHeaders[i].name, injectNames[j], strlen(injectNames[j])) == 0)){

					found = 1;
					break;

				} else {

					found = 0;

				}
			}

			if (!found){

				fprintf(stdout, "ERROR: \"%s\" is not in the logo bin !!!!\n", injectNames[j]);
				exitFlag = 1;
			}
		}

		if ((exitFlag) && (!badAss)){

			fclose(originalLogoBin);
			exit(0);

		}

		memcpy(&ihMainOffsets , &imageHeaders[0].offsets, SIZEOFLONGINT * MAXOFFSETS);
		fseek(originalLogoBin, 0, SEEK_SET);

		if ((modifiedLogoBin = fopen("modified.logo.bin", "wb+")) == NULL){

			fclose(modifiedLogoBin);
			fclose(originalLogoBin);
			fprintf(stderr, "modified.logo.bin could not be opened\n");
			return 0;

		}

		for (i = 0 ; i < numberOfOffsets ; i++ , injected = 0 ){

			for (j = 0; j < k ; j++){

				if((strcasecmp(imageHeaders[i].name, injectNames[j]) == 0) ||
				    (strncasecmp(imageHeaders[i].name, injectNames[j], strlen(injectNames[j])) == 0)){

					if (InjectNewStyle(originalLogoBin, imageHeaders , numberOfOffsets, imageHeaders[i].name, i, modifiedLogoBin, ihMainOffsets) == 0){

						fprintf(stderr, "Error: Injecting %s\n", imageHeaders[i].name);
						fclose(originalLogoBin);
						fclose(modifiedLogoBin);
						return 0;

					}

					if ( i != numberOfOffsets - 1 ){

						fseek(originalLogoBin, imageHeaders[0].offsets[i+1], SEEK_SET);

					}

					injected = 1;
					break;
				}
			}

			if (!injected){

				Copy(originalLogoBin , imageHeaders, numberOfOffsets, i, modifiedLogoBin);

			}
		}

		uint16_t modifiedNumberOfOffsets = 0;

		if (GetNumberOfOffsets(modifiedLogoBin) != numberOfOffsets){

			fprintf(stderr, "ERROR: The number of offsets doesn't match the Original file!!\n");
			fclose(modifiedLogoBin);

			if (!badAss){
				
				unlink("modified.logo.bin");

			}
			
			exit(0);

		}
		fprintf(stdout, "\n\nContents of the NEW \"modified.logo.bin\":\n");
		fprintf(stdout, "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n\n");
		
		ListFileDetails(modifiedLogoBin, imageHeaders);
		fprintf(stdout, "\n\n_____________________________________________________________\nOriginal filesize: ");
		PrintFileSize(GetFileSize(originalLogoBin));
		fprintf(stdout, "Modified filesize: ");
		PrintFileSize(GetFileSize(modifiedLogoBin));
		fprintf(stdout, "-------------------------------------------------------------\n");
		fclose(originalLogoBin);
		fclose(modifiedLogoBin);

		return 1;
	}		

	if (decodeAllOpt){

		DecodeLogoBin(originalLogoBin, imageHeaders);
		fclose(originalLogoBin);

		return 1;
	}

	fclose(originalLogoBin);
	return 1;
	
}
 
Last edited:

treChoy

Senior Member
Aug 15, 2012
247
146
After a little trial-and-error and some time in our beloved QHSUSB_DLOAD mode, I finally got it to work! I own a OnePlus One, and I had to use the -s parameter to get it to work correctly. Just a heads-up for any OPO owners who wants to use this. Great work, OP!
 
  • Like
Reactions: makers_mark

makers_mark

Senior Member
Sep 21, 2013
192
477
Kings Mountain
After a little trial-and-error and some time in our beloved QHSUSB_DLOAD mode, I finally got it to work! I own a OnePlus One, and I had to use the -s parameter to get it to work correctly. Just a heads-up for any OPO owners who wants to use this. Great work, OP!

Thanks for chiming in, I was going to ask you to test for me initially. Can you elaborate on what happened?
 

treChoy

Senior Member
Aug 15, 2012
247
146
Thanks for chiming in, I was going to ask you to test for me initially. Can you elaborate on what happened?

Just a foreword that I was using a Windows 8.1 machine, which is bound to be the cause of some of the issues I ran into.

After I unzipped the program and put the logo.bin in the extracted folder, I kept running the commands, but each time, I'd get an error message saying that the program didn't support my OS version, or something to that effect. I tried rewording the commands, but to no avail. Eventually, I just deleted the whole folder and extracted the package again. That seemed to do the trick.

So I had all the images extracted, and I created the ones I wanted to replace. There was a bit of confusion repackaging the image, since the OPO's logo.bin places the ".png" into the name of the images, but eventually, I got it all right. I flashed the modified logo.bin, but when I tried to reboot, my computer started installing drivers for QHSUSB. This had happened before when I was playing around with the LOGO partition, and it was an easy fix. I just jammed the power button for 30 seconds, and prayed to God. Thankfully, the phone booted up, but the splash screen I had created had its colors messed up. I assumed that I needed to swap the red and the blue, so I used the parameter you provided and packaged a new splash screen. I flashed it, and everything looked fine.

It's definitely a little more intimidating than the tool that @chillstep1998 created, but with a little trial-and-error, it's certainly doable. Great work!
 
  • Like
Reactions: makers_mark

Jadelor

Senior Member
Apr 23, 2015
119
60
Oulu
Oh, yeah. I needed to use the -s parameter too and I skipped putting the logo.bin in through fastboot - I just modded an install zip and flashed it in with TWRP.
 

nicesoni_ash

Senior Member
May 26, 2012
6,099
10,955
127.0.0.1
Thanks for this program. Glad that it's back from someone for CM12 as we waited for quite some time now. I have a query though about repacking.

logoinjector.exe -i logo.bin -j (image name you want to replace)

Is it possible to put different file names at the same time if I want to replace two or three files at the same time like this

logoinjector.exe -i logo.bin -j 4-fastboot.png 5-lowpower.png

because it doesn't work for me, I will have to run this command for the number of times I have files to replaced?
 

gps3dx

Senior Member
Jan 24, 2010
780
396
HTC Desire
Samsung Galaxy Tab 10.1
Code:
/* 
 * Logo Injector v1.0
[/QUOTE]

WOW - Thanks !
I've waited a LONG time for this !
Few things to let you know
1. On my Win 8.1 x64 I run Comodo CIS  - which prevents LogoInjector.exe from creating the PNG images after I run "logoInjector.exe -i logo.bin -d".
This is of course the behavior of a false-positive, the overprotection of comodo A/V.
So once I temporary disable it -LogoInjector can successfully create the PNGs.

2. I also, as already reported, needed to use the -s switch inorder to get the right colors
3. I would also very much appreciate if it will be possible to inject multiple images at once with one command.
4. I can advise to update the OP with the size limits of the logo.bin ( if there is at all )
   I injected a 276KB png into 335KB logo.bin and got a modified logo.bin size 12,171KB ( 12MB ! ) - never the less - After I flashed it - everything is OK.
5. I can advise to put in the OP a link to a tool/method ( if exist at all ) that can enable extraction of the current installed logo.bin from the phone it self.

button line - VERY GOOD WORK ! :good: :good: :good::highfive:

[B][U]EDIT:[/U][/B]
I attach a[B] FLASHABLE ZIP FILE that INSTALLS the logo.bin[/B] found inside the zip.
just replace the logo.bin in the root of the zip with your custom made "logo.bin".
This method is an alternative to the fastboot command "fastboot flash LOGO logo.bin"
 

Attachments

  • Logo_Installer.zip
    242.7 KB · Views: 122
Last edited:

ranger1021994

Member
Nov 28, 2010
11
0
OnePlus 8
LOGO.bin file size

Size depends on the size of embedded images.

Sent from my "GT-I9300/1+1" powered by Carbon Rom & Boeffla/ak Kernel
Fueled by 7000mAh ZeroLemon Battery

My original LOGO file is 16MB big.
How can my modified file be only 330KB?
I don't know what is causing the file size to come down drastically from 16MB to just 330KB. Is it normal? Because I'm not sure it is
 

nicesoni_ash

Senior Member
May 26, 2012
6,099
10,955
127.0.0.1
My original LOGO file is 16MB big.
How can my modified file be only 330KB?
I don't know what is causing the file size to come down drastically from 16MB to just 330KB. Is it normal? Because I'm not sure it is
Check all image files size individually and if the difference is not that huge then surely something is wrong.

Sent from my "GT-I9300/1+1" powered by Carbon Rom & Boeffla/ak Kernel
Fueled by 7000mAh ZeroLemon Battery
 

gps3dx

Senior Member
Jan 24, 2010
780
396
HTC Desire
Samsung Galaxy Tab 10.1
Check all image files size individually and if the difference is not that huge then surely something is wrong.

My original LOGO file is 16MB big.
How can my modified file be only 330KB?
I don't know what is causing the file size to come down drastically from 16MB to just 330KB. Is it normal? Because I'm not sure it is

I injected a 276KB png into 335KB logo.bin and got a modified logo.bin size 12,171KB ( 12MB ! ) - never the less - After I flashed it - everything is OK.

@read my quote.
if you enter an image with only ONE COLOR background ( Same RBG values, not gradient ! ) it can drastically lower the final file size.
You can of course use black as background color and crop the images size to your content, so that the cropped areas will be filled automatically by the OPO as black color.
The idea here is that if you'll have full sized photo (1080x1920) with small area content (like 300x400), it contains black areas ( for no reason ) which enlarges the final file size - which make no sense.
nevertheless, Read my quote, as you can see I flash a ~12MB file while the original file was 335KB - and everything works!
 
  • Like
Reactions: nicesoni_ash

nicesoni_ash

Senior Member
May 26, 2012
6,099
10,955
127.0.0.1
I have a stupid question, how can I know whether I have a CM12 or CM11 logo in my oneplus? I have flashed CM11 as a primary rom and flashed CM12 as a secondary rom. I do remember that I flashed a CM12 zip to be able to flash CM12 as a secondary rom but that's a faint memory and I want to be sure before flashing a logo because last time I did that, I lost everything in my Oneplus and had to start from the beginning first by reviving it from its dead state.

Thanks.
 

treChoy

Senior Member
Aug 15, 2012
247
146
I have a stupid question, how can I know whether I have a CM12 or CM11 logo in my oneplus? I have flashed CM11 as a primary rom and flashed CM12 as a secondary rom. I do remember that I flashed a CM12 zip to be able to flash CM12 as a secondary rom but that's a faint memory and I want to be sure before flashing a logo because last time I did that, I lost everything in my Oneplus and had to start from the beginning first by reviving it from its dead state.

Thanks.
EDIT: Deleted for misinformation
 
Last edited:
  • Like
Reactions: nicesoni_ash

ranger1021994

Member
Nov 28, 2010
11
0
OnePlus 8
It works!!

@read my quote.
if you enter an image with only ONE COLOR background ( Same RBG values, not gradient ! ) it can drastically lower the final file size.
You can of course use black as background color and crop the images size to your content, so that the cropped areas will be filled automatically by the OPO as black color.
The idea here is that if you'll have full sized photo (1080x1920) with small area content (like 300x400), it contains black areas ( for no reason ) which enlarges the final file size - which make no sense.
nevertheless, Read my quote, as you can see I flash a ~12MB file while the original file was 335KB - and everything works!

AMAZING!
It works!!
Finally
Thanks a lot!
 

Top Liked Posts

  • There are no posts matching your filters.
  • 23
    This is a program that I wrote to decode the newer style "logo.bin" files used in some OPPO, and OnePlus devices. Please read below so you can better understand this type of encoding being used:
    What Is A Raw Image?

    A raw image, whether it be a file or an image in memory, is simply pixel data. There is no extra information like width, height, name, end of line... Absolutely nothing, just pixel data. If you have an image that is raw and the resolution is 1080x1920 and you are using a typical RGB24 or BGR24 (like the ones used here), then your exact filesize or size in memory will be 1080x1920x3! We use 3 here because there is one byte for the R or red component, one for the G (green), and one for the B(blue).

    What Is A Run Length Encoded Image?

    A run length image encoding uses a count ;usually a single byte (char), 2 bytes (short int), or 4 bytes (long int); and then the pixel components. So instead of writing out 300 bytes of '0's to make a line of 100 black pixels. Black is RGB(0,0,0). You could encode this as 100, 0, 0, 0. And only use 4 bytes of data to get the exact same image as the 300 byte raw image. All the run length encoding I've found, except the Motorola style which is a little different, use a run length encoding that is pixel-oriented like this.

    Now I've figured out this new one and it is a byte-oriented run length encoding. This is for runs of bytes, not pixels. You may think, well whats the big deal? When you add a little area of color, you increase the run length encoded image in you logo.bin immensely! You use 6 bytes per pixel if there aren't any runs of color data. If you had an image that was a 1080x1920 black image with a 25 pixel wide, by 25 pixel high red box in the middle. The encoder would be doing runs of black data efficiently until it reached the red area.
    .....0 255 0 255 0 255 0 255 0 255 0 133 /// we've reached the top left corner of the red square /// 13 1 30 1 255 1 // << that was just one red pixel!! in bgr color order (13, 30, 255) <<// And it keeps going through the rest of the red pixels on that line using 6 bytes per pixel, which is the opposite of compression. Before reaching the red square the encoding was decoding to 255 zeros over and over, until finally 133 zeros. 255 zeros is 85 black pixels stored in just 2 bytes!

    This type of encoding is only good for grey scale images. It is not good with color, but it still will handle color of course. In grey scale, the Red, Blue, and Green data components are always the same values. All the way from black (0,0,0) to white (255, 255, 255); including every shade of grey in between>>>(1,1,1) (2,2,2) (3,3,3)....(243, 243, 243) (244, 244, 244)<<<

    One other difference in this method of run length encoding is that the color byte is before the count, which is backwards from all of the other methods.​

    The attachment contains the C source code (which is also in the 2nd post) and the executable that was compiled using mingw32 on a 64 bit Windows 7 pc. The png library that I used is LodePng, the source is in the download.

    To use logoinjector:

    Decode your logo.bin:
    Code:
    logoInjector.exe -i logo.bin -d

    All the PNG 's will be extracted from logo.bin. Edit the PNGs that you want to change...

    Note:
    Your original "logo.bin" file is never changed, it is just read. If the file you try to load isn't a logo.bin file, or if it is the older style, then the program will tell you and exit​

    Inject the image(s) back in to the logo.bin:
    Code:
    logoinjector.exe -i logo.bin -j image_name_1 image_name_3
    To list whats in your logo file:
    Code:
    logoinjector.exe -i logo.bin -l
    For a more detailed list:
    Code:
    logoinjector.exe -i logo.bin -L
    If the colors are messed up use the "-s" switch while decoding.
    Code:
    logoinjector.exe -i logo.bin -d -s
    If you had to use the "-s" switch to decode properly, you'll have to use it to inject also:
    Code:
    logoinjector.exe -i logo.bin -j image_name -s
    Note:
    With version 1.2, you can put as many names after "-j" as you want, and it's not case sensitive. You also don't have to put the whole name. If you just put "-j fhd" every image in the logo.bin that starts with "fhd" will be injected. There has to be a PNG with the name in the directory though​

    The size of your modified.logo.bin will displayed along with the original size, if everything went good. Please know the size of you logo partition. I made this program to encompass any device using this format, and there is no set size of the logo partition between devices. Fastboot will just error out if you try to flash data bigger than the partition before it writes anything. But if someone gets brave and trys to "DD" to the logo partition, it could get ugly.:cyclops:

    Flash the "modified.logo.bin" file through fastboot.


    v1.2
    • made it possible for multiple injections in one command
    • doesn't add png to the decoded png if it was already in the name
    • fixed out of scope with image 26 in OPPO find 7 logo.bin
    • added LodePng source in the download
    • made the default color order BGR
    • displays the modified logo file size as well as the original file size
    • runs the modified.logo.bin back through the list function after injecting
    • checks the number of offsets between the original and modified logo.bin

    Use this at your own risk.
    Always make backups.
    Always.
    6
    Code:
    /* 
    /* 
     * Logo Injector v1.2
     *
     * Copyright (C) 2015 Joseph Andrew Fornecker
     * makers_mark @ xda-developers.com
     * [email protected]
     *
     * This program is free software; you can redistribute it and/or modify it
     * under the terms of the GNU General Public License as published by the
     * Free Software Foundation; either version 3 of the License, or (at your
     * opinion) any later version. See <http://www.gnu.org/licenses/gpl.html>
     *
     * New in v1.2:
     * 
     * - Fixed out of scope crash involving image #26 in oppo find 7 logo.bin (26 IS BIG) 
     * - Multiple injection names possible after the -j parameter
     * - Injection names are now case insensitive
     * - BGR is the the default color order, instead of RGB
     * - Added more error checks
     * - Show the change in file size of original logo.bin compare to the modified logo.bin
     * - Several small changes dealing with readability
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdint.h>
    #include "lodepng.h"
    
    #define SWAP32(x) (( x >> 24 )&0xff) | ((x << 8)&0xff0000) | ((x >> 8)&0xff00) | ((x << 24)&0xff000000)
    #define BLOCK 512
    #define OFFSETSTART 48
    #define BYTESPERPIXEL 3
    #define MAXOFFSETS 28
    #define SIZEOFLONGINT 4
    #define TWOTOTHETEN 1024
    
    typedef struct {
    
    	uint8_t header[8];
    	uint8_t blank[24];
    	uint32_t width;
    	uint32_t height;
    	uint32_t lengthOfData;
    	uint32_t special;
    	uint32_t offsets[MAXOFFSETS];
    	uint8_t name[64];
    	uint8_t metaData[288];
    
    } IMAGEHEAD;
    
    uint16_t Copy(FILE *, IMAGEHEAD *, uint16_t , uint16_t, FILE *);
    int32_t InjectNewStyle(FILE *, IMAGEHEAD *, uint16_t , uint8_t *, uint16_t, FILE *, uint32_t * );
    int32_t RewriteHeaderZero( uint32_t , uint16_t,  FILE* , int32_t, uint32_t * );
    uint32_t Encode(uint8_t*, uint8_t*, uint32_t);
    uint32_t GetEncodedSize(uint8_t*, uint32_t);
    uint32_t GetWidth(FILE*);
    uint32_t GetHeight(FILE*);
    uint64_t BlockIt(uint32_t);
    uint16_t GetNumberOfOffsets(FILE*);
    int32_t DecodeLogoBin(FILE*, IMAGEHEAD *);
    int32_t ListFileDetails(FILE*, IMAGEHEAD *);
    uint8_t* Decode(FILE*, uint32_t, uint32_t, uint32_t, uint8_t*);
    int32_t IsItTheNewStyle(FILE*);
    IMAGEHEAD* ParseHeaders(FILE*, uint16_t);
    int32_t IsItALogo(FILE*);
    void PrintFileSize(uint32_t);
    uint32_t GetFileSize(FILE *);
    
    uint16_t badAss = 0;
    int16_t rgb2bgr = 1;
    uint16_t convertToPNG = 1;
    uint8_t HEADER[] = {0x53,0x50,0x4C,0x41,0x53,0x48,0x21,0x21};
    	
    
    int32_t IsItALogo(FILE *originalLogoBin){
    
    	uint8_t string[9];
    	uint16_t i;
    
    	fread(string, 1, 8, originalLogoBin);
    
    	for (i = 0 ; i < 8 ; i++){
    
    		if (string[i] == HEADER[i]){
    
    			continue;
    
    		} else {
    
    			return 0;
    
    		}
    
    	}
    
    	return 1;
    }
    
    int32_t IsItTheNewStyle(FILE *originalLogoBin){
    
    	int32_t newStyle = 0;
    
    	fread(&newStyle, 1, SIZEOFLONGINT, originalLogoBin);
    
    	if (newStyle == 0){
    
    		return 1;
    
    	} else {
    
    		return 0;
    
    	}
    }	
    
    IMAGEHEAD *ParseHeaders(FILE *originalLogoBin, uint16_t numberOfOffsets){
    
    	uint8_t i = 0;
    	IMAGEHEAD *imageHeaders;
    
    	imageHeaders = malloc(BLOCK * numberOfOffsets);
    
    	memset(imageHeaders, 0, BLOCK * numberOfOffsets);
    	fseek(originalLogoBin, 0, SEEK_SET);
    	fread(&imageHeaders[i], 1 , BLOCK, originalLogoBin);
    
    	for ( i = 1 ; i < numberOfOffsets ; ++i ){
    
    		fseek(originalLogoBin, imageHeaders[0].offsets[i], SEEK_SET);
    		fread(&imageHeaders[i], 1 , BLOCK, originalLogoBin);
    
    	}
    
    	return imageHeaders;
    }
    
    uint16_t GetNumberOfOffsets(FILE *originalLogoBin){
    
    		uint16_t i = 0;
    		uint32_t readAs = 0;
    
    		fseek(originalLogoBin, OFFSETSTART, SEEK_SET);
    
    		while(i < MAXOFFSETS){
    
    			fread(&readAs, 1, SIZEOFLONGINT, originalLogoBin);
    
    			if ((readAs == 0) && (i != 0)){
    
    				break;
    
    			} else {
    
    				i++;
    
    			}
    
    		}
    
    		return i;
    }
    
    uint8_t* Decode(FILE *originalLogoBin, uint32_t start, uint32_t length, uint32_t imageBytes, uint8_t* image){
    
    	uint32_t decodedBytes = 0, i = 0;
    	uint8_t* data; 
    
    	fseek(originalLogoBin, start, SEEK_SET);
    	data = (uint8_t*)malloc(length);
    
    	if (fread(data, 1, length, originalLogoBin) != length) {
    
    		fprintf(stderr, "Could not read file!!\n");
    		exit(0);
    
    	}
    
    	while((i < length) && (decodedBytes < imageBytes)){
    
    		memset(&image[decodedBytes], data[i], (data[i + 1]));
    		decodedBytes += (uint8_t)data[i+1];
    		i += 2;
    
    		if ((i  < length) && (imageBytes - decodedBytes < (uint8_t)data[i + 1])){
    
    			memset(&image[decodedBytes], data[i], imageBytes - decodedBytes);
    			decodedBytes = imageBytes;
    			fprintf(stdout, "More information was in encoding than resolution called for.\n");
    			break;
    
    		}
    
        }
    
    	fprintf(stdout, "%ld decoded bytes\n", decodedBytes);
    	free(data);
    
    	if( rgb2bgr == 1 ){
    
    		uint8_t old;
    		i = 0;
    
    		while( i < imageBytes){
    
    			old = image[i];
    			memset(&image[i], image[i + 2], 1);
    			memset(&image[i + 2], old, 1);
    			i += BYTESPERPIXEL;
    
    		}
    
    	}
    
    	return image;
    }
    
    int32_t DecodeLogoBin(FILE *originalLogoBin, IMAGEHEAD *imageHeaders){
    
    	uint32_t size, imageBytes, start;
    	uint8_t* image;
    	uint8_t name[65];
    	uint8_t r = 0;
    	uint16_t i , numberOfOffsets = GetNumberOfOffsets(originalLogoBin);
    
    	for ( i = 0 ; i < numberOfOffsets ; i++ ){
    
    		fprintf(stdout,"\n\n\n#%d: Offset:%ld\n", i + 1, imageHeaders[0].offsets[i]);
    
    		if ((imageHeaders[i].width == 0) || (imageHeaders[i].height == 0)){
    
    			fprintf(stdout, "Placeholder for %s\n", imageHeaders[i].metaData);
    			continue;
    
    		}
    
    		fprintf(stdout, "Header=%s\nWidth=%ld\nHeight=%ld\nData Length=%ld\nSpecial=%ld\nName=%s\nMetadata=%s\n",
    			imageHeaders[i].header, imageHeaders[i].width, imageHeaders[i].height,
    			imageHeaders[i].lengthOfData, imageHeaders[i].special, imageHeaders[i].name, imageHeaders[i].metaData);
    
    		if (convertToPNG){
    
    			start = imageHeaders[0].offsets[i] + BLOCK;
    			imageBytes = imageHeaders[i].width * (imageHeaders[i].height) * BYTESPERPIXEL;
    			image = malloc(imageBytes);
    			uint8_t lengthOfName = strlen(imageHeaders[i].name);
    			uint8_t *ext;
    
    			ext = strrchr(imageHeaders[i].name, '.');
    
    			if (((ext[1] == 'p') || (ext[1] == 'P')) && 
    				((ext[2] == 'n') || (ext[2] == 'N')) &&
    				((ext[3] == 'g') || (ext[3] == 'G')) &&
    				((ext[0] == '.'))){
    
    				sprintf(name, "%s", imageHeaders[i].name);
    
    			} else {
    
    				sprintf(name, "%s.png", imageHeaders[i].name);
    
    			}
    
    			lodepng_encode24_file(name, Decode(originalLogoBin, (uint32_t)start, (uint32_t)imageHeaders[i].lengthOfData, (uint32_t)imageBytes, image) , (unsigned)imageHeaders[i].width, (unsigned)imageHeaders[i].height);
    			free(image);
    
    		}
    
    	}
    
    	return 0;
    }
    
    int32_t ListFileDetails(FILE *originalLogoBin, IMAGEHEAD *imageHeaders){
    
    	uint32_t i = 0, j = 0;
    	fseek(originalLogoBin, 0, SEEK_SET);
    	uint16_t numberOfOffsets = GetNumberOfOffsets(originalLogoBin);
    
    	fprintf(stdout, "Resolution\tOffset\tName\n");
    	fprintf(stdout, "-------------------------------------------------------------\n");
    
    	for ( i = 0 ; i < numberOfOffsets ; i++ ){
    
    		if ((imageHeaders[i].width == 0) || (imageHeaders[i].height == 0)){
    
    			fprintf(stdout, "(placeholder) for %s\n", imageHeaders[i].metaData);
    			continue;
    
    		}
    
    		fprintf(stdout,"%dx%d\t", imageHeaders[i].width, imageHeaders[i].height);
    		if ((imageHeaders[i].width < 1000) && (imageHeaders[i].height <1000)){fprintf(stdout, "\t");}
    		fprintf(stdout, "%ld\t%s\n", imageHeaders[0].offsets[i], imageHeaders[i].name );
    
    	}
    
    	return 1;
    }
    
     uint16_t Copy(FILE *originalLogoBin, IMAGEHEAD *imageHeaders, uint16_t numberOfOffsets, uint16_t injectionNumber, FILE *modifiedLogoBin){
    
    		uint8_t *data;
    		uint32_t offset, originalOffset;
    		uint32_t imageSize = BlockIt(BLOCK + imageHeaders[injectionNumber].lengthOfData);
    
    		if( imageHeaders[injectionNumber].name[0] == 0){
    
    			fprintf(stdout, "Copying \t#%d:(placeholder) %s\n", injectionNumber + 1 , imageHeaders[injectionNumber].metaData);
    
    		} else {
    
    			fprintf(stdout, "Copying \t#%d:%s\n", injectionNumber + 1 , imageHeaders[injectionNumber].name);
    			
    		}
    
    		data = malloc(imageSize);
    		memset(data, 0 , imageSize);
    		fread(data, 1, imageSize, originalLogoBin);
    		fwrite(data, 1 , imageSize, modifiedLogoBin);
    		free(data);
    }
    
    int32_t InjectNewStyle(FILE *originalLogoBin, IMAGEHEAD *imageHeaders, uint16_t numberOfOffsets, uint8_t *injectionName, uint16_t injectionNumber, FILE *modifiedLogoBin, uint32_t *ihMainOffsets ){
    	
    		uint32_t encodedSize = 0, actualWritten = 0, imageSize = 0;
    		uint8_t *data, *header;
    		int8_t inFileName[69];
    		int32_t blockDifference;
    		uint32_t offset, originalOffset;
    		FILE *pngFile;
    		sprintf(inFileName, "%s", injectionName);
    		
    		if (imageHeaders[injectionNumber].special != 1){
    
    			fprintf(stdout, "ERROR: \"Special\" is not equal to '1' \nThis would not be safe to flash!\nPlease email logo.bin in question to:\[email protected]\n");
    			fclose(originalLogoBin);
    			fclose(modifiedLogoBin);
    			return 0;
    
    		}
    
    		if ((pngFile = fopen(inFileName, "rb")) == NULL){
    
    			sprintf(inFileName, "%s.png", injectionName);
    
    			if ((pngFile = fopen(inFileName, "rb")) == NULL){
    
    				fclose(pngFile);
    				fclose(modifiedLogoBin);
    				fclose(originalLogoBin);
    				fprintf(stderr, "%s could not be read\n", inFileName);
    				return 0;
    
    			}
    		}
    
    		IMAGEHEAD new;
    
    		memset(new.blank, 0, sizeof(new.blank));
    		memset(new.metaData, 0, sizeof(new.metaData));
    		memset(new.offsets, 0, SIZEOFLONGINT * MAXOFFSETS);
    		strncpy(new.header, HEADER , 8);
    		strncpy(new.metaData, imageHeaders[injectionNumber].metaData, sizeof(imageHeaders[injectionNumber].metaData));
    		strncpy(new.name, injectionName, 64);
    		new.special = 1;
    
    		fprintf(stdout, "Injecting\t#%d:%s\n", injectionNumber + 1 , imageHeaders[injectionNumber].name);
    
    		if (((new.width = GetWidth(pngFile)) != imageHeaders[injectionNumber].width) && (!badAss)){
    
    			fprintf(stderr, "Error: Width of PNG to be injected is %d, it must be %d!\n", new.width, imageHeaders[injectionNumber].width);
    			fclose(pngFile);
    			fclose(modifiedLogoBin);
    			fclose(originalLogoBin);
    
    			return 0;
    
    		}
    
    		if (((new.height = GetHeight(pngFile)) != imageHeaders[injectionNumber].height) && (!badAss)){
    
    			fprintf(stderr, "Error: Height of PNG to be injected is %d, it must be %d!\n", new.height, imageHeaders[injectionNumber].height);
    			fclose(pngFile);
    			fclose(modifiedLogoBin);
    			fclose(originalLogoBin);
    
    			return 0;
    
    		}
    
    		uint32_t rawBytes = new.width * new.height * BYTESPERPIXEL;
    		uint8_t *decodedPNG = malloc(rawBytes);
    
    		lodepng_decode24_file(&decodedPNG, (uint32_t*)&new.width, (uint32_t*)&new.height , (const uint8_t*)inFileName);
    
    		if (rgb2bgr == 1){
    
    			uint8_t old;
    			uint32_t k = 0;
    
    			while( k < rawBytes ){
    
    				old = decodedPNG[k];
    				memset(&decodedPNG[k], decodedPNG[k + 2], 1);
    				memset(&decodedPNG[k + 2], old, 1);
    				k += BYTESPERPIXEL;
    
    			}
    		}
    
    		encodedSize = GetEncodedSize(decodedPNG, (new.width * new.height * BYTESPERPIXEL));
    		new.lengthOfData = encodedSize;
    		uint8_t *rlEncoded = malloc(BlockIt(encodedSize));
    		memset(rlEncoded, 0, BlockIt(encodedSize));
    		actualWritten = Encode(decodedPNG, rlEncoded, (new.width * new.height * BYTESPERPIXEL));
    		blockDifference = (((BLOCK + BlockIt(actualWritten)) - (BLOCK + BlockIt(imageHeaders[injectionNumber].lengthOfData))) / BLOCK);
    		fwrite(&new, 1 , BLOCK, modifiedLogoBin);
    		fwrite(rlEncoded, 1 , BlockIt(actualWritten), modifiedLogoBin);
    		free(decodedPNG);
    		free(rlEncoded);
    
    		RewriteHeaderZero( injectionNumber , numberOfOffsets , modifiedLogoBin , blockDifference, ihMainOffsets);
    
    		fclose(pngFile);
    
    		return 1;
    }
    
    int32_t RewriteHeaderZero( uint32_t injectionImageNumber , uint16_t numberOfOffsets, FILE *modifiedLogoBin , int32_t blockDifference, uint32_t *ihMainOffsets){
    
    	uint8_t i, j = injectionImageNumber + 1 ;
    	uint32_t filePosition = ftell(modifiedLogoBin);
    	uint32_t offset = 0;
    
    	for( ; j < numberOfOffsets; j++){
    
    		fseek(modifiedLogoBin, OFFSETSTART + (SIZEOFLONGINT * j), SEEK_SET);
    		offset = ihMainOffsets[j];
    		offset += (blockDifference * BLOCK);
    		fseek(modifiedLogoBin, OFFSETSTART + (SIZEOFLONGINT * j), SEEK_SET);
    		fwrite(&offset, 1 , SIZEOFLONGINT , modifiedLogoBin);
    		ihMainOffsets[j] = offset;
    
    	}
    
    	fseek(modifiedLogoBin, filePosition , SEEK_SET);
    	
    return;
    }
    
    uint32_t GetEncodedSize(uint8_t* data, uint32_t size){
    
    	uint32_t pos = 0, ret = 0;
    	uint16_t count = 1;
    
    	for( pos = 0 ; pos < size ; ++pos , count = 1){
    
    		while((pos < size - 1) && (count < 0xFF) && ((memcmp(&data[pos], &data[pos+1], 1)) == 0)){
    
    			count++;
    			pos++;
    
    		}
    
    		ret += 2;
    
    	}
    
    	return ret;
    }
    
    uint32_t Encode(uint8_t* rawRgbReading, uint8_t* rlEncoded, uint32_t rawSize){
    
    	uint32_t writePosition = 0 , readPosition = 0;
    	uint16_t count = 1;
    
    	for( readPosition = 0 ; readPosition < rawSize ; ++readPosition , count = 1){
    
    		while((readPosition < rawSize - 1 ) && (count < 0xFF) && ((memcmp(&rawRgbReading[readPosition], &rawRgbReading[readPosition+1], 1)) == 0)){
    
    			count++;
    			readPosition++;
    
    		}
    
    		rlEncoded[writePosition] = rawRgbReading[readPosition];
    		rlEncoded[writePosition + 1] = count;
    		writePosition += 2;
    
    	}
    
    	return writePosition;
    }
    
    uint32_t GetWidth(FILE *pngFile){
    
    	uint32_t width;
    
    	fseek(pngFile, 16, SEEK_SET);
    	fread(&width, 1, SIZEOFLONGINT, pngFile);
    
    	return(SWAP32(width));
    
    }
    
    uint32_t GetHeight(FILE *pngFile){
    
    	uint32_t height;
    
    	fseek(pngFile, 20, SEEK_SET);
    	fread(&height, 1, SIZEOFLONGINT, pngFile);
    
    	return(SWAP32(height));
    }
    
    uint64_t BlockIt(uint32_t isize){
    
    	uint32_t blockSize = BLOCK;
    
    	if ((isize % blockSize) == 0){
    
    		return isize;
    
    	}else{
    
    		return isize + (blockSize - (isize % blockSize));
    
    	}
    }
    
    void Usage(){
    
    	fprintf(stdout, "Usage: logoinjector -i \"input file\" [-l] | [-L] | [-d [-s]] | [-j \"image to be replaced\" [-b] | [-s]]\n\n");
    	fprintf(stdout, "Mandatory Arguments:\n\n");
    	fprintf(stdout, "\t-i \"C:\\xda\\logo.bin\"\n");
    	fprintf(stdout, "\t   This is the logo.bin file to analyze or inject an image\n\n");
    	fprintf(stdout, "Optional Arguments:\n\n");
    	fprintf(stdout, "\t-d Decode all images into PNGs, (-s)wap parameter may be needed for proper color.\n");
    	fprintf(stdout, "\t-l Lower case 'L' is to display a short list of what is inside the input file.\n");
    	fprintf(stdout, "\t-L Upper case 'L' is for a more detailed list of logo.bin image contents.\n");
    	fprintf(stdout, "\t-b 'b' is used to tell the program to disregard width or height differences\n");
    	fprintf(stdout, "\t   when encoding an image, the program also won't fail if it can't find a name\n");
    	fprintf(stdout, "\t   that can't be found on the inject list when encoding images\n");
    	fprintf(stdout, "\t-s 's' is used to swap RGB and BGR color order. Can be used on decoding or encoding.\n");
    	fprintf(stdout, "\t   NEW IN THIS V1.2: Swap is on by default, meaning the color order will be BGR. Using\n");
    	fprintf(stdout, "\t   the \"-s\" switch will result in a RGB color order. Bottom line: If you (-d)ecode the\n");
    	fprintf(stdout, "\t   images (that have color) and the colors aren't right, then you should use (-s) to \n");
    	fprintf(stdout, "\t   decode and inject images.\n");
    	fprintf(stdout, "\t-j \"image(s) to be replaced\"\n");
    	fprintf(stdout, "\t   The image(s) name to be replaced as seen in the (-l)ist\n");
    	fprintf(stdout, "\t   NEW IN THIS V1.2: Multiple image names may be put after \"-j\"\n");
    	fprintf(stdout, "\t   The names simply need to be separated by a space. The names now also are not case\n");
    	fprintf(stdout, "\t   sensitive, and it doesn't matter if you put the extension at the end of the name.\n");
    	fprintf(stdout, "\t   You actually only need to put the first characters of the name.\nExample:\n");
    	fprintf(stdout, "\t   logoinjector -i \"your_logo.bin\" -j FHD \n\n");
    	fprintf(stdout, "\t   This will inject a PNG for every name in the logo bin that begins with \"fhd\"\n");
    
    	return;
    }
    
    void PrintFileSize(uint32_t bytes){
    
    	float megaBytes = 0, kiloBytes = 0;
    	kiloBytes = (float)bytes / (float)TWOTOTHETEN;
    	megaBytes = kiloBytes / (float)TWOTOTHETEN;
    	
    	if (kiloBytes < (float)TWOTOTHETEN){
    
    		fprintf(stdout, "\t%.2f KB\n", kiloBytes);
    
    	} else {
    
    		fprintf(stdout, "\t%.2f MB\n", megaBytes);
    
    	}
    
    return;
    }
    
    uint32_t GetFileSize(FILE *temp){
    
    	fseek(temp, 0 , SEEK_END);
    	uint32_t fileSizeZ = ftell(temp);
    
    return(fileSizeZ);
    }
    
    int32_t main(int32_t argc, int8_t **argv){
    
    	int32_t c;
    	int16_t h, i , j , k = 0;
    	FILE *originalLogoBin = NULL, *modifiedLogoBin = NULL;
    	uint8_t *inputFile = NULL;
    	uint8_t *injectNames[MAXOFFSETS];
    	int16_t decodeAllOpt = 0;
    	int16_t encodeOpt = 0;
    	int16_t inject = 0;
    	int16_t listFile = 0;
    	uint16_t numberOfOffsets = 0, injected = 0;
    
    	for(i = 0; i < MAXOFFSETS; i++){
    
    		injectNames[i] = NULL;
    
    	}
    
    	fprintf(stdout, "__________________________________________________________-_-\n");
    	fprintf(stdout, "Logo Injector v1.2\n\nWritten By Makers_Mark @ XDA-DEVELOPERS.COM\n");
    	fprintf(stdout, "_____________________________________________________________\n\n");
    
    	while ((c = getopt (argc, (char**)argv, "sSj:J:hHbBdDlLi:I:")) != -1){
    
    		switch(c)
    		{
    			case 'l':
    
    				listFile = 1;
    				break;
    
    			case 'L':
    
    				decodeAllOpt = 1;
    				convertToPNG = 0;
    				break;
    
    			case 'i':
    			case 'I':
    
    				inputFile = optarg;
    				break;
    
    			case 'b':
    			case 'B':
    
    				badAss = 1;
    				break;
    
    			case 'j':
    			case 'J':
    
    				h = optind - 1 ;
    				uint8_t *nextArg;
    
    				while(h < argc){
    
    					inject = 1;
    					nextArg = strdup(argv[h]);
    					h++;
    
    					if(nextArg[0] != '-'){
    
    						injectNames[k++] = nextArg;
    
    					} else {
    
    						break;
    
    					}
    				}
    				optind = h - 1;
    				break;
    
    			case 'd':
    			case 'D':
    
    				decodeAllOpt = 1 ;
    				break;
    
    			case 's':
    			case 'S':
    
    				rgb2bgr = -1 ;
    				break;
    
    			case 'h':
    			case 'H':
    
    				Usage();
    				return 0;
    				break;
    
    			default:
    				Usage();
    				return 0;
    				break;
    
    		}
    	}
    
    	if (inputFile == NULL){
    
    		Usage();
    		return 0;
    
    	}
    
    	fprintf(stdout, "FILE: %s\n_____________________________________________________________\n\n", inputFile);
    
    	if (rgb2bgr == 1){
    
    		fprintf(stdout, "BGR is the color order. Use \"-s\" switch to change it to RGB.\n\n");
    
    	} else {
    
    		fprintf(stdout, "RGB is the color order. Use \"-s\" switch to change it to BGR.\n\n");
    
    	}
    
    	if ((originalLogoBin = fopen(inputFile, "rb")) == NULL){
    
    		fprintf(stderr, "%s could not be opened\n", inputFile);
    		return 0;
    
    	}
    
    	if (!IsItALogo(originalLogoBin)){
    
    		fprintf(stdout, "\nThis is NOT a valid Logo.bin\n\n");
    		fclose(originalLogoBin);
    		return 0;
    
    	}
    
    	if (!IsItTheNewStyle(originalLogoBin)){
    
    		fprintf(stdout, "\nThis is the old style logo.bin\n\n");
    		fclose(originalLogoBin);
    		return 0;
    
    	}
    
    	numberOfOffsets = GetNumberOfOffsets(originalLogoBin);
    	IMAGEHEAD *imageHeaders = ParseHeaders(originalLogoBin, numberOfOffsets);
    
    	if (listFile){
    
    		ListFileDetails(originalLogoBin, imageHeaders);
    		return 1;
    
    	}
    
    	if(inject){
    
    		uint32_t ihMainOffsets[MAXOFFSETS];
    		uint8_t found = 0, exitFlag = 0;
    
    		for (i = 0; i < MAXOFFSETS ; i++){
    
    			ihMainOffsets[i] = 0;
    
    		}
    
    		for (j = 0; j < k ; j++){
    
    			for (i = 0 ;  i < numberOfOffsets ; i++ ){
    
    				if((strcasecmp(imageHeaders[i].name, injectNames[j]) == 0) ||
    				   (strncasecmp(imageHeaders[i].name, injectNames[j], strlen(injectNames[j])) == 0)){
    
    					found = 1;
    					break;
    
    				} else {
    
    					found = 0;
    
    				}
    			}
    
    			if (!found){
    
    				fprintf(stdout, "ERROR: \"%s\" is not in the logo bin !!!!\n", injectNames[j]);
    				exitFlag = 1;
    			}
    		}
    
    		if ((exitFlag) && (!badAss)){
    
    			fclose(originalLogoBin);
    			exit(0);
    
    		}
    
    		memcpy(&ihMainOffsets , &imageHeaders[0].offsets, SIZEOFLONGINT * MAXOFFSETS);
    		fseek(originalLogoBin, 0, SEEK_SET);
    
    		if ((modifiedLogoBin = fopen("modified.logo.bin", "wb+")) == NULL){
    
    			fclose(modifiedLogoBin);
    			fclose(originalLogoBin);
    			fprintf(stderr, "modified.logo.bin could not be opened\n");
    			return 0;
    
    		}
    
    		for (i = 0 ; i < numberOfOffsets ; i++ , injected = 0 ){
    
    			for (j = 0; j < k ; j++){
    
    				if((strcasecmp(imageHeaders[i].name, injectNames[j]) == 0) ||
    				    (strncasecmp(imageHeaders[i].name, injectNames[j], strlen(injectNames[j])) == 0)){
    
    					if (InjectNewStyle(originalLogoBin, imageHeaders , numberOfOffsets, imageHeaders[i].name, i, modifiedLogoBin, ihMainOffsets) == 0){
    
    						fprintf(stderr, "Error: Injecting %s\n", imageHeaders[i].name);
    						fclose(originalLogoBin);
    						fclose(modifiedLogoBin);
    						return 0;
    
    					}
    
    					if ( i != numberOfOffsets - 1 ){
    
    						fseek(originalLogoBin, imageHeaders[0].offsets[i+1], SEEK_SET);
    
    					}
    
    					injected = 1;
    					break;
    				}
    			}
    
    			if (!injected){
    
    				Copy(originalLogoBin , imageHeaders, numberOfOffsets, i, modifiedLogoBin);
    
    			}
    		}
    
    		uint16_t modifiedNumberOfOffsets = 0;
    
    		if (GetNumberOfOffsets(modifiedLogoBin) != numberOfOffsets){
    
    			fprintf(stderr, "ERROR: The number of offsets doesn't match the Original file!!\n");
    			fclose(modifiedLogoBin);
    
    			if (!badAss){
    				
    				unlink("modified.logo.bin");
    
    			}
    			
    			exit(0);
    
    		}
    		fprintf(stdout, "\n\nContents of the NEW \"modified.logo.bin\":\n");
    		fprintf(stdout, "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n\n");
    		
    		ListFileDetails(modifiedLogoBin, imageHeaders);
    		fprintf(stdout, "\n\n_____________________________________________________________\nOriginal filesize: ");
    		PrintFileSize(GetFileSize(originalLogoBin));
    		fprintf(stdout, "Modified filesize: ");
    		PrintFileSize(GetFileSize(modifiedLogoBin));
    		fprintf(stdout, "-------------------------------------------------------------\n");
    		fclose(originalLogoBin);
    		fclose(modifiedLogoBin);
    
    		return 1;
    	}		
    
    	if (decodeAllOpt){
    
    		DecodeLogoBin(originalLogoBin, imageHeaders);
    		fclose(originalLogoBin);
    
    		return 1;
    	}
    
    	fclose(originalLogoBin);
    	return 1;
    	
    }
    3
    Hey, I used this successfully with the OP2 logo.bin but have tried with the OP3 LOGO.bin and although I can extract the images and inject them back in once edited (I only edited the splash screen, fhd_oppo_1080_1920_result.raw), when I tested by trying to extract the images from the modified logo.bin, the injector crashed and only one image was extracted, the one I edited. So I wouldn't like to try this modified logo.bin! Didn't have this issue with the modified OP2 logo.bin.

    Attached is the OP3 logo.bin

    They have made the blocksize 4096 on the OP3 instead of 512 (also a larger partition for the bin). It, of course, is still the same encoding method. I can change it for this, but it won't be for a couple of days from now. If you just want a splash to pack with a rom right now, pm me the image and i'll make it.
    3
    Thanks for this program. Glad that it's back from someone for CM12 as we waited for quite some time now. I have a query though about repacking.

    logoinjector.exe -i logo.bin -j (image name you want to replace)

    Is it possible to put different file names at the same time if I want to replace two or three files at the same time like this

    logoinjector.exe -i logo.bin -j 4-fastboot.png 5-lowpower.png

    because it doesn't work for me, I will have to run this command for the number of times I have files to replaced?
    2
    Terrific, this works. Thank you a lot!