00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <memory.h>
00014 #include "png.h"
00015 #include "CATImage.h"
00016 #include "CATStreamFile.h"
00017
00018 const CATInt32 kBytesPerPixel = 4;
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 CATResult CATImage::CreateImage( CATImage*& image,
00040 CATInt32 width,
00041 CATInt32 height,
00042 bool init,
00043 bool transparent)
00044 {
00045 image = 0;
00046
00047 try
00048 {
00049 image = new CATImage();
00050 }
00051 catch(...)
00052 {
00053 image = 0;
00054 }
00055
00056 if (image == 0)
00057 {
00058 return CATRESULT(CAT_ERR_OUT_OF_MEMORY);
00059 }
00060
00061 if ((width != 0) && (height != 0))
00062 {
00063 return image->Create(width, height, init, transparent);
00064 }
00065
00066 return CAT_SUCCESS;
00067 }
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 CATResult CATImage::ReleaseImage( CATImage*& image)
00079 {
00080 CATASSERT(image != 0, "Invalid image released!");
00081
00082 if (image != 0)
00083 {
00084
00085 if (image->fRefCount <= 1)
00086 {
00087
00088 delete image;
00089
00090
00091 image = 0;
00092 }
00093 else
00094 {
00095
00096 image->DecRef();
00097 }
00098
00099 return CAT_SUCCESS;
00100 }
00101 return CATRESULT(CAT_ERR_IMAGE_NULL);
00102
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 CATResult CATImage::CreateSub ( const CATImage* orgImg,
00128 CATImage*& dstImg,
00129 CATInt32 xOffset,
00130 CATInt32 yOffset,
00131 CATInt32 width,
00132 CATInt32 height)
00133 {
00134 dstImg = 0;
00135
00136 CATASSERT(xOffset >= 0, "XOffset must be >= 0");
00137 CATASSERT(yOffset >= 0, "YOffset must be >= 0");
00138
00139 CATASSERT(xOffset + width <= orgImg->fWidth,
00140 "Invalid sub image width");
00141
00142 CATASSERT(yOffset + height <= orgImg->fHeight,
00143 "Invalid sub image height");
00144
00145 CATASSERT(orgImg->fData != 0, "Parent image is invalid.");
00146
00147
00148 if ((xOffset < 0) || (yOffset < 0) ||
00149 (xOffset + width > orgImg->fWidth) ||
00150 (yOffset + height > orgImg->fHeight) ||
00151 (orgImg->fData == 0))
00152 {
00153 return CATRESULT(CAT_ERR_IMAGE_INVALID_SUB_POSITION);
00154 }
00155
00156
00157 CATResult result;
00158 if (CATFAILED(result =
00159 CreateImage(dstImg, 0, 0, false)))
00160 {
00161 return result;
00162 }
00163
00164
00165
00166 dstImg->fOwnData = false;
00167 dstImg->fParentImage = (CATImage*)orgImg;
00168 dstImg->fData = orgImg->fData;
00169
00170
00171
00172
00173 dstImg->fWidth = width;
00174 dstImg->fHeight = height;
00175
00176
00177
00178
00179 dstImg->fXOffset = xOffset;
00180 dstImg->fYOffset = yOffset;
00181
00182
00183
00184 dstImg->AddRef();
00185
00186 return CAT_SUCCESS;
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 CATResult CATImage::CopyImage ( const CATImage* srcImg,
00200 CATImage*& dstImg)
00201 {
00202 dstImg = 0;
00203 CATASSERT(srcImg != 0, "Can't copy a null image.");
00204 if (srcImg == 0)
00205 {
00206 return CATRESULT(CAT_ERR_IMAGE_NULL);
00207 }
00208
00209
00210 return CopyImage( srcImg,
00211 dstImg,
00212 srcImg->XOffsetRel(),
00213 srcImg->YOffsetRel(),
00214 srcImg->Width(),
00215 srcImg->Height());
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 CATResult CATImage::CopyImage ( const CATImage* srcImg,
00235 CATImage*& dstImg,
00236 CATInt32 xOffset,
00237 CATInt32 yOffset,
00238 CATInt32 width,
00239 CATInt32 height)
00240 {
00241 dstImg = 0;
00242 CATASSERT(srcImg != 0, "Can't copy a null image.");
00243 if (srcImg == 0)
00244 {
00245 return CATRESULT(CAT_ERR_IMAGE_NULL);
00246 }
00247
00248 CATASSERT(xOffset >= 0, "XOffset must be >= 0");
00249 CATASSERT(yOffset >= 0, "YOffset must be >= 0");
00250 CATASSERT(xOffset + width <= srcImg->fWidth, "Invalid offset/width");
00251 CATASSERT(yOffset + height <= srcImg->fHeight, "Invalid offset/height");
00252 CATASSERT(srcImg->fData != 0, "Source image is invalid.");
00253
00254
00255 if ((xOffset < 0) || (yOffset < 0) ||
00256 (xOffset + width > srcImg->fWidth) ||
00257 (yOffset + height > srcImg->fHeight) ||
00258 (srcImg->fData == 0))
00259 {
00260 return CATRESULT(CAT_ERR_IMAGE_INVALID_SUB_POSITION);
00261 }
00262
00263
00264 CATResult result;
00265 if (CATFAILED(result = CreateImage( dstImg,
00266 width,
00267 height,
00268 false)))
00269 {
00270 return result;
00271 }
00272
00273
00274 CATInt32 y;
00275
00276
00277 CATInt32 srcLineOffset =
00278 (srcImg->XOffsetAbs() + xOffset) * kBytesPerPixel;
00279
00280
00281 unsigned char* srcPtr =
00282 srcImg->fData + srcLineOffset +
00283 ((srcImg->YOffsetAbs() + yOffset) * srcImg->AbsWidth() * kBytesPerPixel);
00284
00285 unsigned char* dstPtr = dstImg->fData;
00286
00287 for (y = 0; y < height; y++)
00288 {
00289
00290 memcpy( dstPtr,
00291 srcPtr,
00292 width * kBytesPerPixel );
00293
00294
00295 srcPtr += srcImg->AbsWidth() * kBytesPerPixel;
00296
00297
00298 dstPtr += width * kBytesPerPixel;
00299 }
00300
00301 return CAT_SUCCESS;
00302 }
00303
00304
00305
00306
00307 unsigned long CATImage::AddRef()
00308 {
00309
00310 if (fParentImage != 0)
00311 {
00312 fParentImage->AddRef();
00313 }
00314
00315 fRefCount++;
00316 return fRefCount;
00317 }
00318
00319
00320
00321
00322 unsigned long CATImage::DecRef()
00323 {
00324 if (fParentImage != 0)
00325 {
00326
00327
00328 ReleaseImage(fParentImage);
00329
00330
00331 if (fParentImage == 0)
00332 {
00333
00334 CATASSERT(fRefCount == 1, "Deleted parent, but we're not done here!");
00335 }
00336 }
00337
00338 CATASSERT(fRefCount != 0, "Decrementing reference count too far!");
00339 if (fRefCount == 0)
00340 return fRefCount;
00341
00342 fRefCount--;
00343 return fRefCount;
00344 }
00345
00346
00347
00348
00349 CATImage::CATImage()
00350 {
00351 fOwnData = false;
00352 fData = 0;
00353 fWidth = 0;
00354 fHeight = 0;
00355 fXOffset = 0;
00356 fYOffset = 0;
00357 fParentImage = 0;
00358 fRefCount = 0;
00359 }
00360
00361
00362
00363
00364 CATImage::~CATImage()
00365 {
00366
00367
00368 if (fData)
00369 DecRef();
00370
00371 CATASSERT(fRefCount == 0, "Destructor called while active!");
00372
00373 if (fOwnData)
00374 {
00375 if (fData != 0)
00376 {
00377 delete [] fData;
00378 fData = 0;
00379 }
00380 }
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390 CATResult CATImage::Create(CATInt32 width, CATInt32 height, bool init, bool transparent)
00391 {
00392 CATResult result = CAT_SUCCESS;
00393
00394 if ( (width == 0) || (height == 0) )
00395 {
00396 return CATRESULT(CAT_ERR_IMAGE_INVALID_SIZE);
00397 }
00398
00399 if (fData != 0)
00400 {
00401 delete [] fData;
00402 }
00403
00404 fData = new unsigned char[width * height * kBytesPerPixel];
00405 if (fData == 0)
00406 {
00407 return CATRESULT(CAT_ERR_OUT_OF_MEMORY);
00408 }
00409 fOwnData = true;
00410
00411 fWidth = width;
00412 fHeight = height;
00413
00414 if (init)
00415 this->Clear(transparent);
00416
00417 this->AddRef();
00418
00419 return CAT_SUCCESS;
00420 }
00421
00422
00423
00424
00425
00426 CATResult CATImage::Clear(bool transparent)
00427 {
00428 CATASSERT(fData != 0, "Can't clear an image unless it's been created.");
00429 if (fData == 0)
00430 {
00431 return CATRESULT(CAT_ERR_IMAGE_MUST_INITIALIZE);
00432 }
00433
00434
00435 CATInt32 dstOffX = this->XOffsetAbs() * kBytesPerPixel;
00436
00437 CATInt32 dstLineLength = this->AbsWidth() * kBytesPerPixel;
00438
00439 CATInt32 dstStep = dstLineLength - (fWidth * kBytesPerPixel);
00440
00441
00442 unsigned char* dstPtr = fData + (YOffsetAbs() * dstLineLength);
00443
00444 unsigned char alpha = (transparent?0:255);
00445
00446
00447 *(CATUInt32 *)dstPtr = 0;
00448 dstPtr[3] = alpha;
00449
00450
00451 CATUInt32 val = *(CATUInt32*)dstPtr;
00452
00453 for (CATInt32 y = 0; y < fHeight; y++)
00454 {
00455 for (CATInt32 x = 0; x < fWidth; x++)
00456 {
00457 *(CATUInt32*)dstPtr = val;
00458 dstPtr += kBytesPerPixel;
00459 }
00460
00461 dstPtr += dstStep;
00462 }
00463
00464 return CAT_SUCCESS;
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 CATResult CATImage::FillRect(const CATRect& rect, const CATColor& color)
00477 {
00478 CATResult result = CAT_SUCCESS;
00479 CATRect imageRect(0,0,fWidth,fHeight);
00480
00481 CATASSERT(color.a != 0, "Uhm... filling with 0 alpha doesn't do much.");
00482
00483 if (!imageRect.Inside(rect))
00484 {
00485 CATASSERT(false,"Rect must be contained by the image.");
00486 return CAT_ERR_IMAGE_FILL_OUT_OF_BOUNDS;
00487 }
00488
00489 CATASSERT(fData != 0, "Image must be created first!");
00490 if (fData == 0)
00491 {
00492 return CATRESULT(CAT_ERR_IMAGE_MUST_INITIALIZE);
00493 }
00494
00495
00496 CATInt32 x,y;
00497
00498
00499 CATInt32 dstOffX = (this->XOffsetAbs() + rect.left) * kBytesPerPixel;
00500
00501
00502 CATInt32 dstLineLength = this->AbsWidth() * kBytesPerPixel;
00503
00504
00505 CATInt32 dstStep = dstLineLength - (rect.Width() * kBytesPerPixel);
00506
00507
00508 unsigned char* dstPtr = fData +
00509 dstOffX +
00510 ((YOffsetAbs() + rect.top) * dstLineLength);
00511
00512
00513 CATASSERT(kBytesPerPixel == 4, "Woops.");
00514
00515
00516 if (color.a != 255)
00517 {
00518
00519 for (y = 0; y < rect.Height(); y++)
00520 {
00521 for (x = 0; x < rect.Width(); x++)
00522 {
00523
00524 dstPtr[0] = (CATUInt8)(((CATInt32)(color.r * color.a) +
00525 (CATInt32)(dstPtr[0] * (255 - color.a))) / 255);
00526
00527 dstPtr[1] = (CATUInt8)(((CATInt32)(color.g * color.a) +
00528 (CATInt32)(dstPtr[1] * (255 - color.a))) / 255);
00529
00530 dstPtr[2] = (CATUInt8)(((CATInt32)(color.b * color.a) +
00531 (CATInt32)(dstPtr[2] * (255 - color.a))) / 255);
00532
00533 dstPtr+=4;
00534 }
00535 dstPtr += dstStep;
00536 }
00537
00538 }
00539 else
00540 {
00541
00542
00543
00544 for (y = 0; y < rect.Height(); y++)
00545 {
00546 for (x = 0; x < rect.Width(); x++)
00547 {
00548 dstPtr[0] = color.r;
00549 dstPtr[1] = color.g;
00550 dstPtr[2] = color.b;
00551
00552 dstPtr += 4;
00553 }
00554
00555 dstPtr += dstStep;
00556 }
00557 }
00558 return result;
00559 }
00560
00561
00562
00563
00564
00565
00566 CATInt32 CATImage::XOffsetRel () const
00567 {
00568 return fXOffset;
00569 }
00570
00571
00572
00573
00574
00575 CATInt32 CATImage::YOffsetRel () const
00576 {
00577 return fYOffset;
00578 }
00579
00580
00581
00582
00583
00584 CATInt32 CATImage::XOffsetAbs () const
00585 {
00586 CATInt32 absOffset = fXOffset;
00587
00588
00589
00590 if (fParentImage != 0)
00591 {
00592 absOffset += fParentImage->XOffsetAbs();
00593 }
00594
00595 return absOffset;
00596 }
00597
00598
00599
00600
00601
00602 CATInt32 CATImage::YOffsetAbs () const
00603 {
00604 CATInt32 absOffset = fYOffset;
00605
00606
00607
00608 if (fParentImage != 0)
00609 {
00610 absOffset += fParentImage->YOffsetAbs();
00611 }
00612
00613 return absOffset;
00614 }
00615
00616
00617
00618
00619 CATInt32 CATImage::AbsWidth () const
00620 {
00621 CATInt32 absWidth = fWidth;
00622 if (fParentImage != 0)
00623 {
00624 absWidth = fParentImage->AbsWidth();
00625 }
00626
00627 return absWidth;
00628 }
00629
00630
00631
00632
00633
00634 CATInt32 CATImage::AbsHeight () const
00635 {
00636 CATInt32 absHeight = fHeight;
00637 if (fParentImage != 0)
00638 {
00639 absHeight = fParentImage->AbsHeight();
00640 }
00641
00642 return absHeight;
00643 }
00644
00645
00646
00647
00648
00649 CATInt32 CATImage::Width() const
00650 {
00651 return fWidth;
00652 }
00653
00654
00655
00656
00657
00658 CATInt32 CATImage::Height() const
00659 {
00660 return fHeight;
00661 }
00662
00663
00664
00665
00666
00667 CATInt32 CATImage::Size() const
00668 {
00669 return fWidth * fHeight * kBytesPerPixel;
00670 }
00671
00672
00673
00674
00675
00676 CATInt32 CATImage::AbsSize() const
00677 {
00678 return AbsWidth() * AbsHeight() * kBytesPerPixel;
00679 }
00680
00681
00682
00683
00684
00685
00686 bool CATImage::IsImageRoot() const
00687 {
00688 bool isRoot = fOwnData;
00689
00690 CATASSERT(isRoot == (fParentImage == 0),
00691 "Root image should not have a parent image, sub images must.");
00692
00693 return isRoot;
00694 }
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716 unsigned char* CATImage::GetRawDataPtr() const
00717 {
00718 return fData;
00719 }
00720
00721
00722
00723
00724
00725
00726
00727
00728 CATImage& CATImage::operator=(const CATImage& img)
00729 {
00730 CATASSERT(false,"operator= not supported for CATImage.");
00731 return *this;
00732 }
00733
00734
00735
00736
00737
00738
00739
00740 CATResult CATImage::SetSubPosition ( CATInt32 newXOffset,
00741 CATInt32 newYOffset,
00742 CATInt32 newWidth,
00743 CATInt32 newHeight )
00744 {
00745
00746
00747 CATASSERT(IsImageRoot() == false,
00748 "Cannot SetSubPosition on a root image.");
00749
00750 if (IsImageRoot())
00751 {
00752 return CATRESULT(CAT_ERR_IMAGE_OPERATION_INVALID_ON_ROOT);
00753 }
00754
00755
00756 CATASSERT(newXOffset >= 0, "XOffset must be >= 0");
00757 CATASSERT(newYOffset >= 0, "YOffset must be >= 0");
00758
00759 CATASSERT(newXOffset + newWidth <= fParentImage->fWidth,
00760 "Invalid sub image width");
00761
00762 CATASSERT(newYOffset + newHeight <= fParentImage->fHeight,
00763 "Invalid sub image height");
00764
00765 CATASSERT(fParentImage->fData != 0, "Parent image is invalid.");
00766
00767
00768 if ((newXOffset < 0) || (newYOffset < 0) ||
00769 (newXOffset + newWidth > fParentImage->fWidth) ||
00770 (newYOffset + newHeight > fParentImage->fHeight) ||
00771 (fParentImage->fData == 0))
00772 {
00773 return CATRESULT(CAT_ERR_IMAGE_INVALID_SUB_POSITION);
00774 }
00775
00776
00777 fXOffset = newXOffset;
00778 fYOffset = newYOffset;
00779 fWidth = newWidth;
00780 fHeight = newHeight;
00781
00782 return CAT_SUCCESS;
00783 }
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 CATResult CATImage::GetPixel( CATInt32 x,
00807 CATInt32 y,
00808 CATColor& color) const
00809 {
00810 return GetPixel(x, y, color.r, color.g, color.b, color.a);
00811 }
00812
00813 CATResult CATImage::GetPixel( CATInt32 x,
00814 CATInt32 y,
00815 unsigned char& r,
00816 unsigned char& g,
00817 unsigned char& b,
00818 unsigned char& a) const
00819 {
00820 CATResult result = CAT_SUCCESS;
00821
00822 CATASSERT(fData != 0, "Image must be created first!");
00823 if (fData == 0)
00824 {
00825 return CATRESULT(CAT_ERR_IMAGE_EMPTY);
00826 }
00827
00828
00829 CATASSERT(( (x >= 0) || (x < fWidth)), "X position is out of bounds!");
00830 CATASSERT(( (y >= 0) || (y < fHeight)), "Y position is out of bounds!");
00831
00832 if ( (x < 0) || (x >= fWidth))
00833 {
00834 return CATRESULT(CAT_ERR_IMAGE_OUT_OF_RANGE);
00835 }
00836
00837 if ( (y < 0) || (y >= fHeight))
00838 {
00839 return CATRESULT(CAT_ERR_IMAGE_OUT_OF_RANGE);
00840 }
00841
00842
00843
00844 CATInt32 lineOffset = (this->XOffsetAbs() + x) * kBytesPerPixel;
00845
00846
00847 CATInt32 lineLength = this->AbsWidth() * kBytesPerPixel;
00848
00849
00850 unsigned char* curPtr = fData + lineOffset +
00851 ((YOffsetAbs() + y) * lineLength);
00852
00853
00854 r = curPtr[0];
00855 g = curPtr[1];
00856 b = curPtr[2];
00857 a = curPtr[3];
00858
00859 return result;
00860 }
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879 CATResult CATImage::SetPixel( CATInt32 x,
00880 CATInt32 y,
00881 const CATColor& color)
00882 {
00883 return SetPixel(x, y, color.r, color.g, color.b, color.a);
00884 }
00885
00886 CATResult CATImage::SetPixel ( CATInt32 x,
00887 CATInt32 y,
00888 unsigned char r,
00889 unsigned char g,
00890 unsigned char b,
00891 unsigned char a)
00892 {
00893 CATResult result = CAT_SUCCESS;
00894
00895 CATASSERT(fData != 0, "Image must be created first!");
00896 if (fData == 0)
00897 {
00898 return CATRESULT(CAT_ERR_IMAGE_EMPTY);
00899 }
00900
00901
00902 CATASSERT(( (x >= 0) || (x < fWidth)), "X position is out of bounds!");
00903 CATASSERT(( (y >= 0) || (y < fHeight)), "Y position is out of bounds!");
00904
00905 if ( (x < 0) || (x >= fWidth))
00906 {
00907 return CATRESULT(CAT_ERR_IMAGE_OUT_OF_RANGE);
00908 }
00909
00910 if ( (y < 0) || (y >= fHeight))
00911 {
00912 return CATRESULT(CAT_ERR_IMAGE_OUT_OF_RANGE);
00913 }
00914
00915
00916 CATInt32 lineOffset = (this->XOffsetAbs() + x) * kBytesPerPixel;
00917
00918
00919 CATInt32 lineLength = this->AbsWidth() * kBytesPerPixel;
00920
00921
00922 unsigned char* curPtr = fData + lineOffset +
00923 ((YOffsetAbs() + y) * lineLength);
00924
00925
00926 curPtr[0] = r;
00927 curPtr[1] = g;
00928 curPtr[2] = b;
00929 curPtr[3] = a;
00930
00931 return result;
00932 }
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954 CATResult CATImage::CopyOver ( const CATImage* srcImg,
00955 CATInt32 dstOffsetX,
00956 CATInt32 dstOffsetY,
00957 CATInt32 srcOffsetX,
00958 CATInt32 srcOffsetY,
00959 CATInt32 width,
00960 CATInt32 height)
00961 {
00962 CATResult result = CAT_SUCCESS;
00963 CATASSERT(srcImg != 0, "Null source image.");
00964
00965
00966 if (srcImg == 0)
00967 {
00968 return CATRESULT(CAT_ERR_IMAGE_NULL);
00969 }
00970
00971
00972 if (width == 0)
00973 {
00974 width = srcImg->Width();
00975 }
00976
00977 if (height == 0)
00978 {
00979 height = srcImg->Height();
00980 }
00981
00982 CATASSERT(width != 0, "Width still null in image copy");
00983 CATASSERT(height != 0, "Height still null in image copy");
00984 if ((width == 0) || (height == 0))
00985 {
00986 return CATRESULT(CAT_ERR_IMAGE_NULL);
00987 }
00988
00989 CATASSERT(width + dstOffsetX <= fWidth, "Out of bounds in image copy");
00990 CATASSERT(height + dstOffsetY <= fHeight, "Out of bounds in image copy");
00991 if ( (width + dstOffsetX > fWidth) ||
00992 (height + dstOffsetY > fHeight))
00993 {
00994 return CATRESULT(CAT_ERR_IMAGE_OVERLAY_OUT_OF_BOUNDS);
00995 }
00996
00997
00998 CATInt32 y;
00999
01000 CATASSERT(fData != 0, "Image must be created first!");
01001 if (fData == 0)
01002 {
01003 return CATRESULT(CAT_ERR_IMAGE_MUST_INITIALIZE);
01004 }
01005
01006
01007
01008 CATInt32 dstOffX = (this->XOffsetAbs() + dstOffsetX) * kBytesPerPixel;
01009
01010
01011 CATInt32 dstLineLength = this->AbsWidth() * kBytesPerPixel;
01012
01013
01014 CATInt32 dstStep = dstLineLength - (width * kBytesPerPixel);
01015
01016
01017 unsigned char* dstPtr = fData +
01018 dstOffX +
01019 ((YOffsetAbs() + dstOffsetY) * dstLineLength);
01020
01021
01022
01023 CATInt32 srcOffX = (srcImg->XOffsetAbs() + srcOffsetX) * kBytesPerPixel;
01024 CATInt32 srcLineLength = srcImg->AbsWidth() * kBytesPerPixel;
01025 CATInt32 srcStep = srcLineLength - (width * kBytesPerPixel);
01026 unsigned char* srcPtr = srcImg->fData +
01027 srcOffX +
01028 ((srcImg->YOffsetAbs() + srcOffsetY) * srcLineLength);
01029
01030 bool alphaUnused = true;
01031
01032 CATASSERT(kBytesPerPixel == 4, "Woops.");
01033
01034
01035
01036 CATUInt32 lineWidth = width*4;
01037
01038 for (y = 0; y < height; y++)
01039 {
01040 memcpy(dstPtr, srcPtr,lineWidth);
01041 dstPtr += dstStep + lineWidth;
01042 srcPtr += srcStep + lineWidth;
01043 }
01044 return result;
01045 }
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069 CATResult CATImage::Overlay( const CATImage* srcImg,
01070 CATInt32 dstOffsetX,
01071 CATInt32 dstOffsetY,
01072 CATInt32 srcOffsetX,
01073 CATInt32 srcOffsetY,
01074 CATInt32 width,
01075 CATInt32 height)
01076 {
01077 CATResult result = CAT_SUCCESS;
01078 CATASSERT(srcImg != 0, "Null source image.");
01079
01080
01081 if (srcImg == 0)
01082 {
01083 return CATRESULT(CAT_ERR_IMAGE_NULL);
01084 }
01085
01086
01087 if (width == 0)
01088 {
01089 width = srcImg->Width();
01090 }
01091
01092 if (height == 0)
01093 {
01094 height = srcImg->Height();
01095 }
01096
01097 CATASSERT(width != 0, "Width still null in image copy");
01098 CATASSERT(height != 0, "Height still null in image copy");
01099 if ((width == 0) || (height == 0))
01100 {
01101 return CATRESULT(CAT_ERR_IMAGE_NULL);
01102 }
01103
01104 CATASSERT(width + dstOffsetX <= fWidth, "Out of bounds in image copy");
01105 CATASSERT(height + dstOffsetY <= fHeight, "Out of bounds in image copy");
01106 if ( (width + dstOffsetX > fWidth) ||
01107 (height + dstOffsetY > fHeight))
01108 {
01109 return CATRESULT(CAT_ERR_IMAGE_OVERLAY_OUT_OF_BOUNDS);
01110 }
01111
01112 if ( (width + dstOffsetX > fWidth) ||
01113 (height + dstOffsetY > fHeight))
01114 {
01115 return CATRESULT(CAT_ERR_IMAGE_OVERLAY_OUT_OF_BOUNDS);
01116 }
01117
01118 CATASSERT(width + srcOffsetX <= srcImg->Width(), "Out of bounds in image copy");
01119 CATASSERT(height + srcOffsetY <= srcImg->Height(), "Out of bounds in image copy");
01120 if (width + srcOffsetX > srcImg->Width())
01121 {
01122 width = srcImg->Width() - srcOffsetX;
01123 }
01124 if (height + srcOffsetY > srcImg->Height())
01125 {
01126 height = srcImg->Height() - srcOffsetY;
01127 }
01128
01129
01130
01131 CATInt32 x,y;
01132 CATASSERT(fData != 0, "Image must be created first!");
01133 if (fData == 0)
01134 {
01135 return CATRESULT(CAT_ERR_IMAGE_MUST_INITIALIZE);
01136 }
01137
01138
01139
01140 CATInt32 dstOffX = (this->XOffsetAbs() + dstOffsetX) * kBytesPerPixel;
01141
01142
01143 CATInt32 dstLineLength = this->AbsWidth() * kBytesPerPixel;
01144
01145
01146 CATInt32 dstStep = dstLineLength - (width * kBytesPerPixel);
01147
01148
01149 unsigned char* dstPtr = fData +
01150 dstOffX +
01151 ((YOffsetAbs() + dstOffsetY) * dstLineLength);
01152
01153
01154
01155 CATInt32 srcOffX = (srcImg->XOffsetAbs() + srcOffsetX) *
01156 kBytesPerPixel;
01157
01158 CATInt32 srcLineLength = srcImg->AbsWidth() * kBytesPerPixel;
01159 CATInt32 srcStep = srcLineLength - (width * kBytesPerPixel);
01160 unsigned char* srcPtr = srcImg->fData +
01161 srcOffX +
01162 ((srcImg->YOffsetAbs() +
01163 srcOffsetY) * srcLineLength);
01164
01165
01166
01167
01168 for (y = 0; y < height; y++)
01169 {
01170 for (x = 0; x < width; x++)
01171 {
01172 CATInt32 i;
01173 unsigned char alpha = srcPtr[3];
01174
01175
01176 if (alpha == 0)
01177 {
01178 srcPtr +=4;
01179 dstPtr +=4;
01180 continue;
01181 }
01182 else if (alpha == 255)
01183 {
01184 for (i=0; i<3; i++)
01185 {
01186 *dstPtr = *srcPtr;
01187 dstPtr++;
01188 srcPtr++;
01189 }
01190 dstPtr ++;
01191 srcPtr ++;
01192 continue;
01193 }
01194
01195
01196 for (i=0; i < 3; i++)
01197 {
01198 *dstPtr = (CATUInt8)((( alpha * (CATInt32)( *srcPtr - *dstPtr) ) + ((CATInt32)(*dstPtr)<<8) ) >> 8);
01199
01200
01201
01202
01203 dstPtr++;
01204 srcPtr++;
01205 }
01206
01207 srcPtr++;
01208 dstPtr++;
01209 }
01210
01211 dstPtr += dstStep;
01212 srcPtr += srcStep;
01213 }
01214
01215
01216
01217
01218 return result;
01219 }
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235 CATResult CATImage::Load ( CATStream* stream,
01236 CATImage*& image)
01237 {
01238 image = 0;
01239
01240 CATResult result = CAT_SUCCESS;
01241
01242 CATASSERT(stream != 0, "Stream must be created and opened first!");
01243 CATASSERT(stream->IsOpen(), "Stream must be created and opened first!");
01244 if ((stream == 0) || (stream->IsOpen() == false))
01245 {
01246 return CATRESULT(CAT_ERR_INVALID_PARAM);
01247 }
01248
01249 image = new CATImage();
01250
01251
01252 png_structp png_ptr;
01253 png_infop info_ptr;
01254 png_uint_32 width, height;
01255
01256 try
01257 {
01258
01259 png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
01260 image,
01261 PNGError,
01262 PNGWarning);
01263
01264 if (png_ptr == NULL)
01265 {
01266 delete image;
01267 image = 0;
01268 return CATRESULT(CAT_ERR_PNG_ERROR_CREATING_READ);
01269 }
01270
01271
01272 info_ptr = png_create_info_struct(png_ptr);
01273
01274
01275 if (info_ptr == NULL)
01276 {
01277 png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
01278 delete image;
01279 image = 0;
01280 return CATRESULT(CAT_ERR_PNG_ERROR_CREATING_READ);
01281 }
01282
01283
01284 png_set_read_fn(png_ptr, (void *)stream, PNGRead);
01285
01286
01287 png_set_expand(png_ptr);
01288 png_set_palette_to_rgb(png_ptr);
01289 png_set_tRNS_to_alpha(png_ptr);
01290 png_set_gray_to_rgb(png_ptr);
01291
01292
01293 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_SHIFT, png_voidp_NULL);
01294
01295
01296
01297 unsigned char** rows = png_get_rows(png_ptr, info_ptr);
01298
01299
01300 width = png_get_image_width(png_ptr, info_ptr);
01301 height = png_get_image_height(png_ptr, info_ptr);
01302
01303 CATUInt32 y,x;
01304
01305
01306
01307
01308 image->Create(width, height, true, false);
01309 unsigned char* rawData = image->GetRawDataPtr();
01310
01311 CATInt32 channels = png_get_channels(png_ptr,info_ptr);
01312
01313 if (channels == 4)
01314 {
01315 for (y=0; y < height; y++)
01316 {
01317 memcpy( rawData + (y * width * kBytesPerPixel),
01318 rows[y],
01319 width * kBytesPerPixel);
01320 }
01321 }
01322 else if (channels == 3)
01323 {
01324 for (y=0; y < height; y++)
01325 {
01326 unsigned char* linePtr = rawData + (y * width * kBytesPerPixel);
01327 unsigned char* srcPtr = rows[y];
01328
01329 for (x = 0; x < width; x++)
01330 {
01331 *linePtr = *srcPtr; linePtr++; srcPtr++;
01332 *linePtr = *srcPtr; linePtr++; srcPtr++;
01333 *linePtr = *srcPtr; linePtr++; srcPtr++;
01334 *linePtr = 255;
01335 linePtr++;
01336 }
01337 }
01338 }
01339 else
01340 {
01341 CATASSERT(false,"Unsupported number of channels in .PNG!");
01342 result = CATRESULTFILE(CAT_ERR_PNG_UNSUPPORTED_FORMAT,stream->GetName());
01343 }
01344
01345
01346 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
01347
01348 return result;
01349 }
01350
01351 catch (CATResult& thrownRes)
01352 {
01353 result = thrownRes;
01354 if (image != 0)
01355 {
01356 delete image;
01357 image = 0;
01358 }
01359 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
01360
01361
01362 return CATRESULTFILE(thrownRes, stream->GetName());
01363 }
01364
01365 }
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381 CATResult CATImage::Save( const CATWChar* filename,
01382 CATImage* image)
01383 {
01384 CATResult result = CAT_SUCCESS;
01385 CATStreamFile outFile;
01386 if (CATFAILED(result = outFile.Open(filename,CATStream::READ_WRITE_CREATE_TRUNC)))
01387 {
01388 return result;
01389 }
01390
01391 result = Save(&outFile, image);
01392
01393 outFile.Close();
01394
01395 return result;
01396 }
01397
01398 CATResult CATImage::Save ( CATStream* stream,
01399 CATImage* image,
01400 CATIMAGEFORMAT imageFormat)
01401 {
01402 CATResult result = CAT_SUCCESS;
01403 unsigned char** row_pointers = 0;
01404
01405 CATASSERT(imageFormat == CATIMAGE_PNG_RGBA32, "Only 32-bit RGBA .PNG's are supported.");
01406 if (imageFormat != CATIMAGE_PNG_RGBA32)
01407 {
01408 return CATRESULT(CAT_ERR_IMAGE_UNKNOWN_FORMAT);
01409 }
01410
01411 CATASSERT(stream != 0, "Stream must be created and opened first!");
01412 CATASSERT(stream->IsOpen(), "Stream must be created and opened first!");
01413 if ((stream == 0) || (stream->IsOpen() == false))
01414 {
01415 return CATRESULT(CAT_ERR_INVALID_PARAM);
01416 }
01417
01418 CATASSERT(image != 0, "Image must be valid for save.");
01419 if ((image == 0) || (image->fData == 0))
01420 {
01421 return CATRESULT(CAT_ERR_INVALID_PARAM);
01422 }
01423
01424 png_structp png_ptr;
01425 png_infop info_ptr;
01426
01427 try
01428 {
01429 png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING,
01430 image,
01431 PNGError,
01432 PNGWarning);
01433
01434 if (png_ptr == NULL)
01435 {
01436 return CATRESULT(CAT_ERR_PNG_ERROR_CREATING_WRITE);
01437 }
01438
01439
01440 info_ptr = png_create_info_struct(png_ptr);
01441 if (info_ptr == NULL)
01442 {
01443 png_destroy_write_struct(&png_ptr, png_infopp_NULL);
01444 return CATRESULT(CAT_ERR_PNG_ERROR_CREATING_WRITE);
01445 }
01446
01447
01448 png_set_write_fn( png_ptr, (void*)stream,
01449 PNGWrite,
01450 PNGFlush);
01451
01452
01453 try
01454 {
01455 row_pointers = new unsigned char*[image->fHeight];
01456 }
01457 catch (...)
01458 {
01459 row_pointers = 0;
01460
01461 throw CATRESULT(CAT_ERR_OUT_OF_MEMORY);
01462 }
01463
01464 for (CATInt32 y = 0; y < image->fHeight; y++)
01465 {
01466 row_pointers[y] = image->fData + (image->XOffsetAbs() * kBytesPerPixel) +
01467 (( (y + image->YOffsetAbs()) * image->AbsWidth())
01468 * kBytesPerPixel);
01469 }
01470
01471 png_set_IHDR( png_ptr,
01472 info_ptr,
01473 image->fWidth,
01474 image->fHeight,
01475 8,
01476 PNG_COLOR_TYPE_RGB_ALPHA,
01477 PNG_INTERLACE_NONE,
01478 PNG_COMPRESSION_TYPE_BASE,
01479 PNG_FILTER_TYPE_BASE);
01480
01481 png_set_rows(png_ptr,info_ptr,row_pointers);
01482
01483 png_write_png(png_ptr, info_ptr, 0, png_voidp_NULL);
01484
01485 delete [] row_pointers;
01486 }
01487 catch (CATResult& thrownRes)
01488 {
01489 if (row_pointers)
01490 {
01491 delete [] row_pointers;
01492 }
01493
01494 result = thrownRes;
01495
01496 result = CATRESULTFILE(result,stream->GetName());
01497 }
01498
01499
01500 png_destroy_write_struct(&png_ptr, &info_ptr);
01501
01502 return result;
01503 }
01504
01505
01506
01507
01508 CATResult CATImage::DbgSave( const CATWChar* filename)
01509 {
01510
01511 CATResult result = CAT_SUCCESS;
01512 CATStreamFile file;
01513 if (CATFAILED(result = file.Open(filename, CATStream::READ_WRITE_CREATE_TRUNC)))
01514 {
01515 return result;
01516 }
01517
01518 result = this->Save(&file,this);
01519
01520 file.Close();
01521
01522 return result;
01523 }
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547 void CATImage::PNGRead( png_structp png_ptr,
01548 png_bytep data,
01549 png_size_t length)
01550 {
01551 CATStream* userStream = (CATStream*)png_ptr->io_ptr;
01552 CATUInt32 amountRead = (CATUInt32)length;
01553 CATResult result = userStream->Read(data,amountRead);
01554 if (CATFAILED(result))
01555 {
01556 throw(result);
01557 }
01558 }
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574 void CATImage::PNGWrite( png_structp png_ptr,
01575 png_bytep data,
01576 png_size_t length)
01577 {
01578 CATStream* userStream = (CATStream*)png_ptr->io_ptr;
01579 CATResult result = userStream->Write(data,(CATUInt32)length);
01580 if (CATFAILED(result))
01581 {
01582 throw(result);
01583 }
01584 }
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597 void CATImage::PNGFlush( png_structp png_ptr)
01598 {
01599 CATStream* userStream = (CATStream*)png_ptr->io_ptr;
01600 }
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610 void CATImage::PNGError( png_structp png_ptr,
01611 png_const_charp error_msg)
01612 {
01613 throw(CATRESULTDESC(CAT_ERR_PNG_CORRUPT,error_msg));
01614 }
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625 void CATImage::PNGWarning( png_structp png_ptr,
01626 png_const_charp warning_msg)
01627 {
01628 throw(CATRESULTDESC(CAT_ERR_PNG_WARNING,warning_msg));
01629 }
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645 CATResult CATImage::CopyOutBGR ( CATUInt8* rgbBuf,
01646 CATInt32 offsetX,
01647 CATInt32 offsetY,
01648 CATInt32 width,
01649 CATInt32 height,
01650 CATInt32 widthBytes)
01651 {
01652 CATASSERT(width != 0, "Width null");
01653 CATASSERT(height != 0, "Height null");
01654 CATASSERT(rgbBuf != 0, "Null buffer passed in.");
01655 if ((width == 0) || (height == 0) || (rgbBuf == 0))
01656 {
01657 return CATRESULT(CAT_ERR_IMAGE_OVERLAY_OUT_OF_BOUNDS);
01658 }
01659
01660 CATASSERT(width + offsetX <= fWidth, "Out of bounds in image copy");
01661 CATASSERT(height + offsetY <= fHeight, "Out of bounds in image copy");
01662 if ( (width + offsetX > fWidth) ||
01663 (height + offsetY > fHeight))
01664 {
01665 return CATRESULT(CAT_ERR_IMAGE_OVERLAY_OUT_OF_BOUNDS);
01666 }
01667
01668
01669 CATInt32 x,y;
01670 CATASSERT(fData != 0, "Image must be created first!");
01671 if (fData == 0)
01672 {
01673 return CATRESULT(CAT_ERR_IMAGE_MUST_INITIALIZE);
01674 }
01675
01676
01677
01678 CATInt32 srcOffX = (this->XOffsetAbs() + offsetX) * kBytesPerPixel;
01679
01680
01681 CATInt32 srcLineLength = this->AbsWidth() * kBytesPerPixel;
01682
01683
01684 CATInt32 srcStep = srcLineLength - (width * kBytesPerPixel);
01685
01686
01687 unsigned char* srcPtr = fData +
01688 srcOffX +
01689 ((YOffsetAbs() + offsetY) * srcLineLength);
01690
01691
01692 unsigned char* dstPtr = rgbBuf;
01693 CATInt32 dstStep = widthBytes - width*3;
01694
01695 CATASSERT(kBytesPerPixel == 4, "Making assumptions on pixel size right now...");
01696
01697
01698 for (y = 0; y < height; y++)
01699 {
01700 CATUInt32* srcDwPtr = (CATUInt32*)srcPtr;
01701
01702 for (x = 0; x < width; x++)
01703 {
01704 CATUInt32 curPixel = *srcDwPtr;
01705 srcDwPtr++;
01706 *dstPtr = (CATUInt8)(curPixel >> 16);
01707 dstPtr++;
01708 *dstPtr = (CATUInt8)(curPixel >> 8);
01709 dstPtr++;
01710 *dstPtr = (CATUInt8)(curPixel);
01711 dstPtr++;
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725 }
01726
01727 srcPtr += srcStep + width*4;
01728 dstPtr += dstStep;
01729 }
01730
01731 return CAT_SUCCESS;
01732 }
01733
01734 unsigned long CATImage::GetRefCount()
01735 {
01736 return this->fRefCount;
01737 }
01738
01739
01740 CATResult CATImage::CreateImageFromDIB( CATImage*& image,
01741 HBITMAP dibSection)
01742 {
01743 CATResult result = CAT_SUCCESS;
01744 image = 0;
01745
01746 try
01747 {
01748 image = new CATImage();
01749 }
01750 catch(...)
01751 {
01752 image = 0;
01753 }
01754
01755 if (image == 0)
01756 {
01757 return CATRESULT(CAT_ERR_OUT_OF_MEMORY);
01758 }
01759
01760 if ((dibSection == 0) || (dibSection == INVALID_HANDLE_VALUE))
01761 {
01762 return CATRESULT(CAT_ERR_INVALID_PARAM);
01763 }
01764
01765 BITMAP bmpInfo;
01766 memset(&bmpInfo,0,sizeof(bmpInfo));
01767 ::GetObject( dibSection, sizeof(BITMAP), &bmpInfo);
01768
01769 CATInt32 width,height;
01770 width = bmpInfo.bmWidth;
01771 height = bmpInfo.bmHeight;
01772
01773 bool upsideDown = (height > 0);
01774 if (!upsideDown)
01775 {
01776 height = -height;
01777 }
01778
01779 if ((width != 0) && (height != 0))
01780 {
01781 result = image->Create(width, height, false, false);
01782 }
01783
01784 if (CATFAILED(result))
01785 {
01786 return result;
01787 }
01788
01789 unsigned char* rawPtr = image->GetRawDataPtr();
01790
01791 CATASSERT(bmpInfo.bmBitsPixel == 24, "Only 24-bit images are currently supported.");
01792
01793 if ((bmpInfo.bmBits != 0) && (bmpInfo.bmBitsPixel == 24))
01794 {
01795 unsigned char* dstPtr = 0;
01796 unsigned char* srcPtr = 0;
01797
01798 for (CATInt32 y = 0; y < height; y++)
01799 {
01800 dstPtr = rawPtr + (y*image->AbsWidth()*4);
01801 srcPtr = (unsigned char*)bmpInfo.bmBits;
01802
01803 if (upsideDown)
01804 srcPtr += ((height-1) - y) * bmpInfo.bmWidthBytes;
01805 else
01806 srcPtr += (y*bmpInfo.bmWidthBytes);
01807
01808
01809 for (CATInt32 x = 0; x < width; x++)
01810 {
01811
01812 *dstPtr = srcPtr[2]; dstPtr++;
01813 *dstPtr = srcPtr[1]; dstPtr++;
01814 *dstPtr = srcPtr[0]; dstPtr++;
01815
01816
01817 *dstPtr = 0xff;
01818 dstPtr++;
01819
01820 srcPtr += 3;
01821 }
01822 }
01823 }
01824
01825 return result;
01826 }