source: liacs/MIR2010/SourceCode/cximage/ximaico.cpp@ 140

Last change on this file since 140 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

File size: 14.0 KB
Line 
1/*
2 * File: ximaico.cpp
3 * Purpose: Platform Independent ICON Image Class Loader and Writer (MS version)
4 * 07/Aug/2001 Davide Pizzolato - www.xdp.it
5 * CxImage version 6.0.0 02/Feb/2008
6 */
7
8#include "ximaico.h"
9
10#if CXIMAGE_SUPPORT_ICO
11
12////////////////////////////////////////////////////////////////////////////////
13#if CXIMAGE_SUPPORT_DECODE
14////////////////////////////////////////////////////////////////////////////////
15bool CxImageICO::Decode(CxFile *hFile)
16{
17 if (hFile==NULL) return false;
18
19 DWORD off = hFile->Tell(); //<yuandi>
20 int page=info.nFrame; //internal icon structure indexes
21
22 // read the first part of the header
23 ICONHEADER icon_header;
24 hFile->Read(&icon_header,sizeof(ICONHEADER),1);
25
26 icon_header.idType = ntohs(icon_header.idType);
27 icon_header.idCount = ntohs(icon_header.idCount);
28
29 // check if it's an icon or a cursor
30 if ((icon_header.idReserved == 0) && ((icon_header.idType == 1)||(icon_header.idType == 2))) {
31
32 info.nNumFrames = icon_header.idCount;
33
34 // load the icon descriptions
35 ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header.idCount * sizeof(ICONDIRENTRY));
36 int c;
37 for (c = 0; c < icon_header.idCount; c++) {
38 hFile->Read(icon_list + c, sizeof(ICONDIRENTRY), 1);
39
40 icon_list[c].wPlanes = ntohs(icon_list[c].wPlanes);
41 icon_list[c].wBitCount = ntohs(icon_list[c].wBitCount);
42 icon_list[c].dwBytesInRes = ntohl(icon_list[c].dwBytesInRes);
43 icon_list[c].dwImageOffset = ntohl(icon_list[c].dwImageOffset);
44 }
45
46 if ((page>=0)&&(page<icon_header.idCount)){
47
48 if (info.nEscape == -1) {
49 // Return output dimensions only
50 head.biWidth = icon_list[page].bWidth;
51 head.biHeight = icon_list[page].bHeight;
52#if CXIMAGE_SUPPORT_PNG
53 if (head.biWidth==0 && head.biHeight==0)
54 { // Vista icon support
55 hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);
56 CxImage png;
57 png.SetEscape(-1);
58 if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){
59 Transfer(png);
60 info.nNumFrames = icon_header.idCount;
61 }
62 }
63#endif //CXIMAGE_SUPPORT_PNG
64 free(icon_list);
65 info.dwType = CXIMAGE_FORMAT_ICO;
66 return true;
67 }
68
69 // get the bit count for the colors in the icon <CoreyRLucier>
70 BITMAPINFOHEADER bih;
71 hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);
72
73 if (icon_list[page].bWidth==0 && icon_list[page].bHeight==0)
74 { // Vista icon support
75#if CXIMAGE_SUPPORT_PNG
76 CxImage png;
77 if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){
78 Transfer(png);
79 info.nNumFrames = icon_header.idCount;
80 }
81 SetType(CXIMAGE_FORMAT_ICO);
82#endif //CXIMAGE_SUPPORT_PNG
83 }
84 else
85 { // standard icon
86 hFile->Read(&bih,sizeof(BITMAPINFOHEADER),1);
87
88 bihtoh(&bih);
89
90 c = bih.biBitCount;
91
92 // allocate memory for one icon
93 Create(icon_list[page].bWidth,icon_list[page].bHeight, c, CXIMAGE_FORMAT_ICO); //image creation
94
95 // read the palette
96 RGBQUAD pal[256];
97 if (bih.biClrUsed)
98 hFile->Read(pal,bih.biClrUsed*sizeof(RGBQUAD), 1);
99 else
100 hFile->Read(pal,head.biClrUsed*sizeof(RGBQUAD), 1);
101
102 SetPalette(pal,head.biClrUsed); //palette assign
103
104 //read the icon
105 if (c<=24){
106 hFile->Read(info.pImage, head.biSizeImage, 1);
107 } else { // 32 bit icon
108 BYTE* buf=(BYTE*)malloc(4*head.biHeight*head.biWidth);
109 BYTE* src = buf;
110 hFile->Read(buf, 4*head.biHeight*head.biWidth, 1);
111#if CXIMAGE_SUPPORT_ALPHA
112 if (!AlphaIsValid()) AlphaCreate();
113#endif //CXIMAGE_SUPPORT_ALPHA
114 for (long y = 0; y < head.biHeight; y++) {
115 BYTE* dst = GetBits(y);
116 for(long x=0;x<head.biWidth;x++){
117 *dst++=src[0];
118 *dst++=src[1];
119 *dst++=src[2];
120#if CXIMAGE_SUPPORT_ALPHA
121 AlphaSet(x,y,src[3]);
122#endif //CXIMAGE_SUPPORT_ALPHA
123 src+=4;
124 }
125 }
126 free(buf);
127 }
128 // apply the AND and XOR masks
129 int maskwdt = ((head.biWidth+31) / 32) * 4; //line width of AND mask (always 1 Bpp)
130 int masksize = head.biHeight * maskwdt; //size of mask
131 BYTE *mask = (BYTE *)malloc(masksize);
132 if (hFile->Read(mask, masksize, 1)){
133
134 bool bGoodMask=false;
135 for (int im=0;im<masksize;im++){
136 if (mask[im]!=255){
137 bGoodMask=true;
138 break;
139 }
140 }
141
142 if (bGoodMask){
143#if CXIMAGE_SUPPORT_ALPHA
144 bool bNeedAlpha = false;
145 if (!AlphaIsValid()){
146 AlphaCreate();
147 } else {
148 bNeedAlpha=true; //32bit icon
149 }
150 int x,y;
151 for (y = 0; y < head.biHeight; y++) {
152 for (x = 0; x < head.biWidth; x++) {
153 if (((mask[y*maskwdt+(x>>3)]>>(7-x%8))&0x01)){
154 AlphaSet(x,y,0);
155 bNeedAlpha=true;
156 }
157 }
158 }
159 if (!bNeedAlpha) AlphaDelete();
160#endif //CXIMAGE_SUPPORT_ALPHA
161
162 //check if there is only one transparent color
163 RGBQUAD cc,ct;
164 long* pcc = (long*)&cc;
165 long* pct = (long*)&ct;
166 int nTransColors=0;
167 int nTransIndex=0;
168 for (y = 0; y < head.biHeight; y++){
169 for (x = 0; x < head.biWidth; x++){
170 if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){
171 cc = GetPixelColor(x,y,false);
172 if (nTransColors==0){
173 nTransIndex = GetPixelIndex(x,y);
174 nTransColors++;
175 ct = cc;
176 } else {
177 if (*pct!=*pcc){
178 nTransColors++;
179 }
180 }
181 }
182 }
183 }
184 if (nTransColors==1){
185 SetTransColor(ct);
186 SetTransIndex(nTransIndex);
187#if CXIMAGE_SUPPORT_ALPHA
188 AlphaDelete(); //because we have a unique transparent color in the image
189#endif //CXIMAGE_SUPPORT_ALPHA
190 }
191
192 // <vho> - Transparency support w/o Alpha support
193 if (c <= 8){ // only for icons with less than 256 colors (XP icons need alpha).
194
195 // find a color index, which is not used in the image
196 // it is almost sure to find one, bcs. nobody uses all possible colors for an icon
197
198 BYTE colorsUsed[256];
199 memset(colorsUsed, 0, sizeof(colorsUsed));
200
201 for (y = 0; y < head.biHeight; y++){
202 for (x = 0; x < head.biWidth; x++){
203 colorsUsed[BlindGetPixelIndex(x,y)] = 1;
204 }
205 }
206
207 int iTransIdx = -1;
208 for (x = (int)(head.biClrUsed-1); x>=0 ; x--){
209 if (colorsUsed[x] == 0){
210 iTransIdx = x; // this one is not in use. we may use it as transparent color
211 break;
212 }
213 }
214
215 // Go thru image and set unused color as transparent index if needed
216 if (iTransIdx >= 0){
217 bool bNeedTrans = false;
218 for (y = 0; y < head.biHeight; y++){
219 for (x = 0; x < head.biWidth; x++){
220 // AND mask (Each Byte represents 8 Pixels)
221 if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){
222 // AND mask is set (!=0). This is a transparent part
223 SetPixelIndex(x, y, (BYTE)iTransIdx);
224 bNeedTrans = true;
225 }
226 }
227 }
228 // set transparent index if needed
229 if (bNeedTrans) SetTransIndex(iTransIdx);
230#if CXIMAGE_SUPPORT_ALPHA
231 AlphaDelete(); //because we have a transparent color in the palette
232#endif //CXIMAGE_SUPPORT_ALPHA
233 }
234 }
235 } else {
236 SetTransIndex(0); //empty mask, set black as transparent color
237 Negative();
238 }
239 }
240 free(mask);
241 }
242 free(icon_list);
243 // icon has been loaded successfully!
244 return true;
245 }
246 free(icon_list);
247 }
248 return false;
249}
250////////////////////////////////////////////////////////////////////////////////
251#endif //CXIMAGE_SUPPORT_DECODE
252////////////////////////////////////////////////////////////////////////////////
253#if CXIMAGE_SUPPORT_ENCODE
254////////////////////////////////////////////////////////////////////////////////
255// Thanks to <Alas>
256bool CxImageICO::Encode(CxFile * hFile, CxImage ** pImages, int nPageCount)
257{
258 cx_try
259 {
260 if (hFile==NULL) cx_throw("invalid file pointer");
261 if (pImages==NULL || nPageCount<=0) cx_throw("multipage ICO, no images!");
262
263 int i;
264 for (i=0; i<nPageCount; i++){
265 if (pImages[i]==NULL)
266 cx_throw("Bad image pointer");
267 if (!(pImages[i]->IsValid()))
268 cx_throw("Empty image");
269 }
270
271 CxImageICO ghost;
272 for (i=0; i<nPageCount; i++){ //write headers
273 ghost.Ghost(pImages[i]);
274 ghost.info.nNumFrames = nPageCount;
275 if (i==0) {
276 if (!ghost.Encode(hFile,false,nPageCount))
277 cx_throw("Error writing ICO file header");
278 }
279 if (!ghost.Encode(hFile,true,nPageCount))
280 cx_throw("Error saving ICO image header");
281 }
282 for (i=0; i<nPageCount; i++){ //write bodies
283 ghost.Ghost(pImages[i]);
284 ghost.info.nNumFrames = nPageCount;
285 if (!ghost.Encode(hFile,true,i))
286 cx_throw("Error saving ICO body");
287 }
288
289 } cx_catch {
290 if (strcmp(message,"")) strncpy(info.szLastError,message,255);
291 return false;
292 }
293 return true;
294}
295////////////////////////////////////////////////////////////////////////////////
296bool CxImageICO::Encode(CxFile * hFile, bool bAppend, int nPageCount)
297{
298 if (EncodeSafeCheck(hFile)) return false;
299
300#if CXIMAGE_SUPPORT_PNG == 0
301 //check format limits
302 if ((head.biWidth>255)||(head.biHeight>255)){
303 strcpy(info.szLastError,"Can't save this image as icon");
304 return false;
305 }
306#endif
307
308 //prepare the palette struct
309 RGBQUAD* pal=GetPalette();
310 if (head.biBitCount<=8 && pal==NULL) return false;
311
312 int maskwdt=((head.biWidth+31)/32)*4; //mask line width
313 int masksize=head.biHeight * maskwdt; //size of mask
314 int bitcount=head.biBitCount;
315 int imagesize=head.biSizeImage;
316#if CXIMAGE_SUPPORT_ALPHA
317 if (AlphaIsValid() && head.biClrUsed==0){
318 bitcount=32;
319 imagesize=4*head.biHeight*head.biWidth;
320 }
321#endif
322
323 //fill the icon headers
324 int nPages = nPageCount;
325 if (nPages<1) nPages = 1;
326
327 ICONHEADER icon_header={0,1,nPages};
328
329 if (!bAppend)
330 m_dwImageOffset = sizeof(ICONHEADER) + nPages * sizeof(ICONDIRENTRY);
331
332 DWORD dwBytesInRes = sizeof(BITMAPINFOHEADER)+head.biClrUsed*sizeof(RGBQUAD)+imagesize+masksize;
333
334 ICONDIRENTRY icon_list={
335 (BYTE)head.biWidth,
336 (BYTE)head.biHeight,
337 (BYTE)head.biClrUsed,
338 0, 0,
339 (WORD)bitcount,
340 dwBytesInRes,
341 m_dwImageOffset
342 };
343
344 BITMAPINFOHEADER bi={
345 sizeof(BITMAPINFOHEADER),
346 head.biWidth,
347 2*head.biHeight,
348 1,
349 (WORD)bitcount,
350 0, imagesize,
351 0, 0, 0, 0
352 };
353
354#if CXIMAGE_SUPPORT_PNG // Vista icon support
355 CxImage png(*this);
356 CxMemFile memfile;
357 if (head.biWidth>255 || head.biHeight>255){
358 icon_list.bWidth = icon_list.bHeight = 0;
359 memfile.Open();
360 png.Encode(&memfile,CXIMAGE_FORMAT_PNG);
361 icon_list.dwBytesInRes = dwBytesInRes = memfile.Size();
362 }
363#endif //CXIMAGE_SUPPORT_PNG
364
365 if (!bAppend){
366 icon_header.idType = ntohs(icon_header.idType);
367 icon_header.idCount = ntohs(icon_header.idCount);
368 hFile->Write(&icon_header,sizeof(ICONHEADER),1); //write the file header
369 icon_header.idType = ntohs(icon_header.idType);
370 icon_header.idCount = ntohs(icon_header.idCount);
371 }
372
373
374 if ((bAppend && nPageCount==info.nNumFrames) || (!bAppend && nPageCount==0)){
375 icon_list.wPlanes = ntohs(icon_list.wPlanes);
376 icon_list.wBitCount = ntohs(icon_list.wBitCount);
377 icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes);
378 icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset);
379 hFile->Write(&icon_list,sizeof(ICONDIRENTRY),1); //write the image entry
380 icon_list.wPlanes = ntohs(icon_list.wPlanes);
381 icon_list.wBitCount = ntohs(icon_list.wBitCount);
382 icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes);
383 icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset);
384
385 m_dwImageOffset += dwBytesInRes; //update offset for next header
386 }
387
388 if ((bAppend && nPageCount<info.nNumFrames) || (!bAppend && nPageCount==0))
389 {
390#if CXIMAGE_SUPPORT_PNG
391 if (icon_list.bWidth==0 && icon_list.bHeight==0) { // Vista icon support
392 hFile->Write(memfile.GetBuffer(false),dwBytesInRes,1);
393 } else
394#endif //CXIMAGE_SUPPORT_PNG
395 { // standard icon
396 bihtoh(&bi);
397 hFile->Write(&bi,sizeof(BITMAPINFOHEADER),1); //write the image header
398 bihtoh(&bi);
399
400 bool bTransparent = info.nBkgndIndex >= 0;
401 RGBQUAD ct = GetTransColor();
402 if (pal){
403 if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,0,0,0,0);
404 hFile->Write(pal,head.biClrUsed*sizeof(RGBQUAD),1); //write palette
405 if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,ct);
406 }
407
408#if CXIMAGE_SUPPORT_ALPHA
409 if (AlphaIsValid() && head.biClrUsed==0){
410 BYTE* buf=(BYTE*)malloc(imagesize);
411 BYTE* dst = buf;
412 for (long y = 0; y < head.biHeight; y++) {
413 BYTE* src = GetBits(y);
414 for(long x=0;x<head.biWidth;x++){
415 *dst++=*src++;
416 *dst++=*src++;
417 *dst++=*src++;
418 *dst++=AlphaGet(x,y);
419 }
420 }
421 hFile->Write(buf,imagesize, 1);
422 free(buf);
423 } else {
424 hFile->Write(info.pImage,imagesize,1); //write image
425 }
426#else
427 hFile->Write(info.pImage,imagesize,1); //write image
428#endif
429
430 //save transparency mask
431 BYTE* mask=(BYTE*)calloc(masksize,1); //create empty AND/XOR masks
432 if (!mask) return false;
433
434 //prepare the variables to build the mask
435 BYTE* iDst;
436 int pos,i;
437 RGBQUAD c={0,0,0,0};
438 long* pc = (long*)&c;
439 long* pct= (long*)&ct;
440#if CXIMAGE_SUPPORT_ALPHA
441 bool bAlphaPaletteIsValid = AlphaPaletteIsValid();
442 bool bAlphaIsValid = AlphaIsValid();
443#endif
444 //build the mask
445 for (int y = 0; y < head.biHeight; y++) {
446 for (int x = 0; x < head.biWidth; x++) {
447 i=0;
448#if CXIMAGE_SUPPORT_ALPHA
449 if (bAlphaIsValid && AlphaGet(x,y)==0) i=1;
450 if (bAlphaPaletteIsValid && BlindGetPixelColor(x,y).rgbReserved==0) i=1;
451#endif
452 c=GetPixelColor(x,y,false);
453 if (bTransparent && *pc==*pct) i=1;
454 iDst = mask + y*maskwdt + (x>>3);
455 pos = 7-x%8;
456 *iDst &= ~(0x01<<pos);
457 *iDst |= ((i & 0x01)<<pos);
458 }
459 }
460 //write AND/XOR masks
461 hFile->Write(mask,masksize,1);
462 free(mask);
463 }
464 }
465
466 return true;
467}
468////////////////////////////////////////////////////////////////////////////////
469#endif // CXIMAGE_SUPPORT_ENCODE
470////////////////////////////////////////////////////////////////////////////////
471#endif // CXIMAGE_SUPPORT_ICO
472
Note: See TracBrowser for help on using the repository browser.