[GUIDE] How to Create Custom Splash Screen (Boot Logo) for Mi 5/5s & Mi Max/Mix

Search This thread

GokulNC

Senior Member
Jan 10, 2015
826
1,440
Chennai
github.com
Does this work for non rooted phones but unlocked (so basically fastboot flashing).?
Yes :)
Code:
fastboot flash splash splash.img


Is it possible to flash recovery also via terminal same as splash logo?
Yes :)
Code:
fastboot flash recovery twrp.img


Can I reprint your post to MIUI BBS(CN) ? I think your GUIDE is very useful .
Yes :) Feel free to do anything, but please do put a link back to this thread..


You can create custom splash in fastboot to with this method...
Tested with libra (mi4c)
It should works in mi5 too...
http://xdaforums.com/oneplus-one/themes-apps/mod-customize-ones-bootlogo-t2857153/page16
Use this for Mi 4c: Mi 4c bootlogo and fastboot changing


Working on mi note 2.
Thanks, will add it to the devices list soon.
BTW, it will be more helpful if you send the stock splash.img of Mi Note 2.. (There might be certain variations that you might not have noticed, that may cause problems with other pictures like fastboot/recovery)


Please may you share the required files on Android 7 to flash the splash.img as the current way not letting a new splash.img to be change..
this method doesn't work anymore with new N firmwares right? can't get rid of the mi logo with red unlocked BL sign anymore with fastboot flash splash method :(
I use Mi Max Hydrogen 2/16, and is'nt working on latest MIUI 8 dev ( android 7.0 ). I just got blank screen.
do you need my splash.img to fix this?
if yes, just tell me :)

I don't know what's the problem with Android N firmwares..
Anyway, send the the original stock splash.img from Android N firmware, I'll check it out :)
 
Last edited:

GokulNC

Senior Member
Jan 10, 2015
826
1,440
Chennai
github.com

I checked the splash.img ..
It's completely the same as that of other Android versions..

I guess there are 2 possibilities:

a. Try picture with low very resolution (like the stock logo which has resolution 161x321)
b. Maybe the bootloader verifies the checksum of the splash partition before booting up; so only if it matches, it may display the image. If this is the case, I can't do anything about that..
 
Last edited:

pykfree

Senior Member
Mar 13, 2012
282
234
Payakumbuh, Indonesia
I checked the splash.img ..
It's completely the same as that of other Android versions..

I guess there are 2 possibilities:

a. Try picture with low very resolution (like the stock logo which has resolution 161x321)
b. Maybe the bootloader verifies the checksum of the splash partition before booting up; so only if it matches, it may display the image. If this is the case, I can't do anything about that..

I'll check it later. thank you for your help :)
 

SubwayChamp

Senior Member
Aug 6, 2016
5,151
5
1,856
@GokuINC Thx for your answer, I expressed my question incomplete, I meant if is it possible flash recovery via a terminal app in same device.
 

Chema_F

Senior Member
Jan 23, 2012
640
698
Zaragoza
I guess you're already aware of this but I'd love being able to change the logo so..

I tried to make some changes in dev/block/bootdevice/by-name with ES Explorer (rooted) adding files, renaming... And once rebooted any change had been done, everything was exactly like before.

I'm wondering if the problem when flashing the splash.img with fastboot command could be related to this.

Please excuse if this is a big nonsense.
 

Cynob

Member
Nov 20, 2016
19
13
Hello
@Hoschi@ has asked me if i could take a look at it how to change the bootlogo in new versions. I dont own that phone so its a little limited what i could test and do but here is what i found out:

I think the splash.img dont get read at start and the Mi Logo is in logo.img file
Why that? If you overwrite the logo.img on the phone with garbage data the hardcoded linux penguin got shown instead of the mi logo.

Ok what i have tested:
build a kernel:
for gemini there are two "options" in the kernel ( maybe there are more but i didnt find something other useful till now)
one is for the hardcoded linux penguin in /drivers/video/logo/
the other is in /drivers/video/msm/mdss and called mdss_mdp_splash_logo

Ok now i editet the /drivers/video/msm/mdss/splash.h and wrote my own image with same size and 8bit ( used rgb instead bgr - should work >read mdss_mdp_formats.h) in the "splash_bgr888_image" char array.
result: standard mi logo is shown anymore at boot. No changes ....

Now i dissected the splash.img :

There we have a header with 512 byte:
There is the "SPLASH!!" header followed of the size of the picture in INT32 format
Code:
#	Raw	                UINT32
0	41 4C 50 53	1095520339          //"SPLASH!! 
4	21 21 48 53	555829331            //"SPLASH!!
8	00 00 00 A1	161                  // width
12	00 00 01 41	321                 // heigh

After the first 512 bytes the image starts.
you can calculate: heigh * with * bpp to get the filesize of the picture:
161x321x3 = 155043 byte
Now you can skip the first 512 bytes of the splash.img and extract the next 155043 bytes to a file.
There is the Mi picture ( without header but you could open it with avconv or ffmpeg)

Ok now if i do the same with logo.img i see the "SPLASH!!" header and something that looks like resolutions but in the wrong order:
Code:
#	Raw	                UINT32
0	41 4C 50 53	1095520339
4	21 21 48 53	555829331
8	00 00 00 A1	161
12	00 00 02 2E	558
16	00 00 00 B2	178
20	00 00 04 38	1080
24	00 00 04 38	1080
28	00 00 01 41	321
32	00 00 03 E0	992
36	00 00 01 5E	350
40	00 00 07 80	1920
44	00 00 07 80	1920

It looks like i have 5 files in it. First all widths get listet and then all heights.
I tried to extract a single picture like above with splash.img but i didnt get a working file till now.
I have found out that for Mi3 there is a tool which should open the logo.img file to edit whats in it - but it didnt worked for me.

I hope somebody here know what to do to get the pictures out of the logo.img and can help me or give me a hint how to solve this puzzle?
kind regarts Cynob
 
Last edited:
  • Like
Reactions: Burs

GokulNC

Senior Member
Jan 10, 2015
826
1,440
Chennai
github.com
@GokuINC Thx for your answer, I expressed my question incomplete, I meant if is it possible flash recovery via a terminal app in same device.

Yeah, use Flashify app from Play Store to do that easily..

I guess you're already aware of this but I'd love being able to change the logo so..

I tried to make some changes in dev/block/bootdevice/by-name with ES Explorer (rooted) adding files, renaming... And once rebooted any change had been done, everything was exactly like before.

I'm wondering if the problem when flashing the splash.img with fastboot command could be related to this.

Please excuse if this is a big nonsense.

You cannot just rename those files ;)
And that is totally irrelevant to what's going on here :)

Hello
@Hoschi@ has asked me if i could take a look at it how to change the bootlogo in new versions. I dont own that phone so its a little limited what i could test and do but here is what i found out:


I think the splash.img dont get read at start and the Mi Logo is in logo.img file
Why that? If you overwrite the logo.img on the phone with garbage data the hardcoded linux penguin got shown instead of the mi logo.

Ok what i have tested:
build a kernel:
for gemini there are two "options" in the kernel ( maybe there are more but i didnt find something other useful till now)
one is for the hardcoded linux penguin in /drivers/video/logo/
the other is in /drivers/video/msm/mdss and called mdss_mdp_splash_logo

Ok now i editet the /drivers/video/msm/mdss/splash.h and wrote my own image with same size and 8bit ( used rgb instead bgr - should work >read mdss_mdp_formats.h) in the "splash_bgr888_image" char array.
result: standard mi logo is shown anymore at boot. No changes ....

Now i dissected the splash.img :

There we have a header with 512 byte:
There is the "SPLASH!!" header followed of the size of the picture in INT32 format
Code:
#	Raw	                UINT32
0	41 4C 50 53	1095520339          //"SPLASH!! 
4	21 21 48 53	555829331            //"SPLASH!!
8	00 00 00 A1	161                  // width
12	00 00 01 41	321                 // heigh

After the first 512 bytes the image starts.
you can calculate: heigh * with * bpp to get the filesize of the picture:
161x321x3 = 155043 byte
Now you can skip the first 512 bytes of the splash.img and extract the next 155043 bytes to a file.
There is the Mi picture ( without header but you could open it with avconv or ffmpeg)

Ok now if i do the same with logo.img i see the "SPLASH!!" header and something that looks like resolutions but in the wrong order:
Code:
#	Raw	                UINT32
0	41 4C 50 53	1095520339
4	21 21 48 53	555829331
8	00 00 00 A1	161
12	00 00 02 2E	558
16	00 00 00 B2	178
20	00 00 04 38	1080
24	00 00 04 38	1080
28	00 00 01 41	321
32	00 00 03 E0	992
36	00 00 01 5E	350
40	00 00 07 80	1920
44	00 00 07 80	1920

It looks like i have 5 files in it. First all widths get listet and then all heights.
I tried to extract a single picture like above with splash.img but i didnt get a working file till now.
I have found out that for Mi3 there is a tool which should open the logo.img file to edit whats in it - but it didnt worked for me.

I hope somebody here know what to do to get the pictures out of the logo.img and can help me or give me a hint how to solve this puzzle?
kind regarts Cynob

While I was creating this tutorial, I had downloaded the stock firmware of Mi 5...
At that time, what I saw was, splash.img had bootlogo and logo.img had fastboot picture..

Seems things have changed now..
Attach the new logo.img, I'll check it out :)

And BTW, yeah, if bootloader fails to load splash, it loads the default tux logo from kernel..
But changing that is not the right solution, since not everyone can compile a kernel each time just to change splash.. (Just saying, I'm not saying you're recommending that ;) )
 

Cynob

Member
Nov 20, 2016
19
13
Thank you for looking at it! I am curious...
I have told @Hoschi@ that he will upload the file soon. My account have to less posts for uploading or showing a link to the file.
 

GokulNC

Senior Member
Jan 10, 2015
826
1,440
Chennai
github.com
Thanks bro, I just checked it out...
I don't think it's of a general format (as in CAF)
It seems Xiaomi has done a few modifications to it..
The original script supports only 1 picture, but now, it seems it can contain as many pics as you want, thanks to Xiaomi's modifications with new Upgrade to Nougat (ofcourse the code seems to be proprietary)...

Thank you for looking at it! I am curious...
I have told @Hoschi@ that he will upload the file soon. My account have to less posts for uploading or showing a link to the file.

This is the format of your logo.img:
(The first 4KiB is the header)
Code:
SPLASH!!
Width (of 5 pictures)
Height (of 5 pictures)
SUPPORT_RLE24_COMPRESSIONT (of 5 pictures) (1 means it is RLE encoded, 0 means RGB24)
Payload size/4096 (of 5 pictures)
(Offset/4096)-1 (of 5 pictures)

In the logo_gen.py script from the tool, check the encodeRLE24() function..
It shows how the picture is encoded as a payload (RGB pixels -> countRGB)..

Here, if the payload_size is not divisible by 4096, zeros are padded till it is divisible by 4096..
(Why 4096 (4KiB) ? Maybe that's the cluster/block size of the eMMC flash)

I have my exams nearing, so I won't be able to create a tool as of now...
You may try modifying the current logo_gen.py to fit this new format..

BTW, that script has no function to decode the pictures.. (Because it's done by the bootloader only.. Here's the generic code just for reference, no use here)

You may try to write code to decode it if you want..
Or directly code it to create for 5 pictures... (but you may need to find which picture is what, for example, picture 1 is bootlogo, pic5 might be fastboot, etc.)

Or if you're ready to experiment and play, set SUPPORT_RLE24_COMPRESSIONT=0 and see if your bootloader supports RGB24 format.. (But this increases logo.img size)

Hope you understand what I'm blabbering ;)
Feel free to ask if you have any doubts :)
 
Last edited:
  • Like
Reactions: Cynob

Cynob

Member
Nov 20, 2016
19
13
Hey really thanks for your help. I understand :) and will try my luck.
But how did you determined its RLE compressed? I really want to know how you got this info :).

Edith say: ok my fault ... kernel config :D
 
Last edited:

Cynob

Member
Nov 20, 2016
19
13
Ok i have to admit that i never had written something in python before.
And the bitshifting confuse me :silly:
So i know what i want to do but dont know how to write/solve it really :eek:

Ok so this is my first attempt. I dont know if it works and have a few questions:

In the GetPNGFile def - can i use the identifiers for the 5 pictures in this context? could it work?

And to add the 0xFF at the end of the rle till its divisible with 4096:
the encodeRLE24 count the pixels with the same color if i'm right? At the end of the process i put following:

while (len(content) % 4096 != 0):
output.write(struct.pack("B", 0xFF))

I asume :silly: that with this codesnippet put 0xFFs at the end of the file till we have a integer as filesize.

So if anyone find errors i made or if i go complete wrong with my code edit please tell me :confused:

:fingers-crossed:
Code:
#Downloaded from: https://source.codeaurora.org/quic/la/device/qcom/common/tree/display/logo?h=LA.BR.1.2.7_rb1.1

# Copyright (c) 2013,2015, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#     * Neither the name of The Linux Foundation nor the names of its
#       contributors may be used to endorse or promote products derived
#       from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#===========================================================================

#  This script read the logo png and creates the logo.img

# when          who     what, where, why
# --------      ---     -------------------------------------------------------
# 2013-04       QRD     init
# 2015-04       QRD     support the RLE24 compression

# Environment requirement:
#     Python + PIL
#     PIL install:
#         (ubuntu)  sudo apt-get install python-imaging
#         (windows) (http://www.pythonware.com/products/pil/)

# limit:
#    a. This script only support Python 2.7.x, 2.6.x,
#      Can't use in py3x for StringIO module
#    b. This script's input can be a png, jpeg, bmp, gif file.
#    But if it is a gif, only get the first frame by default.
#
# description:
#    struct logo_header {
#       unsigned char[8]; // "SPLASH!!"
#       unsigned width;   // logo's width, little endian
#       unsigned height;  // logo's height, little endian
#       unsigned type;    // 0, Raw Image; 1, RLE24 Compressed Image
#       unsigned blocks;  // block number, real size / 512
#       ......
#    };

#    the logo Image layout:
#       logo_header + Payload data

# ===========================================================================*/
from __future__ import print_function
import sys,os
import struct
import StringIO
from PIL import Image

SUPPORT_RLE24_COMPRESSIONT = 1

## get header
def GetImgHeader(size1, size2, size3, size4, size5, compressed, real_bytes1, real_bytes2, real_bytes3, real_bytes4, real_bytes5):
    SECTOR_SIZE_IN_BYTES = 4096   # Header size
    header = [0 for i in range(SECTOR_SIZE_IN_BYTES)]

    width1, height1 = size1
    width2, height2 = size2
    width3, height3 = size3
    width4, height4 = size4
    width5, height5 = size5
    real_size1 = (real_bytes1  + 4095) / 4096
    real_size2 = (real_bytes2  + real_size1) / 4096
    real_size3 = (real_bytes3  + real_size2) / 4096
    real_size4 = (real_bytes4  + real_size3) / 4096
    real_size5 = (real_bytes5  + real_size4) / 4096
    
    # magic
    header[:8] = [ord('S'),ord('P'), ord('L'), ord('A'),
                   ord('S'),ord('H'), ord('!'), ord('!')]

    # width1
    header[8] = ( width        & 0xFF)
    header[9] = ((width >> 8 ) & 0xFF)
    header[10]= ((width >> 16) & 0xFF)
    header[11]= ((width >> 24) & 0xFF)
    # height1
    header[12]= ( height        & 0xFF)
    header[13]= ((height >>  8) & 0xFF)
    header[14]= ((height >> 16) & 0xFF)
    header[15]= ((height >> 24) & 0xFF)
    
    # width2
    header[16]= ( width        & 0xFF)
    header[17]= ((width >> 8 ) & 0xFF)
    header[18]= ((width >> 16) & 0xFF)
    header[19]= ((width >> 24) & 0xFF)
    # height2
    header[20]= ( height        & 0xFF)
    header[21]= ((height >>  8) & 0xFF)
    header[22]= ((height >> 16) & 0xFF)
    header[23]= ((height >> 24) & 0xFF)

    # width3
    header[24]= ( width        & 0xFF)
    header[25]= ((width >> 8 ) & 0xFF)
    header[26]= ((width >> 16) & 0xFF)
    header[27]= ((width >> 24) & 0xFF)
    # height3
    header[28]= ( height        & 0xFF)
    header[29]= ((height >>  8) & 0xFF)
    header[30]= ((height >> 16) & 0xFF)
    header[31]= ((height >> 24) & 0xFF)
 
    # width4
    header[32]= ( width        & 0xFF)
    header[33]= ((width >> 8 ) & 0xFF)
    header[34]= ((width >> 16) & 0xFF)
    header[35]= ((width >> 24) & 0xFF)
    # height4
    header[36]= ( height        & 0xFF)
    header[37]= ((height >>  8) & 0xFF)
    header[38]= ((height >> 16) & 0xFF)
    header[39]= ((height >> 24) & 0xFF)
 
    # width5
    header[40]= ( width        & 0xFF)
    header[41]= ((width >> 8 ) & 0xFF)
    header[42]= ((width >> 16) & 0xFF)
    header[43]= ((width >> 24) & 0xFF)
    # height5
    header[44]= ( height        & 0xFF)
    header[45]= ((height >>  8) & 0xFF)
    header[46]= ((height >> 16) & 0xFF)
    header[47]= ((height >> 24) & 0xFF)

    #type
    header[48]= ( compressed    & 0xFF)
    header[49]= ( compressed    & 0xFF)
    header[50]= ( compressed    & 0xFF)
    header[51]= ( compressed    & 0xFF)
    header[52]= ( compressed    & 0xFF)

    # block number img 1
    header[53] = ( real_size1        & 0xFF)
    header[54] = ((real_size1 >>  8) & 0xFF)
    header[55] = ((real_size1 >> 16) & 0xFF)
    header[56] = ((real_size1 >> 24) & 0xFF)

    # block number img 2
    header[57] = ( real_size2        & 0xFF)
    header[58] = ((real_size2 >>  8) & 0xFF)
    header[59] = ((real_size2 >> 16) & 0xFF)
    header[60] = ((real_size2 >> 24) & 0xFF)
    
    # block number img 3
    header[61] = ( real_size3        & 0xFF)
    header[62] = ((real_size3 >>  8) & 0xFF)
    header[63] = ((real_size3 >> 16) & 0xFF)
    header[64] = ((real_size3 >> 24) & 0xFF)
    
    # block number img 4
    header[65] = ( real_size4        & 0xFF)
    header[66] = ((real_size4 >>  8) & 0xFF)
    header[67] = ((real_size4 >> 16) & 0xFF)
    header[68] = ((real_size4 >> 24) & 0xFF)
    
    # block number img 5
    header[69] = ( real_size5        & 0xFF)
    header[70] = ((real_size5 >>  8) & 0xFF)
    header[71] = ((real_size5 >> 16) & 0xFF)
    header[72] = ((real_size5 >> 24) & 0xFF)
    output = StringIO.StringIO()
    for i in header:
        output.write(struct.pack("B", i))
    content = output.getvalue()
    output.close()
    return content

def encode(line):
    count = 0
    lst = []
    repeat = -1
    run = []
    total = len(line) - 1
    for index, current in enumerate(line[:-1]):
        if current != line[index + 1]:
            run.append(current)
            count += 1
            if repeat == 1:
                entry = (count+128,run)
                lst.append(entry)
                count = 0
                run = []
                repeat = -1
                if index == total - 1:
                    run = [line[index + 1]]
                    entry = (1,run)
                    lst.append(entry)
            else:
                repeat = 0

                if count == 128:
                    entry = (128,run)
                    lst.append(entry)
                    count = 0
                    run = []
                    repeat = -1
                if index == total - 1:
                    run.append(line[index + 1])
                    entry = (count+1,run)
                    lst.append(entry)
        else:
            if repeat == 0:
                entry = (count,run)
                lst.append(entry)
                count = 0
                run = []
                repeat = -1
                if index == total - 1:
                    run.append( line[index + 1])
                    run.append( line[index + 1])
                    entry = (2+128,run)
                    lst.append(entry)
                    break
            run.append(current)
            repeat = 1
            count += 1
            if count == 128:
                entry = (256,run)
                lst.append(entry)
                count = 0
                run = []
                repeat = -1
            if index == total - 1:
                if count == 0:
                    run = [line[index + 1]]
                    entry = (1,run)
                    lst.append(entry)
                else:
                    run.append(current)
                    entry = (count+1+128,run)
                    lst.append(entry)
    return lst

def encodeRLE24(img):
    width, height = img.size
    output = StringIO.StringIO()

    for h in range(height):
        line = []
        result=[]
        for w in range(width):
            (r, g, b) = img.getpixel((w,h))
            line.append((r << 16)+(g << 8) + b)
        result = encode(line)
        for count, pixel in result:
            output.write(struct.pack("B", count-1))
            if count > 128:
                output.write(struct.pack("B", (pixel[0]) & 0xFF))
                output.write(struct.pack("B", ((pixel[0]) >> 8) & 0xFF))
                output.write(struct.pack("B", ((pixel[0]) >> 16) & 0xFF))
            else:
                for item in pixel:
                    output.write(struct.pack("B", (item) & 0xFF))
                    output.write(struct.pack("B", (item >> 8) & 0xFF))
                    output.write(struct.pack("B", (item >> 16) & 0xFF))
    content = output.getvalue()
    while (len(content) % 4096 != 0):
		output.write(struct.pack("B", 0xFF))
    output.close() 
    return content


## get payload data : BGR Interleaved
def GetImageBody(img, compressed=1):
    color = (0, 0, 0)
    if img.mode == "RGB":
        background = img
    elif img.mode == "RGBA":
        background = Image.new("RGB", img.size, color)
        img.load()
        background.paste(img, mask=img.split()[3]) # alpha channel
    elif img.mode == "P" or img.mode == "L":
        background = Image.new("RGB", img.size, color)
        img.load()
        background.paste(img)
        #background.save("splash.png")
    else:
        print ("sorry, can't support this format")
        sys.exit()
    
    background.load()
    
    if compressed == 1:
        return encodeRLE24(background)
    else:
        r, g, b = background.split()
        return Image.merge("RGB",(b,g,r)).tostring()

## make a image

def MakeLogoImage(logo, out):
    img1 = Image.open(logo['infile1'])
    img2 = Image.open(logo['infile2'])
    img3 = Image.open(logo['infile3'])
    img4 = Image.open(logo['infile4'])
    img5 = Image.open(logo['infile5'])
    file = open(out, "wb")
    body1 = GetImageBody(img1, SUPPORT_RLE24_COMPRESSIONT)
    body2 = GetImageBody(img2, SUPPORT_RLE24_COMPRESSIONT)
    body3 = GetImageBody(img3, SUPPORT_RLE24_COMPRESSIONT)
    body4 = GetImageBody(img4, SUPPORT_RLE24_COMPRESSIONT)
    body5 = GetImageBody(img5, SUPPORT_RLE24_COMPRESSIONT)
    file.write(GetImgHeader(img1.size, img2.size, img3.size, img4.size, img5.size, SUPPORT_RLE24_COMPRESSIONT, len(body1), len(body2), len(body3), len(body4), len(body5)))
    file.write(body1)
    file.write(body2)
    file.write(body3)
    file.write(body4)
    file.write(body5)
    file.close()


## mian

def ShowUsage():
    print(" usage: python logo_gen.py [logo1.png] [logo2.png] [logo3.png] [logo4.png] [logo5.png]")

def GetPNGFile():
    infile1 = "logo1.png" #default file name
    infile2 = "logo2.png"
    infile3 = "logo3.png"
    infile4 = "logo4.png"
    infile5 = "logo5.png"
    num = len(sys.argv)
    if num > 7:
        ShowUsage()
        sys.exit(); # error arg

    if num == 6:
        infile1 = sys.argv[1]
        infile2 = sys.argv[2]
        infile3 = sys.argv[3]
        infile4 = sys.argv[4]
        infile5 = sys.argv[5]

    if os.access(infile, os.R_OK) != True:
        ShowUsage()
        sys.exit(); # error file
    return {'infile1':infile1, 'infile2':infile2, 'infile3':infile3, 'infile4':infile4, 'infile5':infile5 }

if __name__ == "__main__":
    MakeLogoImage(GetPNGFile(), "output/logo.img")


---------- Post added at 08:02 AM ---------- Previous post was at 07:12 AM ----------

Ok update:
Now i took 5 pictures and let my script run with it....
fixed some errors.... aaaand it produces a logo.img file.
I messed up the header a little.... now fixed
but i have the problem that the "real_size" ( the offset of the pictures) doesnt get count correct....:crying:

here is the new code:
Code:
#Downloaded from: https://source.codeaurora.org/quic/la/device/qcom/common/tree/display/logo?h=LA.BR.1.2.7_rb1.1

# Copyright (c) 2013,2015, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#     * Neither the name of The Linux Foundation nor the names of its
#       contributors may be used to endorse or promote products derived
#       from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#===========================================================================

#  This script read the logo png and creates the logo.img

# when          who     what, where, why
# --------      ---     -------------------------------------------------------
# 2013-04       QRD     init
# 2015-04       QRD     support the RLE24 compression

# Environment requirement:
#     Python + PIL
#     PIL install:
#         (ubuntu)  sudo apt-get install python-imaging
#         (windows) (http://www.pythonware.com/products/pil/)

# limit:
#    a. This script only support Python 2.7.x, 2.6.x,
#      Can't use in py3x for StringIO module
#    b. This script's input can be a png, jpeg, bmp, gif file.
#    But if it is a gif, only get the first frame by default.
#
# description:
#    struct logo_header {
#       unsigned char[8]; // "SPLASH!!"
#       unsigned width;   // logo's width, little endian
#       unsigned height;  // logo's height, little endian
#       unsigned type;    // 0, Raw Image; 1, RLE24 Compressed Image
#       unsigned blocks;  // block number, real size / 512
#       ......
#    };

#    the logo Image layout:
#       logo_header + Payload data

# ===========================================================================*/
from __future__ import print_function
import sys,os
import struct
import StringIO
from PIL import Image

SUPPORT_RLE24_COMPRESSIONT = 1

## get header
def GetImgHeader(size1, size2, size3, size4, size5, compressed, real_bytes1, real_bytes2, real_bytes3, real_bytes4, real_bytes5):
    SECTOR_SIZE_IN_BYTES = 4096   # Header size
    header = [0 for i in range(SECTOR_SIZE_IN_BYTES)]

    width1, height1 = size1
    width2, height2 = size2
    width3, height3 = size3
    width4, height4 = size4
    width5, height5 = size5
    real_size1 = (real_bytes1  + 4095) / 4096
    real_size2 = (real_bytes2  + real_size1) / 4096
    real_size3 = (real_bytes3  + real_size2) / 4096
    real_size4 = (real_bytes4  + real_size3) / 4096
    real_size5 = (real_bytes5  + real_size4) / 4096
    
    # magic
    header[:8] = [ord('S'),ord('P'), ord('L'), ord('A'),
                   ord('S'),ord('H'), ord('!'), ord('!')]

    # width1
    header[8] = ( width1        & 0xFF)
    header[9] = ((width1 >> 8 ) & 0xFF)
    header[10]= ((width1 >> 16) & 0xFF)
    header[11]= ((width1 >> 24) & 0xFF)
    # width2
    header[12]= ( width2        & 0xFF)
    header[13]= ((width2 >>  8) & 0xFF)
    header[14]= ((width2 >> 16) & 0xFF)
    header[15]= ((width2 >> 24) & 0xFF)   
    # width3
    header[16]= ( width3        & 0xFF)
    header[17]= ((width3 >> 8 ) & 0xFF)
    header[18]= ((width3 >> 16) & 0xFF)
    header[19]= ((width3 >> 24) & 0xFF)
    # width4
    header[20]= ( width4        & 0xFF)
    header[21]= ((width4 >>  8) & 0xFF)
    header[22]= ((width4 >> 16) & 0xFF)
    header[23]= ((width4 >> 24) & 0xFF)
    # width5
    header[24]= ( width5        & 0xFF)
    header[25]= ((width5 >> 8 ) & 0xFF)
    header[26]= ((width5 >> 16) & 0xFF)
    header[27]= ((width5 >> 24) & 0xFF)

    # height1
    header[28]= ( height1        & 0xFF)
    header[29]= ((height1 >>  8) & 0xFF)
    header[30]= ((height1 >> 16) & 0xFF)
    header[31]= ((height1 >> 24) & 0xFF)
    # height2
    header[32]= ( height2        & 0xFF)
    header[33]= ((height2 >> 8 ) & 0xFF)
    header[34]= ((height2 >> 16) & 0xFF)
    header[35]= ((height2 >> 24) & 0xFF)
    # height3
    header[36]= ( height3        & 0xFF)
    header[37]= ((height3 >>  8) & 0xFF)
    header[38]= ((height3 >> 16) & 0xFF)
    header[39]= ((height3 >> 24) & 0xFF)
    # height4
    header[40]= ( height4        & 0xFF)
    header[41]= ((height4 >> 8 ) & 0xFF)
    header[42]= ((height4 >> 16) & 0xFF)
    header[43]= ((height4 >> 24) & 0xFF)
    # height5
    header[44]= ( height5        & 0xFF)
    header[45]= ((height5 >>  8) & 0xFF)
    header[46]= ((height5 >> 16) & 0xFF)
    header[47]= ((height5 >> 24) & 0xFF)

    #type
    header[48]= ( compressed    & 0xFF)
    #header[49]= 0
    #header[50]= 0
    #header[51]= 0
    header[52]= ( compressed    & 0xFF)
    #header[53]= 0
    #header[54]= 0
    #header[55]= 0
    header[56]= ( compressed    & 0xFF)
    #header[57]= 0
    #header[58]= 0
    #header[59]= 0
    header[60]= ( compressed    & 0xFF)
    #header[61]= 0
    #header[62]= 0
    #header[63]= 0
    header[64]= ( compressed    & 0xFF)
    #header[65]= 0
    #header[66]= 0
    #header[67]= 0

    # block number img 1
    header[68] = ( real_size1        & 0xFF)
    header[69] = ((real_size1 >>  8) & 0xFF)
    header[70] = ((real_size1 >> 16) & 0xFF)
    header[71] = ((real_size1 >> 24) & 0xFF)

    # block number img 2
    header[72] = ( real_size2        & 0xFF)
    header[73] = ((real_size2 >>  8) & 0xFF)
    header[74] = ((real_size2 >> 16) & 0xFF)
    header[75] = ((real_size2 >> 24) & 0xFF)
    
    # block number img 3
    header[76] = ( real_size3        & 0xFF)
    header[77] = ((real_size3 >>  8) & 0xFF)
    header[78] = ((real_size3 >> 16) & 0xFF)
    header[79] = ((real_size3 >> 24) & 0xFF)
    
    # block number img 4
    header[80] = ( real_size4        & 0xFF)
    header[81] = ((real_size4 >>  8) & 0xFF)
    header[82] = ((real_size4 >> 16) & 0xFF)
    header[83] = ((real_size4 >> 24) & 0xFF)
    
    # block number img 5
    header[84] = ( real_size5        & 0xFF)
    header[85] = ((real_size5 >>  8) & 0xFF)
    header[86] = ((real_size5 >> 16) & 0xFF)
    header[87] = ((real_size5 >> 24) & 0xFF)
    output = StringIO.StringIO()
    for i in header:
        output.write(struct.pack("B", i))
    content = output.getvalue()
    output.close()
    return content

def encode(line):
    count = 0
    lst = []
    repeat = -1
    run = []
    total = len(line) - 1
    for index, current in enumerate(line[:-1]):
        if current != line[index + 1]:
            run.append(current)
            count += 1
            if repeat == 1:
                entry = (count+128,run)
                lst.append(entry)
                count = 0
                run = []
                repeat = -1
                if index == total - 1:
                    run = [line[index + 1]]
                    entry = (1,run)
                    lst.append(entry)
            else:
                repeat = 0

                if count == 128:
                    entry = (128,run)
                    lst.append(entry)
                    count = 0
                    run = []
                    repeat = -1
                if index == total - 1:
                    run.append(line[index + 1])
                    entry = (count+1,run)
                    lst.append(entry)
        else:
            if repeat == 0:
                entry = (count,run)
                lst.append(entry)
                count = 0
                run = []
                repeat = -1
                if index == total - 1:
                    run.append( line[index + 1])
                    run.append( line[index + 1])
                    entry = (2+128,run)
                    lst.append(entry)
                    break
            run.append(current)
            repeat = 1
            count += 1
            if count == 128:
                entry = (256,run)
                lst.append(entry)
                count = 0
                run = []
                repeat = -1
            if index == total - 1:
                if count == 0:
                    run = [line[index + 1]]
                    entry = (1,run)
                    lst.append(entry)
                else:
                    run.append(current)
                    entry = (count+1+128,run)
                    lst.append(entry)
    return lst

def encodeRLE24(img):
    width, height = img.size
    output = StringIO.StringIO()

    for h in range(height):
        line = []
        result=[]
        for w in range(width):
            (r, g, b) = img.getpixel((w,h))
            line.append((r << 16)+(g << 8) + b)
        result = encode(line)
        for count, pixel in result:
            output.write(struct.pack("B", count-1))
            if count > 128:
                output.write(struct.pack("B", (pixel[0]) & 0xFF))
                output.write(struct.pack("B", ((pixel[0]) >> 8) & 0xFF))
                output.write(struct.pack("B", ((pixel[0]) >> 16) & 0xFF))
            else:
                for item in pixel:
                    output.write(struct.pack("B", (item) & 0xFF))
                    output.write(struct.pack("B", (item >> 8) & 0xFF))
                    output.write(struct.pack("B", (item >> 16) & 0xFF))
    content = output.getvalue()
    countlenght = len(content)
    while (countlenght % 4096 != 0):
		output.write(struct.pack("B", 0xFF))
		content = output.getvalue()
		countlenght = len(content)
        
    output.close() 
    return content


## get payload data : BGR Interleaved
def GetImageBody(img, compressed=1):
    color = (0, 0, 0)
    if img.mode == "RGB":
        background = img
    elif img.mode == "RGBA":
        background = Image.new("RGB", img.size, color)
        img.load()
        background.paste(img, mask=img.split()[3]) # alpha channel
    elif img.mode == "P" or img.mode == "L":
        background = Image.new("RGB", img.size, color)
        img.load()
        background.paste(img)
        #background.save("splash.png")
    else:
        print ("sorry, can't support this format")
        sys.exit()
    
    background.load()
    
    if compressed == 1:
        return encodeRLE24(background)
    else:
        r, g, b = background.split()
        return Image.merge("RGB",(b,g,r)).tostring()

## make a image

def MakeLogoImage(logo, out):
    img1 = Image.open(logo['infile1'])
    img2 = Image.open(logo['infile2'])
    img3 = Image.open(logo['infile3'])
    img4 = Image.open(logo['infile4'])
    img5 = Image.open(logo['infile5'])
    file = open(out, "wb")
    body1 = GetImageBody(img1, SUPPORT_RLE24_COMPRESSIONT)
    body2 = GetImageBody(img2, SUPPORT_RLE24_COMPRESSIONT)
    body3 = GetImageBody(img3, SUPPORT_RLE24_COMPRESSIONT)
    body4 = GetImageBody(img4, SUPPORT_RLE24_COMPRESSIONT)
    body5 = GetImageBody(img5, SUPPORT_RLE24_COMPRESSIONT)
    file.write(GetImgHeader(img1.size, img2.size, img3.size, img4.size, img5.size, SUPPORT_RLE24_COMPRESSIONT, len(body1), len(body2), len(body3), len(body4), len(body5)))
    file.write(body1)
    file.write(body2)
    file.write(body3)
    file.write(body4)
    file.write(body5)
    file.close()


## mian

def ShowUsage():
    print(" usage: python logo_gen.py [logo1.png] [logo2.png] [logo3.png] [logo4.png] [logo5.png]")

def GetPNGFile():
    infile1 = "logo1.png" #default file name
    infile2 = "logo2.png"
    infile3 = "logo3.png"
    infile4 = "logo4.png"
    infile5 = "logo5.png"
    num = len(sys.argv)
    if num > 7:
        ShowUsage()
        sys.exit(); # error arg

    if num == 6:
        infile1 = sys.argv[1]
        infile2 = sys.argv[2]
        infile3 = sys.argv[3]
        infile4 = sys.argv[4]
        infile5 = sys.argv[5]

    if os.access(infile1, os.R_OK) != True:
        ShowUsage()
        sys.exit(); # error file
    return {'infile1':infile1, 'infile2':infile2, 'infile3':infile3, 'infile4':infile4, 'infile5':infile5 }

if __name__ == "__main__":
    MakeLogoImage(GetPNGFile(), "output/logo.img")


Next Update:

I have edited the real_size vars ... now it counts up but i dont know if it work in real:

Code:
.....
    real_size1 = (real_bytes1  + 4095) / 4096
    real_size2 = (real_bytes1  + real_bytes2  + 4095) / 4096
    real_size3 = (real_bytes1  + real_bytes2  + real_bytes3 + 4095) / 4096
    real_size4 = (real_bytes1  + real_bytes2  + real_bytes3 + real_bytes4 + 4095) / 4096
    real_size5 = (real_bytes1  + real_bytes2  + real_bytes3 + real_bytes4 + real_bytes5 + 4095) / 4096
....
 
Last edited:

Cynob

Member
Nov 20, 2016
19
13
Ok i have it working i think.
The first test with 5 small pictures with only black and white color worked on @Hoschi@`s Mi5

Now i edited the Windows tool and my biggest problem now is how i could upload the new logo Maker tool here....
 

Cynob

Member
Nov 20, 2016
19
13
Sooo i forget to put the filesizes in the header :silly: >>> solved!

If you have a linux machine running you can use the script like:

- put your 5 pictures in the same folder as the logo_gen.py script
- rename them to logo1>5.png
- generate a folder named "output" ( of course in the same folder as the script + pictures)
- open your command prompt in that folder and type
Code:
python logo_gen.py logo1.png logo2.png logo3.png logo4.png logo5.png
to generate a logo.img

The original image sizes are:
picture 1 = 161x321
picture 2 = 558x992
picture 3 = 178x350
picture 4 = 1080x1920
picture 5 = 1080x1920

I dont know how different sizes affect something

one thing i am not sure at the moment. In the original logo.img the first picture offset start at 0 - that means for me the header get ignored by countig that "starthere"offset up?

anyway here is the "should work" script:
Code:
#Downloaded from: https://source.codeaurora.org/quic/la/device/qcom/common/tree/display/logo?h=LA.BR.1.2.7_rb1.1

# Copyright (c) 2013,2015, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#     * Neither the name of The Linux Foundation nor the names of its
#       contributors may be used to endorse or promote products derived
#       from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#===========================================================================

#  This script read the logo png and creates the logo.img

# when          who     what, where, why
# --------      ---     -------------------------------------------------------
# 2013-04       QRD     init
# 2015-04       QRD     support the RLE24 compression

# Environment requirement:
#     Python + PIL
#     PIL install:
#         (ubuntu)  sudo apt-get install python-imaging
#         (windows) (http://www.pythonware.com/products/pil/)

# limit:
#    a. This script only support Python 2.7.x, 2.6.x,
#      Can't use in py3x for StringIO module
#    b. This script's input can be a png, jpeg, bmp, gif file.
#    But if it is a gif, only get the first frame by default.
#
# description:
#    struct logo_header {
#       unsigned char[8]; // "SPLASH!!"
#       unsigned width;   // logo's width, little endian
#       unsigned height;  // logo's height, little endian
#       unsigned type;    // 0, Raw Image; 1, RLE24 Compressed Image
#       unsigned blocks;  // block number, real size / 512
#       ......
#    };

#    the logo Image layout:
#       logo_header + Payload data

# ===========================================================================*/
from __future__ import print_function
import sys,os
import struct
import StringIO
from PIL import Image

SUPPORT_RLE24_COMPRESSIONT = 1

## get header
def GetImgHeader(size1, size2, size3, size4, size5, compressed, real_bytes1, real_bytes2, real_bytes3, real_bytes4, real_bytes5):
    SECTOR_SIZE_IN_BYTES = 4096   # Header size
    header = [0 for i in range(SECTOR_SIZE_IN_BYTES)]

    width1, height1 = size1
    width2, height2 = size2
    width3, height3 = size3
    width4, height4 = size4
    width5, height5 = size5
    payload_size1 = real_bytes1 / 4096
    payload_size2 = real_bytes2 / 4096
    payload_size3 = real_bytes3 / 4096
    payload_size4 = real_bytes4 / 4096
    payload_size5 = real_bytes5 / 4096
    real_size1 = 0
    real_size2 = real_bytes1  / 4096 - 1
    real_size3 = (real_bytes1  + real_bytes2) / 4096 - 1
    real_size4 = (real_bytes1  + real_bytes2  + real_bytes3) / 4096 - 1
    real_size5 = (real_bytes1  + real_bytes2  + real_bytes3 + real_bytes4) / 4096 - 1
    
    # magic
    header[:8] = [ord('S'),ord('P'), ord('L'), ord('A'),
                   ord('S'),ord('H'), ord('!'), ord('!')]

    # width1
    header[8] = ( width1        & 0xFF)
    header[9] = ((width1 >> 8 ) & 0xFF)
    header[10]= ((width1 >> 16) & 0xFF)
    header[11]= ((width1 >> 24) & 0xFF)
    # width2
    header[12]= ( width2        & 0xFF)
    header[13]= ((width2 >>  8) & 0xFF)
    header[14]= ((width2 >> 16) & 0xFF)
    header[15]= ((width2 >> 24) & 0xFF)   
    # width3
    header[16]= ( width3        & 0xFF)
    header[17]= ((width3 >> 8 ) & 0xFF)
    header[18]= ((width3 >> 16) & 0xFF)
    header[19]= ((width3 >> 24) & 0xFF)
    # width4
    header[20]= ( width4        & 0xFF)
    header[21]= ((width4 >>  8) & 0xFF)
    header[22]= ((width4 >> 16) & 0xFF)
    header[23]= ((width4 >> 24) & 0xFF)
    # width5
    header[24]= ( width5        & 0xFF)
    header[25]= ((width5 >> 8 ) & 0xFF)
    header[26]= ((width5 >> 16) & 0xFF)
    header[27]= ((width5 >> 24) & 0xFF)

    # height1
    header[28]= ( height1        & 0xFF)
    header[29]= ((height1 >>  8) & 0xFF)
    header[30]= ((height1 >> 16) & 0xFF)
    header[31]= ((height1 >> 24) & 0xFF)
    # height2
    header[32]= ( height2        & 0xFF)
    header[33]= ((height2 >> 8 ) & 0xFF)
    header[34]= ((height2 >> 16) & 0xFF)
    header[35]= ((height2 >> 24) & 0xFF)
    # height3
    header[36]= ( height3        & 0xFF)
    header[37]= ((height3 >>  8) & 0xFF)
    header[38]= ((height3 >> 16) & 0xFF)
    header[39]= ((height3 >> 24) & 0xFF)
    # height4
    header[40]= ( height4        & 0xFF)
    header[41]= ((height4 >> 8 ) & 0xFF)
    header[42]= ((height4 >> 16) & 0xFF)
    header[43]= ((height4 >> 24) & 0xFF)
    # height5
    header[44]= ( height5        & 0xFF)
    header[45]= ((height5 >>  8) & 0xFF)
    header[46]= ((height5 >> 16) & 0xFF)
    header[47]= ((height5 >> 24) & 0xFF)

    #type
    header[48]= ( compressed    & 0xFF)
    #header[49]= 0
    #header[50]= 0
    #header[51]= 0
    header[52]= ( compressed    & 0xFF)
    #header[53]= 0
    #header[54]= 0
    #header[55]= 0
    header[56]= ( compressed    & 0xFF)
    #header[57]= 0
    #header[58]= 0
    #header[59]= 0
    header[60]= ( compressed    & 0xFF)
    #header[61]= 0
    #header[62]= 0
    #header[63]= 0
    header[64]= ( compressed    & 0xFF)
    #header[65]= 0
    #header[66]= 0
    #header[67]= 0
    
    # filesize logo1
    header[68] = ( payload_size1        & 0xFF)
    header[69] = ((payload_size1 >>  8) & 0xFF)
    header[70] = ((payload_size1 >> 16) & 0xFF)
    header[71] = ((payload_size1 >> 24) & 0xFF)
    # filesize logo2
    header[72] = ( payload_size2        & 0xFF)
    header[73] = ((payload_size2 >>  8) & 0xFF)
    header[74] = ((payload_size2 >> 16) & 0xFF)
    header[75] = ((payload_size2 >> 24) & 0xFF)
    # filesize logo3
    header[76] = ( payload_size3        & 0xFF)
    header[77] = ((payload_size3 >>  8) & 0xFF)
    header[78] = ((payload_size3 >> 16) & 0xFF)
    header[79] = ((payload_size3 >> 24) & 0xFF)
    # filesize logo4
    header[80] = ( payload_size4        & 0xFF)
    header[81] = ((payload_size4 >>  8) & 0xFF)
    header[82] = ((payload_size4 >> 16) & 0xFF)
    header[83] = ((payload_size4 >> 24) & 0xFF)
    # filesize logo5
    header[84] = ( payload_size5        & 0xFF)
    header[85] = ((payload_size5 >>  8) & 0xFF)
    header[86] = ((payload_size5 >> 16) & 0xFF)
    header[87] = ((payload_size5 >> 24) & 0xFF)
        
    # block number img 1
    header[88] = ( real_size1        & 0xFF)
    header[89] = ((real_size1 >>  8) & 0xFF)
    header[90] = ((real_size1 >> 16) & 0xFF)
    header[91] = ((real_size1 >> 24) & 0xFF)

    # block number img 2
    header[92] = ( real_size2        & 0xFF)
    header[93] = ((real_size2 >>  8) & 0xFF)
    header[94] = ((real_size2 >> 16) & 0xFF)
    header[95] = ((real_size2 >> 24) & 0xFF)
    
    # block number img 3
    header[96] = ( real_size3        & 0xFF)
    header[97] = ((real_size3 >>  8) & 0xFF)
    header[98] = ((real_size3 >> 16) & 0xFF)
    header[99] = ((real_size3 >> 24) & 0xFF)
    
    # block number img 4
    header[100] = ( real_size4        & 0xFF)
    header[101] = ((real_size4 >>  8) & 0xFF)
    header[102] = ((real_size4 >> 16) & 0xFF)
    header[103] = ((real_size4 >> 24) & 0xFF)
    
    # block number img 5
    header[104] = ( real_size5        & 0xFF)
    header[105] = ((real_size5 >>  8) & 0xFF)
    header[106] = ((real_size5 >> 16) & 0xFF)
    header[107] = ((real_size5 >> 24) & 0xFF)
    output = StringIO.StringIO()
    for i in header:
        output.write(struct.pack("B", i))
    content = output.getvalue()
    output.close()
    return content

def encode(line):
    count = 0
    lst = []
    repeat = -1
    run = []
    total = len(line) - 1
    for index, current in enumerate(line[:-1]):
        if current != line[index + 1]:
            run.append(current)
            count += 1
            if repeat == 1:
                entry = (count+128,run)
                lst.append(entry)
                count = 0
                run = []
                repeat = -1
                if index == total - 1:
                    run = [line[index + 1]]
                    entry = (1,run)
                    lst.append(entry)
            else:
                repeat = 0

                if count == 128:
                    entry = (128,run)
                    lst.append(entry)
                    count = 0
                    run = []
                    repeat = -1
                if index == total - 1:
                    run.append(line[index + 1])
                    entry = (count+1,run)
                    lst.append(entry)
        else:
            if repeat == 0:
                entry = (count,run)
                lst.append(entry)
                count = 0
                run = []
                repeat = -1
                if index == total - 1:
                    run.append( line[index + 1])
                    run.append( line[index + 1])
                    entry = (2+128,run)
                    lst.append(entry)
                    break
            run.append(current)
            repeat = 1
            count += 1
            if count == 128:
                entry = (256,run)
                lst.append(entry)
                count = 0
                run = []
                repeat = -1
            if index == total - 1:
                if count == 0:
                    run = [line[index + 1]]
                    entry = (1,run)
                    lst.append(entry)
                else:
                    run.append(current)
                    entry = (count+1+128,run)
                    lst.append(entry)
    return lst

def encodeRLE24(img):
    width, height = img.size
    output = StringIO.StringIO()

    for h in range(height):
        line = []
        result=[]
        for w in range(width):
            (r, g, b) = img.getpixel((w,h))
            line.append((r << 16)+(g << 8) + b)
        result = encode(line)
        for count, pixel in result:
            output.write(struct.pack("B", count-1))
            if count > 128:
                output.write(struct.pack("B", (pixel[0]) & 0xFF))
                output.write(struct.pack("B", ((pixel[0]) >> 8) & 0xFF))
                output.write(struct.pack("B", ((pixel[0]) >> 16) & 0xFF))
            else:
                for item in pixel:
                    output.write(struct.pack("B", (item) & 0xFF))
                    output.write(struct.pack("B", (item >> 8) & 0xFF))
                    output.write(struct.pack("B", (item >> 16) & 0xFF))
    content = output.getvalue()
    countlenght = len(content)
    while (countlenght % 4096 != 0):
		output.write(struct.pack("B", 0xFF))
		content = output.getvalue()
		countlenght = len(content)
        
    output.close() 
    return content


## get payload data : BGR Interleaved
def GetImageBody(img, compressed=1):
    color = (0, 0, 0)
    if img.mode == "RGB":
        background = img
    elif img.mode == "RGBA":
        background = Image.new("RGB", img.size, color)
        img.load()
        background.paste(img, mask=img.split()[3]) # alpha channel
    elif img.mode == "P" or img.mode == "L":
        background = Image.new("RGB", img.size, color)
        img.load()
        background.paste(img)
        #background.save("splash.png")
    else:
        print ("sorry, can't support this format")
        sys.exit()
    
    background.load()
    
    if compressed == 1:
        return encodeRLE24(background)
    else:
        r, g, b = background.split()
        return Image.merge("RGB",(b,g,r)).tostring()

## make a image

def MakeLogoImage(logo, out):
    img1 = Image.open(logo['infile1'])
    img2 = Image.open(logo['infile2'])
    img3 = Image.open(logo['infile3'])
    img4 = Image.open(logo['infile4'])
    img5 = Image.open(logo['infile5'])
    file = open(out, "wb")
    body1 = GetImageBody(img1, SUPPORT_RLE24_COMPRESSIONT)
    body2 = GetImageBody(img2, SUPPORT_RLE24_COMPRESSIONT)
    body3 = GetImageBody(img3, SUPPORT_RLE24_COMPRESSIONT)
    body4 = GetImageBody(img4, SUPPORT_RLE24_COMPRESSIONT)
    body5 = GetImageBody(img5, SUPPORT_RLE24_COMPRESSIONT)
    file.write(GetImgHeader(img1.size, img2.size, img3.size, img4.size, img5.size, SUPPORT_RLE24_COMPRESSIONT, len(body1), len(body2), len(body3), len(body4), len(body5)))
    file.write(body1)
    file.write(body2)
    file.write(body3)
    file.write(body4)
    file.write(body5)
    file.close()


## mian

def ShowUsage():
    print(" usage: python logo_gen.py [logo1.png] [logo2.png] [logo3.png] [logo4.png] [logo5.png]")

def GetPNGFile():
    infile1 = "logo1.png" #default file name
    infile2 = "logo2.png"
    infile3 = "logo3.png"
    infile4 = "logo4.png"
    infile5 = "logo5.png"
    num = len(sys.argv)
    if num > 7:
        ShowUsage()
        sys.exit(); # error arg

    if num == 6:
        infile1 = sys.argv[1]
        infile2 = sys.argv[2]
        infile3 = sys.argv[3]
        infile4 = sys.argv[4]
        infile5 = sys.argv[5]

    if os.access(infile1, os.R_OK) != True:
        ShowUsage()
        sys.exit(); # error file
    return {'infile1':infile1, 'infile2':infile2, 'infile3':infile3, 'infile4':infile4, 'infile5':infile5 }

if __name__ == "__main__":
    MakeLogoImage(GetPNGFile(), "output/logo.img")
If somebody like to test it and write what dont work i would be happy :D
 
Last edited:

GokulNC

Senior Member
Jan 10, 2015
826
1,440
Chennai
github.com
@Cynob Awesome, bro...
If it's working, create a complete tool (by modifying this tool itself if you can) and post it as a new thread :)

I'll add a link in this thread to your thread :)

(Make sure to test your tool with someone who has Mi5 before creating thread ;))
 
Last edited:

Top Liked Posts

  • There are no posts matching your filters.
  • 22
    Note:
    This is not bootanimation, this is the splash screen (the 'Mi' boot logo which is displayed when device is switched ON)
    This is for Xiaomi Mi 5(, 5s, 5s Plus) & Mi Max/Mix Only (Snapdragon Variants)..
    For other devices, please send me your splash.img so that I can create a tool for you too.

    Requirements:
    1. Rooted Xiaomi Mi 5 or Mi 5s / 5s Plus or Mi Max or Mi Mix (any ROM)
    2. Optional: Terminal Emulator app or Custom Recovery or atleast working fastboot in computer
    3. You're proceeding at your own risk.

    Seems this tool won't work anymore for the latest updated firmware.

    STEPS to create splash.img:

    Before proceeding, make sure fastboot is setup properly in your computer (just incase something goes wrong)..

    1. Download & Extract this: Splash_Logo_Maker.zip

    2. Make sure you have a picture with resolution equal to your device resolution (for example, 1080x1920px for Mi5) or lesser.

    Note:
    In fact, you don't need 1080x1920 picture, you can even have a picture with any resolution lower than device resolution, which will automatically be centered while booting.
    For example, here's the stock splash with resolution 161x321: Click Here

    3. Now rename your picture as logo.png or logo.jpg (according to the format) & replace it inside "pics" folder of the extracted folder.
    (Or you can also directly edit the picture inside)

    4. Finally, run the 'CREATE_LOGO.bat' to create splash.img , which you can find inside the "output" folder after completion.


    STEPS to flash splash.img:

    Optional: To backup your original splash.img:

    Code:
    dd if=/dev/block/bootdevice/by-name/splash of=/sdcard/splash.img
    (Not necessary though.. You may get it from the stock firmware itself.)

    Now, Choose any one easy method to install:

    a. To flash from recovery:
    Transfer the flashable_splash.zip to your device and flash from TWRP or CWM or Philz or any other custom recovery.

    b. To flash from Terminal Emulator:
    Transfer the splash.img to your device's Internal Storage, Open Terminal Emulator & enter the following to flash it:
    Code:
    su
    dd if=/sdcard/splash.img of=/dev/block/bootdevice/by-name/splash

    c. To flash from Fastboot mode:
    Code:
    fastboot flash splash splash.img

    Note:
    Incase something goes wrong or device doesn't bootup, flash the stock splash.img from custom recovery or fastboot.




    Note:
    For Mi 5 upgraded to Android 7 (Nougat) firmware, if this tool doesn't work, try this tool here by @Cynob:
    Mi 5 (Nougat) Logo Maker


    Credits:
    1. @GokulNC (myself ;)) who wrote this script
    2. Based on logo_gen.py script


    Hit the Thanks :good: button if it worked for you :)

    You're welcome to share here the custom splash screens that you made, since others may find it useful :)
    8
    Thank you for this beatiful script!

    I've made a custom splash screen which looks in my opinion really nice, so I would like to share it. You can find it in my attachements, Thanks!
    4
    Thank you so much!! :good::D
    This is my splash image
    3
    Thank you man, this is my boot splash image :p
    2

    Thanks mate :highfive:

    In the attachements you can see another logo, i just used the Unity 5 logo, so basicly no big work behind it. On the Second Splash Screen, i've created a mosaic like five ans placed it instead of the 5 logo.

    I hope you like it.

    Note: @ work, I only have paint.net... :p