| 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
|
---|