ObjCanvas.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /*
  2. * Copyright (C) =USTC= Fu Li
  3. *
  4. * Author : Fu Li
  5. * Create : 2003-3-30
  6. * Home : http://www.crazy-bit.com/
  7. * Mail : crazybit@263.net
  8. * History :
  9. */
  10. #ifndef __FOO_OBJECT_CANVAS__2003_03_30__H__
  11. #define __FOO_OBJECT_CANVAS__2003_03_30__H__
  12. #include "ObjLayer.h"
  13. #include "ObjSelect.h"
  14. #include "pixelprocessor/PixelProcessorBase.h"
  15. #include "command/Interface_Command.h"
  16. #include "PCL_interface_zoom.h"
  17. #include "PCL_interface_undo.h"
  18. #include <algorithm>
  19. //=============================================================================
  20. /**
  21. * Canvas object - container of layers.
  22. */
  23. class FCObjCanvas : public PCL_Interface_ZoomScale,
  24. public PCL_Interface_Undo<FCCmdArtPrider>
  25. {
  26. public:
  27. /// Constructor.
  28. FCObjCanvas (int nUndoLevel = 20) : PCL_Interface_Undo<FCCmdArtPrider>(nUndoLevel)
  29. {
  30. m_sizeCanvas.cx = m_sizeCanvas.cy = 0 ;
  31. m_pCurrentLayer = 0 ;
  32. m_nResX = m_nResY = 72 ;
  33. }
  34. virtual ~FCObjCanvas()
  35. {
  36. // first, maybe command hold layer's pointer
  37. ClearUndoList() ;
  38. ClearRedoList() ;
  39. // layers
  40. while (!m_LayerList.empty())
  41. {
  42. FCObjLayer * p = m_LayerList.back() ;
  43. m_LayerList.pop_back() ;
  44. delete p ;
  45. }
  46. // removed layers
  47. while (!m_RemovedLayerList.empty())
  48. {
  49. FCObjLayer * p = m_RemovedLayerList.back() ;
  50. m_RemovedLayerList.pop_back() ;
  51. delete p ;
  52. }
  53. m_pCurrentLayer = 0 ;
  54. }
  55. /// Set DPI (dot per inch) resolution.
  56. void SetCanvasResolution (int nResX, int nResY) {m_nResX=nResX ; m_nResY=nResY ;}
  57. /// Get DPI (dot per inch) resolution.
  58. void GetCanvasResolution (int& nResX, int& nResY) const {nResX=m_nResX ; nResY=m_nResY ;}
  59. /// Set canvas's size.
  60. void SetCanvasDimension (SIZE sz) {m_sizeCanvas=sz; assert(sz.cx>=1 && sz.cy>=1);}
  61. /// Get canvas's size.
  62. SIZE GetCanvasDimension () const {return m_sizeCanvas;}
  63. /// Get canvas's scaled size.
  64. SIZE GetCanvasScaledDimension() const
  65. {
  66. POINT pt = {m_sizeCanvas.cx, m_sizeCanvas.cy} ;
  67. Actual_to_Scaled (pt) ;
  68. SIZE sz = {pt.x, pt.y} ;
  69. return sz ;
  70. }
  71. /// Get current selection object on canvas.
  72. const FCObjSelect& GetSelection() const {return m_CurrSel;}
  73. /// Has a selection object on canvas.
  74. bool HasSelected() const {return m_CurrSel.HasSelected();}
  75. /// Bound rect in canvas (rc is coordinate of canvas).
  76. void BoundRect (RECT& rc) const
  77. {
  78. RECT rcCanvas = {0, 0, m_sizeCanvas.cx, m_sizeCanvas.cy} ;
  79. ::IntersectRect (&rc, &rcCanvas, &rc) ;
  80. }
  81. /**
  82. * @name Layers manage.
  83. */
  84. //@{
  85. /// Get number of layers on canvas.
  86. int GetLayerNumber() const {return (int)m_LayerList.size();}
  87. /// Get zero-based index layer.
  88. FCObjLayer* GetLayer (int nIndex) const
  89. {
  90. if ((nIndex >= 0) && (nIndex < GetLayerNumber()))
  91. return m_LayerList[nIndex] ;
  92. else
  93. return 0 ;
  94. }
  95. /// Get current layer of canvas.
  96. FCObjLayer* GetCurrentLayer() const {return m_pCurrentLayer;}
  97. /// Get current layer's index.
  98. int GetCurrentLayerIndex() const {return FindLayer(m_pCurrentLayer);}
  99. /// Set current layer of canvas.
  100. void SetCurrentLayer (int nIndex)
  101. {
  102. FCObjLayer * pLayer = GetLayer(nIndex) ; assert(pLayer) ;
  103. if (pLayer)
  104. m_pCurrentLayer = pLayer ;
  105. }
  106. /**
  107. * Add a new layer into canvas.
  108. * 1) you must use <B>new</B> to create a layer. <BR>
  109. * 2) after the layer be added, you can't delete it any more.
  110. * @param : nIndex - insert position, -1 add to last
  111. */
  112. void AddLayer (FCObjLayer* pLayer, int nIndex = -1)
  113. {
  114. if (!pLayer || (pLayer->ColorBits() != 32)) // now layer must 32-bpp
  115. {assert(false); return;}
  116. // ensure the insert position is valid
  117. if ((nIndex < -1) || (nIndex > GetLayerNumber()))
  118. {
  119. assert(false) ;
  120. nIndex = -1 ;
  121. }
  122. // ensure the new layer isn't in current layer list
  123. std::deque<FCObjLayer*>::iterator pt = __pcl_FindDeque (m_LayerList, pLayer) ;
  124. if (pt != m_LayerList.end()) // already in layer list
  125. {assert(false); return;}
  126. // add into layer list
  127. if (nIndex == -1)
  128. m_LayerList.push_back (pLayer) ;
  129. else
  130. m_LayerList.insert (m_LayerList.begin() + nIndex, pLayer) ;
  131. m_pCurrentLayer = pLayer ;
  132. // remove from <Removed LayerList>
  133. pt = __pcl_FindDeque (m_RemovedLayerList, pLayer) ;
  134. if (pt != m_RemovedLayerList.end())
  135. m_RemovedLayerList.erase (pt) ;
  136. }
  137. /**
  138. * Remove layer from canvas (but not delete layer).
  139. * when only one layer in canvas, you can't remove it.
  140. */
  141. void RemoveLayer (FCObjLayer* pLayer)
  142. {
  143. if (!pLayer || (GetLayerNumber() <= 1))
  144. {assert(false); return;}
  145. // find layer in current layer list
  146. std::deque<FCObjLayer*>::iterator pt = __pcl_FindDeque (m_LayerList, pLayer) ;
  147. if (pt == m_LayerList.end()) // not in layer list
  148. {assert(false); return;}
  149. // remember position then remove from list
  150. int nIndex = pt - m_LayerList.begin() ;
  151. m_LayerList.erase (pt) ;
  152. // update current layer
  153. if (m_pCurrentLayer == pLayer)
  154. {
  155. nIndex = FMin (nIndex, GetLayerNumber()-1) ;
  156. SetCurrentLayer (nIndex) ;
  157. }
  158. // add to removed-layer list
  159. if (__pcl_FindDeque (m_RemovedLayerList, pLayer) == m_RemovedLayerList.end())
  160. m_RemovedLayerList.push_back (pLayer) ;
  161. else
  162. {assert(false);}
  163. }
  164. /// Get the layer's index in canvas.
  165. int FindLayer (const FCObjLayer* pLayer) const
  166. {
  167. for (int i=0 ; i < GetLayerNumber() ; i++)
  168. {
  169. if (pLayer == GetLayer(i))
  170. return i ;
  171. }
  172. return -1 ;
  173. }
  174. /// Delete layer from removed list.
  175. void DeleteLayerFromRemoveList (FCObjLayer* pLayer)
  176. {
  177. if (!pLayer)
  178. {assert(false); return;}
  179. std::deque<FCObjLayer*>::iterator pt = __pcl_FindDeque (m_RemovedLayerList, pLayer) ;
  180. if (pt != m_RemovedLayerList.end()) // in removed layer list
  181. {
  182. m_RemovedLayerList.erase (pt) ;
  183. delete pLayer ;
  184. }
  185. }
  186. //@}
  187. /// Execute a command, mustn't delete command after execute.
  188. void ExecuteEffect (FCCmdArtPrider* cmd, FCObjProgress* pProgress=0)
  189. {
  190. if (!cmd)
  191. {assert(false); return;}
  192. // It's very important to call ClearRedoList before cmd->Execute !!!
  193. ClearRedoList() ;
  194. cmd->Execute (*this, pProgress) ;
  195. // then we manipulate the command according undo-list
  196. if ((GetUndoLevel() > 0) && !cmd->IsNeedDeleteAfterExecute())
  197. {
  198. AddCommand (cmd) ;
  199. }
  200. else
  201. {
  202. delete cmd ;
  203. }
  204. }
  205. /**
  206. * @name Make image.
  207. */
  208. //@{
  209. /// Get canvas's block view.
  210. /// created imgRegion's bpp same to imgBack
  211. /// @param rcRegion : RECT on canvas
  212. void MakeViewWindow (double fScale,
  213. std::deque<FCObjLayer*> layerList,
  214. const FCObjImage& imgBack,
  215. RECT rcRegion,
  216. FCObjImage& imgRegion) const
  217. {
  218. imgRegion.Destroy() ;
  219. // must in canvas
  220. {
  221. RECT rcCanvas = {0,0,0,0} ;
  222. rcCanvas.right = GetCanvasDimension().cx ;
  223. rcCanvas.bottom = GetCanvasDimension().cy ;
  224. if (!IsRectInRect (rcCanvas, rcRegion))
  225. {assert(false); return;}
  226. }
  227. // create image & draw back
  228. {
  229. int nL = (int)(fScale * rcRegion.left),
  230. nT = (int)(fScale * rcRegion.top),
  231. nR = (int)(fScale * rcRegion.right),
  232. nB = (int)(fScale * rcRegion.bottom) ;
  233. if (!imgRegion.Create (nR-nL, nB-nT, imgBack.ColorBits()))
  234. {assert(false); return;}
  235. imgRegion.TileBlock (imgBack, -nL, -nT) ;
  236. }
  237. // draw layers
  238. for (size_t i=0 ; i < layerList.size() ; i++)
  239. {
  240. FCObjLayer * pLayer = layerList[i] ;
  241. if (!pLayer->IsLayerVisible())
  242. continue ;
  243. RECT rcOnLayer = rcRegion ;
  244. pLayer->Canvas_to_Layer (rcOnLayer) ;
  245. pLayer->BoundRect (rcOnLayer) ;
  246. if (IsRectEmpty(&rcOnLayer))
  247. continue ;
  248. // RECT of layer on imgRegion
  249. RECT rcOnImg = rcOnLayer ;
  250. pLayer->Layer_to_Canvas (rcOnImg) ;
  251. OffsetRect (&rcOnImg, -rcRegion.left, -rcRegion.top) ;
  252. rcOnImg.left = (int)(fScale * rcOnImg.left) ;
  253. rcOnImg.top = (int)(fScale * rcOnImg.top) ;
  254. rcOnImg.right = (int)(fScale * rcOnImg.right) ;
  255. rcOnImg.bottom = (int)(fScale * rcOnImg.bottom) ;
  256. if (!IsRectEmpty(&rcOnImg))
  257. {
  258. imgRegion.AlphaBlend (*pLayer, rcOnImg, rcOnLayer, pLayer->GetLayerTransparent()) ;
  259. }
  260. }
  261. }
  262. /// imgThumb's bpp same to imgBack.
  263. void MakeThumbnail (double fScale,
  264. FCObjLayer& rLayer,
  265. const FCObjImage& imgBack,
  266. FCObjImage& imgThumb) const
  267. {
  268. std::auto_ptr<FCMemoLayer> bakMemo (rLayer.CreateMemoObj()),
  269. newMemo (rLayer.CreateMemoObj()) ;
  270. newMemo->m_bLayerVisible = true ;
  271. newMemo->m_nAlphaPercent = 100 ;
  272. rLayer.SetMemoObj (newMemo.get()) ;
  273. RECT rcRegion = {0, 0, GetCanvasDimension().cx, GetCanvasDimension().cy} ;
  274. std::deque<FCObjLayer*> layerList ;
  275. layerList.push_back (&rLayer) ;
  276. MakeViewWindow (fScale, layerList, imgBack, rcRegion, imgThumb) ;
  277. rLayer.SetMemoObj (bakMemo.get()) ;
  278. }
  279. /// Make canvas image (imgCanvas's bpp is 32).
  280. void GetCanvasImage (FCObjImage& imgCanvas) const
  281. {
  282. if (!imgCanvas.Create(m_sizeCanvas.cx, m_sizeCanvas.cy, 32))
  283. {assert(false); return;}
  284. FCPixelFillColor aCmd (FCColor::crWhite(), 0) ;
  285. imgCanvas.SinglePixelProcessProc (aCmd) ; // alpha init 0
  286. for (int i=0 ; i < GetLayerNumber() ; i++)
  287. {
  288. FCObjLayer * pLayer = GetLayer(i) ;
  289. if (pLayer->IsLayerVisible())
  290. imgCanvas.CombineImage (*pLayer,
  291. pLayer->GetGraphObjPos().x,
  292. pLayer->GetGraphObjPos().y,
  293. pLayer->GetLayerTransparent()) ;
  294. }
  295. }
  296. /// Make layer's region.
  297. void MakeRegion (const FCObjLayer& rLayer, FCObjImage& imgRegion) const
  298. {
  299. imgRegion.Destroy() ;
  300. if (!HasSelected())
  301. {
  302. imgRegion = static_cast<const FCObjImage&>(rLayer) ;
  303. }
  304. else
  305. {
  306. RECT rc = {0, 0, m_CurrSel.Width(), m_CurrSel.Height()} ;
  307. m_CurrSel.Layer_to_Canvas (rc) ;
  308. rLayer.Canvas_to_Layer (rc) ;
  309. rLayer.BoundRect (rc) ;
  310. if (IsRectEmpty (&rc))
  311. return ;
  312. // rect on layer & selection
  313. RECT rcOnLayer = rc,
  314. rcOnSel = rc ;
  315. rLayer.Layer_to_Canvas (rcOnSel) ;
  316. m_CurrSel.Canvas_to_Layer (rcOnSel) ;
  317. // out of selection
  318. rLayer.GetSubBlock (&imgRegion, rcOnLayer) ;
  319. for (int y=0 ; y < imgRegion.Height() ; y++)
  320. for (int x=0 ; x < imgRegion.Width() ; x++)
  321. if (*m_CurrSel.GetBits(x+rcOnSel.left, y+rcOnSel.top) == 0)
  322. {
  323. *(RGBQUAD*)imgRegion.GetBits(x,y) = PCL_RGBA(0xFF,0xFF,0xFF,0) ;
  324. }
  325. }
  326. }
  327. //@}
  328. /**
  329. * @name Access .oxo file.
  330. */
  331. //@{
  332. /// Read .oxo file.
  333. bool Load_oXo (const char* szFileName)
  334. {
  335. char * _pCurr = 0 ;
  336. int nFileSize = 0 ;
  337. // load file into memory
  338. FCOXOHelper::LoadFileToBuffer (szFileName, _pCurr, nFileSize) ;
  339. if (!_pCurr)
  340. {assert(false); return false;}
  341. BYTE * pCurr = (BYTE*)_pCurr ;
  342. PCL_array<BYTE> _aAutoDelete (pCurr) ;
  343. // read file's header TAG : "oXo " , version 1
  344. if ((*(DWORD*)pCurr != 0x206F586F) || (*(DWORD*)(pCurr + 4) != 1))
  345. return false ;
  346. pCurr += 8 ;
  347. // read block
  348. while (*(DWORD*)pCurr != OXO_BLOCK_END)
  349. {
  350. BYTE * pBak = pCurr ;
  351. DWORD nBlockSize = *(DWORD*)(pCurr + 4) ; // block size, exclude TAG & SIZE (8-bytes)
  352. if (*(DWORD*)pCurr == OXO_BLOCK_CANVAS) // canvas
  353. {
  354. pCurr += 8 ;
  355. m_sizeCanvas = *(SIZE*)pCurr ;
  356. }
  357. else if (*(DWORD*)pCurr == OXO_BLOCK_CANVAS_DPI) // canvas's DPI
  358. {
  359. pCurr += 8 ;
  360. m_nResX = *(DWORD*)pCurr ; pCurr += 4 ;
  361. m_nResY = *(DWORD*)pCurr ; pCurr += 4 ;
  362. }
  363. else if (*(DWORD*)pCurr == OXO_BLOCK_LAYER) // layer
  364. {
  365. pCurr += 8 ;
  366. FCObjLayer * pLayer = new FCObjLayer ;
  367. pLayer->Serialize (false, pCurr) ;
  368. this->AddLayer(pLayer) ;
  369. }
  370. else if (*(DWORD*)pCurr == OXO_BLOCK_TEXTLAYER) // text layer
  371. {
  372. pCurr += 8 ;
  373. // has discarded after PhoXo V1.6
  374. // first skip text info
  375. pCurr += strlen((char*)pCurr) + 1 + 84 ;
  376. FCObjLayer * pLayer = new FCObjLayer ;
  377. pLayer->Serialize (false, pCurr) ;
  378. this->AddLayer(pLayer) ;
  379. }
  380. else if (*(DWORD*)pCurr == OXO_BLOCK_LAYER_NAME) // layer's name
  381. {
  382. pCurr += 4 ;
  383. DWORD n = *(DWORD*)pCurr ; pCurr += 4 ;
  384. // name string
  385. PCL_array<char> p(n+8) ;
  386. memset (p.get(), 0, n+8) ;
  387. memcpy (p.get(), pCurr, n) ;
  388. if (GetLayerNumber())
  389. {
  390. GetLayer(GetLayerNumber()-1)->LayerName() = p.get() ;
  391. }
  392. }
  393. else
  394. {
  395. // unknow block, do nothing
  396. }
  397. pCurr = pBak + nBlockSize + 8 ;
  398. }
  399. return true ;
  400. }
  401. /// Write .oxo file.
  402. bool Save_oXo (const char* szFileName) const
  403. {
  404. if (GetLayerNumber() <= 0)
  405. {assert(false); return false;}
  406. // estimate size to malloc memory
  407. int nMaxSize = 1024 * 32, i ;
  408. for (i=0 ; i < GetLayerNumber() ; i++)
  409. {
  410. nMaxSize += sizeof(BITMAPINFOHEADER) + 12 ;
  411. nMaxSize = nMaxSize + GetLayer(i)->GetPitch() * GetLayer(i)->Height() ;
  412. }
  413. PCL_array<BYTE> pStart (nMaxSize) ;
  414. BYTE * pCurr = pStart.get() ;
  415. // write signature
  416. *(DWORD*)pCurr = 0x206F586F ; pCurr += 4 ; // "oXo "
  417. // oXo file's version
  418. *(DWORD*)pCurr = 0x01 ; pCurr += 4 ;
  419. // store canvas basic info
  420. *(DWORD*)pCurr = OXO_BLOCK_CANVAS ; pCurr += 4 ;
  421. *(DWORD*)pCurr = sizeof(SIZE) ; pCurr += 4 ;
  422. *(SIZE*)pCurr = m_sizeCanvas ; pCurr += sizeof(SIZE) ;
  423. // store canvas DPI
  424. *(DWORD*)pCurr = OXO_BLOCK_CANVAS_DPI ; pCurr += 4 ;
  425. *(DWORD*)pCurr = 8 ; pCurr += 4 ;
  426. *(DWORD*)pCurr = m_nResX ; pCurr += 4 ;
  427. *(DWORD*)pCurr = m_nResY ; pCurr += 4 ;
  428. // store layer
  429. for (i=0 ; i < GetLayerNumber() ; i++)
  430. {
  431. *(DWORD*)pCurr = OXO_BLOCK_LAYER ; pCurr += 4 ;
  432. *(DWORD*)pCurr = 0 ; pCurr += 4 ; // write size later
  433. int nWrite = GetLayer(i)->Serialize (true, pCurr) ;
  434. *(DWORD*)(pCurr - 4) = nWrite ; pCurr += nWrite ;
  435. // save layer's name
  436. std::string s = GetLayer(i)->LayerName() ;
  437. if (!s.empty())
  438. {
  439. *(DWORD*)pCurr = OXO_BLOCK_LAYER_NAME ; pCurr += 4 ;
  440. *(DWORD*)pCurr = s.length() ; pCurr += 4 ;
  441. memcpy (pCurr, s.c_str(), s.length()) ; pCurr += s.length() ;
  442. }
  443. }
  444. // terminator
  445. *(DWORD*)pCurr = OXO_BLOCK_END ; pCurr += 4 ;
  446. *(DWORD*)pCurr = 0 ; ; pCurr += 4 ;
  447. // write file
  448. return FCOXOHelper::SaveBufferToFile (szFileName, pStart.get(), pCurr - pStart.get()) ;
  449. }
  450. //@}
  451. private:
  452. virtual void PCL_Implement_Undo (FCCmdArtPrider* pCmd) {pCmd->Undo (*this);}
  453. virtual void PCL_Implement_Redo (FCCmdArtPrider* pCmd) {pCmd->Redo (*this);}
  454. enum
  455. {
  456. OXO_BLOCK_UNKNOW = 0, // unknow
  457. OXO_BLOCK_CANVAS = 1, // canvas
  458. OXO_BLOCK_LAYER = 2, // layer
  459. OXO_BLOCK_TEXTLAYER = 3, // text layer -- has discarded after PhoXo V1.6
  460. OXO_BLOCK_CANVAS_DPI = 4, // canvas DPI
  461. OXO_BLOCK_LAYER_NAME = 5, // name of layer, this block follow layer block
  462. OXO_BLOCK_END = 0xFF, // end
  463. };
  464. private:
  465. SIZE m_sizeCanvas ;
  466. FCObjLayer * m_pCurrentLayer ;
  467. std::deque<FCObjLayer*> m_LayerList ;
  468. std::deque<FCObjLayer*> m_RemovedLayerList ; // 被移除的layer,和m_LayerList一起释放
  469. int m_nResX, m_nResY ; // image's DPI resolution (Dot Per Inch)
  470. FCObjSelect m_CurrSel ; // 当前选取的区域对象
  471. static std::deque<FCObjLayer*>::iterator __pcl_FindDeque (std::deque<FCObjLayer*>& listLayer, const FCObjLayer* pLayer)
  472. {
  473. return std::find (listLayer.begin(), listLayer.end(), pLayer) ;
  474. }
  475. friend class FCCmdLayerExchange ;
  476. friend class FCCmdSelectionSetBase ;
  477. };
  478. //=============================================================================
  479. // inline implement
  480. //=============================================================================
  481. #endif