sartFileTool is a command line tool for encoding and decoding the SArtFile.bin (Shared ArtFile) found in
/System/Library/PrivateFrameworks/CoreUI.framework/Versions/A/SArtFile.bin. It its current state it can flawlessly decode and encode SArtFile.bin.
You can find the ArtFile.bin counterpart here!.
In the recent update I refactored the code to be more object oriented for easy "plug and play" for Cocoa applications. They can now internally alter the SArtFile.bin contents without writing to disk right away. Also, the new version supports the encoding of SArtFiles without the help of the originally encoded one – it creates all the data itself.
The tool is pretty straightforward to use. Specify -e or -d for encode or decode, respectively. Optionally, you can specify the operating system for the file being decoded/encoded using the -os option with an argument. (e.g.
The tool has a few new features that would be helpful to the end-user:
- When decoding, not specifying a SArtFile.bin decode causes the tool to automatically pull the one installed on your system at
- The encoding part of the tool no longer needs the originally decoded SArtFile.bin to create a new one from the specified folder.
- Better exception/error catching
-osoption is not longer required. The tool will use the version installed on your system if none is specified
To decode the SArtFile.bin installed on your system to a folder called
$ cd path/To/sartFileTool/Directory $ ./sartFileTool -d sartFiles
The tool would decode the installed SArtFile.bin into a directory called
sartFiles using the current Mac OS X version.
To encode this directory back into a SArtFile.bin after making changes to it:
$ ./sartFileTool -e sartFiles SArtFile.new.bin
Changes to structure
Previous versions of SArtFileTool had images with @2x or pdfs and such. This version does not. Instead, each file follows this format:
fileIndex-imageIndex; where the fileIndex is the 0-based index the file lies within the SArtFile.bin, and the imageIndex is the 1-based index where the image lies within its file.
For example, for a PNG file with a retina resource at index 0, the legacy image would be at 0-1, and the retina image would be at 0-2. This new format calls for more organization within the SArtFile.bin and makes it more future proof.
In addition to the new naming structure, each decoded folder now gets a file called
_receipt.plist. This receipt contains some information that the encoder might need to know about the folder like the OS of the decoded file.
The SArtFile.bin is composed of five key components:
- Master Header
- Descriptor Offsets
- In Progress: Unknown
- File Data
First 8 bytes of the SArtFile.bin. Gives some key information about the file.
|0||2||uint16_t||Believed to be a version number. Only found to be 2 right now.|
|2||2||uint16_t||Amount of file descriptors found within the container.|
|4||4||uint32_t||"Master offset" at which the file data begins. All file data offsets in descriptors is offset by this number.|
|8||…||uint32_t||4 * fileCount size. A list of offsets to each file descriptor.|
** I RECENTLY FOUND OUT THAT THIS SECTION HAS DATA PERTAINING TO THE IMAGES WITH MULTIPLE REPRESENTATIONS AKA 2X **
- This sector is 820 bytes on Lion because there are 205 images with 2x representations on Lion and on Mountain Lion there are 206 (820 / 205 = 4; 824 / 206 = 4)*
Currently, SArtFileTool copies this sector of bytes into the "buffer1" key of the receipt.
I recently found this new sector of 820 bytes (824 under 10.8). It is a very odd area. I investigated this under 10.7.4. They seem to be in 8 byte groupings in this format:
Format on 10.7.4
|0||2||uint16_t||Appears to be an offset to file data|
|2||2||uint16_t||Looks like a Mac OS X version number. I have seen this to be 1073 and 1074 so far.|
|4||4||uint32_t||So far only a 1|
Format on 10.8
On the latest build of 10.8, the format is fairly similar. There did seem to be build numbers instead of MacOSX versions for the second short. Also, it seems that the 32bit "1" comes first on here. I don't know if I was mistaken on Lion. All of the first shorts are divisible by 4.
|0||4||uint32_t||So far only a 1|
|4||2||uint16_t||Looks like an offset to something.|
|6||2||uint16_t||Build number? I've seen 1351, 1348, 1349|
Here is some sample data:
If anyone could shed some light on this it would be greatly appreciated. The data in question is in range 1400-2220 on 10.7.4's SArtFile.bin
12-byte header for a file. Each descriptor can contain multiple sub-image representations. It also contains a flag to indicate its type/purpose.
|0||2||uint16_t||A flag indicating the type of image. 1 = retina_resource, 2 = legacy_resource, 3 = pdf|
|2||2||uint16_t||Amount of representations for the file.|
|4||4||uint32_t||Dropped in 10.8: Unknown. Seems to be skipped over. Also, in the case of PDFs, it is the pdf data length - 47.|
|8||4||uint32_t||Dropped in 10.8: Sum of each image's data length.|
|12/4||…||…||List of image headers. The amount listed has been specified already.|
12-byte image header. Contains details required to access the image data and make sense of it.
|0||2||uint16_t||Width of the image in pixels.|
|2||2||uint16_t||Height of the image in pixels.|
|4||4||uint32_t||Length of the image data.|
|8||4||uint32_t||Offset of the image data. This value is relative to the master offset specified in the beginning of the file.|
All file data (except PDFs) is raw Unpremultiplied ARGB in little-endian (BGRA, bytes go backwards). The last representation is usually (so far always) the retina image with double resolution.
PDFs have a type of 3 (specified in the file descriptor). Their first file data (listed first for the file headers) is always regular PDF data. All PDFs have 3 representations: PDF, legacy image, retina image. There are representations for both sizes always coming with a PDF so that it can be displayed onscreen quickly without interpolation. The file header for PDFs shows its desired bounds size.
SArtFileTool is license under the
Simplified BSD License – modified to forbid any commercial redistribution because I would prefer people not make commercial applications based off of this code. The theming community is supposed to be open and as the name implies: A community. The license in its entirety applies to all works in this GitHub repository and reproduced in its entirety as follows:
Copyright (c) 2011-2012, Alex Zielenski 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. * Any redistribution, use, or modification is done solely for personal benefit and not for any commercial purpose or for monetary gain THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.