00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "plstdpch.h"
00016 #include "plbitmap.h"
00017 #include "plexcept.h"
00018 #include "plfilterquantize.h"
00019 #include "plpixel24.h"
00020 #include "plpixel32.h"
00021
00022 template<class DestPixelC>
00023 void createTrueColorCopy (PLBmp & rDestBmp, const PLBmp & rSrcBmp,
00024 DestPixelC Dummy);
00025
00026
00027
00028
00029
00030 PLBmp::PLBmp ()
00031 : PLObject(),
00032 m_Resolution (0,0),
00033 m_LockCount(0),
00034 m_DitherType(PLDTH_NONE),
00035 m_DitherPaletteType(PLDTHPAL_DEFAULT)
00036 {
00037 }
00038
00039
00040 PLBmp::~PLBmp
00041 ()
00042 {
00043 PLASSERT (m_LockCount == 0);
00044 }
00045
00046 bool const PLBmp::operator ==
00047 ( PLBmp const &Other
00048 )
00049 {
00050 return AlmostEqual (Other, 0);
00051
00052 }
00053
00054
00055
00056 template<class DestPixelC>
00057 void createTrueColorCopy (PLBmp & rDestBmp, const PLBmp & rSrcBmp,
00058 DestPixelC Dummy)
00059 {
00060
00061 PLASSERT (rDestBmp.GetBitsPerPixel() == sizeof (DestPixelC)*8);
00062
00063 int BPPSrc = rSrcBmp.GetBitsPerPixel();
00064 rDestBmp.Lock(false, true);
00065
00066
00067 const_cast<PLBmp &>(rSrcBmp).Lock(true, false);
00068 PLBYTE ** pSrcLines = rSrcBmp.GetLineArray();
00069 DestPixelC ** pDstLines = (DestPixelC**) rDestBmp.GetLineArray();
00070 int SrcLineLen = rSrcBmp.GetWidth();
00071
00072 for (int y = 0; y<rSrcBmp.GetHeight(); ++y)
00073 {
00074 DestPixelC * pDstPixel = pDstLines[y];
00075 switch (BPPSrc)
00076 {
00077 case 32:
00078 {
00079 PLPixel32 * pSrcPixel = (PLPixel32 *)pSrcLines[y];
00080 for (int x = 0; x < SrcLineLen; ++x)
00081 {
00082 *pDstPixel = *pSrcPixel;
00083 ++pSrcPixel;
00084 ++pDstPixel;
00085 }
00086 }
00087 break;
00088 case 24:
00089 {
00090 PLPixel24 * pSrcPixel = (PLPixel24 *)pSrcLines[y];
00091 for (int x = 0; x < SrcLineLen; ++x)
00092 {
00093 *pDstPixel = *pSrcPixel;
00094 ++pSrcPixel;
00095 ++pDstPixel;
00096 }
00097 }
00098 break;
00099 case 8:
00100 {
00101 PLPixel32 *pPal = rSrcBmp.GetPalette();
00102
00103 PLBYTE * pSrcPixel = pSrcLines[y];
00104
00105 for (int x = 0; x < SrcLineLen; ++x)
00106 {
00107 *pDstPixel = pPal[*pSrcPixel];
00108 ++pSrcPixel;
00109 ++pDstPixel;
00110 }
00111 }
00112 break;
00113 case 1:
00114 {
00115 PLPixel32 * pPal = rSrcBmp.GetPalette();
00116 DestPixelC blackDot, whiteDot;
00117
00118 if (pPal)
00119 {
00120 whiteDot = pPal[0];
00121 blackDot = pPal[1];
00122 }
00123 else
00124 {
00125 whiteDot.Set (255,255,255);
00126 blackDot.Set (0,0,0);
00127 }
00128
00129
00130 PLBYTE * pSrcPixel = pSrcLines[y];
00131
00132 for (int x = 0; x < SrcLineLen; ++x)
00133 {
00134 if (pSrcPixel[x / 8] & (128 >> (x & 7)))
00135 *pDstPixel = blackDot;
00136 else
00137 *pDstPixel = whiteDot;
00138 pDstPixel++;
00139 }
00140 }
00141 break;
00142 default:
00143 PLASSERT (false);
00144 }
00145 }
00146 const_cast<PLBmp &>(rSrcBmp).Unlock();
00147 rDestBmp.Unlock();
00148 }
00149
00150 void PLBmp::CreateCopy (const PLBmp & rSrcBmp, int BPPWanted)
00151
00152
00153 {
00154 PLASSERT_VALID (&rSrcBmp);
00155
00156 PLASSERT (BPPWanted == 32 || BPPWanted == 24 || BPPWanted == 8 ||
00157 BPPWanted == 1 || BPPWanted == 0);
00158 int BPPSrc = rSrcBmp.GetBitsPerPixel();
00159 PLASSERT (BPPSrc == 32 || BPPSrc == 24 || BPPSrc == 8 || BPPSrc == 1);
00160
00161 if (BPPWanted == BPPSrc || BPPWanted == 0)
00162 {
00163 if (&rSrcBmp != this)
00164 {
00165
00166 freeMembers ();
00167 internalCopy (rSrcBmp);
00168 }
00169 }
00170 else
00171 {
00172
00173 PLASSERT (&rSrcBmp != this);
00174
00175 bool bDestAlpha = rSrcBmp.HasAlpha() && BPPWanted == 32;
00176 Create (rSrcBmp.GetWidth(), rSrcBmp.GetHeight(),
00177 BPPWanted, bDestAlpha);
00178
00179 switch (BPPWanted)
00180 {
00181 case 32:
00182 createTrueColorCopy (*this, rSrcBmp, PLPixel32());
00183 break;
00184
00185 case 24:
00186 createTrueColorCopy (*this, rSrcBmp, PLPixel24());
00187 break;
00188
00189 case 8:
00190 create8BPPCopy (rSrcBmp);
00191 break;
00192
00193 case 1:
00194 create1BPPCopy (rSrcBmp);
00195 break;
00196 default:
00197 PLASSERT(false);
00198 }
00199 SetResolution (rSrcBmp.GetResolution());
00200 PLASSERT_VALID (this);
00201 }
00202 }
00203
00204 void PLBmp::CreateFilteredCopy (PLBmp & rSrcBmp, const PLFilter & rFilter)
00205 {
00206 PLASSERT_VALID (&rSrcBmp);
00207 rFilter.Apply (&rSrcBmp, this);
00208 }
00209
00210 void PLBmp::SetQuantizationMode (int DitherType, int DitherPaletteType)
00211 {
00212 PLASSERT_VALID (this);
00213 m_DitherType = DitherType;
00214 m_DitherPaletteType = DitherPaletteType;
00215 }
00216
00217 #ifdef _DEBUG
00218 void PLBmp::AssertValid () const
00219 {
00220 if (m_Width != 0 || m_Height != 0)
00221 {
00222
00223 PLASSERT ((m_bpp > 8) == (m_pClrTab == NULL));
00224 PLASSERT (m_Height >= 0);
00225 PLASSERT (m_Width >= 0);
00226
00227
00228 PLASSERT ((m_bpp == 32) || !m_bAlphaChannel);
00229 }
00230 PLASSERT (m_LockCount >= 0);
00231 }
00232 #endif
00233
00234
00236
00237
00238 void PLBmp::Create (PLLONG Width, PLLONG Height, PLWORD BitsPerPixel,
00239 bool bAlphaChannel, const PLPoint& Resolution)
00240
00241 {
00242 PLASSERT_VALID (this);
00243
00244 freeMembers ();
00245 internalCreate (Width, Height, BitsPerPixel, bAlphaChannel);
00246 m_Resolution = Resolution;
00247
00248 PLASSERT_VALID (this);
00249 }
00250
00251
00253
00254
00255 void PLBmp::SetGrayPalette ()
00256
00257 {
00258 PLASSERT (m_pClrTab);
00259
00260 int i;
00261 int NumColors = GetNumColors();
00262 double ColFactor = 255/(NumColors-1);
00263
00264 for (i=0; i<NumColors; i++)
00265 SetPaletteEntry (i, int(i*ColFactor), int(i*ColFactor), int(i*ColFactor), 0xFF);
00266 }
00267
00268 void PLBmp::SetPalette (PLPixel32 * pPal)
00269 {
00270 PLASSERT (m_pClrTab);
00271
00272
00273 memcpy (m_pClrTab, pPal, GetNumColors() * sizeof(PLPixel32));
00274 }
00275
00276
00277 void PLBmp::SetAlphaChannel (PLBmp * pAlphaBmp)
00278
00279 {
00280 PLBYTE * pAlphaLine;
00281 int x,y;
00282 PLPixel32 ** pLineArray;
00283 PLBYTE ** pAlphaLineArray;
00284
00285 PLASSERT_VALID (this);
00286
00287 PLASSERT (GetBitsPerPixel() == 32);
00288
00289 PLASSERT_VALID (pAlphaBmp);
00290
00291 PLASSERT (pAlphaBmp->GetBitsPerPixel() == 8);
00292
00293
00294 PLASSERT (pAlphaBmp->GetWidth() == GetWidth());
00295 PLASSERT (pAlphaBmp->GetHeight() == GetHeight());
00296
00297 Lock(false, true);
00298 pAlphaBmp->Lock(true, false) ;
00299 pLineArray = GetLineArray32();
00300 pAlphaLineArray = pAlphaBmp->GetLineArray();
00301
00302 for (y=0; y < GetHeight(); y++)
00303 {
00304 PLPixel32 * pLine = pLineArray[y];
00305 pAlphaLine = pAlphaLineArray[y];
00306 for (x=0; x < GetWidth(); x++)
00307 {
00308 pLine[x].SetA(pAlphaLine[x]);
00309 }
00310 }
00311 pAlphaBmp->Unlock();
00312 Unlock();
00313
00314 m_bAlphaChannel = true;
00315
00316 PLASSERT_VALID (this);
00317 }
00318
00319 void PLBmp::ApplyFilter
00320 ( const PLFilter& Filter
00321 )
00322 {
00323 Filter.ApplyInPlace (this);
00324 }
00325
00326 void PLBmp::Lock (bool bReadable, bool bWriteable)
00327 {
00328 PLASSERT (m_LockCount >= 0);
00329 PLASSERT (bReadable || bWriteable);
00330 m_LockCount++;
00331 }
00332
00333 void PLBmp::Unlock
00334 ()
00335 {
00336 m_LockCount--;
00337 PLASSERT (m_LockCount >= 0);
00338 }
00339
00340 PLBYTE PLBmp::FindNearestColor (PLPixel32 col)
00341 {
00342 PLPixel32 * pPalette = GetPalette();
00343 PLASSERT (pPalette);
00344
00345 int d1;
00346 int dMin = 100000;
00347 int i;
00348 int index=0;
00349 for (i = 0; i<GetNumColors(); i++)
00350 {
00351 d1 = col.BoxDist (pPalette[i]);
00352 if (d1 < dMin)
00353 {
00354 dMin = d1;
00355 index = i;
00356 }
00357 }
00358 return index;
00359 }
00360
00361 bool PLBmp::AlmostEqual
00362 ( const PLBmp& Bmp,
00363 int epsilon
00364 ) const
00365 {
00366 if (GetWidth() != Bmp.GetWidth() ||
00367 GetHeight() != Bmp.GetHeight() ||
00368 HasAlpha() != Bmp.HasAlpha() ||
00369 GetBitsPerPixel() != Bmp.GetBitsPerPixel())
00370 return false;
00371
00372 if (m_Resolution != Bmp.GetResolution())
00373 return false;
00374
00375 PLBYTE ** ppLines1 = GetLineArray();
00376 PLBYTE ** ppLines2 = Bmp.GetLineArray();
00377 int y,x;
00378 for (y=0; y<GetHeight(); y++)
00379 for (x=0; x<GetWidth(); x++)
00380 switch (GetBitsPerPixel())
00381 {
00382 case 8:
00383 if (abs (ppLines1[y][x] - ppLines2[y][x]) > epsilon)
00384 return false;
00385 break;
00386 case 24:
00387 if (ppLines1[y][x*3+PL_RGBA_RED] != ppLines2[y][x*3+PL_RGBA_RED] ||
00388 ppLines1[y][x*3+PL_RGBA_GREEN] != ppLines2[y][x*3+PL_RGBA_GREEN] ||
00389 ppLines1[y][x*3+PL_RGBA_BLUE] != ppLines2[y][x*3+PL_RGBA_BLUE])
00390 return false;
00391 break;
00392 case 32:
00393 if (abs (ppLines1[y][x*4+PL_RGBA_RED] - ppLines2[y][x*4+PL_RGBA_RED]) > epsilon ||
00394 abs (ppLines1[y][x*4+PL_RGBA_GREEN] - ppLines2[y][x*4+PL_RGBA_GREEN]) > epsilon ||
00395 abs (ppLines1[y][x*4+PL_RGBA_BLUE] - ppLines2[y][x*4+PL_RGBA_BLUE]) > epsilon)
00396 return false;
00397 if (HasAlpha() &&
00398 abs (ppLines1[y][x*4+3] - ppLines2[y][x*4+3]) > epsilon)
00399 return false;
00400 break;
00401 default:
00402
00403 PLASSERT (false);
00404 }
00405
00406
00407 if (GetBitsPerPixel() == 8)
00408 {
00409 int i;
00410 PLPixel32 * pPal1 = GetPalette();
00411 PLPixel32 * pPal2 = Bmp.GetPalette();
00412 for (i=0; i<255; i++)
00413 {
00414 if (abs (pPal1[i].GetR() - pPal2[i].GetR()) > epsilon ||
00415 abs (pPal1[i].GetG() - pPal2[i].GetG()) > epsilon ||
00416 abs (pPal1[i].GetB() - pPal2[i].GetB()) > epsilon)
00417 return false;
00418 }
00419 }
00420
00421 return true;
00422 }
00423
00424
00425
00427
00428
00429
00430 void PLBmp::initLocals (PLLONG Width, PLLONG Height, PLWORD BitsPerPixel, bool bAlphaChannel)
00431 {
00432 m_Width = Width;
00433 m_Height = Height;
00434 m_bpp = BitsPerPixel;
00435 m_bAlphaChannel = bAlphaChannel;
00436
00437
00438 initLineArray ();
00439
00440 if (BitsPerPixel < 16)
00441 {
00442 SetGrayPalette ();
00443 }
00444
00445 PLASSERT_VALID (this);
00446 }
00447
00448 void PLBmp::internalCopy (const PLBmp & rSrcBmp)
00449 {
00450 PLASSERT_VALID(&rSrcBmp);
00451
00452
00453 internalCreate (rSrcBmp.GetWidth(), rSrcBmp.GetHeight(), rSrcBmp.GetBitsPerPixel(),
00454 rSrcBmp.HasAlpha());
00455
00456
00457 const_cast<PLBmp &>(rSrcBmp).Lock(true, false);
00458 Lock(false, true);
00459 PLBYTE ** pSrcLines = rSrcBmp.GetLineArray();
00460 PLBYTE ** pDstLines = GetLineArray();
00461
00462 int LineLen = GetBytesPerLine();
00463
00464 for (int y = 0; y<GetHeight(); y++)
00465 memcpy (pDstLines[y], pSrcLines[y], LineLen);
00466
00467 Unlock();
00468 const_cast<PLBmp &>(rSrcBmp).Unlock();
00469
00470 if (GetBitsPerPixel() <= 8)
00471 SetPalette (rSrcBmp.GetPalette());
00472
00473 SetResolution (rSrcBmp.GetResolution());
00474
00475 PLASSERT_VALID (this);
00476 }
00477
00478 void PLBmp::create8BPPCopy (const PLBmp & rSrcBmp)
00479 {
00480 int BPPSrc = rSrcBmp.GetBitsPerPixel();
00481 Lock(false, true);
00482 const_cast<PLBmp &>(rSrcBmp).Lock(true, false);
00483
00484 if (BPPSrc == 32)
00485 {
00486 PLFilterQuantize Filter (m_DitherPaletteType, m_DitherType);
00487 Filter.Apply (&(const_cast<PLBmp &>(rSrcBmp)), this);
00488 }
00489 else
00490 {
00491 PLPixel32 *pPal = rSrcBmp.GetPalette();
00492
00493 if (pPal)
00494 {
00495 PLBYTE *pWhite = (PLBYTE *) pPal;
00496 PLBYTE *pBlack = (PLBYTE *) (pPal+1);
00497 SetPaletteEntry(0,
00498 pWhite[PL_RGBA_RED],pWhite[PL_RGBA_GREEN],pWhite[PL_RGBA_BLUE],
00499 255);
00500 SetPaletteEntry(1,
00501 pBlack[PL_RGBA_RED],pBlack[PL_RGBA_GREEN],pBlack[PL_RGBA_BLUE],
00502 255);
00503 }
00504 else
00505 {
00506 SetPaletteEntry(0,255,255,255,255);
00507 SetPaletteEntry(1,0,0,0,255);
00508 }
00509
00510 int SrcLineLen = rSrcBmp.GetWidth();
00511
00512 for (int y = 0; y<GetHeight(); ++y)
00513 {
00514 PLBYTE * pSrcPixel = rSrcBmp.GetLineArray()[y];
00515 PLBYTE * pDstPixel = GetLineArray()[y];
00516 for (int x = 0; x < SrcLineLen; ++x)
00517 pDstPixel[x] = pSrcPixel[x / 8] & (128 >> (x & 7)) ? 1 : 0;
00518 }
00519 }
00520 const_cast<PLBmp &>(rSrcBmp).Unlock();
00521 Unlock();
00522 }
00523
00524 void PLBmp::create1BPPCopy (const PLBmp & rSrcBmp)
00525 {
00526 int BPPSrc = rSrcBmp.GetBitsPerPixel();
00527 Lock(false, true);
00528 const_cast<PLBmp &>(rSrcBmp).Lock(true, false);
00529 PLBYTE ** pSrcLines = rSrcBmp.GetLineArray();
00530 PLBYTE ** pDstLines = GetLineArray();
00531 int SrcLineLen = GetWidth();
00532
00533 SetPaletteEntry(0,255,255,255,255);
00534 SetPaletteEntry(1,0,0,0,255);
00535
00536
00537 PLPixel32 *pPal = rSrcBmp.GetPalette();
00538 PLBYTE *pRGBA;
00539 int DstLineLen = GetBytesPerLine();
00540
00541 for (int y = 0; y < GetHeight(); ++y)
00542 {
00543 PLBYTE * pSrcPixel = pSrcLines[y];
00544 PLBYTE * pDstPixel = pDstLines[y];
00545
00546 memset(pDstPixel,0,DstLineLen);
00547
00548 for (int x = 0; x < SrcLineLen; ++x)
00549 {
00550 pRGBA = BPPSrc == 8 ? (PLBYTE*) &pPal[*pSrcPixel] : pSrcPixel;
00551
00552
00553 if (pRGBA[PL_RGBA_RED] < 128 &&
00554 pRGBA[PL_RGBA_GREEN] < 128 &&
00555 pRGBA[PL_RGBA_BLUE] < 128 )
00556 pDstPixel[x / 8] |= 128 >> (x & 7);
00557 pSrcPixel += BPPSrc == 8 ? 1 : sizeof(PLPixel32);
00558 }
00559 }
00560 const_cast<PLBmp &>(rSrcBmp).Unlock();
00561 Unlock();
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687