ObjImage.h 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. /*
  2. * Copyright (C) =USTC= Fu Li
  3. *
  4. * Author : Fu Li
  5. * Create : 2001-4-27
  6. * Home : http://www.crazy-bit.com/
  7. * Mail : crazybit@263.net
  8. * History :
  9. */
  10. #ifndef __PCL_OBJECT_IMAGE__2001_04_27__H__
  11. #define __PCL_OBJECT_IMAGE__2001_04_27__H__
  12. #include "ObjBase.h"
  13. #include "FColor.h"
  14. #include "ObjProgress.h"
  15. #include "oxo_helper.h"
  16. #include "imagefile/Interface_ImageHandle.h"
  17. #include "imagefile/Interface_ImageHandleFactory.h"
  18. #include "pixelprocessor/Interface_PixelProcessor.h"
  19. //=============================================================================
  20. /**
  21. * Basic image object.
  22. @verbatim
  23. 1) the origin (0,0) of image lies at left-top point.
  24. 2) all coordinate in this class (POINT, RECT...) relative to image's (0,0).
  25. 3) after image be created, pixel's data are automatically initialized to 0. and if
  26. image's bpp <= 8, a gray palette will be set automatically.
  27. 4) if you want to use Save / Load, you must call SetImageHandleFactory to set a handle factory.
  28. @endverbatim
  29. */
  30. class FCObjImage : public FCObjGraph
  31. {
  32. public:
  33. /**
  34. * @name Constructor.
  35. */
  36. //@{
  37. /// Create an empty image.
  38. FCObjImage () ;
  39. /// Copy constructor.
  40. FCObjImage (const FCObjImage& img) ;
  41. /// Create an image.
  42. FCObjImage (int nWidth, int nHeight, int nColorBit) ;
  43. /// Create an image from a image file.
  44. FCObjImage (const char* szFileName) ;
  45. FCObjImage& operator= (const FCObjImage& img) ;
  46. virtual ~FCObjImage() {Destroy();}
  47. //@}
  48. /**
  49. * Serialize image object in memory (bpp > 8).
  50. * @see FCObject::Serialize
  51. */
  52. virtual int Serialize (bool bSave, BYTE* pSave) ;
  53. /**
  54. * @name Create/Destroy image.
  55. */
  56. //@{
  57. /**
  58. * Create image.
  59. @verbatim
  60. hint:
  61. 1) if image's bpp <= 8, a gray palette will be set automatically.
  62. 2) after image be created, all pixels are automatically initialized to 0.
  63. @endverbatim
  64. */
  65. bool Create (const BITMAPINFOHEADER* pBmif) ;
  66. /// Create image.
  67. bool Create (int nWidth, int nHeight, int nColorBit) ;
  68. /// Destroy image object.
  69. void Destroy() ;
  70. //@}
  71. /**
  72. * @name Basic attributes.
  73. */
  74. //@{
  75. /// Is current image object is valid.
  76. bool IsValidImage() const {return (m_pByte != 0);}
  77. /// this function don't do boundary check, <B>so crash if iLine exceed</B>.
  78. BYTE* GetBits (int iLine) const ;
  79. /// this function don't do boundary check, <B>so crash if y exceed</B>.
  80. BYTE* GetBits (int x, int y) const ;
  81. /// Get image's pixel start-address (address of left-bottom point).
  82. BYTE* GetMemStart() const {return m_pByte;}
  83. /// Pixel width of image.
  84. int Width() const {return m_DibInfo.biWidth;}
  85. /// Pixel height of image.
  86. int Height() const {return m_DibInfo.biHeight;}
  87. /// Image's bpp (bit per pixel), available : 1,4,8,16,24,32.
  88. WORD ColorBits() const {return m_DibInfo.biBitCount;}
  89. /// Bytes pitch between two lines (the value is 4-bytes rounded).
  90. int GetPitch() const {return 4 * ((Width() * ColorBits() + 31) / 32);}
  91. /**
  92. * Create BITMAPINFOHEADER struct.
  93. * palette(<=8bit) or 3-bit-fields(16bit) was appended. <BR><BR>
  94. * you must use <B>delete[]</B> to delete returned point, high recommended to use PCL_Array wrap returned pointer.
  95. @code
  96. PCL_array<BITMAPINFOHEADER> imgInfo (img.NewImgInfoWithPalette()) ;
  97. imgInfo.get()->biWidth ;
  98. pPalette = imgInfo.get() + 1 ;
  99. @endcode
  100. */
  101. BITMAPINFOHEADER* NewImgInfoWithPalette() const ;
  102. /// bound rc into image.
  103. /// @param rc : coordinate in image.
  104. void BoundRect (RECT& rc) const ;
  105. //@}
  106. /**
  107. * @name Pixel access.
  108. */
  109. //@{
  110. /// Is point (x,y) in image.
  111. bool IsInside (int x, int y) const {return (x>=0) && (x<Width()) && (y>=0) && (y<Height());}
  112. /// Get pixel data at (x,y).
  113. DWORD GetPixelData (int x, int y) const ;
  114. /// Set pixel data at (x,y).
  115. void SetPixelData (int x, int y, DWORD dwPixel) ;
  116. //@}
  117. /**
  118. * @name Palette operations (bpp : 1,4,8)
  119. */
  120. //@{
  121. /// Get palette of image.
  122. /// the iFirstIndex is A <B>zero-based</B> color table index.
  123. bool GetColorTable (int iFirstIndex, int iNumber, RGBQUAD* pColors) const ;
  124. /// Set palette of image.
  125. /// the iFirstIndex is A <B>zero-based</B> color table index.
  126. bool SetColorTable (int iFirstIndex, int iNumber, const RGBQUAD* pColors) ;
  127. /// Duplicate palette from imgSrc.
  128. void CopyPalette (const FCObjImage& imgSrc) ;
  129. //@}
  130. /**
  131. * @name Color convert.
  132. */
  133. //@{
  134. /// Convert current image's bpp to 24.
  135. void ConvertTo24Bit() {__ConvertToTrueColor(24);}
  136. /// Convert current image's bpp to 32 (alpha channel will set 0xFF).
  137. void ConvertTo32Bit() {__ConvertToTrueColor(32);}
  138. //@}
  139. /**
  140. * @name Channel operations (bpp == 32)
  141. */
  142. //@{
  143. /// Get alpha channel of 32bpp image (imgAlpha's bpp == 8).
  144. void GetAlphaChannel (FCObjImage* imgAlpha) const ;
  145. /// Set alpha channel of 32bpp image (alpha8's bpp == 8).
  146. void AppendAlphaChannel (const FCObjImage& alpha8) ;
  147. /// Set 32bpp image's alpha channel value.
  148. void SetAlphaChannelValue (int nValue) ;
  149. //@}
  150. /**
  151. * @name Basic transform.
  152. */
  153. //@{
  154. /// Get a block of image (bpp >= 8).
  155. /// if rcBlock exceed image, it will be bounded in image.
  156. bool GetSubBlock (FCObjImage* SubImg, RECT rcBlock) const ;
  157. /// Cover Img on position (x,y) (bpp >= 8).
  158. bool CoverBlock (const FCObjImage& Img, int x, int y) ;
  159. void TileBlock (const FCObjImage& Img, int x, int y) ;
  160. /// Alpha blend image (bpp >= 24).
  161. void AlphaBlend (const FCObjImage& img32, const RECT& rcDest, const RECT& rcSrc, int nAlphaPercent) ;
  162. /// Combine image (bpp == 32).
  163. void CombineImage (const FCObjImage& img32, int x=0, int y=0, int nAlphaPercent=100) ;
  164. void LogicalBlend (const FCObjImage & MaskImg, LOGICAL_OP LogOP, int x=0, int y=0) ;
  165. /// bpp >= 8.
  166. void ExpandFrame (bool bCopyEdge, int iLeft, int iTop, int iRight, int iBottom) ; // add frame
  167. /// bpp >= 8.
  168. void Stretch (int nNewWidth, int nNewHeight) ; // stretch
  169. /// bpp >= 24.
  170. void Stretch_Smooth (int nNewWidth, int nNewHeight, FCObjProgress * progress = NULL) ; // stretch
  171. /// Perform a processor. more detail refer PixelProcessorBase.h
  172. void SinglePixelProcessProc (FCInterface_PixelProcess& rProcessor, FCObjProgress* pProgress=NULL) ;
  173. //@}
  174. /**
  175. * @name Read/Write image file.
  176. */
  177. //@{
  178. /**
  179. * Set image handle factory.
  180. * You must use <B>new</B> to create object and after the object be setted, you can't delete it later.<BR><BR>
  181. * it's a global setting, you can set at startup of program.
  182. @code
  183. FCObjImage::SetImageHandleFactory (new FCImageHandleFactory_FreeImage) ;
  184. @endcode
  185. */
  186. static void SetImageHandleFactory (FCImageHandleFactory* pFactory) {__ManageImageHandleFactory(false,pFactory);}
  187. /// Get image handle factory.
  188. static FCImageHandleFactory* GetImageHandleFactory() {return __ManageImageHandleFactory(true,0);}
  189. /**
  190. * Load image file.
  191. * this function determine image format by file's ext name.
  192. * @param pProperty : optional, you can pass NULL if you don't care.
  193. */
  194. bool Load (const char* szFileName, FCImageProperty* pProperty = 0) ;
  195. /**
  196. * Load image from memory.
  197. * @param pProperty : optional, you can pass NULL if you don't care.
  198. */
  199. bool Load (BYTE* pStart, int nMemSize, IMAGE_TYPE imgType, FCImageProperty* pProperty = 0) ;
  200. /// Load from DIB format memory.
  201. bool LoadDIBStream (const void* pDIB, int nBufferSize) ;
  202. /**
  203. * Save image to file.
  204. * this function determine image format by file's ext name.
  205. * @param nFlag : depends on the image format. <BR>
  206. @verbatim
  207. JPG : compress quality [1..100], default(82)
  208. GIF : transparent color's index in palette
  209. TGA : 1(use RLE compress) / -1(not use), default(not use)
  210. @endverbatim
  211. */
  212. bool Save (const char* szFileName, int nFlag = -1) const
  213. {
  214. // save property
  215. FCImageProperty imgProp ;
  216. imgProp.SetPropertyValue (PROPERTY_TAG_SAVE_FLAG, FCOXOHelper::X2A(nFlag).c_str()) ;
  217. return Save (szFileName, imgProp) ;
  218. }
  219. /// Save image to file.
  220. bool Save (const char* szFileName, const FCImageProperty& rProp) const ;
  221. //@}
  222. private:
  223. BITMAPINFOHEADER m_DibInfo ; // DIB Info
  224. BYTE * m_pByte ; // Bitmap start bits, from left-bottom start
  225. BYTE ** m_ppLine ; // Line-pointer, ppLine[] ; from top to bottom
  226. DWORD m_dwBitFields[3] ; // only 16bit image, order R,G,B
  227. RGBQUAD * m_pPalette ; // palette
  228. private:
  229. void __SetGrayPalette() ;
  230. void __InitClassMember() ; // initialize the member variant
  231. void __ConvertToTrueColor (int iColor) ; // iColor == 24 or 32
  232. static RGBQUAD __Split16Bit_565 (WORD wPixel) ;
  233. static RGBQUAD __Split16Bit_555 (WORD wPixel) ;
  234. static void __FillImageRect (const FCObjImage& img, const RECT& rcBlock, const void* pSrc) ;
  235. static FCImageHandleFactory* __ManageImageHandleFactory (bool bGet, FCImageHandleFactory* pFactory) ;
  236. } ;
  237. //=============================================================================
  238. // inline Implement
  239. //=============================================================================
  240. inline void FCObjImage::__InitClassMember()
  241. {
  242. memset (&m_DibInfo, 0, sizeof(m_DibInfo)) ;
  243. m_dwBitFields[0]=m_dwBitFields[1]=m_dwBitFields[2]=0 ;
  244. m_pByte=0 ; m_ppLine=0 ; m_pPalette=0 ;
  245. }
  246. //-----------------------------------------------------------------------------
  247. inline FCObjImage::FCObjImage()
  248. {
  249. __InitClassMember() ;
  250. }
  251. inline FCObjImage::FCObjImage (const FCObjImage& img)
  252. {
  253. __InitClassMember() ;
  254. *this = img ;
  255. }
  256. inline FCObjImage::FCObjImage (int nWidth, int nHeight, int nColorBit)
  257. {
  258. __InitClassMember() ;
  259. Create (nWidth, nHeight, nColorBit) ;
  260. }
  261. inline FCObjImage::FCObjImage (const char* szFileName)
  262. {
  263. __InitClassMember() ;
  264. Load (szFileName) ;
  265. }
  266. //-----------------------------------------------------------------------------
  267. inline bool FCObjImage::Create (const BITMAPINFOHEADER* pBmif)
  268. {
  269. // unsupported store format
  270. if (!pBmif || (pBmif->biHeight <= 0) || (pBmif->biWidth <= 0))
  271. {assert(false); return false;}
  272. if (!((pBmif->biCompression == BI_RGB) || (pBmif->biCompression == BI_BITFIELDS)))
  273. {assert(false); return false;}
  274. switch (pBmif->biBitCount) // validate bpp
  275. {
  276. case 1 :
  277. case 4 :
  278. case 8 :
  279. case 16 :
  280. case 24 :
  281. case 32 : break ;
  282. default : assert(false); return false;
  283. }
  284. if (IsValidImage())
  285. Destroy() ;
  286. // init struct
  287. memset (&m_DibInfo, 0, sizeof(m_DibInfo)) ;
  288. m_DibInfo.biSize = sizeof(BITMAPINFOHEADER) ;
  289. m_DibInfo.biWidth = pBmif->biWidth ;
  290. m_DibInfo.biHeight = pBmif->biHeight ;
  291. m_DibInfo.biPlanes = 1 ;
  292. m_DibInfo.biBitCount = pBmif->biBitCount ;
  293. m_DibInfo.biCompression = pBmif->biCompression ;
  294. m_DibInfo.biXPelsPerMeter = pBmif->biXPelsPerMeter ;
  295. m_DibInfo.biYPelsPerMeter = pBmif->biYPelsPerMeter ;
  296. // now flag BI_BITFIELDS is only valid in 16bit image
  297. if (pBmif->biBitCount == 16)
  298. {
  299. m_dwBitFields[0] = MASK16_RED_555 ; // 16-bit default format : 5-5-5
  300. m_dwBitFields[1] = MASK16_GREEN_555 ;
  301. m_dwBitFields[2] = MASK16_BLUE_555 ;
  302. if (pBmif->biCompression == BI_BITFIELDS) // custom
  303. memcpy (m_dwBitFields, pBmif + 1, 12) ;
  304. }
  305. else
  306. m_DibInfo.biCompression = BI_RGB ; // i think it's unnecessary to use mask in 32bit image
  307. // create pixel buffer, pixel must must must initialized to zero !!!
  308. m_pByte = FCOXOHelper::ZeroMalloc (GetPitch()*Height()) ;
  309. assert (((int)m_pByte % 4) == 0) ; // DWORD align
  310. // create a line pointer, to accelerate pixel access
  311. m_ppLine = (BYTE **) new BYTE [sizeof(BYTE*) * Height()] ;
  312. const int nPitch = GetPitch() ;
  313. m_ppLine[0] = m_pByte + (Height() - 1) * nPitch ;
  314. for (int y = 1 ; y < Height() ; y++)
  315. m_ppLine[y] = m_ppLine[y - 1] - nPitch ;
  316. // 8bit color image default set a gray palette
  317. if (ColorBits() <= 8)
  318. {
  319. m_pPalette = new RGBQUAD[1 << ColorBits()] ;
  320. __SetGrayPalette() ;
  321. }
  322. return true ;
  323. }
  324. //-----------------------------------------------------------------------------
  325. inline bool FCObjImage::Create (int nWidth, int nHeight, int nColorBit)
  326. {
  327. BITMAPINFOHEADER bmih ;
  328. memset (&bmih, 0, sizeof(bmih)) ;
  329. bmih.biWidth = nWidth ;
  330. bmih.biHeight = nHeight ;
  331. bmih.biBitCount = nColorBit ;
  332. bmih.biCompression = BI_RGB ;
  333. return this->Create (&bmih) ;
  334. }
  335. //-----------------------------------------------------------------------------
  336. inline void FCObjImage::Destroy()
  337. {
  338. if (m_ppLine)
  339. delete[] m_ppLine ;
  340. FCOXOHelper::ZeroFree (m_pByte) ;
  341. if (m_pPalette)
  342. delete[] m_pPalette ;
  343. __InitClassMember() ;
  344. }
  345. //-----------------------------------------------------------------------------
  346. inline BYTE* FCObjImage::GetBits (int iLine) const
  347. {
  348. assert (IsInside(0,iLine)) ;
  349. return m_ppLine[iLine] ;
  350. }
  351. //-----------------------------------------------------------------------------
  352. inline BYTE* FCObjImage::GetBits (int x, int y) const
  353. {
  354. assert (IsInside(x,y)) ;
  355. if (ColorBits() == 32)
  356. return (m_ppLine[y] + x * 4) ;
  357. if (ColorBits() == 8)
  358. return (m_ppLine[y] + x) ;
  359. return (m_ppLine[y] + x * ColorBits() / 8) ;
  360. }
  361. //-----------------------------------------------------------------------------
  362. inline BITMAPINFOHEADER* FCObjImage::NewImgInfoWithPalette() const
  363. {
  364. // prepare info
  365. const int nColorNum = 1 << ColorBits(),
  366. nPalBytes = ((ColorBits() <= 8) ? (4*nColorNum) : 0) ;
  367. BITMAPINFOHEADER * pBmfh = (BITMAPINFOHEADER*) new BYTE[16 + sizeof(BITMAPINFOHEADER) + nPalBytes] ;
  368. *pBmfh = m_DibInfo ;
  369. // append palette(<=8bit) or bit-fields(16bit)
  370. if (ColorBits() <= 8)
  371. GetColorTable (0, nColorNum, (RGBQUAD*)(pBmfh + 1)) ;
  372. else
  373. memcpy (pBmfh + 1, m_dwBitFields, 12) ;
  374. return pBmfh ;
  375. }
  376. //-----------------------------------------------------------------------------
  377. inline void FCObjImage::BoundRect (RECT& rc) const
  378. {
  379. RECT rcImg = {0, 0, Width(), Height()} ;
  380. ::IntersectRect (&rc, &rcImg, &rc) ;
  381. }
  382. //-----------------------------------------------------------------------------
  383. inline DWORD FCObjImage::GetPixelData (int x, int y) const
  384. {
  385. if (!IsInside(x, y))
  386. {assert(false); return 0;}
  387. const BYTE * pPixel = GetBits (x,y) ;
  388. switch (ColorBits())
  389. {
  390. case 1 : return 0x01 & (*pPixel >> (7 - (x & 7))) ;
  391. case 4 : return 0x0F & (*pPixel >> (x & 1 ? 0 : 4)) ;
  392. case 8 : return *(BYTE*)pPixel ;
  393. case 16 : return *(WORD*)pPixel ;
  394. case 24 :
  395. {
  396. DWORD dwrgb = 0 ;
  397. FCColor::CopyPixel (&dwrgb, pPixel, 3) ;
  398. return dwrgb ;
  399. }
  400. case 32 : return *(DWORD*)pPixel ;
  401. default : assert(false) ;
  402. }
  403. return 0 ;
  404. }
  405. //-----------------------------------------------------------------------------
  406. inline void FCObjImage::SetPixelData (int x, int y, DWORD dwPixel)
  407. {
  408. if (!IsInside(x, y))
  409. {assert(false); return;}
  410. BYTE * pPixel = GetBits (x,y) ;
  411. switch (ColorBits())
  412. {
  413. case 1 : *pPixel &= ~(1 << (7 - (x & 7))) ;
  414. *pPixel |= dwPixel << (7 - (x & 7)) ;
  415. break ;
  416. case 4 : *pPixel &= 0x0F << (x & 1 ? 4 : 0) ;
  417. *pPixel |= dwPixel << (x & 1 ? 0 : 4) ;
  418. break ;
  419. case 8 :
  420. case 16 :
  421. case 24 :
  422. case 32 : FCColor::CopyPixel (pPixel, &dwPixel, ColorBits() / 8) ;
  423. break ;
  424. default : assert(false) ;
  425. }
  426. }
  427. //-----------------------------------------------------------------------------
  428. inline bool FCObjImage::GetColorTable (int iFirstIndex, int iNumber, RGBQUAD* pColors) const
  429. {
  430. if (!IsValidImage() || (ColorBits() > 8) || (iFirstIndex < 0) || !pColors || !m_pPalette)
  431. {assert(false); return false;}
  432. const int nColorNum = 1 << ColorBits() ;
  433. for (int i=0 ; i < iNumber ; i++)
  434. {
  435. int nIndex = iFirstIndex + i ;
  436. if (nIndex < nColorNum)
  437. pColors[i] = m_pPalette[nIndex] ;
  438. }
  439. return true ;
  440. }
  441. //-----------------------------------------------------------------------------
  442. inline bool FCObjImage::SetColorTable (int iFirstIndex, int iNumber, const RGBQUAD* pColors)
  443. {
  444. if (!IsValidImage() || (ColorBits() > 8) || (iFirstIndex < 0) || !pColors || !m_pPalette)
  445. {assert(false); return false;}
  446. const int nColorNum = 1 << ColorBits() ;
  447. for (int i=0 ; i < iNumber ; i++)
  448. {
  449. int nIndex = iFirstIndex + i ;
  450. if (nIndex < nColorNum)
  451. m_pPalette[nIndex] = pColors[i] ;
  452. }
  453. return true ;
  454. }
  455. //-----------------------------------------------------------------------------
  456. inline void FCObjImage::CopyPalette (const FCObjImage& imgSrc)
  457. {
  458. if (!IsValidImage() || (ColorBits() > 8) || (ColorBits() != imgSrc.ColorBits()))
  459. {assert(false); return;}
  460. RGBQUAD pPal[256] ;
  461. int nNum = 1 << imgSrc.ColorBits() ;
  462. imgSrc.GetColorTable (0, nNum, pPal) ;
  463. SetColorTable (0, nNum, pPal) ;
  464. }
  465. //-----------------------------------------------------------------------------
  466. inline void FCObjImage::__SetGrayPalette()
  467. {
  468. if (!IsValidImage() || (ColorBits() > 8))
  469. {assert(false); return;}
  470. // calculate palette
  471. RGBQUAD pPal[256] ;
  472. const int nNum = 1 << ColorBits(),
  473. nSpan = 255 / (nNum - 1) ;
  474. for (int i=0 ; i < nNum ; i++)
  475. {
  476. PCL_R(&pPal[i]) = PCL_G(&pPal[i]) = PCL_B(&pPal[i]) = i * nSpan ;
  477. }
  478. SetColorTable (0, nNum, pPal) ;
  479. }
  480. //-----------------------------------------------------------------------------
  481. inline RGBQUAD FCObjImage::__Split16Bit_565 (WORD wPixel)
  482. {
  483. RGBQUAD rgb ;
  484. PCL_R(&rgb) = (MASK16_RED_565 & wPixel) >> 8 ;
  485. PCL_G(&rgb) = (MASK16_GREEN_565 & wPixel) >> 3 ;
  486. PCL_B(&rgb) = (MASK16_BLUE_565 & wPixel) << 3 ;
  487. return rgb ;
  488. }
  489. inline RGBQUAD FCObjImage::__Split16Bit_555 (WORD wPixel)
  490. {
  491. RGBQUAD rgb ;
  492. PCL_R(&rgb) = (MASK16_RED_555 & wPixel) >> 7 ;
  493. PCL_G(&rgb) = (MASK16_GREEN_555 & wPixel) >> 2 ;
  494. PCL_B(&rgb) = (MASK16_BLUE_555 & wPixel) << 3 ;
  495. return rgb ;
  496. }
  497. //-----------------------------------------------------------------------------
  498. inline void FCObjImage::__ConvertToTrueColor (int iColor)
  499. {
  500. if (!IsValidImage() || (ColorBits() == iColor))
  501. return ;
  502. if ((iColor != 24) && (iColor != 32))
  503. {assert(false); return;}
  504. // backup image
  505. const FCObjImage OldPic (*this) ;
  506. if (!Create (OldPic.Width(), OldPic.Height(), iColor))
  507. return ;
  508. // get palette
  509. RGBQUAD pPal[256] ;
  510. if (OldPic.ColorBits() <= 8)
  511. OldPic.GetColorTable (0, 1 << OldPic.ColorBits(), pPal) ;
  512. // start color convert
  513. const int nNewSpan = this->ColorBits() / 8, // 3 or 4
  514. nOldSpan = OldPic.ColorBits() / 8 ;
  515. for (int y=0 ; y < Height() ; y++)
  516. {
  517. const BYTE * pOld = OldPic.GetBits (y) ;
  518. BYTE * pNew = this->GetBits (y) ;
  519. for (int x=0 ; x < Width() ; x++, pNew+=nNewSpan, pOld+=nOldSpan)
  520. {
  521. switch (OldPic.ColorBits())
  522. {
  523. case 1 :
  524. case 4 :
  525. case 8 : // 1,4,8 ==> 24,32
  526. FCColor::CopyPixel (pNew, &pPal[OldPic.GetPixelData(x,y)], 3) ;
  527. break ;
  528. case 16 : // 16 ==> 24,32
  529. {
  530. RGBQUAD crTrans ;
  531. if (OldPic.m_dwBitFields[1] == MASK16_GREEN_555)
  532. crTrans = __Split16Bit_555 (*(WORD*)pOld) ;
  533. else if (OldPic.m_dwBitFields[1] == MASK16_GREEN_565)
  534. crTrans = __Split16Bit_565 (*(WORD*)pOld) ;
  535. FCColor::CopyPixel (pNew, &crTrans, 3) ;
  536. }
  537. break ;
  538. case 24 :
  539. case 32 : // 24,32 ==> 32,24
  540. FCColor::CopyPixel (pNew, pOld, 3) ;
  541. break ;
  542. }
  543. }
  544. }
  545. if (iColor == 32)
  546. SetAlphaChannelValue (0xFF) ; // set alpha to 0xFF
  547. }
  548. //-----------------------------------------------------------------------------
  549. inline void FCObjImage::GetAlphaChannel (FCObjImage* imgAlpha) const
  550. {
  551. // create alpha-channel image, it's a 8-bit color image
  552. if (!imgAlpha || !IsValidImage() || (ColorBits() != 32) || (imgAlpha == this)
  553. || !imgAlpha->Create (Width(), Height(), 8))
  554. {
  555. assert(false) ; return ;
  556. }
  557. // get alpha channel
  558. for (int y=0 ; y < Height() ; y++)
  559. for (int x=0 ; x < Width() ; x++)
  560. *imgAlpha->GetBits(x,y) = PCL_A(GetBits(x,y)) ;
  561. }
  562. //-----------------------------------------------------------------------------
  563. inline void FCObjImage::AppendAlphaChannel (const FCObjImage& alpha)
  564. {
  565. if (!IsValidImage() || !alpha.IsValidImage() || (ColorBits() != 32) || (alpha.ColorBits() != 8) ||
  566. (Width() != alpha.Width()) || (Height() != alpha.Height()))
  567. {
  568. assert(false) ; return ;
  569. }
  570. // append alpha channel
  571. for (int y=0 ; y < Height() ; y++)
  572. for (int x=0 ; x < Width() ; x++)
  573. PCL_A(GetBits(x,y)) = *alpha.GetBits(x,y) ;
  574. }
  575. //-----------------------------------------------------------------------------
  576. inline void FCObjImage::SetAlphaChannelValue (int nValue)
  577. {
  578. if (!IsValidImage() || (ColorBits() != 32))
  579. {
  580. assert(false) ; return ;
  581. }
  582. for (int y=0 ; y < Height() ; y++)
  583. for (int x=0 ; x < Width() ; x++)
  584. PCL_A(GetBits(x,y)) = nValue ;
  585. }
  586. //-----------------------------------------------------------------------------
  587. inline FCObjImage& FCObjImage::operator= (const FCObjImage& img)
  588. {
  589. if (!img.IsValidImage() || (&img == this))
  590. return (*this) ;
  591. PCL_array<BITMAPINFOHEADER> bmfh (img.NewImgInfoWithPalette()) ;
  592. if (Create (bmfh.get()))
  593. {
  594. // copy the pixels
  595. memcpy (GetMemStart(), img.GetMemStart(), img.GetPitch()*img.Height()) ;
  596. // copy the palette
  597. if (img.ColorBits() <= 8)
  598. CopyPalette (img) ;
  599. // copy position
  600. FCObjGraph::operator=(img) ;
  601. }
  602. return *this ;
  603. }
  604. //-----------------------------------------------------------------------------
  605. inline bool FCObjImage::GetSubBlock (FCObjImage* SubImg, RECT rcBlock) const
  606. {
  607. if (!IsValidImage() || !SubImg || (SubImg == this) || (ColorBits() < 8))
  608. {
  609. assert(false); return false;
  610. }
  611. const RECT rcImage = {0, 0, Width(), Height()} ;
  612. RECT rcD ;
  613. assert (IsRectInRect (rcImage, rcBlock)) ;
  614. if (::IntersectRect (&rcD, &rcImage, &rcBlock) == 0)
  615. {
  616. assert(false); return false; // rect of destination is empty
  617. }
  618. if (!SubImg->Create (RECTWIDTH(rcD), RECTHEIGHT(rcD), ColorBits()))
  619. return false ;
  620. // copy pixel
  621. const int nSubPitch = SubImg->Width() * ColorBits() / 8 ;
  622. for (int i=0 ; i < SubImg->Height() ; i++)
  623. memcpy (SubImg->GetBits(i), GetBits(rcD.left, rcD.top + i), nSubPitch) ;
  624. // copy palette
  625. if (ColorBits() <= 8)
  626. SubImg->CopyPalette (*this) ;
  627. // set relative position
  628. SubImg->SetGraphObjPos (rcD.left, rcD.top) ;
  629. return true ;
  630. }
  631. //-----------------------------------------------------------------------------
  632. inline bool FCObjImage::CoverBlock (const FCObjImage& Img, int x, int y)
  633. {
  634. if (!IsValidImage() || !Img.IsValidImage() || (ColorBits() != Img.ColorBits()) || (ColorBits() < 8))
  635. {
  636. assert(false); return false;
  637. }
  638. // calculate covered RECT
  639. const RECT rcImage = {0, 0, Width(), Height()},
  640. rcCover = {x, y, x+Img.Width(), y+Img.Height()} ;
  641. RECT rcD ;
  642. if (::IntersectRect (&rcD, &rcImage, &rcCover) == 0)
  643. return false ; // rect of destination is empty
  644. // copy pixel
  645. const int nSubPitch = RECTWIDTH(rcD) * Img.ColorBits() / 8 ;
  646. for (int cy=rcD.top ; cy < rcD.bottom ; cy++) // copy
  647. {
  648. const BYTE * pS = Img.GetBits (rcD.left-x, cy-y) ; // calculate edge
  649. BYTE * pD = this->GetBits (rcD.left, cy) ;
  650. memcpy (pD, pS, nSubPitch) ;
  651. }
  652. return true ;
  653. }
  654. //-----------------------------------------------------------------------------
  655. inline void FCObjImage::TileBlock (const FCObjImage & Img, int x, int y)
  656. {
  657. int nYStart = y ;
  658. while (nYStart < Height())
  659. {
  660. int nXStart = x ;
  661. while (nXStart < Width())
  662. {
  663. CoverBlock (Img, nXStart, nYStart) ; // security ensured by CoverBlock
  664. nXStart += Img.Width() ;
  665. }
  666. nYStart += Img.Height() ;
  667. }
  668. }
  669. //-----------------------------------------------------------------------------
  670. inline void FCObjImage::CombineImage (const FCObjImage& Img32, int x, int y, int nAlphaPercent)
  671. {
  672. RECT rcD ;
  673. {
  674. RECT rcImg = {0, 0, Width(), Height()},
  675. rcMask = {x, y, x+Img32.Width(), y+Img32.Height()} ;
  676. ::IntersectRect (&rcD, &rcImg, &rcMask) ;
  677. }
  678. if ((Img32.ColorBits() != 32) || (ColorBits() != 32) || IsRectEmpty(&rcD))
  679. {
  680. assert(false); return;
  681. }
  682. nAlphaPercent = FClamp (nAlphaPercent, 0, 100) ;
  683. for (int cy=rcD.top ; cy < rcD.bottom ; cy++)
  684. {
  685. RGBQUAD * pDest = (RGBQUAD*)this->GetBits (rcD.left, cy),
  686. * pSrc = (RGBQUAD*)Img32.GetBits (rcD.left-x, cy-y) ; // calculate edge
  687. for (int cx=rcD.left ; cx < rcD.right ; cx++, pDest++, pSrc++)
  688. FCColor::CombineAlphaPixel(pDest, *pDest, pSrc,
  689. (nAlphaPercent == 100) ? PCL_A(pSrc)
  690. : (PCL_A(pSrc)*nAlphaPercent/100)) ;
  691. }
  692. }
  693. //-----------------------------------------------------------------------------
  694. // alpha混和是图像处理的心脏,它的效率和安全性关系着整个软件
  695. // 因此我才这么麻烦的处理之
  696. // rcSrc一定要在MaskImg32内部,rcDest可以相交
  697. inline void FCObjImage::AlphaBlend (const FCObjImage& Img32, const RECT& rcDest, const RECT& rcSrc, int nAlphaPercent)
  698. {
  699. if (nAlphaPercent == 0)
  700. return ;
  701. // parameter check, rcSrc一定要在MaskImg32内部
  702. const RECT rcMask = {0, 0, Img32.Width(), Img32.Height()},
  703. rcImg = {0, 0, Width(), Height()} ;
  704. RECT rcT ;
  705. IntersectRect(&rcT, &rcDest, &rcImg) ;
  706. if (!IsValidImage() || (ColorBits() < 24) || !Img32.IsValidImage() || (Img32.ColorBits() != 32) ||
  707. !IsRectInRect (rcMask, rcSrc) || IsRectEmpty(&rcT))
  708. {
  709. assert(false); return;
  710. }
  711. nAlphaPercent = FClamp (nAlphaPercent, 0, 100) ;
  712. const int nSpan = ColorBits() / 8 ; // 3 or 4
  713. if ((RECTWIDTH(rcDest) == RECTWIDTH(rcSrc)) && (RECTHEIGHT(rcDest) == RECTHEIGHT(rcSrc)))
  714. {
  715. const int nSrcX = rcT.left - rcDest.left + rcSrc.left ;
  716. for (int y=rcT.top ; y < rcT.bottom ; y++)
  717. {
  718. const BYTE * pSrc = Img32.GetBits (nSrcX, y-rcDest.top+rcSrc.top) ; // calculate edge
  719. BYTE * pDest = this->GetBits (rcT.left, y) ;
  720. for (int x=rcT.left ; x < rcT.right ; x++, pDest+=nSpan, pSrc+=4)
  721. FCColor::AlphaBlendPixel (pDest, pSrc, (nAlphaPercent==100) ? PCL_A(pSrc)
  722. : PCL_A(pSrc)*nAlphaPercent/100) ;
  723. }
  724. }
  725. else
  726. {
  727. PCL_array<int> pX (RECTWIDTH(rcT)),
  728. pY (RECTHEIGHT(rcT)) ;
  729. int x, y ;
  730. for (y=rcT.top ; y < rcT.bottom ; y++)
  731. pY[y-rcT.top] = rcSrc.top+(y-rcDest.top)*RECTHEIGHT(rcSrc)/RECTHEIGHT(rcDest) ;
  732. for (x=rcT.left ; x < rcT.right ; x++)
  733. pX[x-rcT.left] = rcSrc.left+(x-rcDest.left)*RECTWIDTH(rcSrc)/RECTWIDTH(rcDest) ;
  734. for (y=rcT.top ; y < rcT.bottom ; y++)
  735. {
  736. BYTE * pDest = this->GetBits (rcT.left, y) ;
  737. for (x=rcT.left ; x < rcT.right ; x++, pDest+=nSpan)
  738. {
  739. const BYTE * pSrc = Img32.GetBits (pX[x-rcT.left], pY[y-rcT.top]) ;
  740. FCColor::AlphaBlendPixel (pDest, pSrc, (nAlphaPercent==100) ? PCL_A(pSrc)
  741. : PCL_A(pSrc)*nAlphaPercent/100) ;
  742. }
  743. }
  744. }
  745. }
  746. //-----------------------------------------------------------------------------
  747. inline void FCObjImage::LogicalBlend (const FCObjImage & MaskImg, LOGICAL_OP LogOP, int x, int y)
  748. {
  749. if (!IsValidImage() || !MaskImg.IsValidImage() || (ColorBits() != MaskImg.ColorBits()) || (this == &MaskImg))
  750. {
  751. assert(false) ; return ;
  752. }
  753. assert (ColorBits() == 8) ;
  754. const RECT rcSrc1 = {0, 0, Width(), Height()},
  755. rcSrc2 = {x, y, x+MaskImg.Width(), y+MaskImg.Height()} ;
  756. RECT rcDest ;
  757. if (::IntersectRect (&rcDest, &rcSrc1, &rcSrc2) == 0)
  758. return ; // no intersected rect
  759. const int nSpan = ColorBits() / 8; // 1,2,3,4
  760. for (int cy=rcDest.top ; cy < rcDest.bottom ; cy++)
  761. {
  762. const BYTE * pSrc = MaskImg.GetBits (rcDest.left-x, cy-y) ; // calculate edge
  763. BYTE * pDest = this->GetBits (rcDest.left, cy) ;
  764. for (int cx=rcDest.left ; cx < rcDest.right ; cx++, pDest+=nSpan, pSrc+=nSpan)
  765. switch (LogOP)
  766. {
  767. case LOGI_OR : *pDest |= *pSrc ; break ;
  768. case LOGI_AND : *pDest &= *pSrc ; break ;
  769. case LOGI_XOR : *pDest ^= *pSrc ; break ;
  770. case LOGI_SEL_ADD :
  771. if (*pSrc == 0xFF)
  772. *pDest = 0xFF ;
  773. break ;
  774. case LOGI_SEL_SUB :
  775. if (*pSrc == 0xFF)
  776. *pDest = 0 ;
  777. break ;
  778. default : assert(false);
  779. }
  780. }
  781. }
  782. //-----------------------------------------------------------------------------
  783. inline int FCObjImage::Serialize (bool bSave, BYTE* pSave)
  784. {
  785. const BYTE * pBak = pSave ;
  786. if (bSave) // save
  787. {
  788. assert (ColorBits() > 8) ; // must true color image
  789. memcpy (pSave, &m_DibInfo, sizeof(m_DibInfo)) ; pSave += sizeof(m_DibInfo) ;
  790. memcpy (pSave, m_dwBitFields, 12) ; pSave += 12 ;
  791. int nWrite = GetPitch() * Height() ;
  792. memcpy (pSave, GetMemStart(), nWrite) ; pSave += nWrite ;
  793. }
  794. else // load
  795. {
  796. Create ((BITMAPINFOHEADER*)pSave) ;
  797. pSave += sizeof(m_DibInfo) + 12 ;
  798. int nWrite = GetPitch() * Height() ;
  799. memcpy (GetMemStart(), pSave, nWrite) ;
  800. pSave += nWrite ;
  801. }
  802. pSave += FCObjGraph::Serialize (bSave, pSave) ;
  803. return (int)(pSave - pBak) ;
  804. }
  805. //-----------------------------------------------------------------------------
  806. inline bool FCObjImage::Load (const char* szFileName, FCImageProperty* pProperty)
  807. {
  808. IMAGE_TYPE imgType = GetImageHandleFactory()->QueryImageFileType(szFileName) ;
  809. std::auto_ptr<FCImageHandleBase> pHandler (GetImageHandleFactory()->CreateImageHandle(imgType)) ;
  810. if (!pHandler.get())
  811. return false ;
  812. PCL_Interface_Composite<FCObjImage> listImage ;
  813. std::auto_ptr<FCImageProperty> pImgProp ;
  814. bool bRet = pHandler->LoadImageFile (szFileName, listImage, pImgProp) ;
  815. if (bRet)
  816. {
  817. if (listImage.PCL_GetObjectCount())
  818. *this = *listImage.PCL_GetObject(0) ;
  819. if (pImgProp.get() && pProperty)
  820. *pProperty = *pImgProp ;
  821. }
  822. assert (bRet) ;
  823. return bRet ;
  824. }
  825. //-----------------------------------------------------------------------------
  826. inline bool FCObjImage::Load (BYTE* pStart, int nMemSize, IMAGE_TYPE imgType, FCImageProperty* pProperty)
  827. {
  828. std::auto_ptr<FCImageHandleBase> pHandler (GetImageHandleFactory()->CreateImageHandle(imgType)) ;
  829. if (!pHandler.get())
  830. return false ;
  831. PCL_Interface_Composite<FCObjImage> listImage ;
  832. std::auto_ptr<FCImageProperty> pImgProp ;
  833. bool bRet = pHandler->LoadImageMemory (pStart, nMemSize, listImage, pImgProp) ;
  834. if (bRet)
  835. {
  836. if (listImage.PCL_GetObjectCount())
  837. *this = *listImage.PCL_GetObject(0) ;
  838. if (pImgProp.get() && pProperty)
  839. *pProperty = *pImgProp ;
  840. }
  841. assert (bRet) ;
  842. return bRet ;
  843. }
  844. //-----------------------------------------------------------------------------
  845. inline bool FCObjImage::LoadDIBStream (const void* pDIB, int nBufferSize)
  846. {
  847. const BITMAPINFOHEADER * pBmif = (const BITMAPINFOHEADER*)pDIB ;
  848. if (!Create(pBmif))
  849. {assert(false); return false;}
  850. const BYTE * p = (const BYTE*)pDIB + pBmif->biSize ;
  851. if (ColorBits() <= 8)
  852. {
  853. int n = 1 << ColorBits() ;
  854. SetColorTable (0, n, (const RGBQUAD*)p) ;
  855. p += (4 * n) ;
  856. }
  857. else if (pBmif->biCompression == BI_BITFIELDS)
  858. {
  859. p += 12 ;
  860. }
  861. // copy pixel
  862. int nLeave = nBufferSize - (p - (BYTE*)pDIB) ;
  863. assert (nLeave >= GetPitch()*Height()) ;
  864. memcpy (GetMemStart(), p, FMin (nLeave, GetPitch()*Height())) ;
  865. return true ;
  866. }
  867. //-----------------------------------------------------------------------------
  868. inline bool FCObjImage::Save (const char* szFileName, const FCImageProperty& rProp) const
  869. {
  870. if (!IsValidImage() || !szFileName)
  871. return false ;
  872. IMAGE_TYPE imgType = GetImageHandleFactory()->QueryImageFileType(szFileName) ;
  873. std::auto_ptr<FCImageHandleBase> pHandler (GetImageHandleFactory()->CreateImageHandle(imgType)) ;
  874. if (!pHandler.get())
  875. return false ;
  876. // save list
  877. std::deque<const FCObjImage*> saveList ;
  878. saveList.push_back (this) ;
  879. return pHandler->SaveImageFile (szFileName, saveList, rProp) ;
  880. }
  881. //-----------------------------------------------------------------------------
  882. inline void FCObjImage::__FillImageRect (const FCObjImage& img, const RECT& rcBlock, const void* pSrc)
  883. {
  884. RECT rc = {0, 0, img.Width(), img.Height()} ;
  885. IntersectRect (&rc, &rc, &rcBlock) ;
  886. if (IsRectEmpty(&rc))
  887. return ;
  888. const int nSpan = img.ColorBits() / 8 ; // 1, 2, 3, 4
  889. for (int y=rc.top ; y < rc.bottom ; y++)
  890. {
  891. BYTE * pPixel = img.GetBits (rc.left, y) ;
  892. for (int x=rc.left ; x < rc.right ; x++, pPixel += nSpan)
  893. FCColor::CopyPixel (pPixel, pSrc, nSpan) ;
  894. }
  895. }
  896. // add frame
  897. // bCopyEdge: duplicate edge during copying
  898. inline void FCObjImage::ExpandFrame (bool bCopyEdge, int iLeft, int iTop, int iRight, int iBottom)
  899. {
  900. if ((ColorBits() < 8) || (iLeft < 0) || (iTop < 0) || (iRight < 0) || (iBottom < 0))
  901. {
  902. assert(false) ; return ;
  903. }
  904. if ((iLeft == 0) && (iTop == 0) && (iRight == 0) && (iBottom == 0))
  905. return ;
  906. // backup image then create expanded image
  907. const FCObjImage imgOld(*this) ;
  908. if (!Create (imgOld.Width()+iLeft+iRight, imgOld.Height()+iTop+iBottom, imgOld.ColorBits()))
  909. {
  910. assert(false) ; return ;
  911. }
  912. // adjust image's position
  913. SetGraphObjPos (imgOld.GetGraphObjPos().x - iLeft, imgOld.GetGraphObjPos().y - iTop) ;
  914. // duplicate source image
  915. CoverBlock (imgOld, iLeft, iTop) ;
  916. // edge disposal
  917. if (!bCopyEdge)
  918. return ;
  919. // duplicate corner
  920. const RECT rcUL = {0, 0, iTop, iLeft},
  921. rcUR = {Width()-iRight, 0, Width(), iTop},
  922. rcDL = {0, Height()-iBottom, iLeft, Height()},
  923. rcDR = {Width()-iRight, Height()-iBottom, Width(), Height()} ;
  924. __FillImageRect (*this, rcUL, imgOld.GetBits (0, 0)) ;
  925. __FillImageRect (*this, rcUR, imgOld.GetBits (imgOld.Width()-1, 0)) ;
  926. __FillImageRect (*this, rcDL, imgOld.GetBits (0, imgOld.Height()-1)) ;
  927. __FillImageRect (*this, rcDR, imgOld.GetBits (imgOld.Width()-1, imgOld.Height()-1)) ;
  928. // duplicate four-edge
  929. const int dwPitch = GetPitch(),
  930. nSpan = ColorBits() / 8,
  931. nOldLineBytes = imgOld.Width() * nSpan ;
  932. int m ;
  933. BYTE * pSrc, * pDest ;
  934. // up
  935. pSrc = GetBits (iLeft, iTop) ;
  936. pDest = pSrc + dwPitch ;
  937. for (m=0 ; m < iTop ; m++, pDest += dwPitch)
  938. memcpy (pDest, pSrc, nOldLineBytes) ;
  939. // bottom
  940. pSrc = GetBits (iLeft, imgOld.Height() + iTop - 1) ;
  941. pDest = pSrc - dwPitch ;
  942. for (m=0 ; m < iBottom ; m++, pDest -= dwPitch)
  943. memcpy (pDest, pSrc, nOldLineBytes) ;
  944. // left
  945. pSrc = GetBits (iLeft, iTop) ;
  946. pDest = GetBits (0, iTop) ;
  947. for (m=0 ; m < imgOld.Height() ; m++, pDest -= dwPitch, pSrc -= dwPitch)
  948. {
  949. BYTE * pTemp = pDest ;
  950. for (int i=0 ; i < iLeft ; i++, pTemp += nSpan)
  951. FCColor::CopyPixel (pTemp, pSrc, nSpan) ;
  952. }
  953. // right
  954. pSrc = GetBits (iLeft + imgOld.Width() - 1, iTop) ;
  955. pDest = pSrc + nSpan ;
  956. for (m=0 ; m < imgOld.Height() ; m++, pDest -= dwPitch, pSrc -= dwPitch)
  957. {
  958. BYTE * pTemp = pDest ;
  959. for (int i=0 ; i < iRight ; i++, pTemp += nSpan)
  960. FCColor::CopyPixel (pTemp, pSrc, nSpan) ;
  961. }
  962. }
  963. //-----------------------------------------------------------------------------
  964. // stretch (>=8 bit)
  965. inline void FCObjImage::Stretch (int nNewWidth, int nNewHeight)
  966. {
  967. // parameter check
  968. if (!IsValidImage() || (nNewWidth <= 0) || (nNewHeight <= 0) || (ColorBits() < 8))
  969. {
  970. // assert(false) ;
  971. return ;
  972. }
  973. if ((nNewWidth == Width()) && (nNewHeight == Height()))
  974. return ;
  975. // first backup image
  976. const FCObjImage imgOld(*this) ;
  977. if (!Create (nNewWidth, nNewHeight, imgOld.ColorBits()))
  978. {
  979. assert(false) ; return ;
  980. }
  981. // duplicate palette
  982. if (ColorBits() <= 8)
  983. CopyPalette (imgOld) ;
  984. // initialize index table
  985. const int nSpan = ColorBits() / 8 ;
  986. PCL_array<int> pTabX (Width()) ;
  987. for (int xx=0 ; xx < Width() ; xx++)
  988. {
  989. pTabX[xx] = xx * imgOld.Width() / Width() ; // force to omit float
  990. assert (pTabX[xx] < imgOld.Width()) ;
  991. }
  992. for (int mm=0 ; mm < (Width() - 1) ; mm++)
  993. pTabX[mm] = (pTabX[mm+1] - pTabX[mm]) * nSpan ;
  994. // pTabX[i] put X byte span
  995. for (int y=0 ; y < Height() ; y++)
  996. {
  997. const BYTE * pOld = imgOld.GetBits (y * imgOld.Height() / Height()) ;
  998. BYTE * pPixel = GetBits (y) ;
  999. for (int x=0 ; x < Width() ; x++)
  1000. {
  1001. FCColor::CopyPixel (pPixel, pOld, nSpan) ;
  1002. pOld += pTabX[x] ;
  1003. pPixel += nSpan ;
  1004. }
  1005. }
  1006. }
  1007. //-----------------------------------------------------------------------------
  1008. // stretch (>=24 bit)
  1009. inline void FCObjImage::Stretch_Smooth (int nNewWidth, int nNewHeight, FCObjProgress * progress)
  1010. {
  1011. // parameter check
  1012. if (!IsValidImage() || (nNewWidth <= 0) || (nNewHeight <= 0) || (ColorBits() < 24))
  1013. {
  1014. assert(false) ; return ;
  1015. }
  1016. if ((nNewWidth == Width()) && (nNewHeight == Height()))
  1017. return ;
  1018. // in order to bilinear, the source image's W/H must larger than 2
  1019. if ((Width() == 1) || (Height() == 1))
  1020. {
  1021. ExpandFrame (true, 0, 0, (Width()==1) ? 1 : 0, (Height()==1) ? 1 : 0) ;
  1022. }
  1023. // first backup image
  1024. const FCObjImage imgOld(*this) ;
  1025. if (!Create (nNewWidth, nNewHeight, imgOld.ColorBits()))
  1026. {
  1027. assert(false) ; return ;
  1028. }
  1029. // initialize index table, to accelerate
  1030. PCL_array<int> pTabX (Width()),
  1031. pXMod (Width()) ;
  1032. for (int i=0 ; i < Width() ; i++)
  1033. {
  1034. pTabX[i] = i * imgOld.Width() / Width() ;
  1035. pXMod[i] = (i * imgOld.Width()) % Width() ;
  1036. // approximate to last col
  1037. if (pTabX[i] >= imgOld.Width()-1)
  1038. {
  1039. pTabX[i] = imgOld.Width() - 2 ;
  1040. pXMod[i] = Width() - 1 ;
  1041. }
  1042. }
  1043. // stretch pixel
  1044. const int nSpan = ColorBits() / 8,
  1045. nPitch = imgOld.GetPitch() ;
  1046. if (progress)
  1047. progress->ResetProgress() ; // reset to 0
  1048. for (int y=0 ; y < Height() ; y++)
  1049. {
  1050. int nSrcY = y * imgOld.Height() / Height(),
  1051. nYMod = (y * imgOld.Height()) % Height() ;
  1052. if (nSrcY >= imgOld.Height()-1) // approximate to last row
  1053. {
  1054. nSrcY = imgOld.Height() - 2 ;
  1055. nYMod = Height() - 1 ;
  1056. }
  1057. const double un_y = nYMod / (double)Height() ;
  1058. BYTE * pWrite = GetBits(y) ;
  1059. for (int x=0 ; x < Width() ; x++, pWrite += nSpan)
  1060. {
  1061. // 计算原图对应点
  1062. const int nSrcX = pTabX[x],
  1063. nXMod = pXMod[x] ;
  1064. const BYTE * pOldPix = imgOld.GetBits (nSrcX, nSrcY) ;
  1065. if ((nXMod == 0) && (nYMod == 0))
  1066. {
  1067. FCColor::CopyPixel (pWrite, pOldPix, nSpan) ;
  1068. }
  1069. else
  1070. {
  1071. const BYTE * pcrPixel[4] =
  1072. {
  1073. pOldPix, pOldPix + nSpan,
  1074. pOldPix - nPitch, pOldPix - nPitch + nSpan
  1075. } ;
  1076. RGBQUAD crRet = FCColor::Get_Bilinear_Pixel (nXMod/(double)Width(), un_y, ColorBits() == 32, pcrPixel) ;
  1077. FCColor::CopyPixel (pWrite, &crRet, nSpan) ;
  1078. }
  1079. }
  1080. if (progress)
  1081. progress->SetProgress (y * 100 / Height()) ;
  1082. }
  1083. }
  1084. //-----------------------------------------------------------------------------
  1085. inline void FCObjImage::SinglePixelProcessProc (FCInterface_PixelProcess& rProcessor, FCObjProgress* pProgress)
  1086. {
  1087. if (!rProcessor.ValidateColorBits (this))
  1088. {assert(false); return;}
  1089. // before
  1090. rProcessor.OnEnterProcess (this) ;
  1091. if (pProgress)
  1092. pProgress->ResetProgress() ; // reset to 0
  1093. switch (rProcessor.QueryProcessType())
  1094. {
  1095. case FCInterface_PixelProcess::PROCESS_TYPE_PIXEL :
  1096. {
  1097. for (int y=0 ; y < Height() ; y++)
  1098. {
  1099. for (int x=0 ; x < Width() ; x++)
  1100. {
  1101. rProcessor.ProcessPixel (this, x, y, GetBits(x,y)) ;
  1102. }
  1103. if (pProgress)
  1104. pProgress->SetProgress ((y+1) * 100 / Height()) ;
  1105. }
  1106. }
  1107. break ;
  1108. case FCInterface_PixelProcess::PROCESS_TYPE_WHOLE :
  1109. rProcessor.ProcessWholeImage (this, pProgress) ;
  1110. break ;
  1111. }
  1112. // after
  1113. rProcessor.OnLeaveProcess (this) ;
  1114. }
  1115. #endif