Click here to Skip to main content
Licence CPOL
First Posted 7 Oct 2011
Views 5,060
Downloads 201
Bookmarked 6 times

Reading Apple iDevice CPBitmap Files

By | 9 Oct 2011 | Article
Provides a means of loading an Apple CPBitmap file into a .NET Bitmap object

Please take a moment to check out the Web application.

Introduction

This article introduces a class that can read CPBitmap files, which are used (primarily, from what I can see) as the file format for Wallpaper images on an iDevice (iPod, iPhone, iPad, etc.).

Background

(Skip past the first 4 paragraphs if you don't care about why I did this! :D)

Today, I was asked by my CEO to recover the wallpaper from an old iPhone 3GS (currently on an iPhone 4). This seemed straight forward -> I had the backup on my PC, and I had bought a nifty program called "iPhone backup extractor". Off I went, opened up iPhone backup extractor, and exported the photos it found. Unfortunately, it found everything EXCEPT the wallpaper.

After a bit of Googling around, I managed to figure out that the wallpaper is actually stored under the Springboard folder in the "Library". So, I extracted the file (called HomeBackground.cpbitmap) to my PC, and had a look.

Unfortunately, changing the extension to one of the known types didn't work (PNG, JPEG, BMP, etc.). So I again decided to turn to Google (at this point, I will tell you that the iPhone isn't jailbroken.. and in fact, I was looking at a backup of an iPhone, not the physical device itself). Turning to Google turned up a lot of sites where people had jailbroken their phones and they were all extremely frustrated that they couldn't produce CPBitmap files. So I decided to open the file in Wordpad and take a look.

How I Figured It Out

I don't claim to be a genius, but I figure this may help some people somehow.

Both the top and bottom of the file were almost identical.

This made me say, "hey wait.. there isn't any header for this image, it jumps straight into pixel data".

With that, I decided to look up a 3GS display resolution, which just so happens to be 320x480. With a little brain work, I came up with this extremely difficult equation: 320x480x4. Why 4? There are 4 bytes in a 32-bit Integer (int, or, Int32), 1 byte for the Red component, 1 byte for the Green component, 1 byte for the Blue component and 1 byte for the Alpha component.

I double checked the files and sure enough, Windows displays 600KB (614,424 bytes) for both the LockBackground and HomeBackground, even though they were completely different pictures. 320x480x4 = 614,400 ... we're close!

The rest was basically trial and error. The file has the width and height stored at the end, as well as some random unknown fields that I'm not sure what they're for. Reading those into the Bitmap crashed the application, so I just debugged it until I figured out what the issue was!

Using the Code

With all of that being said... I present the first, open source attempt at loading CPBitmap files. They aren't complicated at all.. so I'm surprised I seem to be the first one who attempted to load them. If that is a false statement, please link me to the other authors work.. I couldn't find anything after half a day of looking!

Usage of the class couldn't be simpler, you just need to supply a FileStream:

FileStream fileStream = new FileStream("<path_to_file_here>.cpbitmap", 
            FileMode.Open, FileAccess.Read);
CPBitmap cpBitmap = new CPBitmap(fileStream);
// .. Bitmap is accessible via cpBitmap.BitmapObject
fileStream.Close();        

The provided example paints the Bitmap into a PictureBox, and also allows you to save the Bitmap as a JPEG file. Feel free to change the constructor... the only reason I supply a filestream is for the example.

The drawing is done using an unsafe pointer and the BitmapData class. It doesn't have to be done this way... SetPixel is "quick enough" if you have trouble understanding the pointer. The "meat" of the code is below for reference:

private unsafe void Load()
{
    // Create a temporary Bitmap to load the data into
    Bitmap _bitmap = new Bitmap(320, 480, PixelFormat.Format32bppPArgb);
    // Lock the Bitmap into memory so we can play with it
    BitmapData _bitmapData = _bitmap.LockBits(new Rectangle
    (0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.ReadWrite, 
    PixelFormat.Format32bppPArgb);
    
    // Setup our pointer at 0,0
    int* xy = (int*)_bitmapData.Scan0.ToPointer();
    
    // Read the file in and add each 4-byte pixel (sizeof(int) = 4) to the pixel list
    using (BinaryReader _binaryReader = new BinaryReader(_fileStream))
    {
        int _filePosition = 0;
        
        int _fileLength = (int)_binaryReader.BaseStream.Length;
        
        while (_filePosition < _fileLength)
        {
            // If this is less than the area where pixels are stored, 
            // then add it to the Bitmap
            if (_filePosition < _endOfPixelDataCalculation) // 320x480 = 153600
            {
                *(xy++) = _binaryReader.ReadInt32();
            }
            else
            {
                // If we've passed the pixel data.. then its the other data.
                switch (_filePosition)
                {
                    case _endOfPixelDataCalculation:
                        // Bit field, unknown use
                        UnknownField1 = _binaryReader.ReadInt32();
                        break;
                    case _endOfPixelDataCalculation + 4:
                        WidthInFile = _binaryReader.ReadInt32();
                        break;
                    case _endOfPixelDataCalculation + 8:
                        HeightInFile = _binaryReader.ReadInt32();
                        break;
                    case _endOfPixelDataCalculation + 12:
                        // Bit field, unknown use
                        UnknownField2 = _binaryReader.ReadInt32();
                        break;
                    case _endOfPixelDataCalculation + 16:
                        // Bit field, unknown use
                        UnknownField3 = _binaryReader.ReadInt32();
                        break;
                    case _endOfPixelDataCalculation + 20:
                        // I have no idea what this value stands for..
                        UnknownField4 = _binaryReader.ReadInt32();
                        break;
                }
            }
            _filePosition += sizeof(int);
        }
    }
    
    // Unlock the Bitmap
    _bitmap.UnlockBits(_bitmapData);
    // Store the result
    BitmapObject = _bitmap;
} 

Points of Interest

I searched high and low for this and couldn't find it. I hope this helps someone. Losing a wallpaper in a backup was previously unavoidable... not anymore!

History

  • 8/10/2011 12:00:00 AM - Initial version released

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Simon_Whitehead

Software Developer (Senior)
RSPCA
Australia Australia

Member

I am a young developer from Australia. I have been programming since I was 11, when I started with Visual Basic. I have since moved onto a degree in C++ (with an emphasis on game development) and I am currently the Application/Web Developer for RSPCA Victoria (http://www.rspcavic.org), which is a not-for-profit organisation for the protection of animals.
 
I enjoy: my young family - my partner and my daughter - Mortal Kombat, Aussie Beer, C++, C#, any form of music not including Opera and my dog "Buddy".

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
BugiPad compatible? PinmemberMember 87378737:57 17 Mar '12  
GeneralRe: iPad compatible? PinmemberSimon_Whitehead18:04 18 Mar '12  
GeneralRe: iPad compatible? PinmemberSimon_Whitehead18:21 18 Mar '12  
GeneralRe: iPad compatible? PinmemberMember 87378734:53 24 Mar '12  
GeneralRe: iPad compatible? PinmemberSimon_Whitehead5:14 24 Mar '12  
GeneralRe: iPad compatible? PinmemberKerry_Campbell13:10 28 Mar '12  
GeneralRe: iPad compatible? PinmemberSimon_Whitehead13:43 28 Mar '12  
GeneralRe: iPad compatible? Pinmembertanguy928:09 23 May '12  
QuestionExtending support for Retina Display Pingroupmonomalvado19:26 20 Feb '12  
AnswerRe: Extending support for Retina Display PinmemberSimon_Whitehead9:23 22 Feb '12  
QuestionCPBitmap Converter PinmemberMember 859754320:54 25 Jan '12  
AnswerRe: CPBitmap Converter PinmemberSimon_Whitehead16:49 26 Jan '12  
GeneralRe: CPBitmap Converter PinmemberMember 859754321:21 26 Jan '12  
GeneralRe: CPBitmap Converter PinmemberSimon_Whitehead1:04 27 Jan '12  
QuestionPlease help me out.. ;) PinmemberMember 85777795:13 18 Jan '12  
AnswerRe: Please help me out.. ;) PinmemberSimon_Whitehead10:00 18 Jan '12  
AnswerRe: Please help me out.. ;) PinmemberSimon_Whitehead16:49 26 Jan '12  
QuestionHow do I use this??? PinmemberMember 834648319:27 24 Oct '11  
AnswerRe: How do I use this??? PinmemberSimon_Whitehead20:01 24 Oct '11  
GeneralRe: How do I use this??? PinmemberRandy Rucker13:25 26 Nov '11  
GeneralRe: How do I use this??? PinmemberSimon_Whitehead17:25 30 Nov '11  
GeneralRe: How do I use this??? PinmemberRandy Rucker6:01 24 Dec '11  
GeneralRe: How do I use this??? PinmemberSimon_Whitehead12:56 26 Dec '11  
GeneralRe: How do I use this??? PinmemberRandy Rucker4:06 27 Dec '11  
GeneralRe: How do I use this??? PinmemberSimon_Whitehead17:00 26 Jan '12  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120517.1 | Last Updated 9 Oct 2011
Article Copyright 2011 by Simon_Whitehead
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid