Command.h 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067
  1. /*
  2. * Copyright (C) =USTC= Fu Li
  3. *
  4. * Author : Fu Li
  5. * Create : 2003-4-8
  6. * Home : http://www.crazy-bit.com/
  7. * Mail : crazybit@263.net
  8. * History :
  9. */
  10. #ifndef __FOO_COMMAND__2003_04_08__H__
  11. #define __FOO_COMMAND__2003_04_08__H__
  12. #include "../ObjCanvas.h"
  13. // base class of normal image effect command
  14. class FCCmdImgEffect ;
  15. class FCCmdImgPixelProcessor ; // receive a FCSinglePixelProcessBase object
  16. class FCCmdImgSetAlpha ; // set image's alpha
  17. class FCCmdImgAddShadow ; // add shadow
  18. class FCCmdImageMask ; // create image to mask
  19. class FCCmdMaskColor ; // mask color on layer
  20. class FCCmdMaskGradientBase ; // base class of mask gradient on layer
  21. class FCCmdMaskGradientLine ; // mask linear gradient on layer
  22. class FCCmdMaskGradientBiLine ; // mask bilinear gradient on layer
  23. class FCCmdMaskGradientConicalSym ; // mask symmetric conical gradient on layer
  24. class FCCmdMaskGradientConicalASym ; // mask anti-symmetric conical gradient on layer
  25. class FCCmdMaskGradientRect ; // mask rectangle gradient on layer
  26. class FCCmdMaskGradientRadial ; // mask radial gradient on layer
  27. class FCCmdMaskLineBase ; // base class of mask line on layer
  28. // auto enlarge layer to fill up canvas
  29. class FCCmdAutoEnlargeLayer ;
  30. // selection operation
  31. class FCCmdSelectionSetBase ; // base class to set canvas's region
  32. class FCCmdSelectionInvert ; // invert current region
  33. class FCCmdSelectionCanvasAll ; // select all canvas
  34. class FCCmdSelectionClear ; // clear selection
  35. class FCCmdSelectionSmooth ; // smooth selection
  36. class FCCmdSelectionBlendHaloBase ;
  37. class FCCmdSelectionExpand ; // expand selection
  38. class FCCmdSelectionShrink ; // shrink selection
  39. class FCCmdSelectionBorder ; // border selection
  40. class FCCmdSelectionCreateBase ;
  41. class FCCmdSelectionCreateRect ; // rectangle region
  42. class FCCmdSelectionCreateEllipse ; // ellipse region
  43. class FCCmdSelectionCreatePolygonBase ; // polygon region
  44. class FCCmdSelectionCreateMagicWand ; // magic wand
  45. // Layer's operation
  46. class FCCmdLayerOperation ;
  47. class FCCmdLayerStretch ; // stretch layer
  48. class FCCmdLayerRotate ; // rotate layer
  49. class FCCmdLayerRotate90 ; // clockwise rotate 90'
  50. class FCCmdLayerRotate270 ; // clockwise rotate 270'
  51. class FCCmdLayerSkew ; // skew transform
  52. class FCCmdLayerLens ; // lens transform
  53. class FCCmdLayerCrop ; // crop layer
  54. class FCCmdLayerMove ; // move layer
  55. class FCCmdLayerAdd ; // add new layer to canvas
  56. class FCCmdLayerRemove ; // remove layer from canvas
  57. class FCCmdLayerSaveProperty ; // save layer's property
  58. class FCCmdLayerExchange ; // change layer's sequence in canvas
  59. // 组合命令,可以把频繁使用的cmd(如:layer move组合成为一个cmd)
  60. // class FCCmdComposite ;
  61. class FCCmdLayerMerge ; // merge layers
  62. class FCCmdLayerListRemove ; // delete layers from canvas
  63. class FCCmdCanvasOperation ;
  64. class FCCmdCanvasResize ; // resize canvas
  65. class FCCmdCanvasRotate90 ; // canvas rotate 90'
  66. class FCCmdCanvasRotate270 ; // canvas rotate 270'
  67. class FCCmdCanvasRotate ; // rotate canvas
  68. class FCCmdCanvasStretch ; // stretch canvas
  69. class FCCmdCanvasCrop ; // crop canvas
  70. class FCCmdCanvasAutoCrop ; // 自动裁减画布/auto crop canvas
  71. //=============================================================================
  72. /**
  73. * Base class of image effect command.
  74. */
  75. class FCCmdImgEffect : public FCCmdArtPrider
  76. {
  77. public:
  78. FCCmdImgEffect() : m_pLayer(0) {}
  79. protected:
  80. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  81. {
  82. m_pLayer = canvas.GetCurrentLayer() ;
  83. if (!m_pLayer || !m_pLayer->IsValidImage())
  84. return ;
  85. // start
  86. if (pProgress)
  87. pProgress->ResetProgress() ;
  88. if (!canvas.HasSelected())
  89. {
  90. // save whole layer
  91. m_Undo = *static_cast<FCObjImage*>(m_pLayer) ;
  92. this->Implement (*m_pLayer, pProgress) ;
  93. // don't change alpha channel
  94. if (IsLayerLimited(*m_pLayer))
  95. for (int y=0 ; y < m_Undo.Height() ; y++)
  96. for (int x=0 ; x < m_Undo.Width() ; x++)
  97. PCL_A(m_pLayer->GetBits(x,y)) = PCL_A(m_Undo.GetBits(x,y)) ;
  98. }
  99. else
  100. {
  101. RECT rcOnSel ;
  102. {
  103. RECT rcOnLayer = {0, 0, canvas.GetSelection().Width(), canvas.GetSelection().Height()} ;
  104. canvas.GetSelection().Layer_to_Canvas (rcOnLayer) ;
  105. m_pLayer->Canvas_to_Layer (rcOnLayer) ;
  106. m_pLayer->BoundRect (rcOnLayer) ;
  107. if (IsRectEmpty (&rcOnLayer))
  108. return ;
  109. m_pRectOnLayer = std::auto_ptr<RECT>(new RECT) ;
  110. rcOnSel = *m_pRectOnLayer = rcOnLayer ;
  111. m_pLayer->Layer_to_Canvas (rcOnSel) ;
  112. canvas.GetSelection().Canvas_to_Layer (rcOnSel) ;
  113. }
  114. // save region
  115. m_pLayer->GetSubBlock (&m_Undo, *m_pRectOnLayer) ;
  116. m_Undo.SetGraphObjPos (m_pLayer->GetGraphObjPos().x + m_pRectOnLayer->left,
  117. m_pLayer->GetGraphObjPos().y + m_pRectOnLayer->top) ;
  118. // set alpha == 0 out of selection, some effect need (such as box blur)
  119. FCObjImage block(m_Undo) ;
  120. {
  121. for (int y=0 ; y < block.Height() ; y++)
  122. for (int x=0 ; x < block.Width() ; x++)
  123. if (*canvas.GetSelection().GetBits (x+rcOnSel.left, y+rcOnSel.top) == 0)
  124. *(RGBQUAD*)block.GetBits(x,y) = PCL_RGBA(0xFF,0xFF,0xFF,0) ;
  125. }
  126. // process
  127. this->Implement (block, pProgress) ;
  128. // put back
  129. for (int y=0 ; y < block.Height() ; y++)
  130. for (int x=0 ; x < block.Width() ; x++)
  131. if (*canvas.GetSelection().GetBits (x+rcOnSel.left, y+rcOnSel.top))
  132. FCColor::CopyPixel (m_pLayer->GetBits (x+m_pRectOnLayer->left, y+m_pRectOnLayer->top),
  133. block.GetBits(x,y),
  134. IsLayerLimited(*m_pLayer) ? 3 : 4) ;
  135. }
  136. if (pProgress)
  137. pProgress->SetProgress (100) ; // set 100%
  138. }
  139. virtual void Undo (FCObjCanvas& canvas)
  140. {
  141. if (!m_Undo.IsValidImage() || !m_pLayer)
  142. {assert(false); return;}
  143. if (!m_pRectOnLayer.get())
  144. {
  145. // whole image
  146. m_Redo = *static_cast<FCObjImage*>(m_pLayer) ;
  147. *static_cast<FCObjImage*>(m_pLayer) = m_Undo ;
  148. }
  149. else
  150. {
  151. m_pLayer->GetSubBlock (&m_Redo, *m_pRectOnLayer) ;
  152. m_pLayer->CoverBlock (m_Undo, m_pRectOnLayer->left, m_pRectOnLayer->top) ;
  153. }
  154. m_Undo.Destroy() ;
  155. }
  156. virtual void Redo (FCObjCanvas& canvas)
  157. {
  158. if (!m_Redo.IsValidImage() || !m_pLayer)
  159. {assert(false); return;}
  160. if (!m_pRectOnLayer.get())
  161. {
  162. // whole image
  163. m_Undo = *static_cast<FCObjImage*>(m_pLayer) ;
  164. *static_cast<FCObjImage*>(m_pLayer) = m_Redo ;
  165. }
  166. else
  167. {
  168. m_pLayer->GetSubBlock (&m_Undo, *m_pRectOnLayer) ;
  169. m_pLayer->CoverBlock (m_Redo, m_pRectOnLayer->left, m_pRectOnLayer->top) ;
  170. }
  171. m_Redo.Destroy() ;
  172. }
  173. /// Process image, don't change img's size & position.
  174. virtual void Implement (FCObjImage& img, FCObjProgress* pProgress) {}
  175. virtual bool IsLayerLimited (const FCObjLayer& rLayer) const
  176. {
  177. return rLayer.IsLayerLimited() ? true : false ;
  178. }
  179. FCObjLayer * m_pLayer ;
  180. FCObjImage m_Undo ;
  181. FCObjImage m_Redo ;
  182. std::auto_ptr<RECT> m_pRectOnLayer ;
  183. };
  184. //=============================================================================
  185. /**
  186. * Process image use a FCSinglePixelProcessBase command.
  187. */
  188. class FCCmdImgPixelProcessor : public FCCmdImgEffect
  189. {
  190. public:
  191. /// Constructor (pProcessor must use <B>new</B> to create).
  192. FCCmdImgPixelProcessor (FCSinglePixelProcessBase* pProcessor) : m_pProcessor(pProcessor) {}
  193. virtual void Implement (FCObjImage& img, FCObjProgress* pProgress)
  194. {
  195. if (m_pProcessor.get())
  196. img.SinglePixelProcessProc (*m_pProcessor, pProgress) ;
  197. }
  198. private:
  199. std::auto_ptr<FCInterface_PixelProcess> m_pProcessor ;
  200. };
  201. //=============================================================================
  202. /**
  203. * Set layer's alpha, ignore layer's limited.
  204. */
  205. class FCCmdImgSetAlpha : public FCCmdImgEffect
  206. {
  207. public:
  208. /// Constructor.
  209. FCCmdImgSetAlpha (int nAlpha) : m_nAlpha(FClamp0255(nAlpha)) {}
  210. private:
  211. virtual void Implement (FCObjImage& img, FCObjProgress* pProgress)
  212. {
  213. if (img.IsValidImage() && (img.ColorBits() == 32))
  214. img.SetAlphaChannelValue (m_nAlpha) ;
  215. }
  216. virtual bool IsLayerLimited (const FCObjLayer& rLayer) const
  217. {
  218. return false ;
  219. }
  220. private:
  221. int m_nAlpha ;
  222. };
  223. //=============================================================================
  224. /**
  225. * Add shadow.
  226. */
  227. class FCCmdImgAddShadow : public FCCmdImgEffect
  228. {
  229. public:
  230. /// Constructor.
  231. FCCmdImgAddShadow (SHADOWDATA ShData)
  232. {
  233. m_ShadowData = ShData ;
  234. m_ShadowData.nSmooth = FMax (2, (int)m_ShadowData.nSmooth) ;
  235. m_ShadowData.nAlpha = FClamp ((int)m_ShadowData.nAlpha, 1, 100) ;
  236. }
  237. private:
  238. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  239. {
  240. m_pLayer = canvas.GetCurrentLayer() ;
  241. if (!m_pLayer || !m_pLayer->IsValidImage())
  242. return ;
  243. // start
  244. if (pProgress)
  245. pProgress->ResetProgress() ;
  246. if (!canvas.HasSelected())
  247. {
  248. // save whole layer
  249. m_Undo = *static_cast<FCObjImage*>(m_pLayer) ;
  250. this->Implement (*m_pLayer, pProgress) ;
  251. }
  252. else
  253. {
  254. RECT rcOnSel ;
  255. {
  256. RECT rcOnLayer = {0, 0, canvas.GetSelection().Width(), canvas.GetSelection().Height()} ;
  257. canvas.GetSelection().Layer_to_Canvas (rcOnLayer) ;
  258. m_pLayer->Canvas_to_Layer (rcOnLayer) ;
  259. m_pLayer->BoundRect (rcOnLayer) ;
  260. if (IsRectEmpty (&rcOnLayer))
  261. return ;
  262. m_pRectOnLayer = std::auto_ptr<RECT>(new RECT) ;
  263. rcOnSel = *m_pRectOnLayer = rcOnLayer ;
  264. m_pLayer->Layer_to_Canvas (rcOnSel) ;
  265. canvas.GetSelection().Canvas_to_Layer (rcOnSel) ;
  266. }
  267. // set alpha == 0 out of selection
  268. FCObjImage imgBlock ;
  269. m_pLayer->GetSubBlock (&imgBlock, *m_pRectOnLayer) ;
  270. {
  271. for (int y=0 ; y < imgBlock.Height() ; y++)
  272. for (int x=0 ; x < imgBlock.Width() ; x++)
  273. if (*canvas.GetSelection().GetBits (x+rcOnSel.left, y+rcOnSel.top) == 0)
  274. *(RGBQUAD*)imgBlock.GetBits(x,y) = PCL_RGBA(0xFF,0xFF,0xFF,0) ;
  275. }
  276. // calculate shadowed image size
  277. RECT rcShadow = *m_pRectOnLayer ;
  278. ::OffsetRect (&rcShadow, m_ShadowData.nOffsetX, m_ShadowData.nOffsetY) ;
  279. ::InflateRect (&rcShadow, m_ShadowData.nSmooth, m_ShadowData.nSmooth) ;
  280. ::UnionRect (&rcShadow, m_pRectOnLayer.get(), &rcShadow) ;
  281. // calculate the expand size
  282. const RECT rcLayer = {0, 0, m_pLayer->Width(), m_pLayer->Height()} ;
  283. if (IsRectInRect (rcLayer, rcShadow))
  284. {
  285. *m_pRectOnLayer = rcShadow ;
  286. m_pLayer->GetSubBlock (&m_Undo, rcShadow) ;
  287. }
  288. else
  289. {
  290. m_pRectOnLayer = std::auto_ptr<RECT>() ;
  291. m_Undo = *static_cast<FCObjImage*>(m_pLayer) ;
  292. int nExpL = (rcShadow.left >= 0) ? 0 : -rcShadow.left,
  293. nExpT = (rcShadow.top >= 0) ? 0 : -rcShadow.top,
  294. nExpR = (rcShadow.right > rcLayer.right) ? (rcShadow.right-rcLayer.right) : 0,
  295. nExpB = (rcShadow.bottom > rcLayer.bottom) ? (rcShadow.bottom-rcLayer.bottom) : 0 ;
  296. m_pLayer->ExpandFrame (false, nExpL, nExpT, nExpR, nExpB) ;
  297. OffsetRect (&rcShadow, nExpL, nExpT) ;
  298. }
  299. // make shadow image
  300. FCCmdImgSetAlpha cmdClear(0) ;
  301. static_cast<FCCmdArtPrider&>(cmdClear).Execute (canvas, NULL) ; // clear region and combine later
  302. this->Implement (imgBlock, pProgress) ;
  303. m_pLayer->CombineImage (imgBlock, rcShadow.left, rcShadow.top) ;
  304. }
  305. if (pProgress)
  306. pProgress->SetProgress (100) ; // set 100%
  307. }
  308. virtual void Implement (FCObjImage& img, FCObjProgress* pProgress)
  309. {
  310. FCPixelAddShadow aCmd(m_ShadowData) ;
  311. img.SinglePixelProcessProc(aCmd, pProgress) ;
  312. }
  313. private:
  314. SHADOWDATA m_ShadowData ;
  315. };
  316. //=============================================================================
  317. /**
  318. * Create image to mask.
  319. */
  320. class FCCmdImageMask : public FCCmdImgEffect
  321. {
  322. virtual void Implement (FCObjImage& img, FCObjProgress* pProgress)
  323. {
  324. FCObjImage imgMask ;
  325. CreateMaskImage (img, imgMask, pProgress) ;
  326. img.CombineImage (imgMask) ;
  327. }
  328. protected:
  329. /// Create 32bpp mask image as imgMask.
  330. virtual void CreateMaskImage (const FCObjImage& img, FCObjImage& imgMask, FCObjProgress* pProgress) =0 ;
  331. };
  332. //=============================================================================
  333. /**
  334. * Mask color on layer.
  335. */
  336. class FCCmdMaskColor : public FCCmdImageMask
  337. {
  338. virtual void CreateMaskImage (const FCObjImage& img, FCObjImage& imgMask, FCObjProgress* pProgress)
  339. {
  340. imgMask.Create (img.Width(), img.Height(), 32) ;
  341. FCPixelCombineColor aCmd(m_crFill) ;
  342. imgMask.SinglePixelProcessProc (aCmd, pProgress) ;
  343. }
  344. RGBQUAD m_crFill ;
  345. public:
  346. /// Constructor (combine base on alpha of crFill).
  347. FCCmdMaskColor (RGBQUAD crFill) : m_crFill(crFill) {}
  348. };
  349. //=============================================================================
  350. /**
  351. * Base class of mask gradient on layer.
  352. */
  353. class FCCmdMaskGradientBase : public FCCmdImageMask
  354. {
  355. virtual void CreateMaskImage (const FCObjImage& img, FCObjImage& imgMask, FCObjProgress* pProgress)
  356. {
  357. imgMask.Create (img.Width(), img.Height(), 32) ;
  358. std::auto_ptr<FCPixelGradientBase> m_pCmd (CreateGradientCommand (img, m_cr1, m_cr2, m_nRepeat)) ;
  359. imgMask.SinglePixelProcessProc (*m_pCmd, pProgress) ;
  360. imgMask.SetAlphaChannelValue (m_nAlpha) ;
  361. }
  362. RGBQUAD m_cr1, m_cr2 ;
  363. REPEAT_MODE m_nRepeat ;
  364. int m_nAlpha ;
  365. public:
  366. /// Constructor.
  367. FCCmdMaskGradientBase (int nAlpha, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat) : m_nAlpha(nAlpha), m_cr1(cr1), m_cr2(cr2), m_nRepeat(nRepeat) {}
  368. /// New a gradient fill command.
  369. virtual FCPixelGradientBase* CreateGradientCommand (const FCObjImage& img, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat) =0 ;
  370. };
  371. //=============================================================================
  372. /**
  373. * Mask linear gradient on layer.
  374. */
  375. class FCCmdMaskGradientLine : public FCCmdMaskGradientBase
  376. {
  377. virtual FCPixelGradientBase* CreateGradientCommand (const FCObjImage& img, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat)
  378. {
  379. POINT pt1=m_pt1, pt2=m_pt2 ;
  380. img.Canvas_to_Layer (pt1) ;
  381. img.Canvas_to_Layer (pt2) ;
  382. return new FCPixelGradientLine (pt1, pt2, cr1, cr2, nRepeat) ;
  383. }
  384. POINT m_pt1, m_pt2 ; // on canvas
  385. public:
  386. /// Constructor.
  387. FCCmdMaskGradientLine (int nAlpha, POINT pt1, POINT pt2, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat) : FCCmdMaskGradientBase(nAlpha, cr1, cr2, nRepeat)
  388. {
  389. m_pt1=pt1 ; m_pt2=pt2 ;
  390. }
  391. };
  392. //=============================================================================
  393. /**
  394. * Mask bilinear gradient on layer.
  395. */
  396. class FCCmdMaskGradientBiLine : public FCCmdMaskGradientBase
  397. {
  398. virtual FCPixelGradientBase* CreateGradientCommand (const FCObjImage& img, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat)
  399. {
  400. POINT pt1=m_pt1, pt2=m_pt2 ;
  401. img.Canvas_to_Layer (pt1) ;
  402. img.Canvas_to_Layer (pt2) ;
  403. return new FCPixelGradientBiLine (pt1, pt2, cr1, cr2, nRepeat) ;
  404. }
  405. POINT m_pt1, m_pt2 ; // on canvas
  406. public:
  407. /// Constructor.
  408. FCCmdMaskGradientBiLine (int nAlpha, POINT pt1, POINT pt2, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat) : FCCmdMaskGradientBase(nAlpha, cr1, cr2, nRepeat)
  409. {
  410. m_pt1=pt1 ; m_pt2=pt2 ;
  411. }
  412. };
  413. //=============================================================================
  414. /**
  415. * Mask symmetric conical gradient on layer.
  416. */
  417. class FCCmdMaskGradientConicalSym : public FCCmdMaskGradientBase
  418. {
  419. virtual FCPixelGradientBase* CreateGradientCommand (const FCObjImage& img, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat)
  420. {
  421. POINT pt1=m_pt1, pt2=m_pt2 ;
  422. img.Canvas_to_Layer (pt1) ;
  423. img.Canvas_to_Layer (pt2) ;
  424. return new FCPixelGradientConicalSym (pt1, pt2, cr1, cr2, nRepeat) ;
  425. }
  426. POINT m_pt1, m_pt2 ; // on canvas
  427. public:
  428. /// Constructor.
  429. FCCmdMaskGradientConicalSym (int nAlpha, POINT pt1, POINT pt2, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat) : FCCmdMaskGradientBase(nAlpha, cr1, cr2, nRepeat)
  430. {
  431. m_pt1=pt1 ; m_pt2=pt2 ;
  432. }
  433. };
  434. //=============================================================================
  435. /**
  436. * Mask anti-symmetric conical gradient on layer.
  437. */
  438. class FCCmdMaskGradientConicalASym : public FCCmdMaskGradientBase
  439. {
  440. virtual FCPixelGradientBase* CreateGradientCommand (const FCObjImage& img, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat)
  441. {
  442. POINT pt1=m_pt1, pt2=m_pt2 ;
  443. img.Canvas_to_Layer (pt1) ;
  444. img.Canvas_to_Layer (pt2) ;
  445. return new FCPixelGradientConicalASym (pt1, pt2, cr1, cr2, nRepeat) ;
  446. }
  447. POINT m_pt1, m_pt2 ; // on canvas
  448. public:
  449. /// Constructor.
  450. FCCmdMaskGradientConicalASym (int nAlpha, POINT pt1, POINT pt2, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat) : FCCmdMaskGradientBase(nAlpha, cr1, cr2, nRepeat)
  451. {
  452. m_pt1=pt1 ; m_pt2=pt2 ;
  453. }
  454. };
  455. //=============================================================================
  456. /**
  457. * Mask rectangle gradient on layer.
  458. */
  459. class FCCmdMaskGradientRect : public FCCmdMaskGradientBase
  460. {
  461. virtual FCPixelGradientBase* CreateGradientCommand (const FCObjImage& img, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat)
  462. {
  463. RECT rc = m_rcOnCanvas ;
  464. img.Canvas_to_Layer (rc) ;
  465. return new FCPixelGradientRect (rc, cr1, cr2, nRepeat) ;
  466. }
  467. RECT m_rcOnCanvas ;
  468. public:
  469. /// Constructor.
  470. FCCmdMaskGradientRect (int nAlpha, RECT rcOnCanvas, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat) : FCCmdMaskGradientBase(nAlpha, cr1, cr2, nRepeat)
  471. {
  472. m_rcOnCanvas = rcOnCanvas ;
  473. }
  474. };
  475. //=============================================================================
  476. /**
  477. * Mask radial gradient on layer.
  478. */
  479. class FCCmdMaskGradientRadial : public FCCmdMaskGradientBase
  480. {
  481. virtual FCPixelGradientBase* CreateGradientCommand (const FCObjImage& img, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat)
  482. {
  483. RECT rc = m_rcOnCanvas ;
  484. img.Canvas_to_Layer (rc) ;
  485. return new FCPixelGradientRadial (rc, cr1, cr2, nRepeat) ;
  486. }
  487. RECT m_rcOnCanvas ;
  488. public:
  489. /// Constructor.
  490. FCCmdMaskGradientRadial (int nAlpha, RECT rcOnCanvas, RGBQUAD cr1, RGBQUAD cr2, REPEAT_MODE nRepeat) : FCCmdMaskGradientBase(nAlpha, cr1, cr2, nRepeat)
  491. {
  492. m_rcOnCanvas = rcOnCanvas ;
  493. }
  494. };
  495. //=============================================================================
  496. /**
  497. * Base class of mask line on layer.
  498. */
  499. class FCCmdMaskLineBase : public FCCmdImageMask
  500. {
  501. virtual void CreateMaskImage (const FCObjImage& img, FCObjImage& imgMask, FCObjProgress* pProgress)
  502. {
  503. FCObjImage imgLine ;
  504. imgLine.Create (img.Width(), img.Height(), 24) ;
  505. MaskDrawLine (img, imgLine, m_nPenWidth, m_LineStyle) ;
  506. FCPixelConvertTo8BitGray aCmd ;
  507. imgLine.SinglePixelProcessProc (aCmd) ;
  508. imgMask.Create (img.Width(), img.Height(), 32) ;
  509. for (int y=0 ; y < img.Height() ; y++)
  510. for (int x=0 ; x < img.Width() ; x++)
  511. {
  512. RGBQUAD cr = m_cr ;
  513. PCL_A(&cr) = PCL_B(imgLine.GetBits(x,y)) * m_nAlpha / 0xFF ;
  514. *(RGBQUAD*)imgMask.GetBits(x,y) = cr ;
  515. }
  516. }
  517. int m_nAlpha ;
  518. RGBQUAD m_cr ;
  519. int m_nPenWidth ;
  520. LINE_STYLE m_LineStyle ;
  521. public:
  522. /// Constructor.
  523. FCCmdMaskLineBase (int nAlpha, RGBQUAD cr, int nPenWidth, LINE_STYLE LineStyle) : m_nAlpha(nAlpha), m_cr(cr), m_nPenWidth(nPenWidth), m_LineStyle(LineStyle) {}
  524. /// Draw line on imgLine.
  525. virtual void MaskDrawLine (const FCObjImage& img, FCObjImage& imgLine, int nPenWidth, LINE_STYLE LineStyle) =0 ;
  526. };
  527. //=============================================================================
  528. /**
  529. * Auto enlarge layer to fill up canvas.
  530. */
  531. class FCCmdAutoEnlargeLayer : public FCCmdArtPrider
  532. {
  533. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  534. {
  535. m_pLayer = canvas.GetCurrentLayer() ;
  536. if (!m_pLayer || !m_pLayer->IsValidImage())
  537. return ;
  538. // not handle when limited
  539. if (m_pLayer->IsLayerLimited())
  540. return ;
  541. // enlarge to full up canvas
  542. RECT rcLayer = {0, 0, m_pLayer->Width(), m_pLayer->Height()} ;
  543. m_pLayer->Layer_to_Canvas (rcLayer) ;
  544. SIZE sizeCanvas = canvas.GetCanvasDimension() ;
  545. int nExpL = (rcLayer.left <= 0) ? 0 : rcLayer.left,
  546. nExpT = (rcLayer.top <= 0) ? 0 : rcLayer.top,
  547. nExpR = (rcLayer.right < sizeCanvas.cx) ? (sizeCanvas.cx-rcLayer.right) : 0,
  548. nExpB = (rcLayer.bottom < sizeCanvas.cy) ? (sizeCanvas.cy-rcLayer.bottom) : 0 ;
  549. if (nExpL || nExpT || nExpR || nExpB)
  550. {
  551. m_Undo = *static_cast<FCObjImage*>(m_pLayer) ;
  552. m_pLayer->ExpandFrame (false, nExpL, nExpT, nExpR, nExpB) ;
  553. }
  554. }
  555. virtual void Undo (FCObjCanvas& canvas)
  556. {
  557. if (m_pLayer && m_Undo.IsValidImage())
  558. {
  559. m_Redo = *static_cast<FCObjImage*>(m_pLayer) ;
  560. *static_cast<FCObjImage*>(m_pLayer) = m_Undo ;
  561. m_Undo.Destroy() ;
  562. }
  563. }
  564. virtual void Redo (FCObjCanvas& canvas)
  565. {
  566. if (m_pLayer && m_Redo.IsValidImage())
  567. {
  568. m_Undo = *static_cast<FCObjImage*>(m_pLayer) ;
  569. *static_cast<FCObjImage*>(m_pLayer) = m_Redo ;
  570. m_Redo.Destroy() ;
  571. }
  572. }
  573. FCObjLayer * m_pLayer ;
  574. FCObjImage m_Undo ;
  575. FCObjImage m_Redo ;
  576. public:
  577. FCCmdAutoEnlargeLayer() : m_pLayer(0) {}
  578. };
  579. //=============================================================================
  580. /**
  581. * Base class to set canvas's region.
  582. */
  583. class FCCmdSelectionSetBase : public FCCmdArtPrider
  584. {
  585. protected:
  586. /// Derived class put new selection into newSelect.
  587. virtual void OnCalculateNewSelection (FCObjCanvas& canvas, FCObjSelect& newSelect) =0 ;
  588. private:
  589. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  590. {
  591. this->OnCalculateNewSelection (canvas, m_Select) ;
  592. m_Select.SelectionOptimize() ;
  593. m_Select.RecalculateEdge (canvas.GetZoomScale(), true) ;
  594. this->Redo (canvas) ;
  595. }
  596. virtual void Undo (FCObjCanvas& canvas)
  597. {
  598. this->Redo (canvas) ;
  599. }
  600. virtual void Redo (FCObjCanvas& canvas)
  601. {
  602. FSwap (canvas.m_CurrSel, m_Select) ;
  603. }
  604. private:
  605. FCObjSelect m_Select ;
  606. };
  607. //=============================================================================
  608. /**
  609. * Invert current region.
  610. */
  611. class FCCmdSelectionInvert : public FCCmdSelectionSetBase
  612. {
  613. virtual void OnCalculateNewSelection (FCObjCanvas& canvas, FCObjSelect& newSelect)
  614. {
  615. const SIZE sizeCanvas = canvas.GetCanvasDimension() ;
  616. if (!canvas.HasSelected() || (sizeCanvas.cx <= 0) || (sizeCanvas.cy <= 0))
  617. {
  618. assert(false); return;
  619. }
  620. // create selection & combine with old selection
  621. newSelect.Create (sizeCanvas.cx, sizeCanvas.cy, 8) ;
  622. const POINT ptPos = canvas.GetSelection().GetGraphObjPos() ;
  623. newSelect.CoverBlock (canvas.GetSelection(), ptPos.x, ptPos.y) ;
  624. // start invert operation
  625. for (int y=0 ; y < newSelect.Height() ; y++)
  626. for (int x=0 ; x < newSelect.Width() ; x++)
  627. {
  628. BYTE * p = newSelect.GetBits (x,y) ;
  629. *p = ~*p ;
  630. }
  631. // position
  632. newSelect.SetGraphObjPos (0, 0) ;
  633. }
  634. };
  635. //=============================================================================
  636. /**
  637. * Select all canvas.
  638. */
  639. class FCCmdSelectionCanvasAll : public FCCmdSelectionSetBase
  640. {
  641. virtual void OnCalculateNewSelection (FCObjCanvas& canvas, FCObjSelect& newSelect)
  642. {
  643. const SIZE sizeCanvas = canvas.GetCanvasDimension() ;
  644. if ((sizeCanvas.cx <= 0) || (sizeCanvas.cy <= 0))
  645. {
  646. assert(false); return;
  647. }
  648. // create selection
  649. newSelect.Create (sizeCanvas.cx, sizeCanvas.cy, 8) ;
  650. memset (newSelect.GetMemStart(), 0xFF, newSelect.GetPitch()*newSelect.Height()) ;
  651. newSelect.SetGraphObjPos (0, 0) ;
  652. }
  653. };
  654. //=============================================================================
  655. /**
  656. * Clear selection.
  657. */
  658. class FCCmdSelectionClear : public FCCmdSelectionSetBase
  659. {
  660. virtual void OnCalculateNewSelection (FCObjCanvas& canvas, FCObjSelect& newSelect)
  661. {
  662. newSelect = FCObjSelect() ;
  663. }
  664. };
  665. //=============================================================================
  666. /**
  667. * Smooth selection.
  668. */
  669. class FCCmdSelectionSmooth : public FCCmdSelectionSetBase
  670. {
  671. public:
  672. /// Constructor.
  673. FCCmdSelectionSmooth (int nStep) : m_nStep(nStep) {}
  674. private:
  675. virtual void OnCalculateNewSelection (FCObjCanvas& canvas, FCObjSelect& newSelect)
  676. {
  677. newSelect = canvas.GetSelection() ;
  678. if (!newSelect.HasSelected())
  679. {
  680. assert(false); return;
  681. }
  682. // smooth
  683. newSelect.ConvertTo24Bit() ;
  684. FCPixelBlur_Box cmdSmooth (m_nStep, false) ;
  685. newSelect.SinglePixelProcessProc (cmdSmooth) ;
  686. FCPixelConvertTo8BitGray aCmd ;
  687. newSelect.SinglePixelProcessProc(aCmd) ;
  688. // convert to 2-state
  689. for (int y=0 ; y < newSelect.Height() ; y++)
  690. for (int x=0 ; x < newSelect.Width() ; x++)
  691. {
  692. BYTE * p = newSelect.GetBits (x,y) ;
  693. *p = ((*p < 128) ? 0 : 0xFF) ;
  694. }
  695. }
  696. private:
  697. int m_nStep ;
  698. };
  699. //=============================================================================
  700. /**
  701. * Base class of blend halo.
  702. */
  703. class FCCmdSelectionBlendHaloBase : public FCCmdSelectionSetBase
  704. {
  705. protected:
  706. /// Constructor.
  707. FCCmdSelectionBlendHaloBase (int nPixel) : m_nPixel(nPixel) {}
  708. void BlendEdgeHalo (FCObjSelect& newSelect, LOGICAL_OP logOp, int nHaloValue, bool bClear)
  709. {
  710. if (!newSelect.HasSelected() || (m_nPixel <= 0))
  711. {
  712. assert(false) ; return ;
  713. }
  714. newSelect.ExpandFrame (false, m_nPixel, m_nPixel, m_nPixel, m_nPixel) ;
  715. // find edge point
  716. std::deque<POINT> ptList ;
  717. GetEdgePointList (newSelect, ptList) ;
  718. // clear image
  719. if (bClear)
  720. memset (newSelect.GetMemStart(), 0, newSelect.GetPitch()*newSelect.Height()) ;
  721. // create RECT halo (round halo better ?)
  722. FCObjImage imgMask (2*m_nPixel+1, 2*m_nPixel+1, 8) ;
  723. memset (imgMask.GetMemStart(), nHaloValue, imgMask.GetPitch()*imgMask.Height()) ;
  724. // blend halo
  725. for (size_t i=0 ; i < ptList.size() ; i++)
  726. {
  727. newSelect.LogicalBlend (imgMask, logOp, ptList[i].x-m_nPixel, ptList[i].y-m_nPixel) ;
  728. }
  729. }
  730. private:
  731. // find the points of edge
  732. static void GetEdgePointList (const FCObjSelect& sel, std::deque<POINT>& ptList)
  733. {
  734. ptList.clear() ;
  735. // is edge point : current is selected around is non-selected
  736. // brim point must be edge point
  737. for (int y=0 ; y < sel.Height() ; y++)
  738. for (int x=0 ; x < sel.Width() ; x++)
  739. if (*sel.GetBits(x,y) == 0xFF)
  740. if ((y == 0) || (*sel.GetBits(x,y-1) == 0) || // up
  741. (y == sel.Height()-1) || (*sel.GetBits(x,y+1) == 0) || // down
  742. (x == 0) || (*sel.GetBits(x-1,y) == 0) || // left
  743. (x == sel.Width()-1) || (*sel.GetBits(x+1,y) == 0) || // right
  744. (*sel.GetBits(x+1,y-1) == 0) || // right-up
  745. (*sel.GetBits(x+1,y+1) == 0) || // right-down
  746. (*sel.GetBits(x-1,y+1) == 0) || // left-down
  747. (*sel.GetBits(x-1,y-1) == 0)) // left-up
  748. {
  749. POINT pt = {x,y} ;
  750. ptList.push_back (pt) ;
  751. }
  752. }
  753. private:
  754. int m_nPixel ;
  755. };
  756. //=============================================================================
  757. /**
  758. * Expand selection.
  759. */
  760. class FCCmdSelectionExpand : public FCCmdSelectionBlendHaloBase
  761. {
  762. public:
  763. /// Constructor.
  764. FCCmdSelectionExpand (int nPixel) : FCCmdSelectionBlendHaloBase(nPixel) {}
  765. private:
  766. virtual void OnCalculateNewSelection (FCObjCanvas& canvas, FCObjSelect& newSelect)
  767. {
  768. newSelect = canvas.GetSelection() ;
  769. BlendEdgeHalo (newSelect, LOGI_OR, 0xFF, false) ;
  770. }
  771. };
  772. //=============================================================================
  773. /**
  774. * Shrink selection.
  775. */
  776. class FCCmdSelectionShrink : public FCCmdSelectionBlendHaloBase
  777. {
  778. public:
  779. /// Constructor.
  780. FCCmdSelectionShrink (int nPixel) : FCCmdSelectionBlendHaloBase(nPixel) {}
  781. private:
  782. virtual void OnCalculateNewSelection (FCObjCanvas& canvas, FCObjSelect& newSelect)
  783. {
  784. newSelect = canvas.GetSelection() ;
  785. BlendEdgeHalo (newSelect, LOGI_AND, 0, false) ;
  786. }
  787. };
  788. //=============================================================================
  789. /**
  790. * Border selection.
  791. */
  792. class FCCmdSelectionBorder : public FCCmdSelectionBlendHaloBase
  793. {
  794. public:
  795. /// Constructor.
  796. FCCmdSelectionBorder (int nPixel) : FCCmdSelectionBlendHaloBase(nPixel) {}
  797. private:
  798. virtual void OnCalculateNewSelection (FCObjCanvas& canvas, FCObjSelect& newSelect)
  799. {
  800. newSelect = canvas.GetSelection() ;
  801. BlendEdgeHalo (newSelect, LOGI_OR, 0xFF, true) ;
  802. }
  803. };
  804. //=============================================================================
  805. /**
  806. * Base class to handle selection.
  807. */
  808. class FCCmdSelectionCreateBase : public FCCmdSelectionSetBase
  809. {
  810. protected:
  811. /// Constructor.
  812. FCCmdSelectionCreateBase (FCObjSelect::RGN_TYPE nType) : m_nType(nType) {}
  813. virtual void CreateSelection (FCObjCanvas& canvas, FCObjSelect& selCreate) =0 ;
  814. private:
  815. FCObjSelect::RGN_TYPE m_nType ;
  816. private:
  817. virtual void OnCalculateNewSelection (FCObjCanvas& canvas, FCObjSelect& newSelect)
  818. {
  819. if (!canvas.HasSelected() || (m_nType == FCObjSelect::RGN_CREATE))
  820. {
  821. // create new create
  822. CreateSelection (canvas, newSelect) ;
  823. }
  824. else
  825. {
  826. FCObjSelect selCreate ;
  827. CreateSelection (canvas, selCreate) ;
  828. newSelect = canvas.GetSelection() ;
  829. if (m_nType == FCObjSelect::RGN_ADD)
  830. AddSelection (newSelect, selCreate) ;
  831. else if (m_nType == FCObjSelect::RGN_SUB)
  832. SubSelection (newSelect, selCreate) ;
  833. }
  834. }
  835. void AddSelection (FCObjSelect& selCurr, const FCObjSelect& sel)
  836. {
  837. if (!selCurr.HasSelected() || !sel.HasSelected())
  838. {assert(false); return;}
  839. // selection's canvas position
  840. RECT rcSel = {0, 0, sel.Width(), sel.Height()},
  841. rcCurr = {0, 0, selCurr.Width(), selCurr.Height()} ;
  842. selCurr.Layer_to_Canvas (rcCurr) ;
  843. sel.Layer_to_Canvas (rcSel) ;
  844. // merge
  845. if (!::IsRectInRect (rcCurr, rcSel))
  846. {
  847. // we need create new bitmap
  848. RECT rcDest ;
  849. ::UnionRect (&rcDest, &rcSel, &rcCurr) ;
  850. if (IsRectEmpty(&rcDest))
  851. {assert(false); return;}
  852. FCObjImage imgOld (selCurr) ;
  853. selCurr.Create (RECTWIDTH(rcDest), RECTHEIGHT(rcDest), 8) ;
  854. selCurr.CoverBlock (imgOld, rcCurr.left-rcDest.left, rcCurr.top-rcDest.top) ; // 覆盖原图
  855. selCurr.SetGraphObjPos (rcDest.left, rcDest.top) ;
  856. rcCurr = rcDest ; // rcCurr now put rect of new selection on canvas
  857. }
  858. // cover sel
  859. selCurr.LogicalBlend (sel, LOGI_SEL_ADD, rcSel.left - rcCurr.left,
  860. rcSel.top - rcCurr.top) ;
  861. }
  862. void SubSelection (FCObjSelect& selCurr, const FCObjSelect& sel)
  863. {
  864. if ((&selCurr == &sel) || !selCurr.HasSelected() || !sel.HasSelected())
  865. {assert(false); return;}
  866. // selection's canvas position
  867. RECT rcSel = {0, 0, sel.Width(), sel.Height()} ,
  868. rcCurr = {0, 0, selCurr.Width(), selCurr.Height()} ;
  869. selCurr.Layer_to_Canvas (rcCurr) ;
  870. sel.Layer_to_Canvas (rcSel) ;
  871. // cover sel
  872. selCurr.LogicalBlend (sel, LOGI_SEL_SUB, rcSel.left - rcCurr.left,
  873. rcSel.top - rcCurr.top) ;
  874. }
  875. };
  876. //=============================================================================
  877. /**
  878. * Rectangle region.
  879. */
  880. class FCCmdSelectionCreateRect : public FCCmdSelectionCreateBase
  881. {
  882. public:
  883. /// Constructor.
  884. /// @param rcRect : rect on canvas.
  885. FCCmdSelectionCreateRect (RECT rcRect, FCObjSelect::RGN_TYPE nType) : m_rcRect(rcRect), FCCmdSelectionCreateBase(nType) {}
  886. private:
  887. virtual void CreateSelection (FCObjCanvas& canvas, FCObjSelect& selCreate)
  888. {
  889. // ::NormalizeRect (m_rcRect) ;
  890. if (::IsRectEmpty(&m_rcRect))
  891. return ;
  892. // create new rect region
  893. selCreate.Create (RECTWIDTH(m_rcRect), RECTHEIGHT(m_rcRect), 8) ;
  894. memset (selCreate.GetMemStart(), 0xFF, selCreate.GetPitch()*selCreate.Height()) ;
  895. selCreate.SetGraphObjPos (m_rcRect.left, m_rcRect.top) ;
  896. }
  897. private:
  898. RECT m_rcRect ;
  899. };
  900. //=============================================================================
  901. /**
  902. * Ellipse region.
  903. */
  904. class FCCmdSelectionCreateEllipse : public FCCmdSelectionCreateBase
  905. {
  906. public:
  907. /// Constructor.
  908. /// @param rcRect : rect on canvas.
  909. FCCmdSelectionCreateEllipse (RECT rcEllipse, FCObjSelect::RGN_TYPE nType) : m_rcEllipse(rcEllipse), FCCmdSelectionCreateBase(nType) {}
  910. private:
  911. virtual void CreateSelection (FCObjCanvas& canvas, FCObjSelect& selCreate)
  912. {
  913. // ::NormalizeRect (m_rcEllipse) ;
  914. if (::IsRectEmpty(&m_rcEllipse))
  915. return ;
  916. // create new elliptic region
  917. selCreate.Create (RECTWIDTH(m_rcEllipse), RECTHEIGHT(m_rcEllipse), 8) ;
  918. double fCenX = selCreate.Width() / 2.0,
  919. fCenY = selCreate.Height() / 2.0 ;
  920. for (int y=0 ; y < selCreate.Height() ; y++)
  921. for (int x=0 ; x < selCreate.Width() ; x++)
  922. {
  923. double fX = (x+0.5-fCenX) / fCenX,
  924. fY = (y+0.5-fCenY) / fCenY ;
  925. *selCreate.GetBits(x,y) = (FHypot(fX, fY) > 1.0) ? 0 : 0xFF ;
  926. }
  927. selCreate.SetGraphObjPos (m_rcEllipse.left, m_rcEllipse.top) ;
  928. }
  929. private:
  930. RECT m_rcEllipse ;
  931. };
  932. //=============================================================================
  933. /**
  934. * Polygon region.
  935. */
  936. class FCCmdSelectionCreatePolygonBase : public FCCmdSelectionCreateBase
  937. {
  938. public:
  939. /// Constructor.
  940. /// @param PointList : point on canvas.
  941. FCCmdSelectionCreatePolygonBase (std::deque<POINT> PointList, FCObjSelect::RGN_TYPE nType) : FCCmdSelectionCreateBase(nType), m_PointList(PointList) {}
  942. protected:
  943. /// @param ppt : point on img.
  944. virtual void ImplementDrawPolygon (FCObjImage& img, const POINT* ppt, size_t cNum) =0 ;
  945. private:
  946. RECT FindPolygonBoundRect() const
  947. {
  948. RECT rc ;
  949. rc.left = rc.top = 0x7FFFFFFF ;
  950. rc.right = rc.bottom = -0x7FFFFFFF ;
  951. for (size_t i=0 ; i < m_PointList.size() ; i++)
  952. {
  953. if (m_PointList[i].x < rc.left) rc.left = m_PointList[i].x ;
  954. if (m_PointList[i].x > rc.right) rc.right = m_PointList[i].x ;
  955. if (m_PointList[i].y < rc.top) rc.top = m_PointList[i].y ;
  956. if (m_PointList[i].y > rc.bottom) rc.bottom = m_PointList[i].y ;
  957. }
  958. return rc ;
  959. }
  960. virtual void CreateSelection (FCObjCanvas& canvas, FCObjSelect& selCreate)
  961. {
  962. PCL_array<POINT> ppt (m_PointList.size()) ;
  963. if (m_PointList.size())
  964. for (size_t i=0 ; i < m_PointList.size() ; i++)
  965. ppt[i] = m_PointList[i] ;
  966. RECT rcBound = FindPolygonBoundRect() ;
  967. if (::IsRectEmpty(&rcBound))
  968. return ;
  969. // create new polygon region
  970. FCObjImage img ;
  971. img.Create (RECTWIDTH(rcBound), RECTHEIGHT(rcBound), 24) ;
  972. // draw polygon
  973. for (size_t i=0 ; i < m_PointList.size() ; i++)
  974. {
  975. ppt[i].x = ppt[i].x - rcBound.left ;
  976. ppt[i].y = ppt[i].y - rcBound.top ;
  977. }
  978. ImplementDrawPolygon (img, ppt.get(), m_PointList.size()) ;
  979. selCreate.Create (img.Width(), img.Height(), 8) ;
  980. for (int y=0 ; y < img.Height() ; y++)
  981. for (int x=0 ; x < img.Width() ; x++)
  982. *selCreate.GetBits(x,y) = PCL_B(img.GetBits(x,y)) ;
  983. selCreate.SetGraphObjPos (rcBound.left, rcBound.top) ;
  984. }
  985. private:
  986. std::deque<POINT> m_PointList ;
  987. };
  988. //=============================================================================
  989. /**
  990. * Magic wand selection.
  991. */
  992. class FCCmdSelectionCreateMagicWand : public FCCmdSelectionCreateBase
  993. {
  994. public:
  995. /// Constructor.
  996. FCCmdSelectionCreateMagicWand (POINT ptCanvas, int nTolerance, bool bContinuous, FCObjSelect::RGN_TYPE nType) : FCCmdSelectionCreateBase(nType)
  997. {
  998. m_ptCanvas = ptCanvas ;
  999. m_nTolerance = nTolerance ;
  1000. m_bContinuous = bContinuous ;
  1001. }
  1002. private:
  1003. virtual void CreateSelection (FCObjCanvas& canvas, FCObjSelect& selCreate)
  1004. {
  1005. FCObjLayer * pLayer = canvas.GetCurrentLayer() ;
  1006. if (!pLayer)
  1007. {assert(false); return;}
  1008. POINT ptLayer = m_ptCanvas ;
  1009. pLayer->Canvas_to_Layer (ptLayer) ;
  1010. if (!pLayer->IsInside (ptLayer.x, ptLayer.y)) // click point out of current layer
  1011. {
  1012. // select region that alpha==0
  1013. const SIZE sizeCanvas = canvas.GetCanvasDimension() ;
  1014. // create selection
  1015. selCreate.Create (sizeCanvas.cx, sizeCanvas.cy, 8) ;
  1016. selCreate.SetGraphObjPos (0, 0) ;
  1017. for (int y=0 ; y < selCreate.Height() ; y++)
  1018. for (int x=0 ; x < selCreate.Width() ; x++)
  1019. {
  1020. POINT ptCur = {x, y} ;
  1021. pLayer->Canvas_to_Layer (ptCur) ;
  1022. if (!pLayer->IsInside (ptCur.x,ptCur.y) || !PCL_A(pLayer->GetBits(ptCur.x,ptCur.y)))
  1023. *selCreate.GetBits(x,y) = 0xFF ;
  1024. }
  1025. }
  1026. else
  1027. if (m_bContinuous)
  1028. {
  1029. SeedFillMask (ptLayer, m_nTolerance, *pLayer, selCreate) ;
  1030. }
  1031. else
  1032. {
  1033. selCreate.Create (pLayer->Width(), pLayer->Height(), 8) ;
  1034. selCreate.SetGraphObjPos (pLayer->GetGraphObjPos()) ;
  1035. const RGBQUAD crClick = *(RGBQUAD*)pLayer->GetBits (ptLayer.x, ptLayer.y) ; // color of click point
  1036. for (int y=0 ; y < pLayer->Height() ; y++)
  1037. for (int x=0 ; x < pLayer->Width() ; x++)
  1038. if (IsInTolerance (pLayer->GetBits(x,y), crClick, m_nTolerance))
  1039. *selCreate.GetBits(x,y) = 0xFF ;
  1040. }
  1041. }
  1042. static bool IsInTolerance (const void* pCurr, RGBQUAD crOrigin, int nTolerance)
  1043. {
  1044. return (abs(PCL_B(pCurr) - PCL_B(&crOrigin)) <= nTolerance) &&
  1045. (abs(PCL_G(pCurr) - PCL_G(&crOrigin)) <= nTolerance) &&
  1046. (abs(PCL_R(pCurr) - PCL_R(&crOrigin)) <= nTolerance) &&
  1047. (PCL_A(pCurr) == PCL_A(&crOrigin)) ;
  1048. }
  1049. static void SeedFillMask (POINT ptImg, int nTolerance, const FCObjImage& img, FCObjSelect& sel)
  1050. {
  1051. if (!img.IsInside (ptImg.x, ptImg.y))
  1052. return ;
  1053. // color of click
  1054. const RGBQUAD crOrigin = *(RGBQUAD*)img.GetBits (ptImg.x, ptImg.y) ;
  1055. sel.Create (img.Width(), img.Height(), 8) ; // same size
  1056. sel.SetGraphObjPos (img.GetGraphObjPos()) ; // canvas's coordinate
  1057. std::deque<POINT> ptUnfilled ;
  1058. POINT ptCurr = {ptImg.x, ptImg.y} ;
  1059. ptUnfilled.push_back (ptCurr) ;
  1060. while (!ptUnfilled.empty())
  1061. {
  1062. ptCurr = ptUnfilled.back() ; ptUnfilled.pop_back() ;
  1063. *sel.GetBits (ptCurr.x, ptCurr.y) = 0xFF ; // set filled
  1064. // up
  1065. if ((ptCurr.y > 0) && (*sel.GetBits (ptCurr.x, ptCurr.y-1) == 0) &&
  1066. IsInTolerance (img.GetBits (ptCurr.x, ptCurr.y-1), crOrigin, nTolerance))
  1067. {
  1068. POINT pt = {ptCurr.x, ptCurr.y-1} ;
  1069. ptUnfilled.push_back (pt) ;
  1070. }
  1071. // right
  1072. if ((ptCurr.x < img.Width()-1) && (*sel.GetBits (ptCurr.x+1, ptCurr.y) == 0) &&
  1073. IsInTolerance (img.GetBits (ptCurr.x+1, ptCurr.y), crOrigin, nTolerance))
  1074. {
  1075. POINT pt = {ptCurr.x+1, ptCurr.y} ;
  1076. ptUnfilled.push_back (pt) ;
  1077. }
  1078. // bottom
  1079. if ((ptCurr.y < img.Height()-1) && (*sel.GetBits (ptCurr.x, ptCurr.y+1) == 0) &&
  1080. IsInTolerance (img.GetBits (ptCurr.x, ptCurr.y+1), crOrigin, nTolerance))
  1081. {
  1082. POINT pt = {ptCurr.x, ptCurr.y+1} ;
  1083. ptUnfilled.push_back (pt) ;
  1084. }
  1085. // left
  1086. if ((ptCurr.x > 0) && (*sel.GetBits (ptCurr.x-1, ptCurr.y) == 0) &&
  1087. IsInTolerance (img.GetBits (ptCurr.x-1, ptCurr.y), crOrigin, nTolerance))
  1088. {
  1089. POINT pt = {ptCurr.x-1, ptCurr.y} ;
  1090. ptUnfilled.push_back (pt) ;
  1091. }
  1092. }
  1093. }
  1094. private:
  1095. POINT m_ptCanvas ;
  1096. int m_nTolerance ;
  1097. bool m_bContinuous ;
  1098. };
  1099. //=============================================================================
  1100. /**
  1101. * Handle layer.
  1102. */
  1103. class FCCmdLayerOperation : public FCCmdArtPrider
  1104. {
  1105. protected:
  1106. /// Constructor.
  1107. FCCmdLayerOperation (FCObjLayer* pLayer) : m_pLayer(pLayer) {}
  1108. /// Process layer.
  1109. virtual void ProcessLayer (FCObjCanvas& canvas, FCObjLayer& rLayer, FCObjProgress* pProgress) =0 ;
  1110. private:
  1111. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  1112. {
  1113. if (!m_pLayer)
  1114. {assert(false); return;}
  1115. m_UndoLayer = *m_pLayer ;
  1116. m_pUndoMemo = std::auto_ptr<FCMemoLayer>(m_pLayer->CreateMemoObj()) ;
  1117. this->ProcessLayer (canvas, *m_pLayer, pProgress) ;
  1118. }
  1119. virtual void Undo (FCObjCanvas& canvas)
  1120. {
  1121. if (!m_pLayer)
  1122. {assert(false); return;}
  1123. m_RedoLayer = *m_pLayer ;
  1124. m_pRedoMemo = std::auto_ptr<FCMemoLayer>(m_pLayer->CreateMemoObj()) ;
  1125. *m_pLayer = m_UndoLayer ;
  1126. m_pLayer->SetMemoObj (m_pUndoMemo.get()) ;
  1127. }
  1128. virtual void Redo (FCObjCanvas& canvas)
  1129. {
  1130. if (!m_pLayer)
  1131. {assert(false); return;}
  1132. m_UndoLayer = *m_pLayer ;
  1133. m_pUndoMemo = std::auto_ptr<FCMemoLayer>(m_pLayer->CreateMemoObj()) ;
  1134. *m_pLayer = m_RedoLayer ;
  1135. m_pLayer->SetMemoObj (m_pRedoMemo.get()) ;
  1136. }
  1137. private:
  1138. FCObjLayer * m_pLayer ;
  1139. FCObjLayer m_UndoLayer, m_RedoLayer ;
  1140. std::auto_ptr<FCMemoLayer> m_pUndoMemo, m_pRedoMemo ;
  1141. };
  1142. //=============================================================================
  1143. /**
  1144. * Stretch layer.
  1145. */
  1146. class FCCmdLayerStretch : public FCCmdLayerOperation
  1147. {
  1148. public:
  1149. /// Constructor.
  1150. FCCmdLayerStretch (FCObjLayer* pLayer, int nNewW, int nNewH, INTERPOLATION_TYPE InterplType) : FCCmdLayerOperation(pLayer)
  1151. {
  1152. m_nNewWidth = nNewW ;
  1153. m_nNewHeight = nNewH ;
  1154. m_InterplType = InterplType ;
  1155. }
  1156. private:
  1157. virtual void ProcessLayer (FCObjCanvas& canvas, FCObjLayer& rLayer, FCObjProgress* pProgress)
  1158. {
  1159. // don't change layer's position
  1160. const POINT ptLayer = rLayer.GetGraphObjPos() ;
  1161. switch (m_InterplType)
  1162. {
  1163. case INTERPOLATION_NONE : rLayer.Stretch (m_nNewWidth, m_nNewHeight) ; break ;
  1164. case INTERPOLATION_BILINEAR : rLayer.Stretch_Smooth (m_nNewWidth, m_nNewHeight, pProgress) ; break ;
  1165. default : assert(false) ;
  1166. }
  1167. rLayer.SetGraphObjPos (ptLayer) ;
  1168. }
  1169. private:
  1170. int m_nNewWidth ;
  1171. int m_nNewHeight ;
  1172. INTERPOLATION_TYPE m_InterplType ;
  1173. };
  1174. //=============================================================================
  1175. /**
  1176. * Rotate layer.
  1177. */
  1178. class FCCmdLayerRotate : public FCCmdLayerOperation
  1179. {
  1180. public:
  1181. /// Constructor.
  1182. /// @param nAngle : 0 -- 360
  1183. FCCmdLayerRotate (FCObjLayer* pLayer, int nAngle) : FCCmdLayerOperation(pLayer)
  1184. {
  1185. m_nAngle = nAngle ;
  1186. }
  1187. private:
  1188. virtual void ProcessLayer (FCObjCanvas& canvas, FCObjLayer& rLayer, FCObjProgress* pProgress)
  1189. {
  1190. // the central point is fixed in rotate
  1191. POINT ptCenter = rLayer.GetGraphObjPos() ;
  1192. ptCenter.x += rLayer.Width()/2 ; ptCenter.y += rLayer.Height()/2 ;
  1193. // sawtooth :-(
  1194. FCPixelRotate aCmd(m_nAngle) ;
  1195. rLayer.SinglePixelProcessProc (aCmd, pProgress) ;
  1196. // calculate the position of rotated layer
  1197. ptCenter.x -= rLayer.Width()/2 ; ptCenter.y -= rLayer.Height()/2 ;
  1198. rLayer.SetGraphObjPos (ptCenter) ;
  1199. }
  1200. private:
  1201. int m_nAngle ;
  1202. };
  1203. //=============================================================================
  1204. /**
  1205. * Clockwise rotate 90'.
  1206. */
  1207. class FCCmdLayerRotate90 : public FCCmdLayerOperation
  1208. {
  1209. public:
  1210. /// Constructor.
  1211. FCCmdLayerRotate90 (FCObjLayer* pLayer) : FCCmdLayerOperation(pLayer) {}
  1212. private:
  1213. virtual void ProcessLayer (FCObjCanvas& canvas, FCObjLayer& rLayer, FCObjProgress* pProgress)
  1214. {
  1215. // the central point is fixed in rotate
  1216. POINT ptCenter = rLayer.GetGraphObjPos() ;
  1217. ptCenter.x += rLayer.Width()/2 ; ptCenter.y += rLayer.Height()/2 ;
  1218. FCPixelRotate90 cmdRotateImg ;
  1219. rLayer.SinglePixelProcessProc (cmdRotateImg, pProgress) ;
  1220. // calculate the position of rotated layer
  1221. ptCenter.x -= rLayer.Width()/2 ; ptCenter.y -= rLayer.Height()/2 ;
  1222. rLayer.SetGraphObjPos (ptCenter) ;
  1223. }
  1224. };
  1225. //=============================================================================
  1226. /**
  1227. * Clockwise rotate 270'.
  1228. */
  1229. class FCCmdLayerRotate270 : public FCCmdLayerOperation
  1230. {
  1231. public:
  1232. /// Constructor.
  1233. FCCmdLayerRotate270 (FCObjLayer* pLayer) : FCCmdLayerOperation(pLayer) {}
  1234. private:
  1235. virtual void ProcessLayer (FCObjCanvas& canvas, FCObjLayer& rLayer, FCObjProgress* pProgress)
  1236. {
  1237. // the central point is fixed in rotate
  1238. POINT ptCenter = rLayer.GetGraphObjPos() ;
  1239. ptCenter.x += rLayer.Width()/2 ; ptCenter.y += rLayer.Height()/2 ;
  1240. FCPixelRotate270 cmdRotateImg ;
  1241. rLayer.SinglePixelProcessProc (cmdRotateImg, pProgress) ;
  1242. // calculate the position of rotated layer
  1243. ptCenter.x -= rLayer.Width()/2 ; ptCenter.y -= rLayer.Height()/2 ;
  1244. rLayer.SetGraphObjPos (ptCenter) ;
  1245. }
  1246. };
  1247. //=============================================================================
  1248. /**
  1249. * Skew transform.
  1250. */
  1251. class FCCmdLayerSkew : public FCCmdLayerOperation
  1252. {
  1253. public:
  1254. /// Constructor.
  1255. /// @param ptPos : new position of left-up, right-up, right-down, left-down point.
  1256. FCCmdLayerSkew (FCObjLayer* pLayer, const POINT ptPos[4]) : FCCmdLayerOperation(pLayer)
  1257. {
  1258. memcpy (m_ptNewPos, ptPos, sizeof(POINT) * 4) ;
  1259. }
  1260. private:
  1261. virtual void ProcessLayer (FCObjCanvas& canvas, FCObjLayer& rLayer, FCObjProgress* pProgress)
  1262. {
  1263. FCPixelSkew aCmd (m_ptNewPos) ;
  1264. rLayer.SinglePixelProcessProc (aCmd, pProgress) ;
  1265. }
  1266. private:
  1267. POINT m_ptNewPos[4] ; // left-up, right-up, right-down, left-down
  1268. };
  1269. //=============================================================================
  1270. /**
  1271. * Lens transform.
  1272. */
  1273. class FCCmdLayerLens : public FCCmdLayerOperation
  1274. {
  1275. public:
  1276. /// Constructor.
  1277. /// @param ptPos : new position of left-up, right-up, right-down, left-down point.
  1278. FCCmdLayerLens (FCObjLayer* pLayer, const POINT ptPos[4]) : FCCmdLayerOperation(pLayer)
  1279. {
  1280. memcpy (m_ptNewPos, ptPos, sizeof(POINT) * 4) ;
  1281. }
  1282. private:
  1283. virtual void ProcessLayer (FCObjCanvas& canvas, FCObjLayer& rLayer, FCObjProgress* pProgress)
  1284. {
  1285. FCPixelPerspective aCmd (m_ptNewPos) ;
  1286. rLayer.SinglePixelProcessProc (aCmd, pProgress) ;
  1287. }
  1288. private:
  1289. POINT m_ptNewPos[4] ; // left-up, right-up, right-down, left-down
  1290. };
  1291. //=============================================================================
  1292. /**
  1293. * Crop layer.
  1294. */
  1295. class FCCmdLayerCrop : public FCCmdLayerOperation
  1296. {
  1297. public:
  1298. /// Constructor.
  1299. FCCmdLayerCrop (FCObjLayer* pLayer, FCObjImage* pImgMask, RECT rcLayer, int nPercent) : FCCmdLayerOperation(pLayer), m_pImgMask(pImgMask)
  1300. {
  1301. m_rcLayer = rcLayer ;
  1302. m_nPercent = nPercent ;
  1303. }
  1304. private:
  1305. virtual void ProcessLayer (FCObjCanvas& canvas, FCObjLayer& rLayer, FCObjProgress* pProgress)
  1306. {
  1307. if (!m_pImgMask.get() || (m_pImgMask->ColorBits() != 24))
  1308. {assert(false); return;}
  1309. const POINT ptOldImg = rLayer.GetGraphObjPos() ;
  1310. // get selected region
  1311. FCObjImage imgBlock ;
  1312. rLayer.GetSubBlock (&imgBlock, m_rcLayer) ;
  1313. if (!rLayer.IsValidImage())
  1314. {assert(false); return;}
  1315. m_pImgMask->Stretch_Smooth (imgBlock.Width(), imgBlock.Height()) ;
  1316. // process
  1317. for (int y=0 ; y < imgBlock.Height() ; y++)
  1318. for (int x=0 ; x < imgBlock.Width() ; x++)
  1319. {
  1320. int nGray = 0xFF - FCColor::GetGrayscale (m_pImgMask->GetBits(x,y)) ;
  1321. BYTE * p = imgBlock.GetBits(x,y) ;
  1322. PCL_A(p) = PCL_A(p) * nGray * (100-m_nPercent) / 0xFF / 100 ;
  1323. }
  1324. static_cast<FCObjImage&>(rLayer) = imgBlock ;
  1325. rLayer.SetGraphObjPos (ptOldImg.x + m_rcLayer.left, ptOldImg.y + m_rcLayer.top) ;
  1326. }
  1327. private:
  1328. std::auto_ptr<FCObjImage> m_pImgMask ; // 24-bit mask image
  1329. RECT m_rcLayer ; // RECT on layer
  1330. int m_nPercent ;
  1331. };
  1332. //=============================================================================
  1333. /**
  1334. * Move graph object.
  1335. */
  1336. class FCCmdLayerMove : public FCCmdArtPrider
  1337. {
  1338. public:
  1339. /// Constructor.
  1340. FCCmdLayerMove (FCObjGraph* pGraph, POINT NewPoint) : m_pGraph(pGraph), m_ptOld(NewPoint) {}
  1341. private:
  1342. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  1343. {
  1344. this->Redo(canvas) ;
  1345. }
  1346. virtual void Undo (FCObjCanvas& canvas)
  1347. {
  1348. this->Redo(canvas) ;
  1349. }
  1350. virtual void Redo (FCObjCanvas& canvas)
  1351. {
  1352. if (!m_pGraph)
  1353. {assert(false); return;}
  1354. const POINT pt = m_pGraph->GetGraphObjPos() ;
  1355. m_pGraph->SetGraphObjPos (m_ptOld) ;
  1356. m_ptOld = pt ;
  1357. }
  1358. private:
  1359. POINT m_ptOld ;
  1360. FCObjGraph * m_pGraph ;
  1361. };
  1362. //=============================================================================
  1363. /**
  1364. * Insert a new layer into canvas.
  1365. */
  1366. class FCCmdLayerAdd : public FCCmdArtPrider
  1367. {
  1368. public:
  1369. /**
  1370. * Insert a new layer into canvas (<B>after be added, you can't delete the layer any more</B>).
  1371. * @param nPos : the pAddLayer's 0-base index in canvas.
  1372. */
  1373. FCCmdLayerAdd (FCObjLayer* pAddLayer, int nPos)
  1374. {
  1375. m_pAddLayer = pAddLayer ; assert(pAddLayer);
  1376. m_nPos = nPos ;
  1377. m_pCanvas = 0 ;
  1378. // why we need this flag : think about this scene
  1379. // 1)undo level set(2) 2)add a layer 3)merge layer include it 4)add a layer 5)undo
  1380. // the step 2, first layer will be removed, but the step 3 hold its pointer
  1381. m_bRemoved = false ;
  1382. }
  1383. virtual ~FCCmdLayerAdd()
  1384. {
  1385. // 其实图层remove时就该被删除,只是为了节省内存,才暂时放到remove列表中
  1386. if (m_bRemoved)
  1387. m_pCanvas->DeleteLayerFromRemoveList (m_pAddLayer) ;
  1388. }
  1389. private:
  1390. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  1391. {
  1392. m_pCanvas = &canvas ;
  1393. this->Redo(canvas) ;
  1394. }
  1395. virtual void Undo (FCObjCanvas& canvas)
  1396. {
  1397. m_bRemoved = true ;
  1398. canvas.RemoveLayer (m_pAddLayer) ; // not delete
  1399. }
  1400. virtual void Redo (FCObjCanvas& canvas)
  1401. {
  1402. m_bRemoved = false ;
  1403. canvas.AddLayer (m_pAddLayer, m_nPos) ;
  1404. }
  1405. private:
  1406. int m_nPos ;
  1407. FCObjLayer * m_pAddLayer ;
  1408. FCObjCanvas * m_pCanvas ;
  1409. bool m_bRemoved ;
  1410. };
  1411. //=============================================================================
  1412. /**
  1413. * Remove a layer from canvas.
  1414. */
  1415. class FCCmdLayerRemove : public FCCmdArtPrider
  1416. {
  1417. public:
  1418. /// Remove pRemoveLayer from canvas.
  1419. FCCmdLayerRemove (FCObjLayer* pRemoveLayer)
  1420. {
  1421. m_pRemoveLayer = pRemoveLayer; assert(pRemoveLayer);
  1422. m_pCanvas = 0 ;
  1423. m_bRemoved = true ;
  1424. }
  1425. virtual ~FCCmdLayerRemove()
  1426. {
  1427. // 其实图层remove时就该被删除,只是为了节省内存,才暂时放到remove列表中
  1428. if (m_bRemoved)
  1429. m_pCanvas->DeleteLayerFromRemoveList (m_pRemoveLayer) ;
  1430. }
  1431. private:
  1432. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  1433. {
  1434. m_pCanvas = &canvas ;
  1435. this->Redo(canvas) ;
  1436. }
  1437. virtual void Undo (FCObjCanvas& canvas)
  1438. {
  1439. m_bRemoved = false ;
  1440. canvas.AddLayer (m_pRemoveLayer, m_nPos) ;
  1441. }
  1442. virtual void Redo (FCObjCanvas& canvas)
  1443. {
  1444. m_bRemoved = true ;
  1445. m_nPos = canvas.FindLayer(m_pRemoveLayer) ;
  1446. canvas.RemoveLayer (m_pRemoveLayer) ; // not delete
  1447. }
  1448. private:
  1449. int m_nPos ;
  1450. FCObjLayer * m_pRemoveLayer ;
  1451. FCObjCanvas * m_pCanvas ;
  1452. bool m_bRemoved ;
  1453. };
  1454. //=============================================================================
  1455. /**
  1456. * Save layer's current property.
  1457. */
  1458. class FCCmdLayerSaveProperty : public FCCmdArtPrider
  1459. {
  1460. public:
  1461. /// Constructor (save layer's current property when constructor).
  1462. FCCmdLayerSaveProperty (FCObjLayer* pLayer)
  1463. {
  1464. m_pLayer = pLayer ;
  1465. m_pMemo = m_pLayer ? m_pLayer->CreateMemoObj() : 0 ;
  1466. }
  1467. virtual ~FCCmdLayerSaveProperty() {if(m_pMemo) delete m_pMemo;}
  1468. private:
  1469. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress) {}
  1470. virtual void Undo (FCObjCanvas& canvas)
  1471. {
  1472. this->Redo(canvas) ;
  1473. }
  1474. virtual void Redo (FCObjCanvas& canvas)
  1475. {
  1476. if (m_pLayer && m_pMemo)
  1477. {
  1478. FCMemoLayer * pCurr = m_pLayer->CreateMemoObj() ;
  1479. m_pLayer->SetMemoObj (m_pMemo) ;
  1480. delete m_pMemo ;
  1481. m_pMemo = pCurr ;
  1482. }
  1483. else
  1484. {assert(false);}
  1485. }
  1486. private:
  1487. FCMemoLayer * m_pMemo ;
  1488. FCObjLayer * m_pLayer ;
  1489. };
  1490. //=============================================================================
  1491. /**
  1492. * Change layer's sequence in canvas.
  1493. */
  1494. class FCCmdLayerExchange : public FCCmdArtPrider
  1495. {
  1496. public:
  1497. FCCmdLayerExchange (std::deque<FCObjLayer*> NewList) : m_LayerList(NewList) {}
  1498. private:
  1499. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  1500. {
  1501. this->Redo(canvas) ;
  1502. }
  1503. virtual void Undo (FCObjCanvas& canvas)
  1504. {
  1505. this->Redo(canvas) ;
  1506. }
  1507. virtual void Redo (FCObjCanvas& canvas)
  1508. {
  1509. FSwap (canvas.m_LayerList, m_LayerList) ;
  1510. }
  1511. private:
  1512. std::deque<FCObjLayer*> m_LayerList ;
  1513. };
  1514. //=============================================================================
  1515. /**
  1516. * Merge layers.
  1517. */
  1518. class FCCmdLayerMerge : public FCCmdComposite
  1519. {
  1520. public:
  1521. /// Constructor.
  1522. /// @param IndexList : list of layer's index.
  1523. FCCmdLayerMerge (std::deque<int> IndexList)
  1524. {
  1525. if (IndexList.empty())
  1526. {assert(false); return;}
  1527. PCL_array<int> arr(IndexList.size()) ;
  1528. for (size_t i=0 ; i < IndexList.size() ; i++)
  1529. arr[i] = IndexList[i] ;
  1530. // sort by small to big, delete layer from big
  1531. FCOXOHelper::BubbleSort (arr.get(), IndexList.size()) ;
  1532. for (size_t j=0 ; j < IndexList.size() ; j++)
  1533. m_IndexList.push_back (arr[j]) ;
  1534. }
  1535. private:
  1536. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  1537. {
  1538. if (m_IndexList.empty())
  1539. {assert(false); return;}
  1540. // calculate merged layer size
  1541. RECT rcNewLayer = {0,0,0,0} ;
  1542. int i ;
  1543. for (i=0 ; i < (int)m_IndexList.size() ; i++)
  1544. {
  1545. FCObjLayer * pLayer = canvas.GetLayer(m_IndexList[i]) ; assert(pLayer);
  1546. if (!pLayer)
  1547. continue ;
  1548. // layer's RECT
  1549. RECT rcLayer = {0, 0, pLayer->Width(), pLayer->Height()} ;
  1550. POINT pt = pLayer->GetGraphObjPos() ;
  1551. OffsetRect (&rcLayer, pt.x, pt.y) ;
  1552. if (i == 0)
  1553. rcNewLayer = rcLayer ;
  1554. else
  1555. UnionRect (&rcNewLayer, &rcNewLayer, &rcLayer) ;
  1556. }
  1557. // make new merged layer
  1558. FCObjLayer * pNewLayer = new FCObjLayer ;
  1559. if (!pNewLayer->Create (RECTWIDTH(rcNewLayer), RECTHEIGHT(rcNewLayer), 32))
  1560. {
  1561. delete pNewLayer ;
  1562. assert(false); return;
  1563. }
  1564. // merge layers (from bottom to top)
  1565. for (i=0 ; i < (int)m_IndexList.size() ; i++)
  1566. {
  1567. FCObjLayer * pLayer = canvas.GetLayer(m_IndexList[i]) ; assert(pLayer);
  1568. if (!pLayer)
  1569. continue ;
  1570. // position at new layer
  1571. pNewLayer->CombineImage (*pLayer,
  1572. pLayer->GetGraphObjPos().x - rcNewLayer.left,
  1573. pLayer->GetGraphObjPos().y - rcNewLayer.top,
  1574. pLayer->GetLayerTransparent()) ;
  1575. if (pProgress)
  1576. pProgress->SetProgress (100 * (i + 1) / m_IndexList.size()) ;
  1577. }
  1578. // set new merged layer's position
  1579. pNewLayer->SetGraphObjPos (rcNewLayer.left, rcNewLayer.top) ;
  1580. // insert new layer at min index
  1581. PushImgCommand (new FCCmdLayerAdd (pNewLayer, m_IndexList[0])) ;
  1582. // delete layers
  1583. for (i = m_IndexList.size()-1 ; i >=0 ; i--)
  1584. {
  1585. FCObjLayer * pLayer = canvas.GetLayer(m_IndexList[i]) ; assert(pLayer);
  1586. if (pLayer)
  1587. PushImgCommand (new FCCmdLayerRemove (pLayer)) ;
  1588. }
  1589. FCCmdComposite::Execute (canvas, pProgress) ;
  1590. }
  1591. std::deque<int> m_IndexList ;
  1592. };
  1593. //=============================================================================
  1594. /**
  1595. * Delete layers from canvas
  1596. */
  1597. class FCCmdLayerListRemove : public FCCmdComposite
  1598. {
  1599. public:
  1600. /// Constructor.
  1601. /// @param IndexList : list of layer's index.
  1602. FCCmdLayerListRemove (const FCObjCanvas& canvas, std::deque<int> IndexList)
  1603. {
  1604. if (IndexList.empty())
  1605. {assert(false); return;}
  1606. PCL_array<int> arr (IndexList.size()) ;
  1607. for (size_t i=0 ; i < IndexList.size() ; i++)
  1608. arr[i] = IndexList[i] ;
  1609. // sort by small to big, delete layer from big to small
  1610. FCOXOHelper::BubbleSort (arr.get(), IndexList.size()) ;
  1611. for (int j=IndexList.size()-1 ; j >= 0 ; j--)
  1612. PushImgCommand (new FCCmdLayerRemove(canvas.GetLayer(arr[j]))) ;
  1613. }
  1614. };
  1615. //=============================================================================
  1616. /**
  1617. * Handle canvas.
  1618. * <B>derived class must initialize member m_NewCanvasSize at constructor</B>
  1619. */
  1620. class FCCmdCanvasOperation : public FCCmdComposite
  1621. {
  1622. public:
  1623. FCCmdCanvasOperation()
  1624. {
  1625. m_OldCanvasSize.cx = m_OldCanvasSize.cy = -1 ;
  1626. m_NewCanvasSize.cx = m_NewCanvasSize.cy = -1 ;
  1627. }
  1628. virtual void Execute (FCObjCanvas& canvas, FCObjProgress* pProgress)
  1629. {
  1630. m_OldCanvasSize = canvas.GetCanvasDimension() ;
  1631. FCCmdComposite::Execute (canvas, pProgress) ;
  1632. canvas.SetCanvasDimension (m_NewCanvasSize) ;
  1633. }
  1634. virtual void Undo (FCObjCanvas& canvas)
  1635. {
  1636. FCCmdComposite::Undo(canvas) ;
  1637. canvas.SetCanvasDimension (m_OldCanvasSize) ;
  1638. }
  1639. virtual void Redo (FCObjCanvas& canvas)
  1640. {
  1641. FCCmdComposite::Redo(canvas) ;
  1642. canvas.SetCanvasDimension (m_NewCanvasSize) ;
  1643. }
  1644. private:
  1645. SIZE m_OldCanvasSize ;
  1646. protected:
  1647. SIZE m_NewCanvasSize ;
  1648. };
  1649. //=============================================================================
  1650. /**
  1651. * Resize canvas.
  1652. */
  1653. class FCCmdCanvasResize : public FCCmdCanvasOperation
  1654. {
  1655. public:
  1656. /// Constructor.
  1657. /// @param nLeft,nTop,nRight,nBottom : canvas's delta.
  1658. FCCmdCanvasResize (const FCObjCanvas& rCanvas, int nLeft, int nTop, int nRight, int nBottom)
  1659. {
  1660. const SIZE OldSize = rCanvas.GetCanvasDimension() ;
  1661. m_NewCanvasSize.cx = OldSize.cx + nLeft + nRight ;
  1662. m_NewCanvasSize.cy = OldSize.cy + nTop + nBottom ;
  1663. if ((m_NewCanvasSize.cx < 1) || (m_NewCanvasSize.cy < 1))
  1664. {
  1665. m_NewCanvasSize = OldSize ;
  1666. assert(false) ; return ;
  1667. }
  1668. // update position of all layers
  1669. for (int i=0 ; i < rCanvas.GetLayerNumber() ; i++)
  1670. {
  1671. FCObjLayer * pLayer = rCanvas.GetLayer(i) ;
  1672. POINT ptNew = pLayer->GetGraphObjPos() ;
  1673. ptNew.x += nLeft ; ptNew.y += nTop ;
  1674. PushImgCommand (new FCCmdLayerMove (pLayer, ptNew)) ;
  1675. }
  1676. // clear selection
  1677. PushImgCommand (new FCCmdSelectionClear()) ;
  1678. }
  1679. };
  1680. //=============================================================================
  1681. /**
  1682. * Canvas rotate 90'
  1683. */
  1684. class FCCmdCanvasRotate90 : public FCCmdCanvasOperation
  1685. {
  1686. public:
  1687. /// Constructor.
  1688. FCCmdCanvasRotate90 (const FCObjCanvas& rCanvas)
  1689. {
  1690. const SIZE OldSize = rCanvas.GetCanvasDimension() ;
  1691. for (int i=0 ; i < rCanvas.GetLayerNumber() ; i++)
  1692. {
  1693. FCObjLayer * pLayer = rCanvas.GetLayer(i) ;
  1694. PushImgCommand (new FCCmdLayerRotate90 (pLayer)) ;
  1695. // calculate new position
  1696. POINT ptOld = pLayer->GetGraphObjPos(),
  1697. ptLB = {ptOld.x, ptOld.y + pLayer->Height()} ;
  1698. ptOld.x = OldSize.cy - ptLB.y ;
  1699. ptOld.y = ptLB.x ;
  1700. PushImgCommand (new FCCmdLayerMove (pLayer, ptOld)) ;
  1701. }
  1702. PushImgCommand (new FCCmdSelectionClear()) ;
  1703. // new canvas size
  1704. m_NewCanvasSize.cx = OldSize.cy ; m_NewCanvasSize.cy = OldSize.cx ;
  1705. }
  1706. };
  1707. //=============================================================================
  1708. /**
  1709. * Canvas rotate 270'
  1710. */
  1711. class FCCmdCanvasRotate270 : public FCCmdCanvasOperation
  1712. {
  1713. public:
  1714. /// Constructor.
  1715. FCCmdCanvasRotate270 (const FCObjCanvas& rCanvas)
  1716. {
  1717. const SIZE OldSize = rCanvas.GetCanvasDimension() ;
  1718. for (int i=0 ; i < rCanvas.GetLayerNumber() ; i++)
  1719. {
  1720. FCObjLayer * pLayer = rCanvas.GetLayer(i) ;
  1721. PushImgCommand (new FCCmdLayerRotate270 (pLayer)) ;
  1722. // calculate new position
  1723. POINT ptOld = pLayer->GetGraphObjPos(),
  1724. ptRT = {ptOld.x + pLayer->Width(), ptOld.y} ;
  1725. ptOld.x = ptRT.y ;
  1726. ptOld.y = OldSize.cx - ptRT.x ;
  1727. PushImgCommand (new FCCmdLayerMove (pLayer, ptOld)) ;
  1728. }
  1729. PushImgCommand (new FCCmdSelectionClear()) ;
  1730. // new canvas size
  1731. m_NewCanvasSize.cx = OldSize.cy ; m_NewCanvasSize.cy = OldSize.cx ;
  1732. }
  1733. };
  1734. //=============================================================================
  1735. /**
  1736. * Rotate canvas.
  1737. */
  1738. class FCCmdCanvasRotate : public FCCmdCanvasOperation
  1739. {
  1740. public:
  1741. /// Constructor.
  1742. /// @param nAngle : 0 -- 360
  1743. FCCmdCanvasRotate (const FCObjCanvas& rCanvas, int nAngle)
  1744. {
  1745. nAngle = FClamp (nAngle, 0, 360) ;
  1746. // 计算画布新尺寸
  1747. const SIZE OldSize = rCanvas.GetCanvasDimension() ;
  1748. const int nTmpAng = FMax (0, nAngle % 180) ;
  1749. const double fSin = sin(AngleToRadian(nTmpAng % 90)),
  1750. fCos = cos(AngleToRadian(nTmpAng % 90)) ;
  1751. // 注意这里的宽高计算
  1752. if (nTmpAng >= 90)
  1753. {
  1754. m_NewCanvasSize.cx = FRound (OldSize.cx * fSin + OldSize.cy * fCos) ;
  1755. m_NewCanvasSize.cy = FRound (OldSize.cy * fSin + OldSize.cx * fCos) ;
  1756. }
  1757. else
  1758. {
  1759. m_NewCanvasSize.cx = FRound (OldSize.cx * fCos + OldSize.cy * fSin) ;
  1760. m_NewCanvasSize.cy = FRound (OldSize.cy * fCos + OldSize.cx * fSin) ;
  1761. }
  1762. for (int i=0 ; i < rCanvas.GetLayerNumber() ; i++)
  1763. {
  1764. FCObjLayer * pLayer = rCanvas.GetLayer(i) ;
  1765. // 计算新位置
  1766. // 这里特殊点,先移动,后旋转,因为旋转时会绕中心点旋转
  1767. POINT ptNew = pLayer->GetGraphObjPos() ;
  1768. ptNew.x += (m_NewCanvasSize.cx-OldSize.cx)/2 ;
  1769. ptNew.y += (m_NewCanvasSize.cy-OldSize.cy)/2 ;
  1770. PushImgCommand (new FCCmdLayerMove (pLayer, ptNew)) ;
  1771. PushImgCommand (new FCCmdLayerRotate (pLayer, nAngle)) ;
  1772. }
  1773. PushImgCommand (new FCCmdSelectionClear()) ;
  1774. }
  1775. };
  1776. //=============================================================================
  1777. /**
  1778. * Stretch canvas.
  1779. */
  1780. class FCCmdCanvasStretch : public FCCmdCanvasOperation
  1781. {
  1782. public:
  1783. FCCmdCanvasStretch (const FCObjCanvas& rCanvas, int nNewW, int nNewH, INTERPOLATION_TYPE InterplType)
  1784. {
  1785. const SIZE OldSize = rCanvas.GetCanvasDimension() ;
  1786. if ((nNewW <= 0) || (nNewH <= 0) || (OldSize.cx <= 0) || (OldSize.cy <= 0))
  1787. {
  1788. m_NewCanvasSize = OldSize ;
  1789. assert(false) ; return ;
  1790. }
  1791. for (int i=0 ; i < rCanvas.GetLayerNumber() ; i++)
  1792. {
  1793. FCObjLayer * pLayer = rCanvas.GetLayer(i) ;
  1794. PushImgCommand (new FCCmdLayerStretch (pLayer,
  1795. pLayer->Width() * nNewW / OldSize.cx,
  1796. pLayer->Height() * nNewH / OldSize.cy,
  1797. InterplType)) ;
  1798. // calculate new position
  1799. POINT ptOld = pLayer->GetGraphObjPos() ;
  1800. ptOld.x = ptOld.x * nNewW / OldSize.cx ;
  1801. ptOld.y = ptOld.y * nNewH / OldSize.cy ;
  1802. PushImgCommand (new FCCmdLayerMove (pLayer, ptOld)) ;
  1803. }
  1804. PushImgCommand (new FCCmdSelectionClear()) ;
  1805. m_NewCanvasSize.cx = nNewW ; m_NewCanvasSize.cy = nNewH ;
  1806. }
  1807. };
  1808. //=============================================================================
  1809. /**
  1810. * Crop canvas.
  1811. */
  1812. class FCCmdCanvasCrop : public FCCmdCanvasOperation
  1813. {
  1814. public:
  1815. /// Constructor.
  1816. FCCmdCanvasCrop (const FCObjCanvas& rCanvas, RECT rcCanvas)
  1817. {
  1818. RECT rcSel = rcCanvas ;
  1819. rCanvas.BoundRect (rcSel) ;
  1820. if (IsRectEmpty(&rcSel))
  1821. {
  1822. m_NewCanvasSize = rCanvas.GetCanvasDimension() ;
  1823. return ;
  1824. }
  1825. for (int i=0 ; i < rCanvas.GetLayerNumber() ; i++)
  1826. {
  1827. // crop all layers
  1828. PushImgCommand (new FCCmdCanvasCrop_Layer (rCanvas.GetLayer(i), rcSel)) ;
  1829. }
  1830. // clear selection
  1831. PushImgCommand (new FCCmdSelectionClear()) ;
  1832. m_NewCanvasSize.cx = RECTWIDTH(rcSel) ;
  1833. m_NewCanvasSize.cy = RECTHEIGHT(rcSel) ;
  1834. }
  1835. private:
  1836. // 裁剪单层逻辑
  1837. class FCCmdCanvasCrop_Layer : public FCCmdLayerOperation
  1838. {
  1839. public:
  1840. FCCmdCanvasCrop_Layer (FCObjLayer* pLayer, RECT rcCanvas) : FCCmdLayerOperation(pLayer), m_rcCanvas(rcCanvas) {}
  1841. virtual void ProcessLayer (FCObjCanvas& canvas, FCObjLayer& rLayer, FCObjProgress* pProgress)
  1842. {
  1843. // calculate RECT in layer
  1844. RECT rcLayer = m_rcCanvas ;
  1845. rLayer.Canvas_to_Layer (rcLayer) ;
  1846. rLayer.BoundRect (rcLayer) ;
  1847. if (IsRectEmpty (&rcLayer))
  1848. {
  1849. // create transparency layer
  1850. rLayer.Create (RECTWIDTH(m_rcCanvas), RECTHEIGHT(m_rcCanvas), 32) ;
  1851. FCPixelFillColor cmdFillCr (FCColor::crWhite(), 0) ;
  1852. rLayer.SinglePixelProcessProc (cmdFillCr, pProgress) ;
  1853. rLayer.SetGraphObjPos (0, 0) ;
  1854. }
  1855. else
  1856. {
  1857. FCObjImage imgCrop ;
  1858. canvas.MakeRegion (rLayer, imgCrop) ;
  1859. // calc new layer's position, notice sequence !!!!!!
  1860. rLayer.Layer_to_Canvas (rcLayer) ;
  1861. (FCObjImage&)rLayer = imgCrop ;
  1862. rLayer.SetGraphObjPos (rcLayer.left-m_rcCanvas.left, rcLayer.top-m_rcCanvas.top) ;
  1863. }
  1864. }
  1865. private:
  1866. RECT m_rcCanvas ; // rect of canvas
  1867. };
  1868. };
  1869. //============================================================================
  1870. // 自动裁减画布/auto crop canvas,裁掉canvas边上透明的区域
  1871. class FCCmdCanvasAutoCrop : public FCCmdCanvasOperation
  1872. {
  1873. public:
  1874. FCCmdCanvasAutoCrop (const FCObjCanvas& rCanvas)
  1875. {
  1876. const SIZE sizeOld = rCanvas.GetCanvasDimension() ;
  1877. m_NewCanvasSize = sizeOld ; // must set size before return
  1878. RECT rcBound = {0,0,0,0} ;
  1879. for (int i=0 ; i < rCanvas.GetLayerNumber() ; i++)
  1880. {
  1881. FCObjLayer * pLayer = rCanvas.GetLayer(i) ;
  1882. FCPixelGetOptimizedRect aCmd ;
  1883. pLayer->SinglePixelProcessProc (aCmd) ;
  1884. pLayer->Layer_to_Canvas (aCmd.m_rcOptimized) ;
  1885. if (i == 0)
  1886. rcBound = aCmd.m_rcOptimized ;
  1887. else
  1888. ::UnionRect (&rcBound, &rcBound, &aCmd.m_rcOptimized) ;
  1889. }
  1890. if (IsRectEmpty (&rcBound))
  1891. return ;
  1892. rCanvas.BoundRect (rcBound) ;
  1893. if (IsRectEmpty(&rcBound))
  1894. return ;
  1895. int nRight = rcBound.right - sizeOld.cx,
  1896. nBottom = rcBound.bottom - sizeOld.cy ;
  1897. PushImgCommand (new FCCmdCanvasResize(rCanvas, -rcBound.left, -rcBound.top, nRight, nBottom)) ;
  1898. m_NewCanvasSize.cx = sizeOld.cx - rcBound.left + nRight ;
  1899. m_NewCanvasSize.cy = sizeOld.cy - rcBound.top + nBottom ;
  1900. }
  1901. };
  1902. #endif