1 | /*␊ |
2 | * libeg/load_icns.c␊ |
3 | * Loading function for .icns Apple icon images␊ |
4 | *␊ |
5 | * Copyright (c) 2006 Christoph Pfisterer␊ |
6 | * All rights reserved.␊ |
7 | *␊ |
8 | * Redistribution and use in source and binary forms, with or without␊ |
9 | * modification, are permitted provided that the following conditions are␊ |
10 | * met:␊ |
11 | *␊ |
12 | * * Redistributions of source code must retain the above copyright␊ |
13 | * notice, this list of conditions and the following disclaimer.␊ |
14 | *␊ |
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␊ |
18 | * distribution.␊ |
19 | *␊ |
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.␊ |
23 | *␊ |
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.␊ |
35 | */␊ |
36 | ␊ |
37 | #include "libegint.h"␊ |
38 | ␊ |
39 | //␊ |
40 | // Decompress .icns RLE data␊ |
41 | //␊ |
42 | ␊ |
43 | VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT8 *PixelData, IN UINTN PixelCount)␊ |
44 | {␊ |
45 | UINT8 *cp;␊ |
46 | UINT8 *cp_end;␊ |
47 | UINT8 *pp;␊ |
48 | UINTN pp_left;␊ |
49 | UINTN len, i;␊ |
50 | UINT8 value;␊ |
51 | ␊ |
52 | // setup variables␊ |
53 | cp = *CompData;␊ |
54 | cp_end = cp + *CompLen;␊ |
55 | pp = PixelData;␊ |
56 | pp_left = PixelCount;␊ |
57 | ␊ |
58 | // decode␊ |
59 | while (cp + 1 < cp_end && pp_left > 0) {␊ |
60 | len = *cp++;␊ |
61 | if (len & 0x80) { // compressed data: repeat next byte␊ |
62 | len -= 125;␊ |
63 | if (len > pp_left)␊ |
64 | break;␊ |
65 | value = *cp++;␊ |
66 | for (i = 0; i < len; i++) {␊ |
67 | *pp = value;␊ |
68 | pp += 4;␊ |
69 | }␊ |
70 | } else { // uncompressed data: copy bytes␊ |
71 | len++;␊ |
72 | if (len > pp_left || cp + len > cp_end)␊ |
73 | break;␊ |
74 | for (i = 0; i < len; i++) {␊ |
75 | *pp = *cp++;␊ |
76 | pp += 4;␊ |
77 | }␊ |
78 | }␊ |
79 | pp_left -= len;␊ |
80 | }␊ |
81 | ␊ |
82 | if (pp_left > 0) {␊ |
83 | printf(" egDecompressIcnsRLE: still need %d bytes of pixel data\n", pp_left);␊ |
84 | }␊ |
85 | ␊ |
86 | // record what's left of the compressed data stream␊ |
87 | *CompData = cp;␊ |
88 | *CompLen = (UINTN)(cp_end - cp);␊ |
89 | }␊ |
90 | ␊ |
91 | //␊ |
92 | // Load Apple .icns icons␊ |
93 | //␊ |
94 | ␊ |
95 | EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha)␊ |
96 | {␊ |
97 | EG_IMAGE *NewImage;␊ |
98 | UINT8 *Ptr, *BufferEnd, *DataPtr, *MaskPtr;␊ |
99 | UINT32 BlockLen, DataLen, MaskLen;␊ |
100 | UINTN FetchPixelSize, PixelCount, i;␊ |
101 | UINT8 *CompData;␊ |
102 | UINTN CompLen;␊ |
103 | UINT8 *SrcPtr;␊ |
104 | EG_PIXEL *DestPtr;␊ |
105 | ␊ |
106 | if (FileDataLength < 8 || FileData == NULL ||␊ |
107 | FileData[0] != 'i' || FileData[1] != 'c' || FileData[2] != 'n' || FileData[3] != 's') {␊ |
108 | // not an icns file...␊ |
109 | return NULL;␊ |
110 | }␊ |
111 | ␊ |
112 | FetchPixelSize = IconSize;␊ |
113 | for (;;) {␊ |
114 | DataPtr = NULL;␊ |
115 | DataLen = 0;␊ |
116 | MaskPtr = NULL;␊ |
117 | MaskLen = 0;␊ |
118 | ␊ |
119 | Ptr = FileData + 8;␊ |
120 | BufferEnd = FileData + FileDataLength;␊ |
121 | // iterate over tagged blocks in the file␊ |
122 | while (Ptr + 8 <= BufferEnd) {␊ |
123 | BlockLen = ((UINT32)Ptr[4] << 24) + ((UINT32)Ptr[5] << 16) + ((UINT32)Ptr[6] << 8) + (UINT32)Ptr[7];␊ |
124 | if (Ptr + BlockLen > BufferEnd) // block continues beyond end of file␊ |
125 | break;␊ |
126 | ␊ |
127 | // extract the appropriate blocks for each pixel size␊ |
128 | if (FetchPixelSize == 128) {␊ |
129 | if (Ptr[0] == 'i' && Ptr[1] == 't' && Ptr[2] == '3' && Ptr[3] == '2') {␊ |
130 | if (Ptr[8] == 0 && Ptr[9] == 0 && Ptr[10] == 0 && Ptr[11] == 0) {␊ |
131 | DataPtr = Ptr + 12;␊ |
132 | DataLen = BlockLen - 12;␊ |
133 | }␊ |
134 | } else if (Ptr[0] == 't' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {␊ |
135 | MaskPtr = Ptr + 8;␊ |
136 | MaskLen = BlockLen - 8;␊ |
137 | }␊ |
138 | ␊ |
139 | } else if (FetchPixelSize == 48) {␊ |
140 | if (Ptr[0] == 'i' && Ptr[1] == 'h' && Ptr[2] == '3' && Ptr[3] == '2') {␊ |
141 | DataPtr = Ptr + 8;␊ |
142 | DataLen = BlockLen - 8;␊ |
143 | } else if (Ptr[0] == 'h' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {␊ |
144 | MaskPtr = Ptr + 8;␊ |
145 | MaskLen = BlockLen - 8;␊ |
146 | }␊ |
147 | ␊ |
148 | } else if (FetchPixelSize == 32) {␊ |
149 | if (Ptr[0] == 'i' && Ptr[1] == 'l' && Ptr[2] == '3' && Ptr[3] == '2') {␊ |
150 | DataPtr = Ptr + 8;␊ |
151 | DataLen = BlockLen - 8;␊ |
152 | } else if (Ptr[0] == 'l' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {␊ |
153 | MaskPtr = Ptr + 8;␊ |
154 | MaskLen = BlockLen - 8;␊ |
155 | }␊ |
156 | ␊ |
157 | } else if (FetchPixelSize == 16) {␊ |
158 | if (Ptr[0] == 'i' && Ptr[1] == 's' && Ptr[2] == '3' && Ptr[3] == '2') {␊ |
159 | DataPtr = Ptr + 8;␊ |
160 | DataLen = BlockLen - 8;␊ |
161 | } else if (Ptr[0] == 's' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {␊ |
162 | MaskPtr = Ptr + 8;␊ |
163 | MaskLen = BlockLen - 8;␊ |
164 | }␊ |
165 | ␊ |
166 | }␊ |
167 | ␊ |
168 | Ptr += BlockLen;␊ |
169 | }␊ |
170 | ␊ |
171 | /* FUTURE: try to load a different size and scale it later␊ |
172 | if (DataPtr == NULL && FetchPixelSize == 32) {␊ |
173 | FetchPixelSize = 128;␊ |
174 | continue;␊ |
175 | }␊ |
176 | */␊ |
177 | break;␊ |
178 | }␊ |
179 | ␊ |
180 | if (DataPtr == NULL)␊ |
181 | return NULL; // no image found␊ |
182 | ␊ |
183 | // allocate image structure and buffer␊ |
184 | NewImage = egCreateImage(FetchPixelSize, FetchPixelSize, WantAlpha);␊ |
185 | if (NewImage == NULL)␊ |
186 | return NULL;␊ |
187 | PixelCount = FetchPixelSize * FetchPixelSize;␊ |
188 | ␊ |
189 | if (DataLen < PixelCount * 3) {␊ |
190 | ␊ |
191 | // pixel data is compressed, RGB planar␊ |
192 | CompData = DataPtr;␊ |
193 | CompLen = DataLen;␊ |
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␊ |
198 | if (CompLen > 0) {␊ |
199 | printf(" egLoadICNSIcon: %d bytes of compressed data left\n", CompLen);␊ |
200 | }␊ |
201 | ␊ |
202 | } else {␊ |
203 | ␊ |
204 | // pixel data is uncompressed, RGB interleaved␊ |
205 | SrcPtr = DataPtr;␊ |
206 | DestPtr = NewImage->PixelData;␊ |
207 | for (i = 0; i < PixelCount; i++, DestPtr++) {␊ |
208 | DestPtr->r = *SrcPtr++;␊ |
209 | DestPtr->g = *SrcPtr++;␊ |
210 | DestPtr->b = *SrcPtr++;␊ |
211 | }␊ |
212 | ␊ |
213 | }␊ |
214 | ␊ |
215 | // add/set alpha plane␊ |
216 | if (MaskPtr != NULL && MaskLen >= PixelCount && WantAlpha)␊ |
217 | egInsertPlane(MaskPtr, PLPTR(NewImage, a), PixelCount);␊ |
218 | else␊ |
219 | egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount);␊ |
220 | ␊ |
221 | // FUTURE: scale to originally requested size if we had to load another size␊ |
222 | ␊ |
223 | return NewImage;␊ |
224 | }␊ |
225 | ␊ |
226 | /* EOF */␊ |
227 | |