]> Creatis software - clitk.git/blob - utilities/CxImage/ximage.cpp
Debug RTStruct conversion with empty struc
[clitk.git] / utilities / CxImage / ximage.cpp
1 // ximage.cpp : main implementation file
2 /* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it
3  * CxImage version 6.0.0 02/Feb/2008
4  */
5
6 #include "ximage.h"
7
8 ////////////////////////////////////////////////////////////////////////////////
9 // CxImage 
10 ////////////////////////////////////////////////////////////////////////////////
11 /**
12  * Initialize the internal structures
13  */
14 void CxImage::Startup(DWORD imagetype)
15 {
16         //init pointers
17         pDib = pSelection = pAlpha = NULL;
18         ppLayers = ppFrames = NULL;
19         //init structures
20         memset(&head,0,sizeof(BITMAPINFOHEADER));
21         memset(&info,0,sizeof(CXIMAGEINFO));
22         //init default attributes
23     info.dwType = imagetype;
24         info.fQuality = 90.0f;
25         info.nAlphaMax = 255;
26         info.nBkgndIndex = -1;
27         info.bEnabled = true;
28         SetXDPI(CXIMAGE_DEFAULT_DPI);
29         SetYDPI(CXIMAGE_DEFAULT_DPI);
30
31         short test = 1;
32         info.bLittleEndianHost = (*((char *) &test) == 1);
33 }
34 ////////////////////////////////////////////////////////////////////////////////
35 /**
36  * Empty image constructor
37  * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS
38  */
39 CxImage::CxImage(DWORD imagetype)
40 {
41         Startup(imagetype);
42 }
43 ////////////////////////////////////////////////////////////////////////////////
44 /**
45  * Call this function to destroy image pixels, alpha channel, selection and sub layers.
46  * - Attributes are not erased, but IsValid returns false.
47  *
48  * \return true if everything is freed, false if the image is a Ghost
49  */
50 bool CxImage::Destroy()
51 {
52         //free this only if it's valid and it's not a ghost
53         if (info.pGhost==NULL){
54                 if (ppLayers) { 
55                         for(long n=0; n<info.nNumLayers;n++){ delete ppLayers[n]; }
56                         delete [] ppLayers; ppLayers=0; info.nNumLayers = 0;
57                 }
58                 if (pSelection) {free(pSelection); pSelection=0;}
59                 if (pAlpha) {free(pAlpha); pAlpha=0;}
60                 if (pDib) {free(pDib); pDib=0;}
61                 return true;
62         }
63         return false;
64 }
65 ////////////////////////////////////////////////////////////////////////////////
66 bool CxImage::DestroyFrames()
67 {
68         if (info.pGhost==NULL) {
69                 if (ppFrames) {
70                         for (long n=0; n<info.nNumFrames; n++) { delete ppFrames[n]; }
71                         delete [] ppFrames; ppFrames = NULL; info.nNumFrames = 0;
72                 }
73                 return true;
74         }
75         return false;
76 }
77 ////////////////////////////////////////////////////////////////////////////////
78 /**
79  * Sized image constructor
80  * \param dwWidth: width
81  * \param dwHeight: height
82  * \param wBpp: bit per pixel, can be 1, 4, 8, 24
83  * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS
84  */
85 CxImage::CxImage(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype)
86 {
87         Startup(imagetype);
88         Create(dwWidth,dwHeight,wBpp,imagetype);
89 }
90 ////////////////////////////////////////////////////////////////////////////////
91 /**
92  * image constructor from existing source
93  * \param src: source image.
94  * \param copypixels: copy the pixels from the source image into the new image.
95  * \param copyselection: copy the selection from source
96  * \param copyalpha: copy the alpha channel from source
97  * \sa Copy
98  */
99 CxImage::CxImage(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)
100 {
101         Startup(src.GetType());
102         Copy(src,copypixels,copyselection,copyalpha);
103 }
104 ////////////////////////////////////////////////////////////////////////////////
105 /**
106  * Copies the image from an exsisting source
107  * \param src: source image.
108  * \param copypixels: copy the pixels from the source image into the new image.
109  * \param copyselection: copy the selection from source
110  * \param copyalpha: copy the alpha channel from source
111  */
112 void CxImage::Copy(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)
113 {
114         // if the source is a ghost, the copy is still a ghost
115         if (src.info.pGhost){
116                 Ghost(&src);
117                 return;
118         }
119         //copy the attributes
120         memcpy(&info,&src.info,sizeof(CXIMAGEINFO));
121         memcpy(&head,&src.head,sizeof(BITMAPINFOHEADER)); // [andy] - fix for bitmap header DPI
122         //rebuild the image
123         Create(src.GetWidth(),src.GetHeight(),src.GetBpp(),src.GetType());
124         //copy the pixels and the palette, or at least copy the palette only.
125         if (copypixels && pDib && src.pDib) memcpy(pDib,src.pDib,GetSize());
126         else SetPalette(src.GetPalette());
127         long nSize = head.biWidth * head.biHeight;
128         //copy the selection
129         if (copyselection && src.pSelection){
130                 if (pSelection) free(pSelection);
131                 pSelection = (BYTE*)malloc(nSize);
132                 memcpy(pSelection,src.pSelection,nSize);
133         }
134         //copy the alpha channel
135         if (copyalpha && src.pAlpha){
136                 if (pAlpha) free(pAlpha);
137                 pAlpha = (BYTE*)malloc(nSize);
138                 memcpy(pAlpha,src.pAlpha,nSize);
139         }
140 }
141 ////////////////////////////////////////////////////////////////////////////////
142 /**
143  * Copies the image attributes from an existing image.
144  * - Works only on an empty image, and the image will be still empty.
145  * - <b> Use it before Create() </b>
146  */
147 void CxImage::CopyInfo(const CxImage &src)
148 {
149         if (pDib==NULL) memcpy(&info,&src.info,sizeof(CXIMAGEINFO));
150 }
151 ////////////////////////////////////////////////////////////////////////////////
152 /**
153  * \sa Copy
154  */
155 CxImage& CxImage::operator = (const CxImage& isrc)
156 {
157         if (this != &isrc) Copy(isrc);
158         return *this;
159 }
160 ////////////////////////////////////////////////////////////////////////////////
161 /**
162  * Initializes or rebuilds the image.
163  * \param dwWidth: width
164  * \param dwHeight: height
165  * \param wBpp: bit per pixel, can be 1, 4, 8, 24
166  * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS
167  * \return pointer to the internal pDib object; NULL if an error occurs.
168  */
169 void* CxImage::Create(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype)
170 {
171         // destroy the existing image (if any)
172         if (!Destroy())
173                 return NULL;
174
175         // prevent further actions if width or height are not vaild <Balabasnia>
176         if ((dwWidth == 0) || (dwHeight == 0)){
177                 strcpy(info.szLastError,"CxImage::Create : width and height must be greater than zero");
178                 return NULL;
179         }
180
181     // Make sure bits per pixel is valid
182     if          (wBpp <= 1)     wBpp = 1;
183     else if (wBpp <= 4) wBpp = 4;
184     else if (wBpp <= 8) wBpp = 8;
185     else                                wBpp = 24;
186
187         // limit memory requirements (and also a check for bad parameters)
188         if (((dwWidth*dwHeight*wBpp)>>3) > CXIMAGE_MAX_MEMORY ||
189                 ((dwWidth*dwHeight*wBpp)/wBpp) != (dwWidth*dwHeight))
190         {
191                 strcpy(info.szLastError,"CXIMAGE_MAX_MEMORY exceeded");
192                 return NULL;
193         }
194
195         // set the correct bpp value
196     switch (wBpp){
197         case 1:
198             head.biClrUsed = 2; break;
199         case 4:
200             head.biClrUsed = 16; break;
201         case 8:
202             head.biClrUsed = 256; break;
203         default:
204             head.biClrUsed = 0;
205     }
206
207         //set the common image informations
208     info.dwEffWidth = ((((wBpp * dwWidth) + 31) / 32) * 4);
209     info.dwType = imagetype;
210
211     // initialize BITMAPINFOHEADER
212         head.biSize = sizeof(BITMAPINFOHEADER); //<ralphw>
213     head.biWidth = dwWidth;             // fill in width from parameter
214     head.biHeight = dwHeight;   // fill in height from parameter
215     head.biPlanes = 1;                  // must be 1
216     head.biBitCount = (WORD)wBpp;               // from parameter
217     head.biCompression = BI_RGB;    
218     head.biSizeImage = info.dwEffWidth * dwHeight;
219 //    head.biXPelsPerMeter = 0; See SetXDPI
220 //    head.biYPelsPerMeter = 0; See SetYDPI
221 //    head.biClrImportant = 0;  See SetClrImportant
222
223         pDib = malloc(GetSize()); // alloc memory block to store our bitmap
224     if (!pDib){
225                 strcpy(info.szLastError,"CxImage::Create can't allocate memory");
226                 return NULL;
227         }
228
229         //clear the palette
230         RGBQUAD* pal=GetPalette();
231         if (pal) memset(pal,0,GetPaletteSize());
232         //Destroy the existing selection
233 #if CXIMAGE_SUPPORT_SELECTION
234         if (pSelection) SelectionDelete();
235 #endif //CXIMAGE_SUPPORT_SELECTION
236         //Destroy the existing alpha channel
237 #if CXIMAGE_SUPPORT_ALPHA
238         if (pAlpha) AlphaDelete();
239 #endif //CXIMAGE_SUPPORT_ALPHA
240
241     // use our bitmap info structure to fill in first part of
242     // our DIB with the BITMAPINFOHEADER
243     BITMAPINFOHEADER*  lpbi;
244         lpbi = (BITMAPINFOHEADER*)(pDib);
245     *lpbi = head;
246
247         info.pImage=GetBits();
248
249     return pDib; //return handle to the DIB
250 }
251 ////////////////////////////////////////////////////////////////////////////////
252 /**
253  * \return pointer to the image pixels. <b> USE CAREFULLY </b>
254  */
255 BYTE* CxImage::GetBits(DWORD row)
256
257         if (pDib){
258                 if (row) {
259                         if (row<(DWORD)head.biHeight){
260                                 return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize() + (info.dwEffWidth * row));
261                         } else {
262                                 return NULL;
263                         }
264                 } else {
265                         return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize());
266                 }
267         }
268         return NULL;
269 }
270 ////////////////////////////////////////////////////////////////////////////////
271 /**
272  * \return the size in bytes of the internal pDib object
273  */
274 long CxImage::GetSize()
275 {
276         return head.biSize + head.biSizeImage + GetPaletteSize();
277 }
278 ////////////////////////////////////////////////////////////////////////////////
279 /**
280  * Checks if the coordinates are inside the image
281  * \return true if x and y are both inside the image
282  */
283 bool CxImage::IsInside(long x, long y)
284 {
285   return (0<=y && y<head.biHeight && 0<=x && x<head.biWidth);
286 }
287 ////////////////////////////////////////////////////////////////////////////////
288 /**
289  * Sets the image bits to the specified value
290  * - for indexed images, the output color is set by the palette entries.
291  * - for RGB images, the output color is a shade of gray.
292  */
293 void CxImage::Clear(BYTE bval)
294 {
295         if (pDib == 0) return;
296
297         if (GetBpp() == 1){
298                 if (bval > 0) bval = 255;
299         }
300         if (GetBpp() == 4){
301                 bval = (BYTE)(17*(0x0F & bval));
302         }
303
304         memset(info.pImage,bval,head.biSizeImage);
305 }
306 ////////////////////////////////////////////////////////////////////////////////
307 /**
308  * Transfers the image from an existing source image. The source becomes empty.
309  * \return true if everything is ok
310  */
311 bool CxImage::Transfer(CxImage &from, bool bTransferFrames /*=true*/)
312 {
313         if (!Destroy())
314                 return false;
315
316         memcpy(&head,&from.head,sizeof(BITMAPINFOHEADER));
317         memcpy(&info,&from.info,sizeof(CXIMAGEINFO));
318
319         pDib = from.pDib;
320         pSelection = from.pSelection;
321         pAlpha = from.pAlpha;
322         ppLayers = from.ppLayers;
323
324         memset(&from.head,0,sizeof(BITMAPINFOHEADER));
325         memset(&from.info,0,sizeof(CXIMAGEINFO));
326         from.pDib = from.pSelection = from.pAlpha = NULL;
327         from.ppLayers = NULL;
328
329         if (bTransferFrames){
330                 DestroyFrames();
331                 ppFrames = from.ppFrames;
332                 from.ppFrames = NULL;
333         }
334
335         return true;
336 }
337 ////////////////////////////////////////////////////////////////////////////////
338 /**
339  * (this) points to the same pDib owned by (*from), the image remains in (*from)
340  * but (this) has the access to the pixels. <b>Use carefully !!!</b>
341  */
342 void CxImage::Ghost(const CxImage *from)
343 {
344         if (from){
345                 memcpy(&head,&from->head,sizeof(BITMAPINFOHEADER));
346                 memcpy(&info,&from->info,sizeof(CXIMAGEINFO));
347                 pDib = from->pDib;
348                 pSelection = from->pSelection;
349                 pAlpha = from->pAlpha;
350                 ppLayers = from->ppLayers;
351                 ppFrames = from->ppFrames;
352                 info.pGhost=(CxImage *)from;
353         }
354 }
355 ////////////////////////////////////////////////////////////////////////////////
356 /**
357  * turns a 16 or 32 bit bitfield image into a RGB image
358  */
359 void CxImage::Bitfield2RGB(BYTE *src, DWORD redmask, DWORD greenmask, DWORD bluemask, BYTE bpp)
360 {
361         switch (bpp){
362         case 16:
363         {
364                 DWORD ns[3]={0,0,0};
365                 // compute the number of shift for each mask
366                 for (int i=0;i<16;i++){
367                         if ((redmask>>i)&0x01) ns[0]++;
368                         if ((greenmask>>i)&0x01) ns[1]++;
369                         if ((bluemask>>i)&0x01) ns[2]++;
370                 }
371                 ns[1]+=ns[0]; ns[2]+=ns[1];     ns[0]=8-ns[0]; ns[1]-=8; ns[2]-=8;
372                 // dword aligned width for 16 bit image
373                 long effwidth2=(((head.biWidth + 1) / 2) * 4);
374                 WORD w;
375                 long y2,y3,x2,x3;
376                 BYTE *p=info.pImage;
377                 // scan the buffer in reverse direction to avoid reallocations
378                 for (long y=head.biHeight-1; y>=0; y--){
379                         y2=effwidth2*y;
380                         y3=info.dwEffWidth*y;
381                         for (long x=head.biWidth-1; x>=0; x--){
382                                 x2 = 2*x+y2;
383                                 x3 = 3*x+y3;
384                                 w = (WORD)(src[x2]+256*src[1+x2]);
385                                 p[  x3]=(BYTE)((w & bluemask)<<ns[0]);
386                                 p[1+x3]=(BYTE)((w & greenmask)>>ns[1]);
387                                 p[2+x3]=(BYTE)((w & redmask)>>ns[2]);
388                         }
389                 }
390                 break;
391         }
392         case 32:
393         {
394                 DWORD ns[3]={0,0,0};
395                 // compute the number of shift for each mask
396                 for (int i=8;i<32;i+=8){
397                         if (redmask>>i) ns[0]++;
398                         if (greenmask>>i) ns[1]++;
399                         if (bluemask>>i) ns[2]++;
400                 }
401                 // dword aligned width for 32 bit image
402                 long effwidth4 = head.biWidth * 4;
403                 long y4,y3,x4,x3;
404                 BYTE *p=info.pImage;
405                 // scan the buffer in reverse direction to avoid reallocations
406                 for (long y=head.biHeight-1; y>=0; y--){
407                         y4=effwidth4*y;
408                         y3=info.dwEffWidth*y;
409                         for (long x=head.biWidth-1; x>=0; x--){
410                                 x4 = 4*x+y4;
411                                 x3 = 3*x+y3;
412                                 p[  x3]=src[ns[2]+x4];
413                                 p[1+x3]=src[ns[1]+x4];
414                                 p[2+x3]=src[ns[0]+x4];
415                         }
416                 }
417         }
418
419         }
420         return;
421 }
422 ////////////////////////////////////////////////////////////////////////////////
423 /**
424  * Creates an image from a generic buffer
425  * \param pArray: source memory buffer
426  * \param dwWidth: image width
427  * \param dwHeight: image height
428  * \param dwBitsperpixel: can be 1,4,8,24,32
429  * \param dwBytesperline: line alignment, in bytes, for a single row stored in pArray
430  * \param bFlipImage: tune this parameter if the image is upsidedown
431  * \return true if everything is ok
432  */
433 bool CxImage::CreateFromArray(BYTE* pArray,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage)
434 {
435         if (pArray==NULL) return false;
436         if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||
437                 (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;
438
439         if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;
440
441         if (dwBitsperpixel<24) SetGrayPalette();
442
443 #if CXIMAGE_SUPPORT_ALPHA
444         if (dwBitsperpixel==32) AlphaCreate();
445 #endif //CXIMAGE_SUPPORT_ALPHA
446
447         BYTE *dst,*src;
448
449         for (DWORD y = 0; y<dwHeight; y++) {
450                 dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;
451                 src = pArray + y * dwBytesperline;
452                 if (dwBitsperpixel==32){
453                         for(DWORD x=0;x<dwWidth;x++){
454                                 *dst++=src[0];
455                                 *dst++=src[1];
456                                 *dst++=src[2];
457 #if CXIMAGE_SUPPORT_ALPHA
458                                 AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);
459 #endif //CXIMAGE_SUPPORT_ALPHA
460                                 src+=4;
461                         }
462                 } else {
463                         memcpy(dst,src,__min(info.dwEffWidth,dwBytesperline));
464                 }
465         }
466         return true;
467 }
468 ////////////////////////////////////////////////////////////////////////////////
469 /**
470  * \sa CreateFromArray
471  */
472 bool CxImage::CreateFromMatrix(BYTE** ppMatrix,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage)
473 {
474         if (ppMatrix==NULL) return false;
475         if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||
476                 (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;
477
478         if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;
479
480         if (dwBitsperpixel<24) SetGrayPalette();
481
482 #if CXIMAGE_SUPPORT_ALPHA
483         if (dwBitsperpixel==32) AlphaCreate();
484 #endif //CXIMAGE_SUPPORT_ALPHA
485
486         BYTE *dst,*src;
487
488         for (DWORD y = 0; y<dwHeight; y++) {
489                 dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;
490                 src = ppMatrix[y];
491                 if (src){
492                         if (dwBitsperpixel==32){
493                                 for(DWORD x=0;x<dwWidth;x++){
494                                         *dst++=src[0];
495                                         *dst++=src[1];
496                                         *dst++=src[2];
497 #if CXIMAGE_SUPPORT_ALPHA
498                                         AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);
499 #endif //CXIMAGE_SUPPORT_ALPHA
500                                         src+=4;
501                                 }
502                         } else {
503                                 memcpy(dst,src,__min(info.dwEffWidth,dwBytesperline));
504                         }
505                 }
506         }
507         return true;
508 }
509 ////////////////////////////////////////////////////////////////////////////////
510 /**
511  * \return lightness difference between elem1 and elem2
512  */
513 int CxImage::CompareColors(const void *elem1, const void *elem2)
514 {
515         RGBQUAD* c1 = (RGBQUAD*)elem1;
516         RGBQUAD* c2 = (RGBQUAD*)elem2;
517
518         int g1 = (int)RGB2GRAY(c1->rgbRed,c1->rgbGreen,c1->rgbBlue);
519         int g2 = (int)RGB2GRAY(c2->rgbRed,c2->rgbGreen,c2->rgbBlue);
520         
521         return (g1-g2);
522 }
523 ////////////////////////////////////////////////////////////////////////////////
524 /**
525  * simply calls "if (memblock) free(memblock);".
526  * Useful when calling Encode for a memory buffer,
527  * from a DLL compiled with different memory management options.
528  * CxImage::FreeMemory will use the same memory environment used by Encode. 
529  * \author [livecn]
530  */
531 void CxImage::FreeMemory(void* memblock)
532 {
533         if (memblock)
534                 free(memblock);
535 }
536 ////////////////////////////////////////////////////////////////////////////////
537 //EOF