]>
code.delx.au - refind/blob - libeg/load_icns.c
3 * Loading function for .icns Apple icon images
5 * Copyright (c) 2006 Christoph Pfisterer
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #define MAX_ICNS_SIZES 4
42 // Decompress .icns RLE data
45 VOID
egDecompressIcnsRLE(IN OUT UINT8
**CompData
, IN OUT UINTN
*CompLen
, IN UINT8
*PixelData
, IN UINTN PixelCount
)
56 cp_end
= cp
+ *CompLen
;
61 while (cp
+ 1 < cp_end
&& pp_left
> 0) {
63 if (len
& 0x80) { // compressed data: repeat next byte
68 for (i
= 0; i
< len
; i
++) {
72 } else { // uncompressed data: copy bytes
74 if (len
> pp_left
|| cp
+ len
> cp_end
)
76 for (i
= 0; i
< len
; i
++) {
85 Print(L
" egDecompressIcnsRLE: still need %d bytes of pixel data\n", pp_left
);
88 // record what's left of the compressed data stream
90 *CompLen
= (UINTN
)(cp_end
- cp
);
94 // Load Apple .icns icons
97 EG_IMAGE
* egDecodeICNS(IN UINT8
*FileData
, IN UINTN FileDataLength
, IN UINTN IconSize
, IN BOOLEAN WantAlpha
)
100 UINT8
*Ptr
, *BufferEnd
, *DataPtr
, *MaskPtr
;
101 UINT32 BlockLen
, DataLen
, MaskLen
;
107 UINTN SizesToTry
[MAX_ICNS_SIZES
+ 1] = {IconSize
, 128, 48, 32, 16};
110 if (FileDataLength
< 8 || FileData
== NULL
||
111 FileData
[0] != 'i' || FileData
[1] != 'c' || FileData
[2] != 'n' || FileData
[3] != 's') {
112 // not an icns file...
123 IconSize
= SizesToTry
[SizeToTry
];
125 BufferEnd
= FileData
+ FileDataLength
;
126 // iterate over tagged blocks in the file
127 while (Ptr
+ 8 <= BufferEnd
) {
128 BlockLen
= ((UINT32
)Ptr
[4] << 24) + ((UINT32
)Ptr
[5] << 16) + ((UINT32
)Ptr
[6] << 8) + (UINT32
)Ptr
[7];
129 if (Ptr
+ BlockLen
> BufferEnd
) // block continues beyond end of file
132 // extract the appropriate blocks for each pixel size
133 if (IconSize
== 128) {
134 if (Ptr
[0] == 'i' && Ptr
[1] == 't' && Ptr
[2] == '3' && Ptr
[3] == '2') {
135 if (Ptr
[8] == 0 && Ptr
[9] == 0 && Ptr
[10] == 0 && Ptr
[11] == 0) {
137 DataLen
= BlockLen
- 12;
139 } else if (Ptr
[0] == 't' && Ptr
[1] == '8' && Ptr
[2] == 'm' && Ptr
[3] == 'k') {
141 MaskLen
= BlockLen
- 8;
144 } else if (IconSize
== 48) {
145 if (Ptr
[0] == 'i' && Ptr
[1] == 'h' && Ptr
[2] == '3' && Ptr
[3] == '2') {
147 DataLen
= BlockLen
- 8;
148 } else if (Ptr
[0] == 'h' && Ptr
[1] == '8' && Ptr
[2] == 'm' && Ptr
[3] == 'k') {
150 MaskLen
= BlockLen
- 8;
153 } else if (IconSize
== 32) {
154 if (Ptr
[0] == 'i' && Ptr
[1] == 'l' && Ptr
[2] == '3' && Ptr
[3] == '2') {
156 DataLen
= BlockLen
- 8;
157 } else if (Ptr
[0] == 'l' && Ptr
[1] == '8' && Ptr
[2] == 'm' && Ptr
[3] == 'k') {
159 MaskLen
= BlockLen
- 8;
162 } else if (IconSize
== 16) {
163 if (Ptr
[0] == 'i' && Ptr
[1] == 's' && Ptr
[2] == '3' && Ptr
[3] == '2') {
165 DataLen
= BlockLen
- 8;
166 } else if (Ptr
[0] == 's' && Ptr
[1] == '8' && Ptr
[2] == 'm' && Ptr
[3] == 'k') {
168 MaskLen
= BlockLen
- 8;
175 } while ((DataPtr
== NULL
) && (SizeToTry
++ < MAX_ICNS_SIZES
));
181 return NULL
; // no image found
183 // allocate image structure and buffer
184 NewImage
= egCreateImage(IconSize
, IconSize
, WantAlpha
);
185 if (NewImage
== NULL
)
187 PixelCount
= IconSize
* IconSize
;
189 if (DataLen
< PixelCount
* 3) {
191 // pixel data is compressed, RGB planar
194 egDecompressIcnsRLE(&CompData
, &CompLen
, PLPTR(NewImage
, r
), PixelCount
);
195 egDecompressIcnsRLE(&CompData
, &CompLen
, PLPTR(NewImage
, g
), PixelCount
);
196 egDecompressIcnsRLE(&CompData
, &CompLen
, PLPTR(NewImage
, b
), PixelCount
);
197 // possible assertion: CompLen == 0
199 Print(L
" egLoadICNSIcon: %d bytes of compressed data left\n", CompLen
);
204 // pixel data is uncompressed, RGB interleaved
206 DestPtr
= NewImage
->PixelData
;
207 for (i
= 0; i
< PixelCount
; i
++, DestPtr
++) {
208 DestPtr
->r
= *SrcPtr
++;
209 DestPtr
->g
= *SrcPtr
++;
210 DestPtr
->b
= *SrcPtr
++;
215 // add/set alpha plane
216 if (MaskPtr
!= NULL
&& MaskLen
>= PixelCount
&& WantAlpha
)
217 egInsertPlane(MaskPtr
, PLPTR(NewImage
, a
), PixelCount
);
219 egSetPlane(PLPTR(NewImage
, a
), WantAlpha
? 255 : 0, PixelCount
);
221 // FUTURE: scale to originally requested size if we had to load another size
224 } // EG_IMAGE * egDecodeICNS()