123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 |
- /*
- * Copyright (C) =USTC= Fu Li
- *
- * Author : Fu Li
- * Create : 2003-3-30
- * Home : http://www.crazy-bit.com/
- * Mail : crazybit@263.net
- * History :
- */
- #ifndef __FOO_OBJECT_CANVAS__2003_03_30__H__
- #define __FOO_OBJECT_CANVAS__2003_03_30__H__
- #include "ObjLayer.h"
- #include "ObjSelect.h"
- #include "pixelprocessor/PixelProcessorBase.h"
- #include "command/Interface_Command.h"
- #include "PCL_interface_zoom.h"
- #include "PCL_interface_undo.h"
- #include <algorithm>
- //=============================================================================
- /**
- * Canvas object - container of layers.
- */
- class FCObjCanvas : public PCL_Interface_ZoomScale,
- public PCL_Interface_Undo<FCCmdArtPrider>
- {
- public:
- /// Constructor.
- FCObjCanvas (int nUndoLevel = 20) : PCL_Interface_Undo<FCCmdArtPrider>(nUndoLevel)
- {
- m_sizeCanvas.cx = m_sizeCanvas.cy = 0 ;
- m_pCurrentLayer = 0 ;
- m_nResX = m_nResY = 72 ;
- }
- virtual ~FCObjCanvas()
- {
- // first, maybe command hold layer's pointer
- ClearUndoList() ;
- ClearRedoList() ;
- // layers
- while (!m_LayerList.empty())
- {
- FCObjLayer * p = m_LayerList.back() ;
- m_LayerList.pop_back() ;
- delete p ;
- }
- // removed layers
- while (!m_RemovedLayerList.empty())
- {
- FCObjLayer * p = m_RemovedLayerList.back() ;
- m_RemovedLayerList.pop_back() ;
- delete p ;
- }
- m_pCurrentLayer = 0 ;
- }
- /// Set DPI (dot per inch) resolution.
- void SetCanvasResolution (int nResX, int nResY) {m_nResX=nResX ; m_nResY=nResY ;}
- /// Get DPI (dot per inch) resolution.
- void GetCanvasResolution (int& nResX, int& nResY) const {nResX=m_nResX ; nResY=m_nResY ;}
- /// Set canvas's size.
- void SetCanvasDimension (SIZE sz) {m_sizeCanvas=sz; assert(sz.cx>=1 && sz.cy>=1);}
- /// Get canvas's size.
- SIZE GetCanvasDimension () const {return m_sizeCanvas;}
- /// Get canvas's scaled size.
- SIZE GetCanvasScaledDimension() const
- {
- POINT pt = {m_sizeCanvas.cx, m_sizeCanvas.cy} ;
- Actual_to_Scaled (pt) ;
- SIZE sz = {pt.x, pt.y} ;
- return sz ;
- }
- /// Get current selection object on canvas.
- const FCObjSelect& GetSelection() const {return m_CurrSel;}
- /// Has a selection object on canvas.
- bool HasSelected() const {return m_CurrSel.HasSelected();}
- /// Bound rect in canvas (rc is coordinate of canvas).
- void BoundRect (RECT& rc) const
- {
- RECT rcCanvas = {0, 0, m_sizeCanvas.cx, m_sizeCanvas.cy} ;
- ::IntersectRect (&rc, &rcCanvas, &rc) ;
- }
- /**
- * @name Layers manage.
- */
- //@{
- /// Get number of layers on canvas.
- int GetLayerNumber() const {return (int)m_LayerList.size();}
- /// Get zero-based index layer.
- FCObjLayer* GetLayer (int nIndex) const
- {
- if ((nIndex >= 0) && (nIndex < GetLayerNumber()))
- return m_LayerList[nIndex] ;
- else
- return 0 ;
- }
- /// Get current layer of canvas.
- FCObjLayer* GetCurrentLayer() const {return m_pCurrentLayer;}
- /// Get current layer's index.
- int GetCurrentLayerIndex() const {return FindLayer(m_pCurrentLayer);}
- /// Set current layer of canvas.
- void SetCurrentLayer (int nIndex)
- {
- FCObjLayer * pLayer = GetLayer(nIndex) ; assert(pLayer) ;
- if (pLayer)
- m_pCurrentLayer = pLayer ;
- }
- /**
- * Add a new layer into canvas.
- * 1) you must use <B>new</B> to create a layer. <BR>
- * 2) after the layer be added, you can't delete it any more.
- * @param : nIndex - insert position, -1 add to last
- */
- void AddLayer (FCObjLayer* pLayer, int nIndex = -1)
- {
- if (!pLayer || (pLayer->ColorBits() != 32)) // now layer must 32-bpp
- {assert(false); return;}
- // ensure the insert position is valid
- if ((nIndex < -1) || (nIndex > GetLayerNumber()))
- {
- assert(false) ;
- nIndex = -1 ;
- }
- // ensure the new layer isn't in current layer list
- std::deque<FCObjLayer*>::iterator pt = __pcl_FindDeque (m_LayerList, pLayer) ;
- if (pt != m_LayerList.end()) // already in layer list
- {assert(false); return;}
- // add into layer list
- if (nIndex == -1)
- m_LayerList.push_back (pLayer) ;
- else
- m_LayerList.insert (m_LayerList.begin() + nIndex, pLayer) ;
- m_pCurrentLayer = pLayer ;
-
- // remove from <Removed LayerList>
- pt = __pcl_FindDeque (m_RemovedLayerList, pLayer) ;
- if (pt != m_RemovedLayerList.end())
- m_RemovedLayerList.erase (pt) ;
- }
- /**
- * Remove layer from canvas (but not delete layer).
- * when only one layer in canvas, you can't remove it.
- */
- void RemoveLayer (FCObjLayer* pLayer)
- {
- if (!pLayer || (GetLayerNumber() <= 1))
- {assert(false); return;}
- // find layer in current layer list
- std::deque<FCObjLayer*>::iterator pt = __pcl_FindDeque (m_LayerList, pLayer) ;
- if (pt == m_LayerList.end()) // not in layer list
- {assert(false); return;}
- // remember position then remove from list
- int nIndex = pt - m_LayerList.begin() ;
- m_LayerList.erase (pt) ;
- // update current layer
- if (m_pCurrentLayer == pLayer)
- {
- nIndex = FMin (nIndex, GetLayerNumber()-1) ;
- SetCurrentLayer (nIndex) ;
- }
- // add to removed-layer list
- if (__pcl_FindDeque (m_RemovedLayerList, pLayer) == m_RemovedLayerList.end())
- m_RemovedLayerList.push_back (pLayer) ;
- else
- {assert(false);}
- }
- /// Get the layer's index in canvas.
- int FindLayer (const FCObjLayer* pLayer) const
- {
- for (int i=0 ; i < GetLayerNumber() ; i++)
- {
- if (pLayer == GetLayer(i))
- return i ;
- }
- return -1 ;
- }
- /// Delete layer from removed list.
- void DeleteLayerFromRemoveList (FCObjLayer* pLayer)
- {
- if (!pLayer)
- {assert(false); return;}
- std::deque<FCObjLayer*>::iterator pt = __pcl_FindDeque (m_RemovedLayerList, pLayer) ;
- if (pt != m_RemovedLayerList.end()) // in removed layer list
- {
- m_RemovedLayerList.erase (pt) ;
- delete pLayer ;
- }
- }
- //@}
- /// Execute a command, mustn't delete command after execute.
- void ExecuteEffect (FCCmdArtPrider* cmd, FCObjProgress* pProgress=0)
- {
- if (!cmd)
- {assert(false); return;}
- // It's very important to call ClearRedoList before cmd->Execute !!!
- ClearRedoList() ;
- cmd->Execute (*this, pProgress) ;
- // then we manipulate the command according undo-list
- if ((GetUndoLevel() > 0) && !cmd->IsNeedDeleteAfterExecute())
- {
- AddCommand (cmd) ;
- }
- else
- {
- delete cmd ;
- }
- }
- /**
- * @name Make image.
- */
- //@{
- /// Get canvas's block view.
- /// created imgRegion's bpp same to imgBack
- /// @param rcRegion : RECT on canvas
- void MakeViewWindow (double fScale,
- std::deque<FCObjLayer*> layerList,
- const FCObjImage& imgBack,
- RECT rcRegion,
- FCObjImage& imgRegion) const
- {
- imgRegion.Destroy() ;
- // must in canvas
- {
- RECT rcCanvas = {0,0,0,0} ;
- rcCanvas.right = GetCanvasDimension().cx ;
- rcCanvas.bottom = GetCanvasDimension().cy ;
- if (!IsRectInRect (rcCanvas, rcRegion))
- {assert(false); return;}
- }
- // create image & draw back
- {
- int nL = (int)(fScale * rcRegion.left),
- nT = (int)(fScale * rcRegion.top),
- nR = (int)(fScale * rcRegion.right),
- nB = (int)(fScale * rcRegion.bottom) ;
- if (!imgRegion.Create (nR-nL, nB-nT, imgBack.ColorBits()))
- {assert(false); return;}
- imgRegion.TileBlock (imgBack, -nL, -nT) ;
- }
- // draw layers
- for (size_t i=0 ; i < layerList.size() ; i++)
- {
- FCObjLayer * pLayer = layerList[i] ;
- if (!pLayer->IsLayerVisible())
- continue ;
- RECT rcOnLayer = rcRegion ;
- pLayer->Canvas_to_Layer (rcOnLayer) ;
- pLayer->BoundRect (rcOnLayer) ;
- if (IsRectEmpty(&rcOnLayer))
- continue ;
- // RECT of layer on imgRegion
- RECT rcOnImg = rcOnLayer ;
- pLayer->Layer_to_Canvas (rcOnImg) ;
- OffsetRect (&rcOnImg, -rcRegion.left, -rcRegion.top) ;
- rcOnImg.left = (int)(fScale * rcOnImg.left) ;
- rcOnImg.top = (int)(fScale * rcOnImg.top) ;
- rcOnImg.right = (int)(fScale * rcOnImg.right) ;
- rcOnImg.bottom = (int)(fScale * rcOnImg.bottom) ;
- if (!IsRectEmpty(&rcOnImg))
- {
- imgRegion.AlphaBlend (*pLayer, rcOnImg, rcOnLayer, pLayer->GetLayerTransparent()) ;
- }
- }
- }
- /// imgThumb's bpp same to imgBack.
- void MakeThumbnail (double fScale,
- FCObjLayer& rLayer,
- const FCObjImage& imgBack,
- FCObjImage& imgThumb) const
- {
- std::auto_ptr<FCMemoLayer> bakMemo (rLayer.CreateMemoObj()),
- newMemo (rLayer.CreateMemoObj()) ;
- newMemo->m_bLayerVisible = true ;
- newMemo->m_nAlphaPercent = 100 ;
- rLayer.SetMemoObj (newMemo.get()) ;
- RECT rcRegion = {0, 0, GetCanvasDimension().cx, GetCanvasDimension().cy} ;
- std::deque<FCObjLayer*> layerList ;
- layerList.push_back (&rLayer) ;
- MakeViewWindow (fScale, layerList, imgBack, rcRegion, imgThumb) ;
- rLayer.SetMemoObj (bakMemo.get()) ;
- }
- /// Make canvas image (imgCanvas's bpp is 32).
- void GetCanvasImage (FCObjImage& imgCanvas) const
- {
- if (!imgCanvas.Create(m_sizeCanvas.cx, m_sizeCanvas.cy, 32))
- {assert(false); return;}
- FCPixelFillColor aCmd (FCColor::crWhite(), 0) ;
- imgCanvas.SinglePixelProcessProc (aCmd) ; // alpha init 0
- for (int i=0 ; i < GetLayerNumber() ; i++)
- {
- FCObjLayer * pLayer = GetLayer(i) ;
- if (pLayer->IsLayerVisible())
- imgCanvas.CombineImage (*pLayer,
- pLayer->GetGraphObjPos().x,
- pLayer->GetGraphObjPos().y,
- pLayer->GetLayerTransparent()) ;
- }
- }
- /// Make layer's region.
- void MakeRegion (const FCObjLayer& rLayer, FCObjImage& imgRegion) const
- {
- imgRegion.Destroy() ;
- if (!HasSelected())
- {
- imgRegion = static_cast<const FCObjImage&>(rLayer) ;
- }
- else
- {
- RECT rc = {0, 0, m_CurrSel.Width(), m_CurrSel.Height()} ;
- m_CurrSel.Layer_to_Canvas (rc) ;
- rLayer.Canvas_to_Layer (rc) ;
- rLayer.BoundRect (rc) ;
- if (IsRectEmpty (&rc))
- return ;
- // rect on layer & selection
- RECT rcOnLayer = rc,
- rcOnSel = rc ;
- rLayer.Layer_to_Canvas (rcOnSel) ;
- m_CurrSel.Canvas_to_Layer (rcOnSel) ;
- // out of selection
- rLayer.GetSubBlock (&imgRegion, rcOnLayer) ;
- for (int y=0 ; y < imgRegion.Height() ; y++)
- for (int x=0 ; x < imgRegion.Width() ; x++)
- if (*m_CurrSel.GetBits(x+rcOnSel.left, y+rcOnSel.top) == 0)
- {
- *(RGBQUAD*)imgRegion.GetBits(x,y) = PCL_RGBA(0xFF,0xFF,0xFF,0) ;
- }
- }
- }
- //@}
- /**
- * @name Access .oxo file.
- */
- //@{
- /// Read .oxo file.
- bool Load_oXo (const char* szFileName)
- {
- char * _pCurr = 0 ;
- int nFileSize = 0 ;
- // load file into memory
- FCOXOHelper::LoadFileToBuffer (szFileName, _pCurr, nFileSize) ;
- if (!_pCurr)
- {assert(false); return false;}
- BYTE * pCurr = (BYTE*)_pCurr ;
- PCL_array<BYTE> _aAutoDelete (pCurr) ;
- // read file's header TAG : "oXo " , version 1
- if ((*(DWORD*)pCurr != 0x206F586F) || (*(DWORD*)(pCurr + 4) != 1))
- return false ;
- pCurr += 8 ;
- // read block
- while (*(DWORD*)pCurr != OXO_BLOCK_END)
- {
- BYTE * pBak = pCurr ;
- DWORD nBlockSize = *(DWORD*)(pCurr + 4) ; // block size, exclude TAG & SIZE (8-bytes)
- if (*(DWORD*)pCurr == OXO_BLOCK_CANVAS) // canvas
- {
- pCurr += 8 ;
- m_sizeCanvas = *(SIZE*)pCurr ;
- }
- else if (*(DWORD*)pCurr == OXO_BLOCK_CANVAS_DPI) // canvas's DPI
- {
- pCurr += 8 ;
- m_nResX = *(DWORD*)pCurr ; pCurr += 4 ;
- m_nResY = *(DWORD*)pCurr ; pCurr += 4 ;
- }
- else if (*(DWORD*)pCurr == OXO_BLOCK_LAYER) // layer
- {
- pCurr += 8 ;
- FCObjLayer * pLayer = new FCObjLayer ;
- pLayer->Serialize (false, pCurr) ;
- this->AddLayer(pLayer) ;
- }
- else if (*(DWORD*)pCurr == OXO_BLOCK_TEXTLAYER) // text layer
- {
- pCurr += 8 ;
- // has discarded after PhoXo V1.6
- // first skip text info
- pCurr += strlen((char*)pCurr) + 1 + 84 ;
- FCObjLayer * pLayer = new FCObjLayer ;
- pLayer->Serialize (false, pCurr) ;
- this->AddLayer(pLayer) ;
- }
- else if (*(DWORD*)pCurr == OXO_BLOCK_LAYER_NAME) // layer's name
- {
- pCurr += 4 ;
- DWORD n = *(DWORD*)pCurr ; pCurr += 4 ;
- // name string
- PCL_array<char> p(n+8) ;
- memset (p.get(), 0, n+8) ;
- memcpy (p.get(), pCurr, n) ;
- if (GetLayerNumber())
- {
- GetLayer(GetLayerNumber()-1)->LayerName() = p.get() ;
- }
- }
- else
- {
- // unknow block, do nothing
- }
- pCurr = pBak + nBlockSize + 8 ;
- }
- return true ;
- }
- /// Write .oxo file.
- bool Save_oXo (const char* szFileName) const
- {
- if (GetLayerNumber() <= 0)
- {assert(false); return false;}
- // estimate size to malloc memory
- int nMaxSize = 1024 * 32, i ;
- for (i=0 ; i < GetLayerNumber() ; i++)
- {
- nMaxSize += sizeof(BITMAPINFOHEADER) + 12 ;
- nMaxSize = nMaxSize + GetLayer(i)->GetPitch() * GetLayer(i)->Height() ;
- }
- PCL_array<BYTE> pStart (nMaxSize) ;
- BYTE * pCurr = pStart.get() ;
- // write signature
- *(DWORD*)pCurr = 0x206F586F ; pCurr += 4 ; // "oXo "
- // oXo file's version
- *(DWORD*)pCurr = 0x01 ; pCurr += 4 ;
- // store canvas basic info
- *(DWORD*)pCurr = OXO_BLOCK_CANVAS ; pCurr += 4 ;
- *(DWORD*)pCurr = sizeof(SIZE) ; pCurr += 4 ;
- *(SIZE*)pCurr = m_sizeCanvas ; pCurr += sizeof(SIZE) ;
- // store canvas DPI
- *(DWORD*)pCurr = OXO_BLOCK_CANVAS_DPI ; pCurr += 4 ;
- *(DWORD*)pCurr = 8 ; pCurr += 4 ;
- *(DWORD*)pCurr = m_nResX ; pCurr += 4 ;
- *(DWORD*)pCurr = m_nResY ; pCurr += 4 ;
- // store layer
- for (i=0 ; i < GetLayerNumber() ; i++)
- {
- *(DWORD*)pCurr = OXO_BLOCK_LAYER ; pCurr += 4 ;
- *(DWORD*)pCurr = 0 ; pCurr += 4 ; // write size later
- int nWrite = GetLayer(i)->Serialize (true, pCurr) ;
- *(DWORD*)(pCurr - 4) = nWrite ; pCurr += nWrite ;
- // save layer's name
- std::string s = GetLayer(i)->LayerName() ;
- if (!s.empty())
- {
- *(DWORD*)pCurr = OXO_BLOCK_LAYER_NAME ; pCurr += 4 ;
- *(DWORD*)pCurr = s.length() ; pCurr += 4 ;
- memcpy (pCurr, s.c_str(), s.length()) ; pCurr += s.length() ;
- }
- }
- // terminator
- *(DWORD*)pCurr = OXO_BLOCK_END ; pCurr += 4 ;
- *(DWORD*)pCurr = 0 ; ; pCurr += 4 ;
- // write file
- return FCOXOHelper::SaveBufferToFile (szFileName, pStart.get(), pCurr - pStart.get()) ;
- }
- //@}
- private:
- virtual void PCL_Implement_Undo (FCCmdArtPrider* pCmd) {pCmd->Undo (*this);}
- virtual void PCL_Implement_Redo (FCCmdArtPrider* pCmd) {pCmd->Redo (*this);}
- enum
- {
- OXO_BLOCK_UNKNOW = 0, // unknow
- OXO_BLOCK_CANVAS = 1, // canvas
- OXO_BLOCK_LAYER = 2, // layer
- OXO_BLOCK_TEXTLAYER = 3, // text layer -- has discarded after PhoXo V1.6
- OXO_BLOCK_CANVAS_DPI = 4, // canvas DPI
- OXO_BLOCK_LAYER_NAME = 5, // name of layer, this block follow layer block
- OXO_BLOCK_END = 0xFF, // end
- };
- private:
- SIZE m_sizeCanvas ;
- FCObjLayer * m_pCurrentLayer ;
- std::deque<FCObjLayer*> m_LayerList ;
- std::deque<FCObjLayer*> m_RemovedLayerList ; // 被移除的layer,和m_LayerList一起释放
- int m_nResX, m_nResY ; // image's DPI resolution (Dot Per Inch)
- FCObjSelect m_CurrSel ; // 当前选取的区域对象
- static std::deque<FCObjLayer*>::iterator __pcl_FindDeque (std::deque<FCObjLayer*>& listLayer, const FCObjLayer* pLayer)
- {
- return std::find (listLayer.begin(), listLayer.end(), pLayer) ;
- }
- friend class FCCmdLayerExchange ;
- friend class FCCmdSelectionSetBase ;
- };
- //=============================================================================
- // inline implement
- //=============================================================================
- #endif
|