source: liacs/MIR2010/SourceCode/cximage/ximage.cpp@ 147

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

Bad boy, improper move of directory

File size: 16.3 KB
Line 
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 */
14void 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 */
39CxImage::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 */
50bool 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////////////////////////////////////////////////////////////////////////////////
66bool 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 */
85CxImage::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 */
99CxImage::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 */
112void 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 */
147void CxImage::CopyInfo(const CxImage &src)
148{
149 if (pDib==NULL) memcpy(&info,&src.info,sizeof(CXIMAGEINFO));
150}
151////////////////////////////////////////////////////////////////////////////////
152/**
153 * \sa Copy
154 */
155CxImage& 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 */
169void* 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 */
255BYTE* 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 */
274long 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 */
283bool 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 */
293void 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 */
311bool 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 */
342void 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 */
359void 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 */
433bool 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 */
472bool 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 */
513int 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 */
531void CxImage::FreeMemory(void* memblock)
532{
533 if (memblock)
534 free(memblock);
535}
536////////////////////////////////////////////////////////////////////////////////
537//EOF
Note: See TracBrowser for help on using the repository browser.