PixelProcessorBase.h 136 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030
  1. /*
  2. * Copyright (C) =USTC= Fu Li
  3. *
  4. * Author : Fu Li
  5. * Create : 2005-7-29
  6. * Home : http://www.crazy-bit.com/
  7. * Mail : crazybit@263.net
  8. * History :
  9. */
  10. #ifndef __FOO_PIXEL_PROCESSOR_BASE__2005_07_29__H__
  11. #define __FOO_PIXEL_PROCESSOR_BASE__2005_07_29__H__
  12. #include "../FHistogram.h"
  13. //class FCInterface_PixelProcess ;
  14. class FCSinglePixelProcessBase ;
  15. class FCPixelConvertTo16Bit ; // 1, 4, 8, 24, 32 ==> 16
  16. class FCPixelConvertTo8BitGray ; // 1, 4, 8, 16, 24, 32 ==> 8bit gray
  17. class FCPixelGrayscale ; // gray scale (>=24 bit)
  18. class FCPixelFillColor ; // fill color (>=24 bit)
  19. class FCPixelFillPattern ; // fill pattern (32 bit)
  20. class FCPixelCombineColor ; // combine color (32 bit)
  21. class FCPixelHueSaturation ; // hue saturation (>=24 bit)]
  22. class FCPixelMirror ; // mirror (>=8 bit)
  23. class FCPixelFlip ; // flip (>=8 bit)
  24. class FCPixelShift ; // shift (>=24 bit)
  25. class FCPixelAutoContrast ; // auto contrast (>=24 bit)
  26. class FCPixelAutoColorEnhance ; // auto color enhance (>=24 bit)
  27. class FCPixelEmboss ; // emboss (>=24 bit)
  28. class FCPixelIllusion ; // illusion (>=24 bit)
  29. class FCPixelBlinds ; // blinds (>=24 bit)
  30. class FCPixelMosaic ; // mosaic (32 bit)
  31. class FCPixelFill3DSolidFrame ; // fill 3D solid frame (>=24 bit)
  32. class FCPixelAdjustRGB ; // adjust RGB (>=24 bit)
  33. class FCPixelColorLevel ; // color level (>=24 bit)
  34. class FCPixelThreshold ; // threshold (>=24 bit)
  35. class FCPixelRotate90 ; // clockwise rotate 90' (>=8 bit)
  36. class FCPixelRotate270 ; // clockwise rotate 270' (>=8 bit)
  37. class FCPixelDeinterlace ; // de-interlace (32 bit)
  38. class FCPixelHalftoneM3 ; // halftone (>=24 bit)
  39. class FCPixelOilPaint ; // oil paint (>=24 bit)
  40. class FCPixelColorTone ; // color tone (>=24 bit)
  41. class FCPixelAddRandomNoise ; // add random noise (>=24 bit)
  42. class FCPixelSplash ; // splash (>=24 bit)
  43. class FCPixelVideo ; // video (>=24 bit)
  44. class FCPixelColorBalance ; // color balance (>=24 bit)
  45. class FCPixelFillGrid ; // fill grid (>=24 bit)
  46. class FCPixel3DGrid ; // add 3D grid (>=24 bit)
  47. class FCPixelMedianFilter ; // Median filter (>=24 bit)
  48. class FCPixelSpliteChannel_RGB ; // splite RGB channel (>=24 bit)
  49. class FCPixelCombineChannel_RGB ; // combine RGB channel (>=24 bit)
  50. class FCPixelConvolute ; // image convolute (>= 24 bit)
  51. class FCPixelGaussianBlur3x3 ; // Standard 3x3 gaussian blur (>=24 bit)
  52. class FCPixelGaussianBlur5x5 ; // Standard 5x5 gaussian blur (>=24 bit)
  53. class FCPixelDetectEdges ; // Detect edges (>=24 bit)
  54. class FCPixelSharp ; // Sharp (laplacian template) (>=24 bit)
  55. class FCPixelGradientBase ; // base class of gradient fill (>=24 bit)
  56. class FCPixelGradientLine ; // gradient fill linear (>=24 bit)
  57. class FCPixelGradientBiLine ; // gradient fill bilinear (>=24 bit)
  58. class FCPixelGradientConicalSym ; // gradient fill symmetric conical (>=24 bit)
  59. class FCPixelGradientConicalASym ; // gradient fill Anti-symmetric conical (>=24 bit)
  60. class FCPixelGradientRect ; // gradient fill rect (>=24 bit)
  61. class FCPixelGradientRadial ; // gradient fill radial (>=24 bit)
  62. class FCPixelBilinearDistord ; // bilinear distord (>=24 bit)
  63. class FCPixelCylinder ; // cylinder (>=24 bit)
  64. class FCPixelWave ; // wave (>=24 bit)
  65. class FCPixelWhirlPinch ; // whirl & pinch (>=24 bit)
  66. class FCPixelFractalTrace ; // Fractal trace (>=24 bit)
  67. class FCPixelLens ; // lens (>=24 bit)
  68. class FCPixelSkew ; // skew transform (>=24 bit)
  69. class FCPixelPerspective ; // perspective transform (>=24 bit)
  70. class FCPixelRotate ; // rotate (>=24 bit)
  71. class FCPixelRibbon ; // ribbon (>=24 bit)
  72. class FCPixelRipple ; // ripple (>=24 bit)
  73. class FCPixelSmallTile ; // tile (>=24 bit)
  74. class FCPixelLUTRoutine ; // LUT(look up table) routine (>=24 bit)
  75. class FCPixelBrightness ; // adjust brightness (>=24 bit)
  76. class FCPixelContrast ; // adjust contrast (>=24 bit)
  77. class FCPixelGamma ; // adjust gamma (>=24 bit)
  78. class FCPixelInvert ; // negate (>=24 bit)
  79. class FCPixelSolarize ; // Solarize (>=24 bit)
  80. class FCPixelPosterize ; // posterize (>=24 bit)
  81. class FCPixelColorsCount ; // count image's number of color (>=24 bit)
  82. class FCPixelGetKeyColor ; // Find a color unused in image (>=24 bit)
  83. class FCPixelWholeImageBase ; // process whole image.
  84. class FCPixelExportAscII ; // save a ASCII text file (>=24 bit)
  85. class FCPixelConvertQuantize ; // quantize (Need FREEIMAGE)
  86. class FCPixelGlasstile ; // glasstile (>=24 bit)
  87. class FCPixelBlur_Box ; // box smooth (>=24 bit)
  88. class FCPixelBlur_Zoom ; // blur zoom (>=24 bit)
  89. class FCPixelBlur_Radial ; // blur radial (>=24 bit)
  90. class FCPixelBlur_Motion ; // blur motion (>=24 bit)
  91. class FCPixelBlur_Gauss_IIR ; // blur IIR gauss (>=24 bit)
  92. class FCPixelInnerBevel ; // add inner bevel frame (>=24 bit)
  93. class FCPixelSmoothEdge ; // smooth edge (32 bit)
  94. class FCPixelAddShadow ; // add shadow (32 bit)
  95. //=============================================================================
  96. /**
  97. * Base class of processor.
  98. */
  99. class FCSinglePixelProcessBase : public FCInterface_PixelProcess
  100. {
  101. public:
  102. FCSinglePixelProcessBase() : m_pImgOld(0) {}
  103. virtual ~FCSinglePixelProcessBase() {if(m_pImgOld) delete m_pImgOld;}
  104. /// whether the image can be disposed by this processor.
  105. /// default test image's bpp >= 24
  106. virtual bool ValidateColorBits (const FCObjImage* pImg)
  107. {
  108. return pImg->IsValidImage() && (pImg->ColorBits() >= 24) ;
  109. }
  110. protected:
  111. void SetBackupImage (const FCObjImage* pImg)
  112. {
  113. if (pImg)
  114. {
  115. if (m_pImgOld)
  116. delete m_pImgOld ;
  117. m_pImgOld = new FCObjImage(*pImg) ;
  118. }
  119. }
  120. FCObjImage* GetBackupImage() const {return m_pImgOld;}
  121. private:
  122. FCObjImage * m_pImgOld ; // backup image
  123. };
  124. //=============================================================================
  125. /**
  126. * 1, 4, 8, 24, 32 ==> 16.
  127. @verbatim
  128. example:
  129. FCPixelConvertTo16Bit aCmd ;
  130. img.SinglePixelProcessProc (aCmd) ;
  131. @endverbatim
  132. */
  133. class FCPixelConvertTo16Bit : public FCSinglePixelProcessBase
  134. {
  135. virtual bool ValidateColorBits (const FCObjImage* pImg) {return pImg->IsValidImage() && (pImg->ColorBits() != 16) ;}
  136. virtual void OnEnterProcess (FCObjImage* pImg)
  137. {
  138. SetBackupImage(pImg) ;
  139. // make it easier, now we only need 24(32) ==> 16
  140. if (pImg->ColorBits() <= 8)
  141. GetBackupImage()->ConvertTo24Bit() ;
  142. pImg->Create (pImg->Width(), pImg->Height(), 16) ;
  143. }
  144. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  145. {
  146. *(WORD*)pPixel = Combine16Bit_555 (GetBackupImage()->GetBits(x,y)) ; // 24,32 ==> 16
  147. }
  148. static WORD Combine16Bit_555 (const void* pRGB)
  149. {
  150. const WORD wR = ((PCL_R(pRGB) >> 3) << 10),
  151. wG = ((PCL_G(pRGB) >> 3) << 5),
  152. wB = (PCL_B(pRGB) >> 3) ;
  153. return (wR | wG | wB) ;
  154. }
  155. };
  156. //=============================================================================
  157. /**
  158. * 1, 4, 8, 16, 24, 32 ==> 8bit gray.
  159. @verbatim
  160. example:
  161. FCPixelConvertTo8BitGray aCmd ;
  162. img.SinglePixelProcessProc (aCmd) ;
  163. @endverbatim
  164. */
  165. class FCPixelConvertTo8BitGray : public FCSinglePixelProcessBase
  166. {
  167. virtual bool ValidateColorBits (const FCObjImage* pImg) {return pImg->IsValidImage();}
  168. virtual void OnEnterProcess (FCObjImage* pImg)
  169. {
  170. SetBackupImage(pImg) ;
  171. // make it easier, now we only need 24(32) ==> 8bit gray
  172. if (pImg->ColorBits() <= 16)
  173. GetBackupImage()->ConvertTo24Bit() ;
  174. pImg->Create (pImg->Width(), pImg->Height(), 8) ; // default to set a gray palette
  175. }
  176. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  177. {
  178. *pPixel = FCColor::GetGrayscale (GetBackupImage()->GetBits(x,y)) ;
  179. }
  180. };
  181. //=============================================================================
  182. /**
  183. * Gray scale image (>=24 bit).
  184. * all channel are same after process.
  185. @verbatim
  186. example:
  187. FCPixelGrayscale aCmd ;
  188. img.SinglePixelProcessProc (aCmd) ;
  189. @endverbatim
  190. */
  191. class FCPixelGrayscale : public FCSinglePixelProcessBase
  192. {
  193. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  194. {
  195. PCL_R(pPixel) = PCL_G(pPixel) = PCL_B(pPixel) = FCColor::GetGrayscale(pPixel) ;
  196. }
  197. };
  198. //=============================================================================
  199. /**
  200. * Fill color (>=24 bit).
  201. @verbatim
  202. example:
  203. const RGBQUAD cr = PCL_RGBA(0,0,255) ;
  204. FCPixelFillColor aCmd (cr, 192) ;
  205. img.SinglePixelProcessProc (aCmd) ;
  206. @endverbatim
  207. */
  208. class FCPixelFillColor : public FCSinglePixelProcessBase
  209. {
  210. public:
  211. /// Constructor.
  212. /// @param nAlpha == -1, not fill alpha
  213. FCPixelFillColor (RGBQUAD crFill, int nAlpha=-1) : m_crFill(crFill), m_nAlpha(nAlpha), m_bIsFillAlpha(false) {}
  214. private:
  215. virtual bool ValidateColorBits (const FCObjImage* pImg)
  216. {
  217. if (pImg->IsValidImage() && (pImg->ColorBits() >= 24))
  218. {
  219. m_bIsFillAlpha = ((m_nAlpha != -1) && (pImg->ColorBits() == 32)) ;
  220. PCL_A(&m_crFill) = m_bIsFillAlpha ? FClamp0255(m_nAlpha) : 0 ;
  221. return true ;
  222. }
  223. return false ;
  224. }
  225. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  226. {
  227. FCColor::CopyPixel (pPixel, &m_crFill, m_bIsFillAlpha ? 4 : 3) ;
  228. }
  229. RGBQUAD m_crFill ;
  230. int m_nAlpha ;
  231. bool m_bIsFillAlpha ;
  232. };
  233. //=============================================================================
  234. /**
  235. * Fill pattern image (32 bit).
  236. @verbatim
  237. example:
  238. FCObjImage * pMask = new FCObjImage ("c:\\test.jpg") ;
  239. FCPixelFillPattern aCmd (pMask, 192, false) ;
  240. img.SinglePixelProcessProc (aCmd) ;
  241. @endverbatim
  242. */
  243. class FCPixelFillPattern : public FCSinglePixelProcessBase
  244. {
  245. public:
  246. /// Constructor.
  247. FCPixelFillPattern (FCObjImage* pPattern, int nAlpha, bool bOnlyTexture) : m_pPattern(pPattern), m_nAlpha(FClamp0255(nAlpha)), m_bOnlyTexture(bOnlyTexture)
  248. {
  249. if (pPattern)
  250. pPattern->ConvertTo24Bit() ;
  251. }
  252. private:
  253. virtual bool ValidateColorBits (const FCObjImage* pImg)
  254. {
  255. return pImg->IsValidImage() && (pImg->ColorBits() == 32) && m_pPattern.get() && (m_pPattern->ColorBits() >= 24) ;
  256. }
  257. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  258. {
  259. BYTE * pPat = m_pPattern->GetBits (x % m_pPattern->Width(), y % m_pPattern->Height()) ;
  260. if (m_bOnlyTexture)
  261. {
  262. // calculate texture
  263. int n = (PCL_B(pPat)+PCL_G(pPat)+PCL_R(pPat) - 384) * m_nAlpha / 765 ;
  264. PCL_B(pPixel) = FClamp0255 (PCL_B(pPixel) - n) ;
  265. PCL_G(pPixel) = FClamp0255 (PCL_G(pPixel) - n) ;
  266. PCL_R(pPixel) = FClamp0255 (PCL_R(pPixel) - n) ;
  267. }
  268. else
  269. {
  270. FCColor::CombineAlphaPixel ((RGBQUAD*)pPixel, *(RGBQUAD*)pPixel, pPat, m_nAlpha) ;
  271. }
  272. }
  273. std::auto_ptr<FCObjImage> m_pPattern ; // 24bit or 32bit
  274. int m_nAlpha ;
  275. bool m_bOnlyTexture ;
  276. };
  277. //=============================================================================
  278. /**
  279. * Combine color (32 bit).
  280. @verbatim
  281. example:
  282. const RGBQUAD cr = PCL_RGBA(0,0,255,128) ;
  283. FCPixelCombineColor aCmd (cr) ;
  284. img.SinglePixelProcessProc (aCmd) ;
  285. @endverbatim
  286. */
  287. class FCPixelCombineColor : public FCSinglePixelProcessBase
  288. {
  289. public:
  290. /// Constructor.
  291. FCPixelCombineColor (RGBQUAD crFill) : m_crFill(crFill) {}
  292. private:
  293. virtual bool ValidateColorBits (const FCObjImage* pImg)
  294. {
  295. return pImg->IsValidImage() && (pImg->ColorBits() == 32) ;
  296. }
  297. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  298. {
  299. RGBQUAD * p = (RGBQUAD*)pPixel ;
  300. FCColor::CombineAlphaPixel (p, *p, &m_crFill, PCL_A(&m_crFill)) ;
  301. }
  302. RGBQUAD m_crFill ;
  303. };
  304. //=============================================================================
  305. /**
  306. * Adjust image's hue & saturation (>=24 bit).
  307. @verbatim
  308. example:
  309. FCPixelHueSaturation aCmd (100, 150) ; // not change hue, add 50% saturation
  310. img.SinglePixelProcessProc (aCmd) ;
  311. @endverbatim
  312. */
  313. class FCPixelHueSaturation : public FCSinglePixelProcessBase
  314. {
  315. public:
  316. /// Constructor (param's unit is percentage).
  317. /// nPercentHue range is (0,200)
  318. FCPixelHueSaturation (int nPercentHue, int nPercentSat) : m_nPercentHue(FMax(0,nPercentHue)), m_nPercentSat(FMax(0,nPercentSat)) {}
  319. protected:
  320. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  321. {
  322. double H, L, S ;
  323. FCColor::RGBtoHLS (pPixel, &H, &L, &S) ;
  324. if (m_nPercentHue != 100)
  325. {
  326. if (m_nPercentHue > 100)
  327. {
  328. H = H + (1.0 - H) * (m_nPercentHue-100) / 100 ;
  329. }
  330. else
  331. {
  332. H = H - H * (100-m_nPercentHue) / 100 ;
  333. }
  334. }
  335. if (m_nPercentSat != 100)
  336. {
  337. S = S * m_nPercentSat / 100 ;
  338. }
  339. RGBQUAD cr = FCColor::HLStoRGB (H, L, S) ;
  340. FCColor::CopyPixel (pPixel, &cr, 3) ;
  341. }
  342. int m_nPercentHue, m_nPercentSat ;
  343. };
  344. //=============================================================================
  345. /**
  346. * Left-Right mirror image (>=8 bit).
  347. @verbatim
  348. example:
  349. FCPixelMirror aCmd ;
  350. img.SinglePixelProcessProc (aCmd) ;
  351. @endverbatim
  352. */
  353. class FCPixelMirror : public FCSinglePixelProcessBase
  354. {
  355. virtual bool ValidateColorBits (const FCObjImage* pImg)
  356. {
  357. return pImg->IsValidImage() && (pImg->ColorBits() >= 8) ;
  358. }
  359. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  360. {
  361. if (x < pImg->Width()/2)
  362. {
  363. BYTE * pRight = pImg->GetBits (pImg->Width()-1-x, y) ;
  364. for (int i=0 ; i < pImg->ColorBits()/8 ; i++)
  365. FSwap (pPixel[i], pRight[i]) ; // bytes of per pixel
  366. }
  367. }
  368. };
  369. //=============================================================================
  370. /**
  371. * Top-Bottom flip image (>=8 bit).
  372. @verbatim
  373. example:
  374. FCPixelFlip aCmd ;
  375. img.SinglePixelProcessProc (aCmd) ;
  376. @endverbatim
  377. */
  378. class FCPixelFlip : public FCSinglePixelProcessBase
  379. {
  380. virtual bool ValidateColorBits (const FCObjImage* pImg)
  381. {
  382. return pImg->IsValidImage() && (pImg->ColorBits() >= 8) ;
  383. }
  384. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  385. {
  386. if (y < pImg->Height()/2)
  387. {
  388. BYTE * pBottom = pImg->GetBits (x, pImg->Height()-1-y) ;
  389. for (int i=0 ; i < pImg->ColorBits()/8 ; i++)
  390. FSwap (pPixel[i], pBottom[i]) ; // bytes of per pixel
  391. }
  392. }
  393. };
  394. //=============================================================================
  395. /**
  396. * Shift (>=24 bit).
  397. @verbatim
  398. example:
  399. FCPixelShift aCmd(5) ;
  400. img.SinglePixelProcessProc (aCmd) ;
  401. @endverbatim
  402. */
  403. class FCPixelShift : public FCSinglePixelProcessBase
  404. {
  405. public:
  406. FCPixelShift (int nAmount) : m_nAmount (FMax(0,nAmount)) {srand((unsigned int)time(0));}
  407. private:
  408. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  409. {
  410. const int nSpan = pImg->ColorBits() / 8 ;
  411. int nShift = rand() % (m_nAmount+1) ;
  412. // first pixel every line
  413. if (x || !m_nAmount || !nShift)
  414. return ;
  415. BYTE crLeft[4], crRight[4] ; // L/R edge pixel color
  416. FCColor::CopyPixel (crLeft, pImg->GetBits(y), nSpan) ;
  417. FCColor::CopyPixel (crRight, pImg->GetBits(pImg->Width()-1,y), nSpan) ;
  418. if (rand() % 2)
  419. {
  420. // shift right
  421. if (pImg->Width() > nShift)
  422. memmove (pImg->GetBits(nShift,y), pPixel, (pImg->Width()-nShift)*nSpan) ;
  423. else
  424. nShift = pImg->Width() ;
  425. for (int i=0 ; i < nShift ; i++, pPixel+=nSpan)
  426. FCColor::CopyPixel (pPixel, crLeft, nSpan) ;
  427. }
  428. else
  429. {
  430. // shift left
  431. if (pImg->Width() > nShift)
  432. memmove (pPixel, pImg->GetBits(nShift,y), (pImg->Width()-nShift)*nSpan) ;
  433. else
  434. nShift = pImg->Width() ;
  435. pPixel = pImg->GetBits(pImg->Width()-1, y) ;
  436. for (int i=0 ; i < nShift ; i++, pPixel-=nSpan)
  437. FCColor::CopyPixel (pPixel, crRight, nSpan) ;
  438. }
  439. }
  440. int m_nAmount ; // max shift pixel
  441. };
  442. //=============================================================================
  443. /**
  444. * Auto contrast (>=24 bit).
  445. @verbatim
  446. example:
  447. FCPixelAutoContrast aCmd ;
  448. img.SinglePixelProcessProc (aCmd) ;
  449. @endverbatim
  450. */
  451. class FCPixelAutoContrast : public FCSinglePixelProcessBase
  452. {
  453. virtual void OnEnterProcess (FCObjImage* pImg)
  454. {
  455. BYTE byCmin[3] = {255, 255, 255},
  456. byCmax[3] = {0, 0, 0} ;
  457. // Get minimum and maximum values for each channel
  458. for (int y=0 ; y < pImg->Height() ; y++)
  459. for (int x=0 ; x < pImg->Width() ; x++)
  460. {
  461. BYTE * pPixel = pImg->GetBits(x,y) ;
  462. for (int b=0 ; b < 3 ; b++)
  463. {
  464. if (pPixel[b] < byCmin[b]) byCmin[b] = pPixel[b] ;
  465. if (pPixel[b] > byCmax[b]) byCmax[b] = pPixel[b] ;
  466. }
  467. }
  468. // Calculate LUTs with stretched contrast
  469. for (int b=0 ; b < 3 ; b++)
  470. {
  471. const int nRange = byCmax[b] - byCmin[b] ;
  472. if (nRange)
  473. {
  474. for (int x=byCmin[b] ; x <= byCmax[b] ; x++)
  475. m_byLut[x][b] = 255 * (x - byCmin[b]) / nRange ;
  476. }
  477. else
  478. m_byLut[byCmin[b]][b] = byCmin[b] ;
  479. }
  480. }
  481. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  482. {
  483. for (int b=0 ; b < 3 ; b++)
  484. pPixel[b] = m_byLut[pPixel[b]][b] ;
  485. }
  486. BYTE m_byLut[256][3] ;
  487. };
  488. //=============================================================================
  489. /**
  490. * Auto color enhance (>=24 bit).
  491. @verbatim
  492. example:
  493. FCPixelAutoColorEnhance aCmd ;
  494. img.SinglePixelProcessProc (aCmd) ;
  495. @endverbatim
  496. */
  497. class FCPixelAutoColorEnhance : public FCSinglePixelProcessBase
  498. {
  499. virtual void OnEnterProcess (FCObjImage* pImg)
  500. {
  501. m_vhi = 0.0 ; m_vlo = 1.0 ;
  502. // Get minimum and maximum values
  503. for (int y=0 ; y < pImg->Height() ; y++)
  504. for (int x=0 ; x < pImg->Width() ; x++)
  505. {
  506. BYTE * pPixel = pImg->GetBits(x,y) ;
  507. int c = 255 - PCL_B(pPixel),
  508. m = 255 - PCL_G(pPixel),
  509. y = 255 - PCL_R(pPixel),
  510. k = c ;
  511. if (m < k) k = m ;
  512. if (y < k) k = y ;
  513. BYTE byMap[4] = { c-k, m-k, y-k } ;
  514. double h, z, v ;
  515. FCColor::RGBtoHSV (byMap, &h, &z, &v) ;
  516. if (v > m_vhi) m_vhi = v ;
  517. if (v < m_vlo) m_vlo = v ;
  518. }
  519. }
  520. virtual void ProcessPixel (FCObjImage* pImg, int nx, int ny, BYTE* pPixel)
  521. {
  522. int c = 255 - PCL_B(pPixel),
  523. m = 255 - PCL_G(pPixel),
  524. y = 255 - PCL_R(pPixel),
  525. k = c ;
  526. if (m < k) k = m ;
  527. if (y < k) k = y ;
  528. BYTE byMap[4] = { c-k, m-k, y-k } ;
  529. double h, z, v ;
  530. FCColor::RGBtoHSV (byMap, &h, &z, &v) ;
  531. if (m_vhi != m_vlo)
  532. v = (v-m_vlo) / (m_vhi-m_vlo) ;
  533. *(RGBQUAD*)byMap = FCColor::HSVtoRGB (h, z, v) ;
  534. c = byMap[0] ; m = byMap[1] ; y = byMap[2] ;
  535. c += k ; if (c > 255) c = 255 ;
  536. m += k ; if (m > 255) m = 255 ;
  537. y += k ; if (y > 255) y = 255 ;
  538. PCL_B(pPixel) = 255 - c ;
  539. PCL_G(pPixel) = 255 - m ;
  540. PCL_R(pPixel) = 255 - y ;
  541. }
  542. double m_vhi, m_vlo ;
  543. };
  544. //=============================================================================
  545. /**
  546. * Emboss effect (>=24 bit).
  547. @verbatim
  548. example:
  549. FCPixelEmboss aCmd(5) ;
  550. img.SinglePixelProcessProc (aCmd) ;
  551. @endverbatim
  552. */
  553. class FCPixelEmboss : public FCSinglePixelProcessBase
  554. {
  555. public:
  556. /// Constructor.
  557. FCPixelEmboss (int nLevel) : m_nLevel(nLevel) {}
  558. private:
  559. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  560. {
  561. int nGray ;
  562. if (x == pImg->Width()-1)
  563. nGray = 128 ; // the last right col pixel
  564. else
  565. {
  566. BYTE * pNext = pImg->GetBits (x+1, y) ;
  567. int nSum = PCL_R(pPixel) + PCL_G(pPixel) + PCL_B(pPixel),
  568. nSumNx = PCL_R(pNext) + PCL_G(pNext) + PCL_B(pNext) ;
  569. nGray = FClamp0255 (m_nLevel * (nSum - nSumNx) / 3 + 128) ;
  570. }
  571. PCL_R(pPixel) = PCL_G(pPixel) = PCL_B(pPixel) = nGray ;
  572. }
  573. int m_nLevel ;
  574. };
  575. //=============================================================================
  576. /**
  577. * Illusion effect (>=24 bit).
  578. @verbatim
  579. example:
  580. FCPixelIllusion aCmd(3) ;
  581. img.SinglePixelProcessProc (aCmd) ;
  582. @endverbatim
  583. */
  584. class FCPixelIllusion : public FCSinglePixelProcessBase
  585. {
  586. public:
  587. FCPixelIllusion (int nAmount) : m_nAmount(nAmount) {}
  588. private:
  589. virtual void OnEnterProcess (FCObjImage* pImg)
  590. {
  591. SetBackupImage (pImg) ;
  592. m_fScale = FHypot ((double)pImg->Width(),(double)pImg->Height()) / 2.0 ;
  593. m_fOffset = (int)(m_fScale / 2.0) ;
  594. }
  595. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  596. {
  597. const double fXCen = pImg->Width() / 2.0,
  598. fYCen = pImg->Height() / 2.0,
  599. cx = (x - fXCen) / m_fScale,
  600. cy = (y - fYCen) / m_fScale,
  601. fTmp = LIB_PI / (double)m_nAmount ;
  602. double angle = floor (atan2(cy,cx) / 2.0 / fTmp) * 2.0 * fTmp + fTmp ;
  603. double radius = FHypot (cx, cy) ;
  604. int xx = (int)(x - m_fOffset * cos (angle)),
  605. yy = (int)(y - m_fOffset * sin (angle)) ;
  606. xx = FClamp (xx, 0, pImg->Width()-1) ;
  607. yy = FClamp (yy, 0, pImg->Height()-1) ;
  608. const BYTE * pPixel2 = GetBackupImage()->GetBits (xx, yy) ;
  609. for (int i=0 ; i < pImg->ColorBits()/8 ; i++)
  610. pPixel[i] = FClamp0255 (pPixel[i] + (int)(radius * (pPixel2[i] - pPixel[i]))) ;
  611. }
  612. int m_nAmount ;
  613. double m_fScale, m_fOffset ;
  614. };
  615. //=============================================================================
  616. /**
  617. * Blind effect (>=24 bit).
  618. @verbatim
  619. example:
  620. FCPixelBlinds aCmd(AXIS_X, 10, 50, PCL_RGBA(0,0,255)) ;
  621. img.SinglePixelProcessProc (aCmd) ;
  622. @endverbatim
  623. */
  624. class FCPixelBlinds : public FCSinglePixelProcessBase
  625. {
  626. public:
  627. /// Constructor.
  628. /// @param nOpacity : percentage [1,100]
  629. FCPixelBlinds (AXIS_SYS nDirect, int nWidth, int nOpacity, RGBQUAD crBlind) : m_nWidth(nWidth), m_crBlind(crBlind)
  630. {
  631. m_nOpacity = FClamp (nOpacity, 1, 100) ;
  632. m_nDirect = nDirect ;
  633. if ((m_nDirect != AXIS_X) && (m_nDirect != AXIS_Y))
  634. m_nDirect = AXIS_X ;
  635. }
  636. private:
  637. virtual void OnEnterProcess (FCObjImage* pImg)
  638. {
  639. int nMaxWidth = FMax (pImg->Width(), pImg->Height()) ;
  640. m_nWidth = FClamp (m_nWidth, 2, nMaxWidth) ;
  641. }
  642. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  643. {
  644. int nMod ;
  645. if (m_nDirect == AXIS_X) // horizontal direction
  646. nMod = y % m_nWidth ;
  647. else if (m_nDirect == AXIS_Y) // vertical direction
  648. nMod = x % m_nWidth ;
  649. double fAlphaAdd = 255.0 * m_nOpacity/100.0 / (m_nWidth-1.0) ;
  650. FCColor::AlphaBlendPixel (pPixel, (BYTE*)&m_crBlind, FClamp0255((int)(nMod * fAlphaAdd))) ;
  651. }
  652. AXIS_SYS m_nDirect ;
  653. int m_nWidth ;
  654. int m_nOpacity ;
  655. RGBQUAD m_crBlind ;
  656. };
  657. //=============================================================================
  658. /**
  659. * Mosaic effect (32 bit).
  660. @verbatim
  661. example:
  662. FCPixelMosaic aCmd(5) ;
  663. img.SinglePixelProcessProc (aCmd) ;
  664. @endverbatim
  665. */
  666. class FCPixelMosaic : public FCSinglePixelProcessBase
  667. {
  668. public:
  669. /// Constructor.
  670. /// @param nBlock : pixel width of block
  671. FCPixelMosaic (int nBlock) : m_nBlock(FMax(2,nBlock)) {}
  672. private:
  673. virtual bool ValidateColorBits (const FCObjImage* pImg) {return pImg->IsValidImage() && (pImg->ColorBits() == 32);}
  674. virtual void OnEnterProcess (FCObjImage* pImg)
  675. {
  676. SetBackupImage (pImg) ;
  677. }
  678. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  679. {
  680. if ((x % m_nBlock == 0) && (y % m_nBlock == 0))
  681. {
  682. RGBQUAD cr = GetBlockAverage(x, y) ;
  683. FCColor::CopyPixel (pPixel, &cr, 4) ;
  684. }
  685. else
  686. FCColor::CopyPixel (pPixel, pImg->GetBits(x/m_nBlock*m_nBlock, y/m_nBlock*m_nBlock), 4) ;
  687. }
  688. RGBQUAD GetBlockAverage (int x, int y)
  689. {
  690. RECT rc = {x, y, x+m_nBlock, y+m_nBlock} ;
  691. GetBackupImage()->BoundRect(rc) ;
  692. int nNum = RECTWIDTH(rc) * RECTHEIGHT(rc) ;
  693. double nSumR=0, nSumG=0, nSumB=0, nSumA=0 ;
  694. for (int yy=rc.top ; yy < rc.bottom ; yy++)
  695. {
  696. for (int xx=rc.left ; xx < rc.right ; xx++)
  697. {
  698. BYTE * p = GetBackupImage()->GetBits (xx, yy) ;
  699. nSumB += PCL_B(p)*PCL_A(p) ; nSumG += PCL_G(p)*PCL_A(p) ;
  700. nSumR += PCL_R(p)*PCL_A(p) ; nSumA += PCL_A(p) ;
  701. }
  702. }
  703. return PCL_RGBA (nSumA ? (int)(nSumR / nSumA) : 0,
  704. nSumA ? (int)(nSumG / nSumA) : 0,
  705. nSumA ? (int)(nSumB / nSumA) : 0,
  706. nNum ? (int)(nSumA / nNum) : 0xFF) ;
  707. }
  708. private:
  709. int m_nBlock ;
  710. };
  711. //=============================================================================
  712. /**
  713. * Fill a 3D solid frame (>=24 bit).
  714. @verbatim
  715. example:
  716. FCPixelFill3DSolidFrame aCmd (5) ;
  717. img.SinglePixelProcessProc (aCmd) ;
  718. @endverbatim
  719. */
  720. class FCPixelFill3DSolidFrame : public FCSinglePixelProcessBase
  721. {
  722. public:
  723. /// Constructor.
  724. FCPixelFill3DSolidFrame (int nWidth) : m_nWidth(FMax(3,nWidth)) {}
  725. private:
  726. virtual void OnEnterProcess (FCObjImage* pImg)
  727. {
  728. m_rcOut.left = m_rcOut.top = 0 ;
  729. m_rcOut.right = pImg->Width() ;
  730. m_rcOut.bottom = pImg->Height() ;
  731. const int nShadow = (int)ceil(m_nWidth / 4.0),
  732. nMid = m_nWidth - 2*nShadow ;
  733. m_rcO = m_rcOut ; InflateRect (&m_rcO, -nShadow, -nShadow) ;
  734. m_rcI = m_rcO ; InflateRect (&m_rcI, -nMid, -nMid) ;
  735. m_rcIn = m_rcI ; InflateRect (&m_rcIn, -nShadow, -nShadow) ;
  736. }
  737. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  738. {
  739. const POINT ptPixel = {x,y} ;
  740. if (PtInRect (&m_rcIn, ptPixel))
  741. return ; // in frame, just return
  742. static RGBQUAD crMain = {192,192,192,255},
  743. crHighlight = FCColor::crWhite(),
  744. crShadow = {128,128,128,255} ;
  745. RGBQUAD crFill ;
  746. if (PtInRect (&m_rcI, ptPixel))
  747. {
  748. crFill = __pcl_CalcRoundColor (ptPixel, m_rcI, m_rcIn, crShadow, crHighlight) ;
  749. }
  750. else if (PtInRect (&m_rcO, ptPixel))
  751. crFill = crMain ;
  752. else if (PtInRect (&m_rcOut, ptPixel))
  753. {
  754. crFill = __pcl_CalcRoundColor (ptPixel, m_rcOut, m_rcO, crHighlight, crShadow) ;
  755. }
  756. FCColor::CopyPixel (pPixel, &crFill, pImg->ColorBits()/8) ;
  757. }
  758. static RGBQUAD __pcl_CalcRoundColor (const POINT& pt, const RECT& rcOut, const RECT& rcIn, RGBQUAD crLT, RGBQUAD crRB)
  759. {
  760. if (pt.x < rcIn.left)
  761. return (pt.y - rcOut.top < RECTHEIGHT(rcOut) + rcOut.left - pt.x) ? crLT : crRB ;
  762. if (pt.x >= rcIn.right)
  763. return (pt.y - rcOut.top < rcOut.right - pt.x) ? crLT : crRB ;
  764. if (pt.y < rcIn.top)
  765. return crLT ;
  766. return crRB ; // pt.y >= rcIn.bottom
  767. }
  768. int m_nWidth ; // >=3
  769. RECT m_rcOut, m_rcO, m_rcI, m_rcIn ;
  770. };
  771. //=============================================================================
  772. /**
  773. * Adjust image's RGB value (>=24 bit).
  774. @verbatim
  775. example:
  776. FCPixelAdjustRGB aCmd (-100, 50, 220) ;
  777. img.SinglePixelProcessProc (aCmd) ;
  778. @endverbatim
  779. */
  780. class FCPixelAdjustRGB : public FCSinglePixelProcessBase
  781. {
  782. public:
  783. /// Constructor (param's unit is delta).
  784. FCPixelAdjustRGB (int nR, int nG, int nB) : m_R(nR), m_G(nG), m_B(nB) {}
  785. void AdjustRGB (BYTE* pPixel)
  786. {
  787. PCL_B(pPixel) = FClamp0255 (PCL_B(pPixel) + m_B) ;
  788. PCL_G(pPixel) = FClamp0255 (PCL_G(pPixel) + m_G) ;
  789. PCL_R(pPixel) = FClamp0255 (PCL_R(pPixel) + m_R) ;
  790. }
  791. private:
  792. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  793. {
  794. AdjustRGB (pPixel) ;
  795. }
  796. int m_R, m_G, m_B ;
  797. };
  798. //=============================================================================
  799. /**
  800. * Color level (>=24 bit).
  801. @verbatim
  802. example:
  803. FCPixelColorLevel aCmd (false, 20, 230) ;
  804. img.SinglePixelProcessProc (aCmd) ;
  805. @endverbatim
  806. */
  807. class FCPixelColorLevel : public FCSinglePixelProcessBase
  808. {
  809. public:
  810. /// Constructor.
  811. FCPixelColorLevel (bool bAuto, int nInLow, int nInHigh, IMAGE_CHANNEL nChannel = CHANNEL_RGB)
  812. {
  813. m_bAuto = bAuto ;
  814. m_nInputLow[0] = m_nInputLow[1] = m_nInputLow[2] = FClamp0255(nInLow) ;
  815. m_nInputHigh[0] = m_nInputHigh[1] = m_nInputHigh[2] = FClamp0255(nInHigh) ;
  816. m_nOutputLow = 0 ; m_nOutputHigh = 255 ;
  817. m_bChannelR = (nChannel & CHANNEL_RED) ? true : false ;
  818. m_bChannelG = (nChannel & CHANNEL_GREEN) ? true : false ;
  819. m_bChannelB = (nChannel & CHANNEL_BLUE) ? true : false ;
  820. }
  821. private:
  822. virtual void OnEnterProcess (FCObjImage* pImg)
  823. {
  824. SetBackupImage (pImg) ;
  825. if (m_bAuto)
  826. {
  827. FCHistogram histo(*pImg) ;
  828. this->AutoColorLevelChannel (histo, CHANNEL_RED) ;
  829. this->AutoColorLevelChannel (histo, CHANNEL_GREEN) ;
  830. this->AutoColorLevelChannel (histo, CHANNEL_BLUE) ;
  831. }
  832. }
  833. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  834. {
  835. double fInten ;
  836. if (m_bChannelB)
  837. {
  838. fInten = PCL_B(pPixel) - m_nInputLow[0] ;
  839. if (m_nInputHigh[0] != m_nInputLow[0])
  840. fInten /= (double)(m_nInputHigh[0] - m_nInputLow[0]) ;
  841. PCL_B(pPixel) = FClamp0255(FRound(fInten * 255.0)) ;
  842. }
  843. if (m_bChannelG)
  844. {
  845. fInten = PCL_G(pPixel) - m_nInputLow[1] ;
  846. if (m_nInputHigh[1] != m_nInputLow[1])
  847. fInten /= (double)(m_nInputHigh[1] - m_nInputLow[1]) ;
  848. PCL_G(pPixel) = FClamp0255(FRound(fInten * 255.0)) ;
  849. }
  850. if (m_bChannelR)
  851. {
  852. fInten = PCL_R(pPixel) - m_nInputLow[2] ;
  853. if (m_nInputHigh[2] != m_nInputLow[2])
  854. fInten /= (double)(m_nInputHigh[2] - m_nInputLow[2]) ;
  855. PCL_R(pPixel) = FClamp0255(FRound(fInten * 255.0)) ;
  856. }
  857. }
  858. void AutoColorLevelChannel (const FCHistogram& histo, IMAGE_CHANNEL nChannel)
  859. {
  860. int nIndex = 0 ;
  861. switch (nChannel)
  862. {
  863. case CHANNEL_RED : nIndex = 2 ; break ;
  864. case CHANNEL_GREEN : nIndex = 1 ; break ;
  865. case CHANNEL_BLUE : nIndex = 0 ; break ;
  866. default : assert(false) ; break ;
  867. }
  868. const int nCount = histo.GetCount (nChannel) ;
  869. if (nCount == 0)
  870. {
  871. m_nInputLow[nIndex] = m_nInputHigh[nIndex] = 0 ;
  872. }
  873. else
  874. {
  875. m_nInputLow[nIndex] = 0 ;
  876. m_nInputHigh[nIndex] = 255 ;
  877. // Set the low input
  878. int new_count = 0, i ;
  879. for (i=0 ; i < 255 ; i++)
  880. {
  881. new_count += histo.GetValueCount (i, nChannel) ;
  882. double percentage = new_count / (double)nCount ;
  883. double next_percentage = (new_count + histo.GetValueCount (i+1, nChannel)) / (double)nCount ;
  884. if (fabs (percentage - 0.006) < fabs (next_percentage - 0.006))
  885. {
  886. m_nInputLow[nIndex] = i + 1 ;
  887. break ;
  888. }
  889. }
  890. // Set the high input
  891. new_count = 0 ;
  892. for (i=255 ; i > 0 ; i--)
  893. {
  894. new_count += histo.GetValueCount (i, nChannel) ;
  895. double percentage = new_count / (double)nCount ;
  896. double next_percentage = (new_count + histo.GetValueCount (i-1, nChannel)) / (double)nCount ;
  897. if (fabs (percentage - 0.006) < fabs (next_percentage - 0.006))
  898. {
  899. m_nInputHigh[nIndex] = i - 1 ;
  900. break ;
  901. }
  902. }
  903. }
  904. }
  905. private:
  906. int m_nInputLow[3], m_nInputHigh[3] ;
  907. int m_nOutputLow, m_nOutputHigh ;
  908. bool m_bAuto, m_bChannelR, m_bChannelG, m_bChannelB ;
  909. };
  910. //=============================================================================
  911. /**
  912. * Threshold image (>=24 bit).
  913. @verbatim
  914. example:
  915. FCPixelThreshold aCmd (128) ;
  916. img.SinglePixelProcessProc (aCmd) ;
  917. @endverbatim
  918. */
  919. class FCPixelThreshold : public FCSinglePixelProcessBase
  920. {
  921. public:
  922. /// Constructor.
  923. FCPixelThreshold (int nLevel) : m_nLevel(FClamp0255(nLevel)) {}
  924. private:
  925. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  926. {
  927. RGBQUAD cr = (FCColor::GetGrayscale(pPixel) > m_nLevel) ? FCColor::crWhite() : FCColor::crBlack() ;
  928. FCColor::CopyPixel (pPixel, &cr, 3) ;
  929. }
  930. int m_nLevel ;
  931. };
  932. //=============================================================================
  933. /**
  934. * Clockwise rotate 90' (>=8 bit).
  935. @verbatim
  936. example:
  937. FCPixelRotate90 aCmd ;
  938. img.SinglePixelProcessProc (aCmd) ;
  939. @endverbatim
  940. */
  941. class FCPixelRotate90 : public FCSinglePixelProcessBase
  942. {
  943. virtual bool ValidateColorBits (const FCObjImage* pImg)
  944. {
  945. return pImg->IsValidImage() && (pImg->ColorBits() >= 8) ;
  946. }
  947. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  948. {
  949. FCColor::CopyPixel (pPixel,
  950. GetBackupImage()->GetBits (y, pImg->Width()-1-x),
  951. pImg->ColorBits()/8) ;
  952. }
  953. virtual void OnEnterProcess (FCObjImage* pImg)
  954. {
  955. SetBackupImage (pImg) ;
  956. // create new rotated image
  957. pImg->Create (pImg->Height(), pImg->Width(), pImg->ColorBits()) ;
  958. if (pImg->ColorBits() <= 8)
  959. pImg->CopyPalette(*GetBackupImage()) ;
  960. }
  961. };
  962. //=============================================================================
  963. /**
  964. * Clockwise rotate 270' (>=8 bit).
  965. @verbatim
  966. example:
  967. FCPixelRotate270 aCmd ;
  968. img.SinglePixelProcessProc (aCmd) ;
  969. @endverbatim
  970. */
  971. class FCPixelRotate270 : public FCPixelRotate90
  972. {
  973. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  974. {
  975. FCColor::CopyPixel (pPixel,
  976. GetBackupImage()->GetBits (pImg->Height()-1-y, x),
  977. pImg->ColorBits()/8) ;
  978. }
  979. };
  980. //=============================================================================
  981. /**
  982. * De-interlace (32 bit).
  983. @verbatim
  984. example:
  985. FCPixelDeinterlace aCmd (FCPixelDeinterlace::SCAN_EVEN) ;
  986. img.SinglePixelProcessProc (aCmd) ;
  987. @endverbatim
  988. */
  989. class FCPixelDeinterlace : public FCSinglePixelProcessBase
  990. {
  991. public:
  992. enum SCAN_FIELDS { SCAN_EVEN=0, SCAN_ODD=1 };
  993. /// Constructor.
  994. /// @param EliminateFields : SCAN_EVEN rebuild even line / SCAN_ODD rebuild odd line.
  995. FCPixelDeinterlace (SCAN_FIELDS EliminateFields) : m_Fields(EliminateFields) {}
  996. private:
  997. virtual bool ValidateColorBits (const FCObjImage* pImg)
  998. {
  999. return pImg->IsValidImage() && (pImg->ColorBits() == 32) ;
  1000. }
  1001. // adapted from GIMP v1.2.5 --- code v1.00
  1002. // Deinterlace is useful for processing images from video capture cards.
  1003. // When only the odd or even fields get captured, deinterlace can be used to
  1004. // interpolate between the existing fields to correct this.
  1005. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1006. {
  1007. if ((y == 0) || (y == pImg->Height()-1))
  1008. return ;
  1009. if (y % 2 == m_Fields)
  1010. {
  1011. BYTE * pUp = pImg->GetBits (x, y-1),
  1012. * pDown = pImg->GetBits (x, y+1) ;
  1013. int nSumA = PCL_A(pUp) + PCL_A(pDown) ;
  1014. PCL_A(pPixel) = nSumA / 2 ;
  1015. if (PCL_A(pPixel))
  1016. for (int i=0 ; i < 3 ; i++)
  1017. pPixel[i] = (pUp[i]*PCL_A(pUp) + pDown[i]*PCL_A(pDown)) / nSumA ;
  1018. }
  1019. }
  1020. SCAN_FIELDS m_Fields ;
  1021. };
  1022. //=============================================================================
  1023. /**
  1024. * Halftone (>=24 bit), use Limb Pattern M3 algorithm.
  1025. @verbatim
  1026. example:
  1027. FCPixelHalftoneM3 aCmd ;
  1028. img.SinglePixelProcessProc (aCmd) ;
  1029. @endverbatim
  1030. */
  1031. class FCPixelHalftoneM3 : public FCSinglePixelProcessBase
  1032. {
  1033. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1034. {
  1035. static const BYTE BayerPattern[8][8] = // 64 level gray
  1036. {
  1037. 0,32,8,40,2,34,10,42,
  1038. 48,16,56,24,50,18,58,26,
  1039. 12,44,4,36,14,46,6,38,
  1040. 60,28,52,20,62,30,54,22,
  1041. 3,35,11,43,1,33,9,41,
  1042. 51,19,59,27,49,17,57,25,
  1043. 15,47,7,39,13,45,5,37,
  1044. 63,31,55,23,61,29,53,21
  1045. };
  1046. const BYTE gr = FCColor::GetGrayscale (pPixel) ;
  1047. PCL_R(pPixel) = PCL_G(pPixel) = PCL_B(pPixel) = (((gr>>2) > BayerPattern[y&7][x&7]) ? 0xFF : 0) ;
  1048. }
  1049. };
  1050. //=============================================================================
  1051. /**
  1052. * Oil paint (>=24 bit).
  1053. @verbatim
  1054. example:
  1055. FCPixelOilPaint aCmd (2) ;
  1056. img.SinglePixelProcessProc (aCmd) ;
  1057. @endverbatim
  1058. */
  1059. class FCPixelOilPaint : public FCSinglePixelProcessBase
  1060. {
  1061. public:
  1062. /// Constructor (nRadius >= 1).
  1063. FCPixelOilPaint (int nRadius)
  1064. {
  1065. m_nRadius = FMax(1,nRadius) ;
  1066. m_nLength = 2*m_nRadius + 1 ; // Stat. block
  1067. }
  1068. private:
  1069. virtual void OnEnterProcess (FCObjImage* pImg)
  1070. {
  1071. SetBackupImage (pImg) ;
  1072. GetBackupImage()->ExpandFrame (true, m_nRadius, m_nRadius, m_nRadius, m_nRadius) ;
  1073. // calculate block gray
  1074. m_ImgGray = *GetBackupImage() ;
  1075. FCPixelConvertTo8BitGray aCmd ;
  1076. m_ImgGray.SinglePixelProcessProc(aCmd) ;
  1077. }
  1078. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1079. {
  1080. BYTE * pSelPixel = NULL ;
  1081. int nMaxNum = 0,
  1082. pHistogram[256] ;
  1083. memset (pHistogram, 0, sizeof(int) * 256) ;
  1084. // replace every pixel use most frequency
  1085. for (int ny=0 ; ny < m_nLength ; ny++)
  1086. {
  1087. BYTE * pGray = m_ImgGray.GetBits (x, y+ny) ;
  1088. for (int i=0 ; i < m_nLength ; i++, pGray++)
  1089. if (++pHistogram[*pGray] > nMaxNum)
  1090. {
  1091. nMaxNum = pHistogram[*pGray] ;
  1092. pSelPixel = GetBackupImage()->GetBits (x+i, y+ny) ;
  1093. }
  1094. }
  1095. FCColor::CopyPixel (pPixel, pSelPixel, 3) ; // leave alpha=channel
  1096. }
  1097. int m_nRadius ; // >= 1
  1098. int m_nLength ; // 2*m_nRadius + 1
  1099. FCObjImage m_ImgGray ;
  1100. };
  1101. //=============================================================================
  1102. /**
  1103. * Color tone (>=24 bit).
  1104. @verbatim
  1105. example:
  1106. FCPixelColorTone aCmd (PCL_RGBA(0,0,255)) ;
  1107. img.SinglePixelProcessProc (aCmd) ;
  1108. @endverbatim
  1109. */
  1110. class FCPixelColorTone : public FCSinglePixelProcessBase
  1111. {
  1112. public:
  1113. /// Constructor.
  1114. FCPixelColorTone (RGBQUAD crTone)
  1115. {
  1116. double L, S ;
  1117. FCColor::RGBtoHLS (&crTone, &m_nHue, &L, &S) ;
  1118. }
  1119. FCPixelColorTone (RGBQUAD crTone, double saturation)
  1120. {
  1121. double L, S ;
  1122. m_saturation=saturation,
  1123. FCColor::RGBtoHLS (&crTone, &m_nHue, &L, &S) ;
  1124. }
  1125. FCPixelColorTone (double crTone, double saturation)
  1126. {
  1127. m_saturation=saturation;
  1128. m_nHue=crTone;
  1129. }
  1130. private:
  1131. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1132. {
  1133. int n = FCColor::GetGrayscale(pPixel) ;
  1134. PCL_B(pPixel) = (BYTE)(255 * pow(n/255.0, 1.2)) ;
  1135. PCL_G(pPixel) = (BYTE)(255 * pow(n/255.0, 1)) ;
  1136. PCL_R(pPixel) = (BYTE)(255 * pow(n/255.0, 0.8)) ;
  1137. double H, L, S ;
  1138. FCColor::RGBtoHLS (pPixel, &H, &L, &S) ;
  1139. if(1)//m_saturation)
  1140. {
  1141. RGBQUAD cr = FCColor::HLStoRGB (m_nHue, L, S * m_saturation) ;
  1142. FCColor::CopyPixel (pPixel, &cr, 3) ;
  1143. }
  1144. else
  1145. {
  1146. RGBQUAD cr = FCColor::HLStoRGB (m_nHue, L, S * 150 / 100) ;
  1147. FCColor::CopyPixel (pPixel, &cr, 3) ;
  1148. }
  1149. }
  1150. double m_nHue ;
  1151. double m_saturation ;
  1152. };
  1153. //=============================================================================
  1154. /**
  1155. * Add random noise (>=24 bit).
  1156. @verbatim
  1157. example:
  1158. FCPixelAddRandomNoise aCmd (5) ;
  1159. img.SinglePixelProcessProc (aCmd) ;
  1160. @endverbatim
  1161. */
  1162. class FCPixelAddRandomNoise : public FCSinglePixelProcessBase
  1163. {
  1164. public:
  1165. /// Constructor.
  1166. FCPixelAddRandomNoise (int nLevel) : m_nLevel(nLevel) {srand((unsigned int)time(NULL));}
  1167. private:
  1168. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1169. {
  1170. int nDelta[3] ;
  1171. for (int i=0 ; i < 3 ; i++)
  1172. {
  1173. nDelta[i] = FRound ((rand()/(double)RAND_MAX - 0.5) * m_nLevel) ;
  1174. }
  1175. PCL_B(pPixel) = FClamp0255 (PCL_B(pPixel) + nDelta[0]) ;
  1176. PCL_G(pPixel) = FClamp0255 (PCL_G(pPixel) + nDelta[1]) ;
  1177. PCL_R(pPixel) = FClamp0255 (PCL_R(pPixel) + nDelta[2]) ;
  1178. }
  1179. int m_nLevel ;
  1180. };
  1181. //=============================================================================
  1182. /**
  1183. * Noisify (>=24 bit).
  1184. @verbatim
  1185. example:
  1186. FCPixelNoisify aCmd (5) ;
  1187. img.SinglePixelProcessProc (aCmd) ;
  1188. @endverbatim
  1189. */
  1190. class FCPixelNoisify : public FCSinglePixelProcessBase
  1191. {
  1192. public:
  1193. /// Constructor.
  1194. /// @param nLevel : level (0 <= nLevel <= 100).
  1195. FCPixelNoisify (int nLevel) : m_nLevel(FClamp(nLevel,0,100)) {srand((unsigned int)time(NULL));}
  1196. private:
  1197. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1198. {
  1199. int nNoise = (int)(m_nLevel * GenGauss() * 127.0 / 100.0) ;
  1200. PCL_B(pPixel) = FClamp0255 (PCL_B(pPixel) + nNoise) ;
  1201. PCL_G(pPixel) = FClamp0255 (PCL_G(pPixel) + nNoise) ;
  1202. PCL_R(pPixel) = FClamp0255 (PCL_R(pPixel) + nNoise) ;
  1203. }
  1204. static double GenGauss()
  1205. {
  1206. return (rand() + rand() + rand() + rand()) * 5.28596089837e-5 - 3.46410161514 ;
  1207. }
  1208. int m_nLevel ;
  1209. };
  1210. //=============================================================================
  1211. /**
  1212. * Splash image (>=24 bit).
  1213. @verbatim
  1214. example:
  1215. FCPixelSplash aCmd (5) ;
  1216. img.SinglePixelProcessProc (aCmd) ;
  1217. @endverbatim
  1218. */
  1219. class FCPixelSplash : public FCSinglePixelProcessBase
  1220. {
  1221. public:
  1222. /// Constructor.
  1223. /// @param nBlock : splash level (>=3).
  1224. FCPixelSplash (int nBlock)
  1225. {
  1226. m_nBlock = FMax (3, nBlock) ;
  1227. srand((unsigned int)time(0)) ;
  1228. }
  1229. private:
  1230. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1231. {
  1232. int xCopy = x - m_nBlock/2 + (rand() % m_nBlock),
  1233. yCopy = y - m_nBlock/2 + (rand() % m_nBlock) ;
  1234. xCopy = FClamp (xCopy, 0, pImg->Width()-1) ;
  1235. yCopy = FClamp (yCopy, 0, pImg->Height()-1) ;
  1236. BYTE * pSrc = GetBackupImage()->GetBits(xCopy,yCopy) ;
  1237. FCColor::CopyPixel (pPixel, pSrc, pImg->ColorBits()/8) ;
  1238. }
  1239. virtual void OnEnterProcess (FCObjImage* pImg)
  1240. {
  1241. SetBackupImage (pImg) ;
  1242. }
  1243. int m_nBlock ;
  1244. };
  1245. //=============================================================================
  1246. /**
  1247. * Video (>=24 bit).
  1248. @verbatim
  1249. example:
  1250. FCPixelVideo aCmd (FCPixelVideo::VIDEO_STAGGERED) ;
  1251. img.SinglePixelProcessProc (aCmd) ;
  1252. @endverbatim
  1253. */
  1254. class FCPixelVideo : public FCSinglePixelProcessBase
  1255. {
  1256. public:
  1257. enum VIDEO_TYPE {VIDEO_STAGGERED=0, VIDEO_TRIPED=1, VIDEO_3X3=2, VIDEO_DOTS=3} ;
  1258. /// Constructor.
  1259. /// @param nVideoType : VIDEO_STAGGERED, VIDEO_TRIPED, VIDEO_3X3, VIDEO_DOTS
  1260. FCPixelVideo (VIDEO_TYPE nVideoType) : m_VideoType(nVideoType)
  1261. {
  1262. assert(nVideoType>=VIDEO_STAGGERED && nVideoType<=VIDEO_DOTS);
  1263. }
  1264. private:
  1265. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1266. {
  1267. static const int pattern_width[] = {2, 1, 3, 5} ;
  1268. static const int pattern_height[] = {6, 3, 3, 15} ;
  1269. static const int video_pattern[4][15 * 5/* max pattern size */] =
  1270. {
  1271. {
  1272. 0, 1,
  1273. 0, 2,
  1274. 1, 2,
  1275. 1, 0,
  1276. 2, 0,
  1277. 2, 1,
  1278. },
  1279. {
  1280. 0,
  1281. 1,
  1282. 2,
  1283. },
  1284. {
  1285. 0, 1, 2,
  1286. 2, 0, 1,
  1287. 1, 2, 0,
  1288. },
  1289. {
  1290. 0, 1, 2, 0, 0,
  1291. 1, 1, 1, 2, 0,
  1292. 0, 1, 2, 2, 2,
  1293. 0, 0, 1, 2, 0,
  1294. 0, 1, 1, 1, 2,
  1295. 2, 0, 1, 2, 2,
  1296. 0, 0, 0, 1, 2,
  1297. 2, 0, 1, 1, 1,
  1298. 2, 2, 0, 1, 2,
  1299. 2, 0, 0, 0, 1,
  1300. 1, 2, 0, 1, 1,
  1301. 2, 2, 2, 0, 1,
  1302. 1, 2, 0, 0, 0,
  1303. 1, 1, 2, 0, 1,
  1304. 1, 2, 2, 2, 0,
  1305. }
  1306. };
  1307. const int nWidth = pattern_width[m_VideoType],
  1308. nHeight = pattern_height[m_VideoType] ;
  1309. for (int i=0 ; i < 3 ; i++)
  1310. if (video_pattern[m_VideoType][nWidth * (y%nHeight) + (x%nWidth)] == i)
  1311. pPixel[i] = FClamp0255 (2 * pPixel[i]) ;
  1312. }
  1313. VIDEO_TYPE m_VideoType ;
  1314. };
  1315. //=============================================================================
  1316. /**
  1317. * Color balance (>=24 bit).
  1318. @verbatim
  1319. example:
  1320. FCPixelColorBalance aCmd (true, TONE_SHADOWS, -30, 20, 30) ;
  1321. img.SinglePixelProcessProc (aCmd) ;
  1322. @endverbatim
  1323. */
  1324. class FCPixelColorBalance : public FCSinglePixelProcessBase
  1325. {
  1326. public:
  1327. /// Constructor.
  1328. FCPixelColorBalance (bool bPreLum, TONE_REGION ToneRgn, int cyan_red, int magenta_green, int yellow_blue)
  1329. {
  1330. m_bPreserveLuminosity = bPreLum ;
  1331. int cyan_red_rgn[3] = {0,0,0},
  1332. magenta_green_rgn[3] = {0,0,0},
  1333. yellow_blue_rgn[3] = {0,0,0} ;
  1334. cyan_red_rgn[ToneRgn] = cyan_red ;
  1335. magenta_green_rgn[ToneRgn] = magenta_green ;
  1336. yellow_blue_rgn[ToneRgn] = yellow_blue ;
  1337. // add for lightening, sub for darkening
  1338. PCL_array<double> highlights_add(256), midtones_add(256), shadows_add(256),
  1339. highlights_sub(256), midtones_sub(256), shadows_sub(256) ;
  1340. int i ;
  1341. for (i=0 ; i < 256 ; i++)
  1342. {
  1343. highlights_add[i] = shadows_sub[255 - i] = (1.075 - 1 / (i / 16.0 + 1)) ;
  1344. midtones_add[i] = midtones_sub[i] = 0.667 * (1 - FSquare ((i - 127.0) / 127.0)) ;
  1345. shadows_add[i] = highlights_sub[i] = 0.667 * (1 - FSquare ((i - 127.0) / 127.0)) ;
  1346. }
  1347. // Set the transfer arrays (for speed)
  1348. double * cyan_red_transfer[3], * magenta_green_transfer[3], * yellow_blue_transfer[3] ;
  1349. cyan_red_transfer[TONE_SHADOWS] = (cyan_red_rgn[TONE_SHADOWS] > 0) ? shadows_add.get() : shadows_sub.get() ;
  1350. cyan_red_transfer[TONE_MIDTONES] = (cyan_red_rgn[TONE_MIDTONES] > 0) ? midtones_add.get() : midtones_sub.get() ;
  1351. cyan_red_transfer[TONE_HIGHLIGHTS] = (cyan_red_rgn[TONE_HIGHLIGHTS] > 0) ? highlights_add.get() : highlights_sub.get() ;
  1352. magenta_green_transfer[TONE_SHADOWS] = (magenta_green_rgn[TONE_SHADOWS] > 0) ? shadows_add.get() : shadows_sub.get() ;
  1353. magenta_green_transfer[TONE_MIDTONES] = (magenta_green_rgn[TONE_MIDTONES] > 0) ? midtones_add.get() : midtones_sub.get() ;
  1354. magenta_green_transfer[TONE_HIGHLIGHTS] = (magenta_green_rgn[TONE_HIGHLIGHTS] > 0) ? highlights_add.get() : highlights_sub.get() ;
  1355. yellow_blue_transfer[TONE_SHADOWS] = (yellow_blue_rgn[TONE_SHADOWS] > 0) ? shadows_add.get() : shadows_sub.get() ;
  1356. yellow_blue_transfer[TONE_MIDTONES] = (yellow_blue_rgn[TONE_MIDTONES] > 0) ? midtones_add.get() : midtones_sub.get() ;
  1357. yellow_blue_transfer[TONE_HIGHLIGHTS] = (yellow_blue_rgn[TONE_HIGHLIGHTS] > 0) ? highlights_add.get() : highlights_sub.get() ;
  1358. for (i=0 ; i < 256 ; i++)
  1359. {
  1360. int r_n = i, g_n = i, b_n = i ;
  1361. r_n += (int)(cyan_red_rgn[TONE_SHADOWS] * cyan_red_transfer[TONE_SHADOWS][r_n]); r_n = FClamp0255(r_n);
  1362. r_n += (int)(cyan_red_rgn[TONE_MIDTONES] * cyan_red_transfer[TONE_MIDTONES][r_n]); r_n = FClamp0255(r_n);
  1363. r_n += (int)(cyan_red_rgn[TONE_HIGHLIGHTS] * cyan_red_transfer[TONE_HIGHLIGHTS][r_n]); r_n = FClamp0255(r_n);
  1364. g_n += (int)(magenta_green_rgn[TONE_SHADOWS] * magenta_green_transfer[TONE_SHADOWS][g_n]); g_n = FClamp0255(g_n);
  1365. g_n += (int)(magenta_green_rgn[TONE_MIDTONES] * magenta_green_transfer[TONE_MIDTONES][g_n]); g_n = FClamp0255(g_n);
  1366. g_n += (int)(magenta_green_rgn[TONE_HIGHLIGHTS] * magenta_green_transfer[TONE_HIGHLIGHTS][g_n]); g_n = FClamp0255(g_n);
  1367. b_n += (int)(yellow_blue_rgn[TONE_SHADOWS] * yellow_blue_transfer[TONE_SHADOWS][b_n]); b_n = FClamp0255(b_n);
  1368. b_n += (int)(yellow_blue_rgn[TONE_MIDTONES] * yellow_blue_transfer[TONE_MIDTONES][b_n]); b_n = FClamp0255(b_n);
  1369. b_n += (int)(yellow_blue_rgn[TONE_HIGHLIGHTS] * yellow_blue_transfer[TONE_HIGHLIGHTS][b_n]); b_n = FClamp0255(b_n);
  1370. m_pLookupR[i] = r_n ;
  1371. m_pLookupG[i] = g_n ;
  1372. m_pLookupB[i] = b_n ;
  1373. }
  1374. }
  1375. private:
  1376. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1377. {
  1378. RGBQUAD rgb ;
  1379. PCL_B(&rgb) = m_pLookupB[PCL_B(pPixel)] ;
  1380. PCL_G(&rgb) = m_pLookupG[PCL_G(pPixel)] ;
  1381. PCL_R(&rgb) = m_pLookupR[PCL_R(pPixel)] ;
  1382. if (m_bPreserveLuminosity) // preserve luminosity
  1383. {
  1384. double H, L, S ;
  1385. FCColor::RGBtoHLS (&rgb, &H, &L, &S) ;
  1386. // calculate L value
  1387. int cmax = FMax (PCL_R(pPixel), FMax (PCL_G(pPixel), PCL_B(pPixel))),
  1388. cmin = FMin (PCL_R(pPixel), FMin (PCL_G(pPixel), PCL_B(pPixel))) ;
  1389. L = (cmax+cmin) / 2.0 / 255.0 ;
  1390. rgb = FCColor::HLStoRGB (H, L, S) ;
  1391. }
  1392. PCL_B(pPixel) = PCL_B(&rgb) ;
  1393. PCL_G(pPixel) = PCL_G(&rgb) ;
  1394. PCL_R(pPixel) = PCL_R(&rgb) ;
  1395. }
  1396. BYTE m_pLookupR[256], m_pLookupG[256], m_pLookupB[256] ;
  1397. bool m_bPreserveLuminosity ;
  1398. };
  1399. //=============================================================================
  1400. /**
  1401. * Fill grid (>=24 bit).
  1402. @verbatim
  1403. example:
  1404. FCPixelFillGrid aCmd (PCL_RGBA(0,255,0), PCL_RGBA(0,0,255), 5) ;
  1405. img.SinglePixelProcessProc (aCmd) ;
  1406. @endverbatim
  1407. */
  1408. class FCPixelFillGrid : public FCSinglePixelProcessBase
  1409. {
  1410. public:
  1411. /// Constructor.
  1412. /// @param nPitch : width of grid.
  1413. FCPixelFillGrid (RGBQUAD cr1, RGBQUAD cr2, int nPitch) : m_cr1(cr1), m_cr2(cr2), m_nPitch(FMax(1,nPitch)) {}
  1414. private:
  1415. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1416. {
  1417. int nX = x / m_nPitch, nY = y / m_nPitch ;
  1418. FCColor::CopyPixel (pPixel, ((nX + nY) % 2 == 0) ? &m_cr1 : &m_cr2, 3) ;
  1419. }
  1420. RGBQUAD m_cr1, m_cr2 ;
  1421. int m_nPitch ;
  1422. };
  1423. //=============================================================================
  1424. /**
  1425. * Add 3D grid (>=24 bit).
  1426. @verbatim
  1427. example:
  1428. FCPixel3DGrid aCmd (32, 60) ;
  1429. img.SinglePixelProcessProc (aCmd) ;
  1430. @endverbatim
  1431. */
  1432. class FCPixel3DGrid : public FCSinglePixelProcessBase
  1433. {
  1434. public:
  1435. FCPixel3DGrid (int nSize, int nDepth) : m_nSize(FMax(1,nSize)), m_nDepth(nDepth) {}
  1436. private:
  1437. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1438. {
  1439. int nDelta = 0 ;
  1440. if (((y-1) % m_nSize == 0) && (x % m_nSize != 0) && ((x+1) % m_nSize != 0))
  1441. nDelta = -m_nDepth ; // top
  1442. else if (((y+2) % m_nSize == 0) && (x % m_nSize != 0) && ((x+1) % m_nSize != 0))
  1443. nDelta = m_nDepth ; // bottom
  1444. else if (((x-1) % m_nSize == 0) && (y % m_nSize != 0) && ((y+1) % m_nSize != 0))
  1445. nDelta = m_nDepth ; // left
  1446. else if (((x+2) % m_nSize == 0) && (y % m_nSize != 0) && ((y+1) % m_nSize != 0))
  1447. nDelta = -m_nDepth ; // right
  1448. PCL_R(pPixel) = FClamp0255 (PCL_R(pPixel) + nDelta) ;
  1449. PCL_G(pPixel) = FClamp0255 (PCL_G(pPixel) + nDelta) ;
  1450. PCL_B(pPixel) = FClamp0255 (PCL_B(pPixel) + nDelta) ;
  1451. }
  1452. int m_nSize, m_nDepth ;
  1453. };
  1454. //=============================================================================
  1455. /**
  1456. * Median filter (>=24 bit).
  1457. @verbatim
  1458. example:
  1459. FCPixelMedianFilter aCmd (3) ;
  1460. img.SinglePixelProcessProc (aCmd) ;
  1461. @endverbatim
  1462. */
  1463. class FCPixelMedianFilter : public FCSinglePixelProcessBase
  1464. {
  1465. public:
  1466. /// Constructor (nSize >= 2).
  1467. FCPixelMedianFilter (int nSize) : m_nSize(nSize), m_pBlock(0), m_nBlockNum(FSquare(nSize)) {}
  1468. virtual ~FCPixelMedianFilter() {if(m_pBlock) delete[] m_pBlock;}
  1469. private:
  1470. virtual void OnEnterProcess (FCObjImage* pImg)
  1471. {
  1472. m_pBlock = new BlockElem[m_nBlockNum] ;
  1473. SetBackupImage (pImg) ;
  1474. // duplicate edge
  1475. int nLeftTop = m_nSize/2,
  1476. nRightDown = nLeftTop ;
  1477. GetBackupImage()->ExpandFrame (true, nLeftTop, nLeftTop, nRightDown, nRightDown) ;
  1478. m_BakImage = *GetBackupImage() ;
  1479. // calculate gray
  1480. FCPixelConvertTo8BitGray aCmd ;
  1481. GetBackupImage()->SinglePixelProcessProc (aCmd) ;
  1482. }
  1483. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1484. {
  1485. int i = 0 ;
  1486. for (int m=0 ; m < m_nSize ; m++)
  1487. for (int n=0 ; n < m_nSize ; n++)
  1488. {
  1489. m_pBlock[i].nGray = *GetBackupImage()->GetBits (x+n, y+m) ;
  1490. FCColor::CopyPixel (&m_pBlock[i].crOrigin, m_BakImage.GetBits(x+n, y+m), 3) ;
  1491. i++ ;
  1492. }
  1493. ::qsort (m_pBlock, m_nBlockNum, sizeof(BlockElem), __CompareGray) ;
  1494. FCColor::CopyPixel (pPixel, &m_pBlock[m_nBlockNum/2], 3) ;
  1495. }
  1496. struct BlockElem
  1497. {
  1498. RGBQUAD crOrigin ;
  1499. int nGray ;
  1500. };
  1501. static int __CompareGray (const void* arg1, const void* arg2)
  1502. {
  1503. return ((BlockElem*)arg1)->nGray - ((BlockElem*)arg2)->nGray ;
  1504. }
  1505. int m_nSize ;
  1506. int m_nBlockNum ;
  1507. BlockElem * m_pBlock ;
  1508. FCObjImage m_BakImage ;
  1509. };
  1510. //=============================================================================
  1511. /**
  1512. * Splite RGB channel (>=24 bit).
  1513. @verbatim
  1514. example:
  1515. FCObjImage imgBlue, imgGreen ;
  1516. FCPixelSpliteChannel_RGB aCmd (NULL, &imgGreen, &imgBlue) ; // get green & blue channel
  1517. img.SinglePixelProcessProc (aCmd) ;
  1518. @endverbatim
  1519. */
  1520. class FCPixelSpliteChannel_RGB : public FCSinglePixelProcessBase
  1521. {
  1522. public:
  1523. /// Constructor (the received image's bpp is 32).
  1524. /// if you needn't some channel, set the param to NULL.
  1525. FCPixelSpliteChannel_RGB (FCObjImage* pImgR, FCObjImage* pImgG, FCObjImage* pImgB) : m_pImgR(pImgR), m_pImgG(pImgG), m_pImgB(pImgB) {}
  1526. private:
  1527. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1528. {
  1529. if (m_pImgB) *(RGBQUAD*)m_pImgB->GetBits(x,y) = PCL_RGBA(PCL_B(pPixel),PCL_B(pPixel),PCL_B(pPixel),PCL_A(pPixel)) ;
  1530. if (m_pImgG) *(RGBQUAD*)m_pImgG->GetBits(x,y) = PCL_RGBA(PCL_G(pPixel),PCL_G(pPixel),PCL_G(pPixel),PCL_A(pPixel)) ;
  1531. if (m_pImgR) *(RGBQUAD*)m_pImgR->GetBits(x,y) = PCL_RGBA(PCL_R(pPixel),PCL_R(pPixel),PCL_R(pPixel),PCL_A(pPixel)) ;
  1532. }
  1533. virtual void OnEnterProcess (FCObjImage* pImg)
  1534. {
  1535. if (m_pImgR) m_pImgR->Create (pImg->Width(), pImg->Height(), 32) ;
  1536. if (m_pImgG) m_pImgG->Create (pImg->Width(), pImg->Height(), 32) ;
  1537. if (m_pImgB) m_pImgB->Create (pImg->Width(), pImg->Height(), 32) ;
  1538. }
  1539. FCObjImage * m_pImgR, * m_pImgG, * m_pImgB ;
  1540. };
  1541. //=============================================================================
  1542. /**
  1543. * Combine RGB channel (>=24 bit).
  1544. * all channel image must same width & height, bpp == 8.
  1545. @verbatim
  1546. example:
  1547. FCPixelCombineChannel_RGB aCmd (&imgRed, &imgGreen, &imgBlue) ;
  1548. img.SinglePixelProcessProc (aCmd) ;
  1549. @endverbatim
  1550. */
  1551. class FCPixelCombineChannel_RGB : public FCSinglePixelProcessBase
  1552. {
  1553. public:
  1554. FCPixelCombineChannel_RGB (FCObjImage* pImgR, FCObjImage* pImgG, FCObjImage* pImgB) : m_pImgR(pImgR), m_pImgG(pImgG), m_pImgB(pImgB) {}
  1555. private:
  1556. virtual bool ValidateColorBits (const FCObjImage* pImg)
  1557. {
  1558. bool b=m_pImgR && m_pImgG && m_pImgB &&
  1559. (m_pImgR->ColorBits() == 8) && (m_pImgG->ColorBits() == 8) && (m_pImgB->ColorBits() == 8) &&
  1560. (m_pImgR->Width() == m_pImgG->Width()) && (m_pImgR->Width() == m_pImgB->Width()) &&
  1561. (m_pImgR->Height() == m_pImgG->Height()) && (m_pImgR->Height() == m_pImgB->Height()) ;
  1562. if (b)
  1563. const_cast<FCObjImage*>(pImg)->Create (m_pImgR->Width(), m_pImgR->Height(), 32) ;
  1564. return b ;
  1565. }
  1566. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1567. {
  1568. PCL_B(pPixel) = *m_pImgB->GetBits(x,y) ;
  1569. PCL_G(pPixel) = *m_pImgG->GetBits(x,y) ;
  1570. PCL_R(pPixel) = *m_pImgR->GetBits(x,y) ;
  1571. PCL_A(pPixel) = 0xFF ;
  1572. }
  1573. FCObjImage * m_pImgR, * m_pImgG, * m_pImgB ;
  1574. };
  1575. //=============================================================================
  1576. /// Image convolute (>= 24 bit)
  1577. class FCPixelConvolute : public FCSinglePixelProcessBase
  1578. {
  1579. public:
  1580. /// Constructor.
  1581. FCPixelConvolute() : m_pElement(0)
  1582. {
  1583. m_iBlock=0 ; m_nOffset=0 ; m_iDivisor=1 ;
  1584. }
  1585. virtual ~FCPixelConvolute()
  1586. {
  1587. if (m_pElement)
  1588. delete[] m_pElement ;
  1589. }
  1590. /**
  1591. * Set convolute kernel.
  1592. * @param nElements : array from top-left of matrix.
  1593. * @param iBlockLen : width of matrix.
  1594. */
  1595. void SetKernel (const int* nElements, int iBlockLen, int iDivisor, int nOffset=0)
  1596. {
  1597. if (!nElements || (iBlockLen < 1))
  1598. {assert(false); return;}
  1599. if (m_pElement)
  1600. delete[] m_pElement ;
  1601. m_pElement = new int[FSquare(iBlockLen)] ;
  1602. for (int i=0 ; i < FSquare(iBlockLen) ; i++)
  1603. m_pElement[i] = nElements[i] ;
  1604. m_iBlock = iBlockLen ;
  1605. m_iDivisor = FMax(1,iDivisor) ;
  1606. m_nOffset = nOffset ;
  1607. }
  1608. private:
  1609. virtual void OnEnterProcess (FCObjImage* pImg)
  1610. {
  1611. SetBackupImage (pImg) ;
  1612. // duplicate edge, easier to processs
  1613. int nLeftTop = m_iBlock/2,
  1614. nRightDown = nLeftTop ;
  1615. GetBackupImage()->ExpandFrame (true, nLeftTop, nLeftTop, nRightDown, nRightDown) ;
  1616. }
  1617. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1618. {
  1619. // calculate the sum of sub-block
  1620. int nSumR=0, nSumG=0, nSumB=0, i=0 ;
  1621. for (int iy=0 ; iy < m_iBlock ; iy++)
  1622. for (int ix=0 ; ix < m_iBlock ; ix++, i++)
  1623. {
  1624. BYTE * pOld = GetBackupImage()->GetBits (x+ix,y+iy) ;
  1625. nSumB += PCL_B(pOld) * m_pElement[i] ;
  1626. nSumG += PCL_G(pOld) * m_pElement[i] ;
  1627. nSumR += PCL_R(pOld) * m_pElement[i] ;
  1628. }
  1629. // set pixel
  1630. PCL_B(pPixel) = FClamp0255 (m_nOffset + nSumB / m_iDivisor) ;
  1631. PCL_G(pPixel) = FClamp0255 (m_nOffset + nSumG / m_iDivisor) ;
  1632. PCL_R(pPixel) = FClamp0255 (m_nOffset + nSumR / m_iDivisor) ;
  1633. }
  1634. int * m_pElement ;
  1635. int m_iBlock, m_iDivisor, m_nOffset ;
  1636. };
  1637. //=============================================================================
  1638. /**
  1639. * Standard 3x3 gaussian blur (>=24 bit).
  1640. @verbatim
  1641. example:
  1642. FCPixelGaussianBlur3x3 aCmd ;
  1643. img.SinglePixelProcessProc (aCmd) ;
  1644. @endverbatim
  1645. */
  1646. class FCPixelGaussianBlur3x3 : public FCPixelConvolute
  1647. {
  1648. public:
  1649. FCPixelGaussianBlur3x3()
  1650. {
  1651. int arKernel[] = {1,2,1,2,4,2,1,2,1},
  1652. nBlock = 3,
  1653. nDivisor = 16,
  1654. nOffset = 0 ;
  1655. SetKernel (arKernel, nBlock, nDivisor, nOffset) ;
  1656. }
  1657. };
  1658. //=============================================================================
  1659. /**
  1660. * Standard 5x5 gaussian blur (>=24 bit).
  1661. @verbatim
  1662. example:
  1663. FCPixelGaussianBlur5x5 aCmd ;
  1664. img.SinglePixelProcessProc (aCmd) ;
  1665. @endverbatim
  1666. */
  1667. class FCPixelGaussianBlur5x5 : public FCPixelConvolute
  1668. {
  1669. public:
  1670. FCPixelGaussianBlur5x5 ()
  1671. {
  1672. int arKernel[] = {0,1,2,1,0,1,3,4,3,1,2,4,8,4,2,1,3,4,3,1,0,1,2,1,0},
  1673. nBlock = 5,
  1674. nDivisor = 52,
  1675. nOffset = 0 ;
  1676. SetKernel (arKernel, nBlock, nDivisor, nOffset) ;
  1677. }
  1678. };
  1679. //=============================================================================
  1680. /**
  1681. * Detect edges (>=24 bit).
  1682. @verbatim
  1683. example:
  1684. FCPixelDetectEdges aCmd(3) ;
  1685. img.SinglePixelProcessProc (aCmd) ;
  1686. @endverbatim
  1687. */
  1688. class FCPixelDetectEdges : public FCPixelConvolute
  1689. {
  1690. public:
  1691. /// Constructor (nRadius >= 1).
  1692. FCPixelDetectEdges (int nRadius = 3)
  1693. {
  1694. int nBlock = 2*FMax(1,nRadius) + 1,
  1695. nDivisor = 1,
  1696. nOffset = 0,
  1697. nWidth = nBlock * nBlock ;
  1698. PCL_array<int> pKernel (nWidth) ;
  1699. for (int i=0 ; i < nWidth ; i++)
  1700. pKernel[i] = -1 ;
  1701. pKernel[nWidth/2] = nWidth - 1 ;
  1702. SetKernel (pKernel.get(), nBlock, nDivisor, nOffset) ;
  1703. }
  1704. };
  1705. //=============================================================================
  1706. /**
  1707. * Sharp (laplacian template) (>=24 bit).
  1708. @verbatim
  1709. example:
  1710. FCPixelSharp aCmd(3) ;
  1711. img.SinglePixelProcessProc (aCmd) ;
  1712. @endverbatim
  1713. */
  1714. class FCPixelSharp : public FCPixelConvolute
  1715. {
  1716. public:
  1717. /// Constructor (nStep >= 1).
  1718. FCPixelSharp (int nStep)
  1719. {
  1720. int arKernel[] = {-1,-1,-1,-1,8+nStep,-1,-1,-1,-1},
  1721. nBlock = 3,
  1722. nDivisor = FMax (1,nStep),
  1723. nOffset = 0 ;
  1724. SetKernel (arKernel, nBlock, nDivisor, nOffset) ;
  1725. }
  1726. };
  1727. //=============================================================================
  1728. /// Base class of gradient fill (>=24 bit)
  1729. class FCPixelGradientBase : public FCSinglePixelProcessBase
  1730. {
  1731. public:
  1732. /// Constructor.
  1733. FCPixelGradientBase (RGBQUAD crStart, RGBQUAD crEnd, REPEAT_MODE nRepeat=REPEAT_NONE) : m_crStart(crStart), m_crEnd(crEnd), m_nRepeat(nRepeat) {}
  1734. protected:
  1735. /// calculate factor of point(x,y)
  1736. virtual double CalculateFactor (int nX, int nY) =0 ;
  1737. private:
  1738. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  1739. {
  1740. double fFac = this->CalculateFactor (x, y) ;
  1741. switch (m_nRepeat)
  1742. {
  1743. case REPEAT_NONE : fFac = FClamp (fFac, 0.0, 1.0); break;
  1744. case REPEAT_SAWTOOTH :
  1745. if (fFac < 0.0)
  1746. fFac = 1.0 - FDoubleMod1 (-fFac) ;
  1747. else
  1748. fFac = FDoubleMod1 (fFac) ;
  1749. break ;
  1750. case REPEAT_TRIANGULAR :
  1751. if (fFac < 0.0)
  1752. fFac = -fFac ;
  1753. if ( ((int)fFac) & 1 )
  1754. fFac = 1.0 - FDoubleMod1 (fFac) ;
  1755. else
  1756. fFac = FDoubleMod1 (fFac) ;
  1757. break ;
  1758. }
  1759. PCL_B(pPixel) = (BYTE)(PCL_B(&m_crStart) + (PCL_B(&m_crEnd)-PCL_B(&m_crStart)) * fFac) ;
  1760. PCL_G(pPixel) = (BYTE)(PCL_G(&m_crStart) + (PCL_G(&m_crEnd)-PCL_G(&m_crStart)) * fFac) ;
  1761. PCL_R(pPixel) = (BYTE)(PCL_R(&m_crStart) + (PCL_R(&m_crEnd)-PCL_R(&m_crStart)) * fFac) ;
  1762. }
  1763. double FDoubleMod1 (const double &x)
  1764. {
  1765. // the function <fmod> is extreme slow :-(, so we just do it.
  1766. // the function == fmod (x, 1.0)
  1767. return x - (int)x ;
  1768. }
  1769. RGBQUAD m_crStart, m_crEnd ;
  1770. REPEAT_MODE m_nRepeat ; // type of repeat
  1771. };
  1772. //=============================================================================
  1773. /**
  1774. * Gradient fill linear (>=24 bit).
  1775. @verbatim
  1776. example:
  1777. POINT ptStart={0,0}, ptEnd={100,100} ;
  1778. FCPixelGradientLine aCmd (ptStart, ptEnd, PCL_RGBA(0,0,0), PCL_RGBA(0,0,255), REPEAT_NONE) ;
  1779. img.SinglePixelProcessProc (aCmd) ;
  1780. @endverbatim
  1781. */
  1782. class FCPixelGradientLine : public FCPixelGradientBase
  1783. {
  1784. public:
  1785. /**
  1786. * Constructor.
  1787. * @param ptStart : start coordinate on image.
  1788. * @param ptEnd : end coordinate on image.
  1789. * @param nRepeat : REPEAT_NONE, REPEAT_SAWTOOTH, REPEAT_TRIANGULAR
  1790. */
  1791. FCPixelGradientLine (POINT ptStart, POINT ptEnd, RGBQUAD crStart, RGBQUAD crEnd, REPEAT_MODE nRepeat = REPEAT_NONE) : FCPixelGradientBase (crStart, crEnd, nRepeat)
  1792. {
  1793. m_ptStart = ptStart; m_ptEnd = ptEnd;
  1794. m_fDist = FHypot ((double)(m_ptStart.x-m_ptEnd.x), (double)(m_ptStart.y-m_ptEnd.y)) ;
  1795. m_fRatX = (m_ptEnd.x-m_ptStart.x) / m_fDist ;
  1796. m_fRatY = (m_ptEnd.y-m_ptStart.y) / m_fDist ;
  1797. }
  1798. protected:
  1799. virtual double CalculateFactor (int nX, int nY)
  1800. {
  1801. double rat = m_fRatX * (nX-m_ptStart.x) + m_fRatY * (nY-m_ptStart.y) ;
  1802. rat = rat / m_fDist ;
  1803. return (rat < 0.0) ? 0.0 : rat ;
  1804. }
  1805. protected:
  1806. POINT m_ptStart, m_ptEnd ; // coordinate on image
  1807. double m_fRatX, m_fRatY ;
  1808. double m_fDist ;
  1809. };
  1810. //=============================================================================
  1811. /**
  1812. * Gradient fill bilinear (>=24 bit).
  1813. @verbatim
  1814. example:
  1815. POINT ptStart={0,0}, ptEnd={100,100} ;
  1816. FCPixelGradientBiLine aCmd (ptStart, ptEnd, PCL_RGBA(0,0,0), PCL_RGBA(0,0,255), REPEAT_NONE) ;
  1817. img.SinglePixelProcessProc (aCmd) ;
  1818. @endverbatim
  1819. */
  1820. class FCPixelGradientBiLine : public FCPixelGradientLine
  1821. {
  1822. public:
  1823. /**
  1824. * Constructor.
  1825. * @param ptStart : start coordinate on image.
  1826. * @param ptEnd : end coordinate on image.
  1827. * @param nRepeat : REPEAT_NONE, REPEAT_SAWTOOTH, REPEAT_TRIANGULAR
  1828. */
  1829. FCPixelGradientBiLine (POINT ptStart, POINT ptEnd, RGBQUAD crStart, RGBQUAD crEnd, REPEAT_MODE nRepeat = REPEAT_NONE) : FCPixelGradientLine (ptStart, ptEnd, crStart, crEnd, nRepeat) {}
  1830. protected:
  1831. virtual double CalculateFactor (int nX, int nY)
  1832. {
  1833. double rat = m_fRatX * (nX-m_ptStart.x) + m_fRatY * (nY-m_ptStart.y) ;
  1834. rat = rat / m_fDist ;
  1835. return fabs(rat) ;
  1836. }
  1837. };
  1838. //=============================================================================
  1839. /**
  1840. * Gradient fill symmetric conical (>=24 bit).
  1841. @verbatim
  1842. example:
  1843. POINT ptStart={0,0}, ptEnd={100,100} ;
  1844. FCPixelGradientConicalSym aCmd (ptStart, ptEnd, PCL_RGBA(0,0,0), PCL_RGBA(0,0,255), REPEAT_NONE) ;
  1845. img.SinglePixelProcessProc (aCmd) ;
  1846. @endverbatim
  1847. */
  1848. class FCPixelGradientConicalSym : public FCPixelGradientLine
  1849. {
  1850. public:
  1851. /**
  1852. * Constructor.
  1853. * @param ptStart : start coordinate on image.
  1854. * @param ptEnd : end coordinate on image.
  1855. * @param nRepeat : REPEAT_NONE, REPEAT_SAWTOOTH, REPEAT_TRIANGULAR
  1856. */
  1857. FCPixelGradientConicalSym (POINT ptStart, POINT ptEnd, RGBQUAD crStart, RGBQUAD crEnd, REPEAT_MODE nRepeat = REPEAT_NONE) : FCPixelGradientLine (ptStart, ptEnd, crStart, crEnd, nRepeat) {}
  1858. protected:
  1859. virtual double CalculateFactor (int nX, int nY)
  1860. {
  1861. double rat ;
  1862. double dx = nX-m_ptStart.x, dy = nY-m_ptStart.y ;
  1863. if ((dx != 0) || (dy != 0))
  1864. {
  1865. double dr = FHypot (dx, dy) ;
  1866. rat = m_fRatX * dx / dr + m_fRatY * dy / dr ;
  1867. rat = FClamp (rat, -1.0, 1.0) ;
  1868. rat = acos(rat) / LIB_PI ;
  1869. rat = FClamp (rat, 0.0, 1.0) ;
  1870. }
  1871. else
  1872. rat = 0.5 ;
  1873. return rat ;
  1874. }
  1875. };
  1876. //=============================================================================
  1877. /**
  1878. * Gradient fill Anti-symmetric conical (>=24 bit).
  1879. @verbatim
  1880. example:
  1881. POINT ptStart={0,0}, ptEnd={100,100} ;
  1882. FCPixelGradientConicalSym aCmd (ptStart, ptEnd, PCL_RGBA(0,0,0), PCL_RGBA(0,0,255), REPEAT_NONE) ;
  1883. img.SinglePixelProcessProc (aCmd) ;
  1884. @endverbatim
  1885. */
  1886. class FCPixelGradientConicalASym : public FCPixelGradientLine
  1887. {
  1888. public:
  1889. /**
  1890. * Constructor.
  1891. * @param ptStart : start coordinate on image.
  1892. * @param ptEnd : end coordinate on image.
  1893. * @param nRepeat : REPEAT_NONE, REPEAT_SAWTOOTH, REPEAT_TRIANGULAR
  1894. */
  1895. FCPixelGradientConicalASym (POINT ptStart, POINT ptEnd, RGBQUAD crStart, RGBQUAD crEnd, REPEAT_MODE nRepeat = REPEAT_NONE) : FCPixelGradientLine (ptStart, ptEnd, crStart, crEnd, nRepeat) {}
  1896. protected:
  1897. virtual double CalculateFactor (int nX, int nY)
  1898. {
  1899. double rat ;
  1900. double dx = nX-m_ptStart.x, dy = nY-m_ptStart.y ;
  1901. if ((dx != 0) || (dy != 0))
  1902. {
  1903. double ang0, ang1, ang ;
  1904. ang0 = atan2 (m_fRatX, m_fRatY) + LIB_PI ;
  1905. ang1 = atan2 (dx, dy) + LIB_PI ;
  1906. ang = ang1 - ang0 ;
  1907. if (ang < 0.0)
  1908. ang += LIB_2PI ;
  1909. rat = ang / LIB_2PI ;
  1910. rat = FClamp (rat, 0.0, 1.0) ;
  1911. }
  1912. else
  1913. rat = 0.5 ;
  1914. return rat ;
  1915. }
  1916. };
  1917. //=============================================================================
  1918. /**
  1919. * Gradient fill rect (>=24 bit).
  1920. @verbatim
  1921. example:
  1922. RECT rc = {0, 0, 100, 100} ;
  1923. FCPixelGradientRect aCmd (rc, PCL_RGBA(0,0,0), PCL_RGBA(0,0,255), REPEAT_NONE) ;
  1924. img.SinglePixelProcessProc (aCmd) ;
  1925. @endverbatim
  1926. */
  1927. class FCPixelGradientRect : public FCPixelGradientBase
  1928. {
  1929. public:
  1930. /**
  1931. * Constructor.
  1932. * @param rcRect : rect on image.
  1933. * @param nRepeat : REPEAT_NONE, REPEAT_SAWTOOTH, REPEAT_TRIANGULAR
  1934. */
  1935. FCPixelGradientRect (RECT rcRect, RGBQUAD crStart, RGBQUAD crEnd, REPEAT_MODE nRepeat = REPEAT_NONE) : FCPixelGradientBase (crStart, crEnd, nRepeat)
  1936. {
  1937. assert (!IsRectEmpty(&rcRect)) ;
  1938. m_fCenX = (rcRect.left + rcRect.right) / 2.0 ;
  1939. m_fCenY = (rcRect.top + rcRect.bottom) / 2.0 ;
  1940. m_fRadiusX = RECTWIDTH(rcRect) / 2.0 ;
  1941. m_fRadiusY = RECTHEIGHT(rcRect) / 2.0 ;
  1942. }
  1943. protected:
  1944. virtual double CalculateFactor (int nX, int nY)
  1945. {
  1946. double ratX = fabs((nX-m_fCenX) / m_fRadiusX),
  1947. ratY = fabs((nY-m_fCenY) / m_fRadiusY) ;
  1948. return FMax(ratX, ratY) ;
  1949. }
  1950. protected:
  1951. double m_fCenX, m_fCenY ;
  1952. double m_fRadiusX, m_fRadiusY ;
  1953. };
  1954. //=============================================================================
  1955. /**
  1956. * Gradient fill radial (>=24 bit).
  1957. @verbatim
  1958. example:
  1959. RECT rc = {0, 0, 100, 100} ;
  1960. FCPixelGradientRadial aCmd (rc, PCL_RGBA(0,0,0), PCL_RGBA(0,0,255), REPEAT_NONE) ;
  1961. img.SinglePixelProcessProc (aCmd) ;
  1962. @endverbatim
  1963. */
  1964. class FCPixelGradientRadial : public FCPixelGradientBase
  1965. {
  1966. public:
  1967. /**
  1968. * Constructor.
  1969. * @param rcEllipse : rect on image.
  1970. * @param nRepeat : REPEAT_NONE, REPEAT_SAWTOOTH, REPEAT_TRIANGULAR
  1971. */
  1972. FCPixelGradientRadial (RECT rcEllipse, RGBQUAD crStart, RGBQUAD crEnd, REPEAT_MODE nRepeat = REPEAT_NONE) : FCPixelGradientBase (crStart, crEnd, nRepeat)
  1973. {
  1974. assert (!IsRectEmpty(&rcEllipse)) ;
  1975. m_fCenX = (rcEllipse.left + rcEllipse.right) / 2.0 ;
  1976. m_fCenY = (rcEllipse.top + rcEllipse.bottom) / 2.0 ;
  1977. m_fRadiusX = RECTWIDTH(rcEllipse) / 2.0 ;
  1978. m_fRadiusY = RECTHEIGHT(rcEllipse) / 2.0 ;
  1979. }
  1980. protected:
  1981. virtual double CalculateFactor (int nX, int nY)
  1982. {
  1983. double rat = FHypot((nX-m_fCenX)/m_fRadiusX, (nY-m_fCenY)/m_fRadiusY) ;
  1984. return rat ;
  1985. }
  1986. private:
  1987. double m_fCenX, m_fCenY ;
  1988. double m_fRadiusX, m_fRadiusY ;
  1989. };
  1990. //=============================================================================
  1991. /// Bilinear distord (>=24 bit).
  1992. /// if derived class override OnEnterProcess, it must call OnEnterProcess of base.
  1993. class FCPixelBilinearDistord : public FCSinglePixelProcessBase
  1994. {
  1995. protected:
  1996. virtual bool ValidateColorBits (const FCObjImage* pImg)
  1997. {
  1998. return FCSinglePixelProcessBase::ValidateColorBits(pImg) && (pImg->Width() >= 2) && (pImg->Height() >= 2) ;
  1999. }
  2000. virtual void OnEnterProcess (FCObjImage* pImg)
  2001. {
  2002. SetBackupImage (pImg) ;
  2003. }
  2004. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  2005. {
  2006. double un_x, un_y ;
  2007. if (!calc_undistorted_coord (x, y, un_x, un_y))
  2008. return ;
  2009. un_x = FClamp (un_x, 0.0, GetBackupImage()->Width() - 1.1) ;
  2010. un_y = FClamp (un_y, 0.0, GetBackupImage()->Height() - 1.1) ;
  2011. const int nSrcX = (int)un_x, nSrcY = (int)un_y,
  2012. nSrcX_1 = nSrcX+1, nSrcY_1 = nSrcY+1 ;
  2013. const BYTE * pcrPixel[4] =
  2014. {
  2015. GetBackupImage()->GetBits(nSrcX,nSrcY),
  2016. GetBackupImage()->GetBits(nSrcX_1,nSrcY),
  2017. GetBackupImage()->GetBits(nSrcX,nSrcY_1),
  2018. GetBackupImage()->GetBits(nSrcX_1,nSrcY_1)
  2019. } ;
  2020. RGBQUAD cr = FCColor::Get_Bilinear_Pixel (un_x-nSrcX, un_y-nSrcY, pImg->ColorBits() == 32, pcrPixel) ;
  2021. FCColor::CopyPixel (pPixel, &cr, pImg->ColorBits()/8) ;
  2022. }
  2023. // returned bool variable to declare continue or not
  2024. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const =0 ;
  2025. };
  2026. //=============================================================================
  2027. /**
  2028. * Cylinder (>=24 bit).
  2029. @verbatim
  2030. example:
  2031. FCPixelCylinder aCmd ;
  2032. img.SinglePixelProcessProc (aCmd) ;
  2033. @endverbatim
  2034. */
  2035. class FCPixelCylinder : public FCPixelBilinearDistord
  2036. {
  2037. virtual void OnEnterProcess (FCObjImage* pImg)
  2038. {
  2039. FCPixelBilinearDistord::OnEnterProcess(pImg) ;
  2040. // pos in origin image.
  2041. double R = pImg->Width() / 2.0 ;
  2042. for (int x=0 ; x < pImg->Width() ; x++)
  2043. {
  2044. double fIndex = pImg->Width() * acos ((R-x)/R) / LIB_PI ;
  2045. m_ColIndex.push_back (fIndex) ;
  2046. }
  2047. }
  2048. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2049. {
  2050. un_x = m_ColIndex[x] ;
  2051. un_y = y ;
  2052. return true ;
  2053. }
  2054. std::deque<double> m_ColIndex ;
  2055. };
  2056. //=============================================================================
  2057. /**
  2058. * Wave (>=24 bit).
  2059. @verbatim
  2060. example:
  2061. FCPixelWave aCmd (25, 30) ;
  2062. img.SinglePixelProcessProc (aCmd) ;
  2063. @endverbatim
  2064. */
  2065. class FCPixelWave : public FCPixelBilinearDistord
  2066. {
  2067. public:
  2068. /// Constructor.
  2069. FCPixelWave (int nWavelength, int nAmplitude, double fPhase=0) : m_nWavelength(2*FMax(1,nWavelength)), m_nAmplitude(FMax(1,nAmplitude)), m_fPhase(fPhase) {}
  2070. private:
  2071. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2072. {
  2073. const int nImgWidth = GetBackupImage()->Width(),
  2074. nImgHeight = GetBackupImage()->Height() ;
  2075. double fScaleX = 1.0, fScaleY = 1.0 ;
  2076. if (nImgWidth < nImgHeight)
  2077. fScaleX = nImgHeight / (double)nImgWidth ;
  2078. else if (nImgWidth > nImgHeight)
  2079. fScaleY = nImgWidth / (double)nImgHeight ;
  2080. // Distances to center, scaled
  2081. double fCenX = GetBackupImage()->Width() / 2.0,
  2082. fCenY = GetBackupImage()->Height() / 2.0,
  2083. dx = (x - fCenX) * fScaleX,
  2084. dy = (y - fCenY) * fScaleY,
  2085. amnt = m_nAmplitude * sin (LIB_2PI * FHypot(dx,dy) / (double)m_nWavelength + m_fPhase) ;
  2086. un_x = (amnt + dx) / fScaleX + fCenX ;
  2087. un_y = (amnt + dy) / fScaleY + fCenY ;
  2088. return true ;
  2089. }
  2090. double m_fPhase ; // [0..2n]
  2091. int m_nAmplitude ;
  2092. int m_nWavelength ;
  2093. };
  2094. //=============================================================================
  2095. /**
  2096. * Whirl & Pinch (>=24 bit).
  2097. @verbatim
  2098. example:
  2099. FCPixelWhirlPinch aCmd (1.5, 0.5) ;
  2100. img.SinglePixelProcessProc (aCmd) ;
  2101. @endverbatim
  2102. */
  2103. class FCPixelWhirlPinch : public FCPixelBilinearDistord
  2104. {
  2105. public:
  2106. /// Constructor.
  2107. /// @param fWhirl : [-2n,2n]
  2108. /// @param fPinch : [-1.0,1.0]
  2109. FCPixelWhirlPinch (double fWhirl, double fPinch)
  2110. {
  2111. m_fWhirl = FClamp (fWhirl, -LIB_2PI, LIB_2PI) ;
  2112. m_fPinch = FClamp (fPinch, -1.0, 1.0) ;
  2113. }
  2114. private:
  2115. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2116. {
  2117. int nImgWidth = GetBackupImage()->Width(),
  2118. nImgHeight = GetBackupImage()->Height() ;
  2119. double fScaleX = 1.0, fScaleY = 1.0 ;
  2120. if (nImgWidth < nImgHeight)
  2121. fScaleX = nImgHeight / (double)nImgWidth ;
  2122. else if (nImgWidth > nImgHeight)
  2123. fScaleY = nImgWidth / (double)nImgHeight ;
  2124. // Distances to center, scaled
  2125. double fCenX = GetBackupImage()->Width() / 2.0,
  2126. fCenY = GetBackupImage()->Height() / 2.0,
  2127. fRadius = FMax (fCenX, fCenY),
  2128. dx = (x - fCenX) * fScaleX,
  2129. dy = (y - fCenY) * fScaleY ;
  2130. double d = dx*dx + dy*dy ; // Distance^2 to center of *circle* (scaled ellipse)
  2131. double fSqrtD = sqrt (d) ;
  2132. // If we are inside circle, then distort, else, just return the same position
  2133. bool bInside = (fSqrtD < fRadius) ;
  2134. // exclude center point
  2135. if (fSqrtD < FLT_EPSILON)
  2136. bInside = false ;
  2137. if (bInside)
  2138. {
  2139. // double fDist = sqrt (d / m_fRadiusScale) / m_fRadius ;
  2140. double fDist = fSqrtD / fRadius ;
  2141. // Pinch
  2142. double fFactor = pow (sin (LIB_PI / 2.0 * fDist), -m_fPinch) ;
  2143. dx *= fFactor ; dy *= fFactor ;
  2144. // Whirl
  2145. double fAng = m_fWhirl * FSquare (1.0 - fDist) ;
  2146. double sina = sin (fAng), cosa = cos (fAng) ;
  2147. un_x = (cosa * dx - sina * dy) / fScaleX + fCenX ;
  2148. un_y = (sina * dx + cosa * dy) / fScaleY + fCenY ;
  2149. }
  2150. else
  2151. {
  2152. un_x = x ; un_y = y ;
  2153. }
  2154. return bInside;
  2155. }
  2156. double m_fWhirl ; // radian of whirl
  2157. double m_fPinch ; // [-1.0, 1.0]
  2158. // double m_fRadiusScale ; // [0.0, 2.0]
  2159. };
  2160. //=============================================================================
  2161. /**
  2162. * Fractal trace (>=24 bit).
  2163. @verbatim
  2164. example:
  2165. FCPixelFractalTrace aCmd (2) ;
  2166. img.SinglePixelProcessProc (aCmd) ;
  2167. @endverbatim
  2168. */
  2169. class FCPixelFractalTrace : public FCPixelBilinearDistord
  2170. {
  2171. public:
  2172. /// Constructor (nDepth >= 1).
  2173. FCPixelFractalTrace (int nDepth) : m_nDepth(FMax(1,nDepth)) {}
  2174. private:
  2175. void mandelbrot (const double& x, const double& y, double* u, double* v) const
  2176. {
  2177. int iter = 0 ;
  2178. double xx = x, yy = y ;
  2179. double x2 = xx * xx,
  2180. y2 = yy * yy ;
  2181. while (iter++ < m_nDepth)
  2182. {
  2183. const double tmp = x2 - y2 + x ;
  2184. yy = 2 * xx * yy + y ;
  2185. xx = tmp ;
  2186. x2 = xx * xx ;
  2187. y2 = yy * yy ;
  2188. }
  2189. *u = xx ; *v = yy ;
  2190. }
  2191. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2192. {
  2193. double fImgWidth = GetBackupImage()->Width(),
  2194. fImgHeight = GetBackupImage()->Height(),
  2195. fScaleX = 1.5 / fImgWidth,
  2196. fScaleY = 2.0 / fImgHeight,
  2197. cy = -1.0 + y * fScaleY,
  2198. cx = -1.0 + x * fScaleX,
  2199. px, py ;
  2200. mandelbrot (cx, cy, &px, &py) ;
  2201. un_x = (px + 1.0) / fScaleX ;
  2202. un_y = (py + 1.0) / fScaleY ;
  2203. if ( !(0 <= un_x && un_x < fImgWidth && 0 <= un_y && un_y < fImgHeight) )
  2204. {
  2205. un_x = fmod (un_x, fImgWidth) ;
  2206. un_y = fmod (un_y, fImgHeight) ;
  2207. if (un_x < 0.0) un_x += fImgWidth ;
  2208. if (un_y < 0.0) un_y += fImgHeight ;
  2209. }
  2210. return true ;
  2211. }
  2212. int m_nDepth ; // >=1
  2213. };
  2214. //=============================================================================
  2215. /**
  2216. * Lens (>=24 bit).
  2217. @verbatim
  2218. example:
  2219. FCPixelLens aCmd (1.5) ;
  2220. img.SinglePixelProcessProc (aCmd) ;
  2221. @endverbatim
  2222. */
  2223. class FCPixelLens : public FCPixelBilinearDistord
  2224. {
  2225. public:
  2226. /// Constructor (fRefraction >= 1.0).
  2227. FCPixelLens (double fRefraction, bool bKeepBk) : m_fRefraction(FMax(1.0,fRefraction)), m_bKeepBk(bKeepBk) {}
  2228. private:
  2229. virtual void OnEnterProcess (FCObjImage* pImg)
  2230. {
  2231. FCPixelBilinearDistord::OnEnterProcess (pImg) ;
  2232. // clear background ?
  2233. if (!m_bKeepBk)
  2234. memset (pImg->GetMemStart(), 0, pImg->GetPitch()*pImg->Height()) ;
  2235. }
  2236. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2237. {
  2238. const double fCenX = GetBackupImage()->Width() / 2.0,
  2239. fCenY = GetBackupImage()->Height() / 2.0,
  2240. asqr = fCenX * fCenX,
  2241. bsqr = fCenY * fCenY,
  2242. csqr = FSquare(FMin(fCenX,fCenY)),
  2243. dy = fCenY - y,
  2244. ysqr = FSquare(dy),
  2245. dx = x - fCenX,
  2246. xsqr = FSquare(dx) ;
  2247. if (ysqr < (bsqr - (bsqr * xsqr) / asqr))
  2248. {
  2249. double fTmp = sqrt ((1 - xsqr/asqr - ysqr/bsqr) * csqr) ;
  2250. double fTmpsqr = FSquare(fTmp) ;
  2251. double nxangle = acos (dx / sqrt(xsqr+fTmpsqr)) ;
  2252. double theta2 = asin (sin (LIB_PI/2.0 - nxangle) / m_fRefraction) ;
  2253. theta2 = LIB_PI/2.0 - nxangle - theta2 ;
  2254. double xx = dx - tan (theta2) * fTmp ;
  2255. double nyangle = acos (dy / sqrt(ysqr+fTmpsqr)) ;
  2256. theta2 = asin (sin (LIB_PI/2.0 - nyangle) / m_fRefraction) ;
  2257. theta2 = LIB_PI/2.0 - nyangle - theta2 ;
  2258. double yy = dy - tan (theta2) * fTmp ;
  2259. un_x = xx + fCenX ;
  2260. un_y = fCenY - yy ;
  2261. return true ;
  2262. }
  2263. return false ;
  2264. }
  2265. double m_fRefraction ; // >= 1.0
  2266. bool m_bKeepBk ;
  2267. };
  2268. //=============================================================================
  2269. /**
  2270. * Skew transform (>=24 bit).
  2271. */
  2272. class FCPixelSkew : public FCPixelBilinearDistord
  2273. {
  2274. public:
  2275. /// Constructor.
  2276. /// @param ptPos, order by LT, RT, RB, LB
  2277. FCPixelSkew (const POINT ptPos[4])
  2278. {
  2279. memcpy (m_ptNewPos, ptPos, sizeof(POINT) * 4) ;
  2280. }
  2281. private:
  2282. virtual void OnEnterProcess (FCObjImage* pImg)
  2283. {
  2284. FCPixelBilinearDistord::OnEnterProcess (pImg) ;
  2285. // create skewed image
  2286. m_nNewWidth = FMax (abs(m_ptNewPos[0].x-m_ptNewPos[2].x), abs(m_ptNewPos[1].x-m_ptNewPos[3].x)) ;
  2287. m_nNewHeight = FMax (abs(m_ptNewPos[0].y-m_ptNewPos[2].y), abs(m_ptNewPos[1].y-m_ptNewPos[3].y)) ;
  2288. pImg->Create (m_nNewWidth, m_nNewHeight, pImg->ColorBits()) ;
  2289. }
  2290. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2291. {
  2292. if (m_ptNewPos[0].x != m_ptNewPos[3].x)
  2293. {
  2294. // x axis slope
  2295. const int nDelta = m_ptNewPos[0].x - m_ptNewPos[3].x ;
  2296. un_x = x - ((nDelta > 0) ? (m_nNewHeight - y) : y) * abs(nDelta) / (double)m_nNewHeight ;
  2297. un_y = y * GetBackupImage()->Height() / (double)m_nNewHeight ;
  2298. }
  2299. else if (m_ptNewPos[0].y != m_ptNewPos[1].y)
  2300. {
  2301. // y axis slope
  2302. const int nDelta = m_ptNewPos[0].y - m_ptNewPos[1].y ;
  2303. un_x = x * GetBackupImage()->Width() / (double)m_nNewWidth ;
  2304. un_y = y - ((nDelta > 0) ? (m_nNewWidth - x) : x) * abs(nDelta) / (double)m_nNewWidth ;
  2305. }
  2306. else
  2307. {
  2308. un_x=x ; un_y=y;
  2309. }
  2310. if (un_x<0.0 || un_x>GetBackupImage()->Width()-1 || un_y<0.0 || un_y>GetBackupImage()->Height()-1)
  2311. return false ;
  2312. else
  2313. return true ;
  2314. }
  2315. private:
  2316. POINT m_ptNewPos[4] ; // LT, RT, RB, LB
  2317. int m_nNewWidth ;
  2318. int m_nNewHeight ;
  2319. };
  2320. //=============================================================================
  2321. /**
  2322. * Perspective transform (>=24 bit).
  2323. */
  2324. class FCPixelPerspective : public FCPixelBilinearDistord
  2325. {
  2326. public:
  2327. /// Constructor.
  2328. /// @param ptPos, order by LT, RT, RB, LB
  2329. FCPixelPerspective (const POINT ptPos[4])
  2330. {
  2331. memcpy (m_ptNewPos, ptPos, sizeof(POINT) * 4) ;
  2332. }
  2333. private:
  2334. virtual void OnEnterProcess (FCObjImage* pImg)
  2335. {
  2336. FCPixelBilinearDistord::OnEnterProcess (pImg) ;
  2337. // create sloped image
  2338. m_nNewWidth = FMax (abs(m_ptNewPos[0].x-m_ptNewPos[1].x), abs(m_ptNewPos[2].x-m_ptNewPos[3].x)) ;
  2339. m_nNewHeight = FMax (abs(m_ptNewPos[0].y-m_ptNewPos[3].y), abs(m_ptNewPos[1].y-m_ptNewPos[2].y)) ;
  2340. pImg->Create (m_nNewWidth, m_nNewHeight, pImg->ColorBits()) ;
  2341. }
  2342. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2343. {
  2344. if (m_ptNewPos[0].y != m_ptNewPos[1].y)
  2345. {
  2346. // y axis perspective
  2347. int nDelta = abs(m_ptNewPos[0].y-m_ptNewPos[3].y) - abs(m_ptNewPos[1].y-m_ptNewPos[2].y) ;
  2348. double fOffset = fabs(nDelta * ((nDelta > 0) ? x : (m_nNewWidth-x)) / (2.0 * m_nNewWidth)) ;
  2349. un_y = GetBackupImage()->Height() * (y - fOffset) / (m_nNewHeight - 2.0 * fOffset) ;
  2350. un_x = GetBackupImage()->Width() * x / (double)m_nNewWidth ;
  2351. }
  2352. else if (m_ptNewPos[0].x != m_ptNewPos[3].x)
  2353. {
  2354. // x axis perspective
  2355. int nDelta = abs(m_ptNewPos[0].x-m_ptNewPos[1].x) - abs(m_ptNewPos[2].x-m_ptNewPos[3].x) ;
  2356. double fOffset = fabs(nDelta * ((nDelta > 0) ? y : (m_nNewHeight-y)) / (2.0 * m_nNewHeight)) ;
  2357. un_x = GetBackupImage()->Width() * (x - fOffset) / (m_nNewWidth - 2.0 * fOffset) ;
  2358. un_y = GetBackupImage()->Height() * y / (double)m_nNewHeight ;
  2359. }
  2360. else
  2361. {
  2362. un_x = x ; un_y = y ;
  2363. }
  2364. if (un_x<0.0 || un_x>GetBackupImage()->Width()-1 || un_y<0.0 || un_y>GetBackupImage()->Height()-1)
  2365. return false ;
  2366. else
  2367. return true ;
  2368. }
  2369. private:
  2370. POINT m_ptNewPos[4] ; // LT, RT, RB, LB
  2371. int m_nNewWidth ;
  2372. int m_nNewHeight ;
  2373. };
  2374. //=============================================================================
  2375. /**
  2376. * Rotate (>=24 bit).
  2377. @verbatim
  2378. example:
  2379. FCPixelRotate aCmd (37) ;
  2380. img.SinglePixelProcessProc (aCmd) ;
  2381. @endverbatim
  2382. */
  2383. class FCPixelRotate : public FCPixelBilinearDistord
  2384. {
  2385. public:
  2386. /// Constructor.
  2387. FCPixelRotate (int nAngle)
  2388. {
  2389. nAngle %= 360 ;
  2390. while (nAngle < 0)
  2391. nAngle += 360 ;
  2392. m_fAngle = AngleToRadian(nAngle) ;
  2393. m_fInvAngle = AngleToRadian(360 - nAngle) ;
  2394. }
  2395. private:
  2396. virtual void OnEnterProcess (FCObjImage* pImg)
  2397. {
  2398. FCPixelBilinearDistord::OnEnterProcess (pImg) ;
  2399. // calculate new width & height
  2400. const POINT_F ptCenter = {pImg->Width()/2.0, pImg->Height()/2.0} ;
  2401. const POINT ptLT = {0,0}, ptRT = {pImg->Width(),0},
  2402. ptLB = {0,pImg->Height()}, ptRB = {pImg->Width(), pImg->Height()} ;
  2403. POINT ptR[4] ;
  2404. ptR[0] = FClockwisePoint (ptLT, ptCenter, m_fAngle) ;
  2405. ptR[1] = FClockwisePoint (ptRT, ptCenter, m_fAngle) ;
  2406. ptR[2] = FClockwisePoint (ptLB, ptCenter, m_fAngle) ;
  2407. ptR[3] = FClockwisePoint (ptRB, ptCenter, m_fAngle) ;
  2408. int L = FMin(ptR[0].x,FMin(ptR[1].x,FMin(ptR[2].x,ptR[3].x))),
  2409. T = FMin(ptR[0].y,FMin(ptR[1].y,FMin(ptR[2].y,ptR[3].y))),
  2410. R = FMax(ptR[0].x,FMax(ptR[1].x,FMax(ptR[2].x,ptR[3].x))),
  2411. B = FMax(ptR[0].y,FMax(ptR[1].y,FMax(ptR[2].y,ptR[3].y))) ;
  2412. m_nNewWidth = R - L ;
  2413. m_nNewHeight = B - T ;
  2414. pImg->Create (m_nNewWidth, m_nNewHeight, pImg->ColorBits()) ;
  2415. }
  2416. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2417. {
  2418. const POINT ptRot = {x, y} ;
  2419. const POINT_F ptCenter = {(m_nNewWidth-1)/2.0, (m_nNewHeight-1)/2.0} ;
  2420. POINT ptR = FClockwisePoint (ptRot, ptCenter, m_fInvAngle) ;
  2421. un_x = ptR.x ;
  2422. un_y = ptR.y ;
  2423. const double fOffX = (m_nNewWidth - GetBackupImage()->Width()) / 2.0,
  2424. fOffY = (m_nNewHeight - GetBackupImage()->Height()) / 2.0 ;
  2425. un_x -= fOffX ;
  2426. un_y -= fOffY ;
  2427. if (un_x<0.0 || un_x>GetBackupImage()->Width()-1 || un_y<0.0 || un_y>GetBackupImage()->Height()-1)
  2428. return false ;
  2429. else
  2430. return true ;
  2431. }
  2432. double m_fAngle, m_fInvAngle ;
  2433. int m_nNewWidth, m_nNewHeight ;
  2434. };
  2435. //=============================================================================
  2436. /**
  2437. * Ribbon (>=24 bit).
  2438. @verbatim
  2439. example:
  2440. FCPixelRibbon aCmd (80, 30) ;
  2441. img.SinglePixelProcessProc (aCmd) ;
  2442. @endverbatim
  2443. */
  2444. class FCPixelRibbon : public FCPixelBilinearDistord
  2445. {
  2446. public:
  2447. /// Constructor.
  2448. /// @param nSwing : [0..100], percentage
  2449. /// @param nFrequency : >=0, a pi every 10
  2450. FCPixelRibbon (int nSwing, int nFrequency)
  2451. {
  2452. m_nSwing = FClamp (nSwing, 0, 100) ;
  2453. m_nFreq = FMax (nFrequency, 0) ;
  2454. }
  2455. private:
  2456. virtual void OnEnterProcess (FCObjImage* pImg)
  2457. {
  2458. FCPixelBilinearDistord::OnEnterProcess (pImg) ;
  2459. // clear image
  2460. memset (pImg->GetMemStart(), 0, pImg->GetPitch()*pImg->Height()) ;
  2461. m_nDelta = m_nSwing * pImg->Height() * 75/100/100 ; // upper, max 75%
  2462. const double fAngleSpan = m_nFreq * LIB_PI / pImg->Width() / 10.0 ;
  2463. for (int x=0 ; x < pImg->Width() ; x++)
  2464. {
  2465. int nPush = FRound ((1.0-cos(x * fAngleSpan)) * m_nDelta / 2.0) ;
  2466. m_ShiftDown.push_back (nPush) ;
  2467. }
  2468. }
  2469. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2470. {
  2471. un_x = x ;
  2472. un_y = y + m_nDelta - m_ShiftDown[x] ;
  2473. if ((un_y < m_nDelta) || (un_y > GetBackupImage()->Height()-1))
  2474. return false ;
  2475. return true ;
  2476. }
  2477. int m_nSwing, m_nFreq ;
  2478. int m_nDelta ;
  2479. std::deque<int> m_ShiftDown ;
  2480. };
  2481. //=============================================================================
  2482. /**
  2483. * Ripple (>=24 bit).
  2484. @verbatim
  2485. example:
  2486. FCPixelRipple aCmd (10, 30) ;
  2487. img.SinglePixelProcessProc (aCmd) ;
  2488. @endverbatim
  2489. */
  2490. class FCPixelRipple : public FCPixelBilinearDistord
  2491. {
  2492. public:
  2493. /// Constructor.
  2494. FCPixelRipple (int nWavelength, int nAmplitude, bool bSinType = true)
  2495. {
  2496. m_nWavelength = FMax (1, nWavelength) ;
  2497. m_nAmplitude = FMax (1, nAmplitude) ;
  2498. m_bSinType = bSinType ;
  2499. }
  2500. private:
  2501. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2502. {
  2503. const double fWidth = GetBackupImage()->Width() ;
  2504. un_x = fmod (x + fWidth + shift_amount(y), fWidth) ;
  2505. un_y = y ;
  2506. return true ;
  2507. }
  2508. double shift_amount (int nPos) const
  2509. {
  2510. if (m_bSinType)
  2511. return m_nAmplitude * sin(nPos*LIB_2PI/(double)m_nWavelength) ;
  2512. else
  2513. return floor (m_nAmplitude * (fabs ((((nPos % m_nWavelength) / (double)m_nWavelength) * 4) - 2) - 1)) ;
  2514. }
  2515. int m_nWavelength ;
  2516. int m_nAmplitude ;
  2517. bool m_bSinType ;
  2518. };
  2519. //=============================================================================
  2520. /**
  2521. * Tile (>=24 bit).
  2522. @verbatim
  2523. example:
  2524. FCPixelSmallTile aCmd (2,2) ;
  2525. img.SinglePixelProcessProc (aCmd) ;
  2526. @endverbatim
  2527. */
  2528. class FCPixelSmallTile : public FCPixelBilinearDistord
  2529. {
  2530. public:
  2531. /// Constructor.
  2532. FCPixelSmallTile (int nXNum, int nYNum) : m_nXNum(FMax(1,nXNum)), m_nYNum(FMax(1,nYNum)) {}
  2533. private:
  2534. virtual bool calc_undistorted_coord (int x, int y, double& un_x, double& un_y) const
  2535. {
  2536. un_x = (x * m_nXNum) % GetBackupImage()->Width() ;
  2537. un_y = (y * m_nYNum) % GetBackupImage()->Height() ;
  2538. return true ;
  2539. }
  2540. int m_nXNum ;
  2541. int m_nYNum ;
  2542. };
  2543. //=============================================================================
  2544. /// LUT(look up table) routine (>=24 bit)
  2545. class FCPixelLUTRoutine : public FCSinglePixelProcessBase
  2546. {
  2547. public:
  2548. /// Constructor.
  2549. /// @param nChannel : process channel, use OR to combine
  2550. FCPixelLUTRoutine (IMAGE_CHANNEL nChannel = CHANNEL_RGB)
  2551. {
  2552. m_bChannelR = nChannel & CHANNEL_RED ;
  2553. m_bChannelG = nChannel & CHANNEL_GREEN ;
  2554. m_bChannelB = nChannel & CHANNEL_BLUE ;
  2555. }
  2556. protected:
  2557. /// Initialize LUT.
  2558. virtual int InitLUTtable (int nLUTIndex) =0 ;
  2559. private:
  2560. virtual void OnEnterProcess (FCObjImage* pImg)
  2561. {
  2562. for (int i=0 ; i <= 0xFF ; i++)
  2563. m_LUT[i] = this->InitLUTtable (i) ;
  2564. }
  2565. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  2566. {
  2567. if (m_bChannelB) PCL_B(pPixel) = m_LUT[PCL_B(pPixel)] ;
  2568. if (m_bChannelG) PCL_G(pPixel) = m_LUT[PCL_G(pPixel)] ;
  2569. if (m_bChannelR) PCL_R(pPixel) = m_LUT[PCL_R(pPixel)] ;
  2570. }
  2571. private:
  2572. int m_LUT[256] ;
  2573. int m_bChannelR, m_bChannelG, m_bChannelB ;
  2574. };
  2575. //=============================================================================
  2576. /**
  2577. * Adjust brightness (>=24 bit).
  2578. @verbatim
  2579. example:
  2580. FCPixelBrightness aCmd (150) ;
  2581. img.SinglePixelProcessProc (aCmd) ;
  2582. @endverbatim
  2583. */
  2584. class FCPixelBrightness : public FCPixelLUTRoutine
  2585. {
  2586. public:
  2587. /// Constructor (param's unit is percentage).
  2588. FCPixelBrightness (int nPercent, IMAGE_CHANNEL nChannel = CHANNEL_RGB) : FCPixelLUTRoutine(nChannel), m_nPercent(FMax(0,nPercent)) {}
  2589. private:
  2590. virtual int InitLUTtable (int nLUTIndex)
  2591. {
  2592. return FClamp0255 (nLUTIndex * m_nPercent / 100) ;
  2593. }
  2594. int m_nPercent ;
  2595. };
  2596. //=============================================================================
  2597. /**
  2598. * Adjust contrast (>=24 bit).
  2599. @verbatim
  2600. example:
  2601. FCPixelContrast aCmd (150) ;
  2602. img.SinglePixelProcessProc (aCmd) ;
  2603. @endverbatim
  2604. */
  2605. class FCPixelContrast : public FCPixelLUTRoutine
  2606. {
  2607. public:
  2608. /// Constructor (param's unit is percentage).
  2609. FCPixelContrast (int nPercent, IMAGE_CHANNEL nChannel = CHANNEL_RGB) : FCPixelLUTRoutine(nChannel), m_nPercent(FMax(0,nPercent)) {}
  2610. private:
  2611. virtual int InitLUTtable (int nLUTIndex)
  2612. {
  2613. return FClamp0255 (128 + (nLUTIndex - 128) * m_nPercent / 100) ;
  2614. }
  2615. int m_nPercent ;
  2616. };
  2617. //=============================================================================
  2618. /**
  2619. * Adjust gamma (>=24 bit).
  2620. @verbatim
  2621. example:
  2622. FCPixelGamma aCmd (0.5) ;
  2623. img.SinglePixelProcessProc (aCmd) ;
  2624. @endverbatim
  2625. */
  2626. class FCPixelGamma : public FCPixelLUTRoutine
  2627. {
  2628. public:
  2629. /// Constructor (param must >= 0.0).
  2630. FCPixelGamma (double fGamma, IMAGE_CHANNEL nChannel = CHANNEL_RGB) : FCPixelLUTRoutine(nChannel)
  2631. {
  2632. fGamma = FMax (0.0, fGamma) ;
  2633. m_fInvGamma = 1.0 / fGamma ;
  2634. }
  2635. private:
  2636. virtual int InitLUTtable (int nLUTIndex)
  2637. {
  2638. double fMax = pow (255.0, m_fInvGamma) / 255.0 ;
  2639. return FClamp0255 (FRound (pow((double)nLUTIndex, m_fInvGamma) / fMax)) ;
  2640. }
  2641. double m_fInvGamma ;
  2642. };
  2643. //=============================================================================
  2644. /**
  2645. * Negate image(>=24 bit).
  2646. @verbatim
  2647. example:
  2648. FCPixelInvert aCmd ;
  2649. img.SinglePixelProcessProc (aCmd) ;
  2650. @endverbatim
  2651. */
  2652. class FCPixelInvert : public FCPixelLUTRoutine
  2653. {
  2654. public:
  2655. FCPixelInvert (IMAGE_CHANNEL nChannel = CHANNEL_RGB) : FCPixelLUTRoutine(nChannel) {}
  2656. private:
  2657. virtual int InitLUTtable (int nLUTIndex)
  2658. {
  2659. return (255 - nLUTIndex) ;
  2660. }
  2661. };
  2662. //=============================================================================
  2663. /**
  2664. * Solarize image(>=24 bit).
  2665. @verbatim
  2666. example:
  2667. FCPixelSolarize aCmd (128) ;
  2668. img.SinglePixelProcessProc (aCmd) ;
  2669. @endverbatim
  2670. */
  2671. class FCPixelSolarize : public FCPixelLUTRoutine
  2672. {
  2673. public:
  2674. /// Constructor (nThreshold in [0-255]).
  2675. FCPixelSolarize (int nThreshold, IMAGE_CHANNEL nChannel = CHANNEL_RGB) : FCPixelLUTRoutine(nChannel), m_nThreshold(FClamp0255(nThreshold)) {}
  2676. private:
  2677. virtual int InitLUTtable (int nLUTIndex)
  2678. {
  2679. return (nLUTIndex >= m_nThreshold) ? (255 - nLUTIndex) : nLUTIndex ;
  2680. }
  2681. int m_nThreshold ;
  2682. };
  2683. //=============================================================================
  2684. /**
  2685. * Posterize image(>=24 bit).
  2686. @verbatim
  2687. example:
  2688. FCPixelPosterize aCmd (2) ;
  2689. img.SinglePixelProcessProc (aCmd) ;
  2690. @endverbatim
  2691. */
  2692. class FCPixelPosterize : public FCPixelLUTRoutine
  2693. {
  2694. public:
  2695. /// Constructor (nLevel >= 2).
  2696. FCPixelPosterize (int nLevel, IMAGE_CHANNEL nChannel = CHANNEL_RGB) : FCPixelLUTRoutine(nChannel), m_nLevel(FMax(2,nLevel)) {}
  2697. private:
  2698. virtual int InitLUTtable (int nLUTIndex)
  2699. {
  2700. double du1 = 255.0 / (m_nLevel - 1.0) ;
  2701. return FClamp0255 (FRound (du1 * FRound (nLUTIndex / du1))) ;
  2702. }
  2703. int m_nLevel ;
  2704. };
  2705. //=============================================================================
  2706. /**
  2707. * Count image's number of color (>=24 bit).
  2708. @verbatim
  2709. example:
  2710. FCPixelColorsCount aCmd ;
  2711. img.SinglePixelProcessProc (aCmd) ;
  2712. aCmd.GetColorsNumber() ;
  2713. @endverbatim
  2714. */
  2715. class FCPixelColorsCount : public FCSinglePixelProcessBase
  2716. {
  2717. public:
  2718. FCPixelColorsCount() : m_pMap(0), m_nCount(0) {}
  2719. virtual ~FCPixelColorsCount() {if(m_pMap) delete[] m_pMap;}
  2720. /// Get used number of color.
  2721. unsigned int GetColorsNumber() const {return m_nCount;}
  2722. protected:
  2723. virtual void OnEnterProcess (FCObjImage* pImg)
  2724. {
  2725. int iMaxColor = 1 << 24 ;
  2726. m_pMap = new BYTE[iMaxColor+1] ;
  2727. memset (m_pMap, 0, iMaxColor+1) ;
  2728. }
  2729. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  2730. {
  2731. DWORD i = 0 ;
  2732. FCColor::CopyPixel (&i, pPixel, 3) ;
  2733. if (m_pMap[i] == 0)
  2734. {
  2735. m_pMap[i] = 1 ;
  2736. m_nCount++ ;
  2737. }
  2738. }
  2739. unsigned int m_nCount ;
  2740. BYTE * m_pMap ;
  2741. };
  2742. //=============================================================================
  2743. /**
  2744. * Find a color unused in image (>=24 bit).
  2745. @verbatim
  2746. example:
  2747. FCPixelGetKeyColor aCmd ;
  2748. img.SinglePixelProcessProc (aCmd) ;
  2749. aCmd.IsFind() ;
  2750. aCmd.GetKeyColor() ;
  2751. @endverbatim
  2752. */
  2753. class FCPixelGetKeyColor : public FCPixelColorsCount
  2754. {
  2755. public:
  2756. /// Is found a color unused in image.
  2757. bool IsFind() const {return m_bFind;}
  2758. /// Get the color unused in image.
  2759. RGBQUAD GetKeyColor() const {return m_crKey;}
  2760. private:
  2761. virtual void OnLeaveProcess (FCObjImage* pImg)
  2762. {
  2763. m_bFind = false ;
  2764. for (int i=0 ; i <= 0xFFFFFF ; i++)
  2765. if (m_pMap[i] == 0)
  2766. {
  2767. *(DWORD*)&m_crKey = i ;
  2768. m_bFind = true ;
  2769. break ;
  2770. }
  2771. }
  2772. RGBQUAD m_crKey ;
  2773. bool m_bFind ;
  2774. };
  2775. //=============================================================================
  2776. /// Base class to process whole image.
  2777. class FCPixelWholeImageBase : public FCSinglePixelProcessBase
  2778. {
  2779. virtual PROCESS_TYPE QueryProcessType() {return PROCESS_TYPE_WHOLE;}
  2780. private:
  2781. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel) {assert(false);}
  2782. };
  2783. //=============================================================================
  2784. /**
  2785. * Save a ASCII text file (>=24 bit).
  2786. @verbatim
  2787. example:
  2788. FCPixelExportAscII aCmd ("c:\\PhoXo.txt") ;
  2789. img.SinglePixelProcessProc (aCmd) ;
  2790. @endverbatim
  2791. */
  2792. class FCPixelExportAscII : public FCPixelWholeImageBase
  2793. {
  2794. public:
  2795. /// Constructor.
  2796. FCPixelExportAscII (const char* szFileName)
  2797. {
  2798. #ifdef VC60
  2799. m_pFile = fopen (szFileName, "wb") ; assert(m_pFile);
  2800. #else
  2801. _tfopen_s(&m_pFile, szFileName, _T("wb"));
  2802. assert(m_pFile);
  2803. #endif
  2804. char ch[95] =
  2805. {
  2806. ' ',
  2807. '`','1','2','3','4','5','6','7','8','9','0','-','=','\\',
  2808. 'q','w','e','r','t','y','u','i','o','p','[',']',
  2809. 'a','s','d','f','g','h','j','k','l',';','\'',
  2810. 'z','x','c','v','b','n','m',',','.','/',
  2811. '~','!','@','#','$','%','^','&','*','(',')','_','+','|',
  2812. 'Q','W','E','R','T','Y','U','I','O','P','{','}',
  2813. 'A','S','D','F','G','H','J','K','L',':','"',
  2814. 'Z','X','C','V','B','N','M','<','>','?'
  2815. };
  2816. int gr[95] =
  2817. {
  2818. 0,
  2819. 7,22,28,31,31,27,32,22,38,32,40, 6,12,20,38,32,26,20,24,40,
  2820. 29,24,28,38,32,32,26,22,34,24,44,33,32,32,24,16, 6,22,26,22,
  2821. 26,34,29,35,10, 6,20,14,22,47,42,34,40,10,35,21,22,22,16,14,
  2822. 26,40,39,29,38,22,28,36,22,36,30,22,22,36,26,36,25,34,38,24,
  2823. 36,22,12,12,26,30,30,34,39,42,41,18,18,22
  2824. };
  2825. // Bubble Sort
  2826. for (int i=0 ; i < 94 ; i++)
  2827. for (int j=i+1 ; j < 95 ; j++)
  2828. if (gr[i] > gr[j])
  2829. {
  2830. FSwap (ch[i], ch[j]) ;
  2831. FSwap (gr[i], gr[j]) ;
  2832. }
  2833. memcpy (m_chIndex, ch, 95*sizeof(char)) ;
  2834. memcpy (m_nGray, gr, 95*sizeof(int)) ;
  2835. }
  2836. virtual ~FCPixelExportAscII()
  2837. {
  2838. if (m_pFile)
  2839. fclose(m_pFile) ;
  2840. }
  2841. private:
  2842. virtual void OnEnterProcess (FCObjImage* pImg)
  2843. {
  2844. SetBackupImage (pImg) ;
  2845. }
  2846. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  2847. {
  2848. FCPixelInvert aCmd ; // most of image is brightness
  2849. GetBackupImage()->SinglePixelProcessProc (aCmd) ;
  2850. FCPixelConvertTo8BitGray aGray ;
  2851. GetBackupImage()->SinglePixelProcessProc (aGray) ;
  2852. const int nTransWidth = pImg->Width() / 8,
  2853. nTransHeight = pImg->Height() / 16 ;
  2854. for (int y=0 ; y < nTransHeight ; y++)
  2855. {
  2856. for (int x=0 ; x < nTransWidth ; x++)
  2857. {
  2858. int nGray = 0 ;
  2859. for (int k=0 ; k < 16 ; k++)
  2860. for(int h=0 ; h < 8 ; h++)
  2861. {
  2862. BYTE * pGray = GetBackupImage()->GetBits (8*x+h, y*16+k) ;
  2863. nGray += *pGray ;
  2864. }
  2865. nGray /= 16*8 ;
  2866. nGray = m_nGray[94] * nGray / 255 ;
  2867. int t = 0 ;
  2868. while (m_nGray[t+1] < nGray)
  2869. t++ ;
  2870. fwrite (&m_chIndex[t], 1, sizeof(char), m_pFile) ;
  2871. }
  2872. char tchar = (char)0x0D ;
  2873. fwrite (&tchar, 1, sizeof(char), m_pFile) ;
  2874. tchar = (char)0x0A ;
  2875. fwrite (&tchar, 1, sizeof(char), m_pFile) ;
  2876. }
  2877. }
  2878. char m_chIndex[95] ;
  2879. int m_nGray[95] ;
  2880. FILE * m_pFile ;
  2881. };
  2882. //=============================================================================
  2883. #ifdef PCL_3RD_LIBRARY_USE_FREEIMAGE
  2884. #include "../FreeImage_Helper.h"
  2885. /**
  2886. * Quantize image.
  2887. @verbatim
  2888. example:
  2889. FCPixelConvertQuantize aCmd (8) ;
  2890. img.SinglePixelProcessProc (aCmd) ;
  2891. @endverbatim
  2892. */
  2893. class FCPixelConvertQuantize : public FCPixelWholeImageBase
  2894. {
  2895. public:
  2896. /// Constructor (nBPP = 1 or 4 or 8).
  2897. FCPixelConvertQuantize (int nBPP) : m_nBPP(nBPP),m_nTransparency(-1) {}
  2898. int GetTransparencyIndex() {return m_nTransparency;}
  2899. private:
  2900. virtual bool ValidateColorBits (const FCObjImage* pImg)
  2901. {
  2902. if ((m_nBPP == 1) || (m_nBPP == 4) || (m_nBPP == 8))
  2903. return pImg->IsValidImage() ;
  2904. assert(false) ;
  2905. return false ;
  2906. }
  2907. virtual void OnEnterProcess (FCObjImage* pImg)
  2908. {
  2909. if (pImg->ColorBits() == 32)
  2910. {
  2911. // find a key color
  2912. FCPixelGetKeyColor aCmd ;
  2913. pImg->SinglePixelProcessProc (aCmd) ;
  2914. const RGBQUAD cr = aCmd.GetKeyColor() ;
  2915. // set pixel (alpha=0) key color
  2916. for (int y=0 ; y < pImg->Height() ; y++)
  2917. for (int x=0 ; x < pImg->Width() ; x++)
  2918. {
  2919. BYTE * p = pImg->GetBits(x,y) ;
  2920. if (PCL_A(p) == 0)
  2921. {
  2922. FCColor::CopyPixel (p, &cr, 3) ;
  2923. m_pt.x=x ; m_pt.y=y ;
  2924. m_nTransparency = 1 ;
  2925. }
  2926. }
  2927. }
  2928. SetBackupImage (pImg) ;
  2929. GetBackupImage()->ConvertTo24Bit() ; // easy to handle
  2930. }
  2931. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  2932. {
  2933. FIBITMAP * pFI = __pcl_AllocateFreeImage (*GetBackupImage()) ;
  2934. if (pFI)
  2935. {
  2936. FIBITMAP * pQu = FreeImage_ColorQuantizeEx (pFI, FIQ_NNQUANT, 1<<m_nBPP) ;
  2937. if (pQu)
  2938. {
  2939. __pcl_FreeImage_to_PCLImage (pQu, *pImg) ;
  2940. FreeImage_Unload (pQu) ;
  2941. }
  2942. FreeImage_Unload (pFI) ;
  2943. }
  2944. // set transparency
  2945. if (pImg->IsValidImage() && (m_nTransparency == 1) && pImg->IsInside(m_pt.x,m_pt.y))
  2946. {
  2947. m_nTransparency = (int)pImg->GetPixelData(m_pt.x,m_pt.y) ;
  2948. }
  2949. }
  2950. POINT m_pt ;
  2951. int m_nBPP ;
  2952. int m_nTransparency ;
  2953. };
  2954. #endif // PCL_3RD_LIBRARY_USE_FREEIMAGE
  2955. //=============================================================================
  2956. /**
  2957. * Glass tile (>=24 bit).
  2958. @verbatim
  2959. example:
  2960. FCPixelGlasstile aCmd (6, 6) ;
  2961. img.SinglePixelProcessProc (aCmd) ;
  2962. @endverbatim
  2963. */
  2964. class FCPixelGlasstile : public FCPixelWholeImageBase
  2965. {
  2966. public:
  2967. /// Constructor (account of X/Y tile).
  2968. FCPixelGlasstile (int nXTile, int nYTile)
  2969. {
  2970. m_nXTile = FMax(2, nXTile) ;
  2971. m_nYTile = FMax(2, nYTile) ;
  2972. }
  2973. private:
  2974. virtual void OnEnterProcess (FCObjImage* pImg)
  2975. {
  2976. SetBackupImage (pImg) ;
  2977. }
  2978. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  2979. {
  2980. int xhalv = m_nXTile / 2, yhalv = m_nYTile / 2 ;
  2981. int xplus = m_nXTile % 2, yplus = m_nYTile % 2 ;
  2982. int ymitt = 0, yoffs = 0 ;
  2983. for (int y=0 ; y < pImg->Height() ; y++)
  2984. {
  2985. int ypixel2 = FClamp (ymitt + yoffs*2, 0, pImg->Height()-1) ;
  2986. yoffs++ ;
  2987. if (yoffs == yhalv)
  2988. {
  2989. ymitt += m_nYTile ;
  2990. yoffs = -(yhalv + yplus) ;
  2991. }
  2992. int xmitt = 0, xoffs = 0 ;
  2993. for (int x=0 ; x < pImg->Width() ; x++)
  2994. {
  2995. int xpixel2 = FClamp (xmitt + xoffs*2, 0, pImg->Width()-1) ;
  2996. FCColor::CopyPixel (pImg->GetBits(x,y), GetBackupImage()->GetBits(xpixel2,ypixel2), pImg->ColorBits()/8) ;
  2997. xoffs++ ;
  2998. if (xoffs == xhalv)
  2999. {
  3000. xmitt += m_nXTile ;
  3001. xoffs = -(xhalv + xplus) ;
  3002. }
  3003. }
  3004. if (pProgress)
  3005. pProgress->SetProgress (100 * y / pImg->Height()) ;
  3006. }
  3007. }
  3008. int m_nXTile, m_nYTile ; // >=2
  3009. };
  3010. //=============================================================================
  3011. /**
  3012. * Box smooth (>=24 bit).
  3013. @verbatim
  3014. example:
  3015. FCPixelBlur_Box aCmd (5, true) ;
  3016. img.SinglePixelProcessProc (aCmd) ;
  3017. @endverbatim
  3018. */
  3019. class FCPixelBlur_Box : public FCPixelWholeImageBase
  3020. {
  3021. public:
  3022. /// Constructor.
  3023. FCPixelBlur_Box (int iBlockLen, bool bCopyEdge)
  3024. {
  3025. m_iBlock = FMax(2, iBlockLen) ;
  3026. m_bCopyEdge = bCopyEdge ;
  3027. }
  3028. private:
  3029. // if m_iBlock>200, the sum maybe exceed int32
  3030. void in_UpdateSum (int& R, int& G, int& B, int& A, const void* pAdd, const void* pSub)
  3031. {
  3032. int nAddA = (GetBackupImage()->ColorBits() == 32) ? PCL_A(pAdd) : 0xFF,
  3033. nSubA = (GetBackupImage()->ColorBits() == 32) ? PCL_A(pSub) : 0xFF ;
  3034. B = B + PCL_B(pAdd)*nAddA - PCL_B(pSub)*nSubA ;
  3035. G = G + PCL_G(pAdd)*nAddA - PCL_G(pSub)*nSubA ;
  3036. R = R + PCL_R(pAdd)*nAddA - PCL_R(pSub)*nSubA ;
  3037. A = A + nAddA - nSubA ;
  3038. }
  3039. void in_SetPixel (int R, int G, int B, int A, void* pPixel)
  3040. {
  3041. PCL_B(pPixel) = A ? (B/A) : 0 ;
  3042. PCL_G(pPixel) = A ? (G/A) : 0 ;
  3043. PCL_R(pPixel) = A ? (R/A) : 0 ;
  3044. if (GetBackupImage()->ColorBits() == 32)
  3045. PCL_A(pPixel) = A / FSquare(m_iBlock) ; // pixel number of block
  3046. }
  3047. virtual void OnEnterProcess (FCObjImage* pImg)
  3048. {
  3049. SetBackupImage (pImg) ;
  3050. // expand edge
  3051. int nLeftTop = m_iBlock/2, // left & top
  3052. nRightDown = nLeftTop; // right & bottom : -((m_iBlock % 2)^1)
  3053. GetBackupImage()->ExpandFrame (m_bCopyEdge, nLeftTop, nLeftTop, nRightDown, nRightDown) ;
  3054. }
  3055. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3056. {
  3057. // RGBA sum of every scanline start
  3058. int iFirstR=0, iFirstG=0, iFirstB=0, iFirstA=0 ;
  3059. for (int y=0 ; y < pImg->Height() ; y++)
  3060. {
  3061. if (y == 0) // first line
  3062. {
  3063. for (int ny=0 ; ny < m_iBlock ; ny++)
  3064. for (int nx=0 ; nx < m_iBlock ; nx++)
  3065. {
  3066. BYTE * pPixel = GetBackupImage()->GetBits (nx,ny) ;
  3067. int nA = (GetBackupImage()->ColorBits() == 32) ? PCL_A(pPixel) : 0xFF ;
  3068. iFirstB += PCL_B(pPixel) * nA ;
  3069. iFirstG += PCL_G(pPixel) * nA ;
  3070. iFirstR += PCL_R(pPixel) * nA ;
  3071. iFirstA += nA ;
  3072. }
  3073. }
  3074. else // Y move down
  3075. {
  3076. // sub up line & add down line
  3077. for (int i=0 ; i < m_iBlock ; i++)
  3078. in_UpdateSum (iFirstR, iFirstG, iFirstB, iFirstA,
  3079. GetBackupImage()->GetBits (i, y-1+m_iBlock),
  3080. GetBackupImage()->GetBits (i, y-1)) ;
  3081. }
  3082. // set first pixel per scanline
  3083. in_SetPixel (iFirstR, iFirstG, iFirstB, iFirstA, pImg->GetBits(y)) ;
  3084. // X move
  3085. int iCurrR=iFirstR, iCurrG=iFirstG, iCurrB=iFirstB, iCurrA=iFirstA ;
  3086. for (int x=1 ; x < pImg->Width() ; x++)
  3087. {
  3088. // sub left pixel & add right pixel
  3089. for (int i=0 ; i < m_iBlock ; i++)
  3090. in_UpdateSum (iCurrR, iCurrG, iCurrB, iCurrA,
  3091. GetBackupImage()->GetBits (x-1+m_iBlock, y+i),
  3092. GetBackupImage()->GetBits (x-1, y+i)) ;
  3093. in_SetPixel (iCurrR, iCurrG, iCurrB, iCurrA, pImg->GetBits(x,y)) ;
  3094. }
  3095. if (pProgress)
  3096. pProgress->SetProgress ((y+1) * 100 / pImg->Height()) ;
  3097. } // end of for(Y)
  3098. }
  3099. int m_iBlock ; // >=2
  3100. bool m_bCopyEdge ;
  3101. };
  3102. //=============================================================================
  3103. /**
  3104. * Blur zoom (>=24 bit).
  3105. @verbatim
  3106. example:
  3107. FCPixelBlur_Zoom aCmd (15) ;
  3108. img.SinglePixelProcessProc (aCmd) ;
  3109. @endverbatim
  3110. */
  3111. class FCPixelBlur_Zoom : public FCPixelWholeImageBase
  3112. {
  3113. public:
  3114. /// Constructor.
  3115. FCPixelBlur_Zoom (int nLength) : m_nLength(FMax(0,nLength)) {}
  3116. private:
  3117. virtual void OnEnterProcess (FCObjImage* pImg)
  3118. {
  3119. SetBackupImage (pImg) ;
  3120. }
  3121. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3122. {
  3123. for (int y=0 ; y < pImg->Height() ; y++)
  3124. {
  3125. for (int x=0 ; x < pImg->Width() ; x++)
  3126. {
  3127. // Stat.
  3128. int nSumB=0, nSumG=0, nSumR=0, nSumA=0,
  3129. i=0 ;
  3130. for (i=0 ; i < m_nLength ; i++)
  3131. {
  3132. int nCenX = pImg->Width()/2, nCenY = pImg->Height()/2,
  3133. xx = (int)(nCenX + (x-nCenX) * (1.0 + 0.02 * i)),
  3134. yy = (int)(nCenY + (y-nCenY) * (1.0 + 0.02 * i)) ;
  3135. if (!GetBackupImage()->IsInside(xx,yy))
  3136. break ;
  3137. BYTE * p = GetBackupImage()->GetBits (xx, yy) ;
  3138. int nA = (pImg->ColorBits() == 32) ? PCL_A(p) : 0xFF ;
  3139. nSumA += nA ;
  3140. nSumB += nA * PCL_B(p) ;
  3141. nSumG += nA * PCL_G(p) ;
  3142. nSumR += nA * PCL_R(p) ;
  3143. }
  3144. // set pixel
  3145. BYTE * pWrite = pImg->GetBits(x,y) ;
  3146. if (nSumA)
  3147. {
  3148. PCL_B(pWrite) = nSumB/nSumA ;
  3149. PCL_G(pWrite) = nSumG/nSumA ;
  3150. PCL_R(pWrite) = nSumR/nSumA ;
  3151. }
  3152. if ((pImg->ColorBits() == 32) && i)
  3153. PCL_A(pWrite) = nSumA/i ;
  3154. }
  3155. if (pProgress)
  3156. pProgress->SetProgress (100 * (y+1) / pImg->Height()) ;
  3157. }
  3158. }
  3159. int m_nLength ;
  3160. };
  3161. //=============================================================================
  3162. /**
  3163. * Blur radial (>=24 bit).
  3164. @verbatim
  3165. example:
  3166. FCPixelBlur_Radial aCmd (30) ;
  3167. img.SinglePixelProcessProc (aCmd) ;
  3168. @endverbatim
  3169. */
  3170. class FCPixelBlur_Radial : public FCPixelWholeImageBase
  3171. {
  3172. public:
  3173. /// Constructor.
  3174. FCPixelBlur_Radial (int nAngle) : m_nAngle(abs(nAngle) % 360) {}
  3175. private:
  3176. virtual void OnEnterProcess (FCObjImage* pImg)
  3177. {
  3178. SetBackupImage (pImg) ;
  3179. }
  3180. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3181. {
  3182. int nCenX = pImg->Width()/2, nCenY = pImg->Height()/2,
  3183. R = (int)FHypot ((double)FMax(nCenX,pImg->Width()-nCenX), (double)FMax(nCenY,pImg->Height()-nCenY)),
  3184. n = (int)(4 * AngleToRadian(m_nAngle) * sqrt((double)R) + 2) ;
  3185. PCL_array<double> ct(n),
  3186. st(n) ;
  3187. double theta = (double)AngleToRadian(m_nAngle) / ((double)(n - 1)),
  3188. offset = double(theta * (n - 1) / 2.0) ;
  3189. for (int i=0 ; i < n ; i++)
  3190. {
  3191. ct[i] = cos (theta * i - offset) ;
  3192. st[i] = sin (theta * i - offset) ;
  3193. }
  3194. for (int y=0 ; y < pImg->Height() ; y++)
  3195. {
  3196. for (int x=0 ; x < pImg->Width() ; x++)
  3197. {
  3198. int xr = x - nCenX, yr = y - nCenY,
  3199. r = (int)sqrt ((double)FSquare(xr) + (double)FSquare(yr)),
  3200. nStep ;
  3201. if (r == 0)
  3202. nStep = 1 ;
  3203. else
  3204. {
  3205. nStep = R/r ;
  3206. if (nStep == 0)
  3207. nStep = 1 ;
  3208. else
  3209. if (nStep > n-1)
  3210. nStep = n-1 ;
  3211. }
  3212. // Stat.
  3213. int nSumB=0, nSumG=0, nSumR=0, nSumA=0,
  3214. nCount = 0 ;
  3215. for (int i=0 ; i < n ; i += nStep)
  3216. {
  3217. int xx = (int)(nCenX + xr * ct[i] - yr * st[i]),
  3218. yy = (int)(nCenY + xr * st[i] + yr * ct[i]) ;
  3219. if (!GetBackupImage()->IsInside(xx,yy))
  3220. continue ;
  3221. nCount++ ;
  3222. BYTE * p = GetBackupImage()->GetBits (xx,yy) ;
  3223. int nA = (pImg->ColorBits() == 32) ? PCL_A(p) : 0xFF ;
  3224. nSumA += nA ;
  3225. nSumB += nA * PCL_B(p) ;
  3226. nSumG += nA * PCL_G(p) ;
  3227. nSumR += nA * PCL_R(p) ;
  3228. }
  3229. // set pixel
  3230. BYTE * pWrite = pImg->GetBits(x,y) ;
  3231. if (nSumA)
  3232. {
  3233. PCL_B(pWrite) = nSumB/nSumA ;
  3234. PCL_G(pWrite) = nSumG/nSumA ;
  3235. PCL_R(pWrite) = nSumR/nSumA ;
  3236. }
  3237. if ((pImg->ColorBits() == 32) && nCount)
  3238. PCL_A(pWrite) = nSumA/nCount ;
  3239. }
  3240. if (pProgress)
  3241. pProgress->SetProgress (100 * (y+1) / pImg->Height()) ;
  3242. }
  3243. }
  3244. int m_nAngle ; // [0, 360]
  3245. };
  3246. //=============================================================================
  3247. /**
  3248. * Blur motion (>=24 bit).
  3249. @verbatim
  3250. example:
  3251. FCPixelBlur_Motion aCmd (15, DIRECT_LEFT) ;
  3252. img.SinglePixelProcessProc (aCmd) ;
  3253. @endverbatim
  3254. */
  3255. class FCPixelBlur_Motion : public FCPixelWholeImageBase
  3256. {
  3257. public:
  3258. /// Constructor.
  3259. FCPixelBlur_Motion (int nStep, DIRECT_SYS Direct) : m_nStep(nStep), m_Direct(Direct) {}
  3260. private:
  3261. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3262. {
  3263. if (pImg->Width() < 5)
  3264. return ;
  3265. m_nStep = FClamp (m_nStep, 2, (int)pImg->Width()-2) ;
  3266. for (int y=0 ; y < pImg->Height() ; y++)
  3267. {
  3268. int nCurrX = 0,
  3269. nSpanX = 1 ;
  3270. RGBQUAD rgb ; // pixel at edge
  3271. switch (m_Direct)
  3272. {
  3273. case DIRECT_LEFT :
  3274. FCColor::CopyPixel (&rgb, pImg->GetBits(pImg->Width()-1, y), pImg->ColorBits()/8) ;
  3275. nCurrX = 0 ;
  3276. nSpanX = 1 ;
  3277. break ;
  3278. case DIRECT_RIGHT :
  3279. FCColor::CopyPixel (&rgb, pImg->GetBits(0, y), pImg->ColorBits()/8) ;
  3280. nCurrX = pImg->Width()-1 ;
  3281. nSpanX = -1 ;
  3282. break ;
  3283. }
  3284. // first block
  3285. int B=0, G=0, R=0, A=0, i=0 ;
  3286. for (i=0 ; i < m_nStep ; i++)
  3287. {
  3288. BYTE * p = pImg->GetBits (nCurrX + i*nSpanX, y) ;
  3289. B += PCL_B(p) ;
  3290. G += PCL_G(p) ;
  3291. R += PCL_R(p) ;
  3292. A += PCL_A(p) ;
  3293. }
  3294. // move block
  3295. for (i=0 ; i < pImg->Width() - 2 ; i++, nCurrX+=nSpanX) // leave 2 pixel edge
  3296. {
  3297. int newB = FClamp0255 (B / m_nStep), // don't set pixel current
  3298. newG = FClamp0255 (G / m_nStep),
  3299. newR = FClamp0255 (R / m_nStep),
  3300. newA = FClamp0255 (A / m_nStep) ;
  3301. BYTE * p = pImg->GetBits (nCurrX, y) ;
  3302. // step
  3303. if (i >= pImg->Width() - m_nStep) // edge
  3304. {
  3305. B = B - PCL_B(p) + PCL_B(&rgb) ;
  3306. G = G - PCL_G(p) + PCL_G(&rgb) ;
  3307. R = R - PCL_R(p) + PCL_R(&rgb) ;
  3308. if (pImg->ColorBits() == 32)
  3309. A = A - PCL_A(p) + PCL_A(&rgb) ;
  3310. }
  3311. else
  3312. {
  3313. BYTE * pA = pImg->GetBits (nCurrX + nSpanX*m_nStep, y) ;
  3314. B = B - PCL_B(p) + PCL_B(pA) ;
  3315. G = G - PCL_G(p) + PCL_G(pA) ;
  3316. R = R - PCL_R(p) + PCL_R(pA) ;
  3317. if (pImg->ColorBits() == 32)
  3318. A = A - PCL_A(p) + PCL_A(pA) ;
  3319. }
  3320. PCL_B(p) = newB ;
  3321. PCL_G(p) = newG ;
  3322. PCL_R(p) = newR ;
  3323. if (pImg->ColorBits() == 32)
  3324. PCL_A(p) = newA ;
  3325. }
  3326. if (pProgress)
  3327. pProgress->SetProgress ((y+1) * 100 / pImg->Height()) ;
  3328. }
  3329. }
  3330. DIRECT_SYS m_Direct ;
  3331. int m_nStep ; // (>= 2)
  3332. };
  3333. //=============================================================================
  3334. /**
  3335. * Blur IIR gauss (>=24 bit).
  3336. @verbatim
  3337. example:
  3338. FCPixelBlur_Gauss_IIR aCmd (10, 10) ;
  3339. img.SinglePixelProcessProc (aCmd) ;
  3340. @endverbatim
  3341. */
  3342. class FCPixelBlur_Gauss_IIR : public FCPixelWholeImageBase
  3343. {
  3344. public:
  3345. FCPixelBlur_Gauss_IIR (int nHorz, int nVert)
  3346. {
  3347. m_nHorz = FMax(1,nHorz) ;
  3348. m_nVert = FMax(1,nVert) ;
  3349. }
  3350. private:
  3351. static void find_constants (double n_p[], double n_m[], double d_p[], double d_m[], double bd_p[], double bd_m[], double std_dev)
  3352. {
  3353. // The constants used in the implemenation of a casual sequence
  3354. // using a 4th order approximation of the gaussian operator
  3355. const double div = sqrt(LIB_2PI) * std_dev ;
  3356. const double constants [8] =
  3357. {
  3358. -1.783/std_dev, -1.723/std_dev, 0.6318/std_dev, 1.997/std_dev,
  3359. 1.6803/div, 3.735/div, -0.6803/div, -0.2598/div
  3360. } ;
  3361. n_p[0] = constants[4] + constants[6] ;
  3362. n_p[1] = exp(constants[1]) * (constants[7] * sin(constants[3]) - (constants[6] + 2*constants[4]) * cos(constants[3])) + exp(constants[0]) * (constants[5] * sin (constants[2]) - (2 * constants[6] + constants[4]) * cos(constants[2])) ;
  3363. n_p[2] = 2 * exp (constants[0] + constants[1]) * ((constants[4] + constants[6]) * cos (constants[3]) * cos (constants[2]) - constants[5] * cos (constants[3]) * sin (constants[2]) - constants[7] * cos (constants[2]) * sin (constants[3]))
  3364. + constants[6] * exp (2 * constants[0]) + constants[4] * exp (2 * constants[1]) ;
  3365. n_p[3] = exp (constants[1] + 2 * constants[0]) * (constants[7] * sin (constants[3]) - constants[6] * cos (constants[3])) + exp (constants[0] + 2 * constants[1]) * (constants[5] * sin (constants[2]) - constants[4] * cos (constants[2])) ;
  3366. n_p[4] = 0.0 ;
  3367. d_p[0] = 0.0 ;
  3368. d_p[1] = -2 * exp (constants[1]) * cos (constants[3]) - 2 * exp (constants[0]) * cos (constants[2]) ;
  3369. d_p[2] = 4 * cos (constants[3]) * cos (constants[2]) * exp (constants[0] + constants[1]) + exp (2 * constants[1]) + exp (2 * constants[0]) ;
  3370. d_p[3] = -2 * cos (constants[2]) * exp (constants[0] + 2 * constants[1]) - 2 * cos (constants[3]) * exp (constants[1] + 2 * constants[0]) ;
  3371. d_p[4] = exp (2 * constants[0] + 2 * constants[1]) ;
  3372. int i ;
  3373. for (i=0 ; i <= 4 ; i++)
  3374. {
  3375. d_m[i] = d_p[i] ;
  3376. }
  3377. n_m[0] = 0.0 ;
  3378. for (i=1 ; i <= 4 ; i++)
  3379. {
  3380. n_m[i] = n_p[i] - d_p[i] * n_p[0] ;
  3381. }
  3382. double sum_n_p=0.0, sum_n_m=0.0, sum_d=0.0 ;
  3383. for (i=0 ; i <= 4 ; i++)
  3384. {
  3385. sum_n_p += n_p[i] ;
  3386. sum_n_m += n_m[i] ;
  3387. sum_d += d_p[i] ;
  3388. }
  3389. const double a = sum_n_p / (1.0 + sum_d),
  3390. b = sum_n_m / (1.0 + sum_d) ;
  3391. for (i = 0; i <= 4; i++)
  3392. {
  3393. bd_p[i] = d_p[i] * a;
  3394. bd_m[i] = d_m[i] * b ;
  3395. }
  3396. }
  3397. void GaussIIRBlurImage (FCObjImage& img, int nLength, FCObjProgress* pProgress)
  3398. {
  3399. int i, j, b;
  3400. double n_p[5], n_m[5], d_p[5], d_m[5], bd_p[5], bd_m[5];
  3401. nLength = FMax (2, nLength + 1) ;
  3402. double std_dev = sqrt (-(nLength * nLength) / (2 * log (1.0 / 255.0)));
  3403. // derive the constants for calculating the gaussian from the std dev
  3404. find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);
  3405. FCObjImage imgOld(img) ;
  3406. int nSpan = img.ColorBits() / 8 ; // 3, 4
  3407. PCL_array<double> val_p(img.Width() * 3),
  3408. val_m(img.Width() * 3) ;
  3409. for (int y=0 ; y < img.Height() ; y++)
  3410. {
  3411. memset(val_p.get(), 0, val_p.GetArrayBytes());
  3412. memset(val_m.get(), 0, val_m.GetArrayBytes());
  3413. BYTE * sp_p = imgOld.GetBits(y) ;
  3414. BYTE * sp_m = imgOld.GetBits(img.Width()-1, y) ;
  3415. double * vp = val_p.get();
  3416. double * vm = val_m.get() + (img.Width() - 1) * 3;
  3417. // Set up the first vals
  3418. int initial_p[3], initial_m[3];
  3419. for (i = 0; i < 3; i++)
  3420. {
  3421. initial_p[i] = sp_p[i];
  3422. initial_m[i] = sp_m[i];
  3423. }
  3424. for (int x=0 ; x < img.Width() ; x++)
  3425. {
  3426. double *vpptr, *vmptr;
  3427. int terms = (x < 4) ? x : 4;
  3428. for (b = 0; b < 3; b++)
  3429. {
  3430. vpptr = vp + b; vmptr = vm + b;
  3431. for (i = 0; i <= terms; i++)
  3432. {
  3433. *vpptr += n_p[i] * sp_p[(-i * nSpan) + b] - d_p[i] * vp[(-i * 3) + b];
  3434. *vmptr += n_m[i] * sp_m[(i * nSpan) + b] - d_m[i] * vm[(i * 3) + b];
  3435. }
  3436. for (j = i; j <= 4; j++)
  3437. {
  3438. *vpptr += (n_p[j] - bd_p[j]) * initial_p[b];
  3439. *vmptr += (n_m[j] - bd_m[j]) * initial_m[b];
  3440. }
  3441. }
  3442. sp_p += nSpan ; sp_m -= nSpan ;
  3443. vp += 3 ; vm -= 3 ;
  3444. }
  3445. double * pTmp_p = val_p.get(), * pTmp_m = val_m.get() ;
  3446. for (int mm=0 ; mm < img.Width() ; mm++)
  3447. {
  3448. BYTE * p = img.GetBits (mm, y) ;
  3449. p[0] = FClamp0255 (int(*pTmp_p + *pTmp_m)) ; pTmp_p++ ; pTmp_m++ ;
  3450. p[1] = FClamp0255 (int(*pTmp_p + *pTmp_m)) ; pTmp_p++ ; pTmp_m++ ;
  3451. p[2] = FClamp0255 (int(*pTmp_p + *pTmp_m)) ; pTmp_p++ ; pTmp_m++ ;
  3452. }
  3453. if (pProgress)
  3454. pProgress->SetProgress ((y+1) * 100 / img.Height()) ;
  3455. }
  3456. }
  3457. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3458. {
  3459. GaussIIRBlurImage (*pImg, m_nHorz, 0) ;
  3460. FCPixelRotate90 aImg90 ;
  3461. pImg->SinglePixelProcessProc (aImg90) ;
  3462. GaussIIRBlurImage (*pImg, m_nVert, pProgress) ;
  3463. FCPixelRotate270 aImg270 ;
  3464. pImg->SinglePixelProcessProc (aImg270) ;
  3465. }
  3466. int m_nHorz, m_nVert ;
  3467. };
  3468. //=============================================================================
  3469. /**
  3470. * Add inner bevel frame (>=24 bit).
  3471. @verbatim
  3472. example:
  3473. FCPixelInnerBevel aCmd (20, 10) ;
  3474. img.SinglePixelProcessProc (aCmd) ;
  3475. @endverbatim
  3476. */
  3477. class FCPixelInnerBevel : public FCPixelWholeImageBase
  3478. {
  3479. public:
  3480. FCPixelInnerBevel (int nSize, int nSmooth)
  3481. {
  3482. m_nSize = FMax (1, nSize) ;
  3483. m_nSmooth = nSmooth ;
  3484. }
  3485. private:
  3486. // the temporary object adjust brightness
  3487. class __FCPixelFillInnerBevel : public FCSinglePixelProcessBase
  3488. {
  3489. public :
  3490. __FCPixelFillInnerBevel (FCObjImage* pImg) : m_pImgBright(pImg) {}
  3491. private:
  3492. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  3493. {
  3494. BYTE * p = m_pImgBright->GetBits(x,y) ;
  3495. PCL_B(pPixel) = FClamp0255 (PCL_B(pPixel) * PCL_A(p) / 100) ;
  3496. PCL_G(pPixel) = FClamp0255 (PCL_G(pPixel) * PCL_A(p) / 100) ;
  3497. PCL_R(pPixel) = FClamp0255 (PCL_R(pPixel) * PCL_A(p) / 100) ;
  3498. }
  3499. FCObjImage * m_pImgBright ;
  3500. };
  3501. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3502. {
  3503. // image brightness
  3504. const int nLeft=160, nTop=160,
  3505. nRight=40, nBottom=40 ;
  3506. FCObjImage imgBright (pImg->Width(), pImg->Height(), 32) ;
  3507. for (int y=0 ; y < imgBright.Height() ; y++)
  3508. for (int x=0 ; x < imgBright.Width() ; x++)
  3509. {
  3510. BYTE * p = imgBright.GetBits(x,y) ;
  3511. if ((x < m_nSize) && (y < imgBright.Height()-x) && (y > x))
  3512. PCL_A(p) = nLeft ;
  3513. else if ((y < m_nSize) && (x < imgBright.Width()-y) && (x > y))
  3514. PCL_A(p) = nTop ;
  3515. else if ((x > imgBright.Width()-m_nSize) && (y > imgBright.Width()-x) && (y < imgBright.Height()+x-imgBright.Width()))
  3516. PCL_A(p) = nRight ;
  3517. else if (y > imgBright.Height()-m_nSize)
  3518. PCL_A(p) = nBottom ;
  3519. else
  3520. PCL_A(p) = 100 ;
  3521. }
  3522. FCPixelBlur_Box cmdBlur (m_nSmooth, true) ;
  3523. imgBright.SinglePixelProcessProc (cmdBlur) ;
  3524. __FCPixelFillInnerBevel cmdBevel (&imgBright) ;
  3525. pImg->SinglePixelProcessProc (cmdBevel, pProgress) ;
  3526. }
  3527. int m_nSize, m_nSmooth ;
  3528. };
  3529. //=============================================================================
  3530. /**
  3531. * Smooth edge (32 bit).
  3532. @verbatim
  3533. example:
  3534. FCPixelSmoothEdge aCmd (15) ;
  3535. img.SinglePixelProcessProc (aCmd) ;
  3536. @endverbatim
  3537. */
  3538. class FCPixelSmoothEdge : public FCPixelWholeImageBase
  3539. {
  3540. public:
  3541. FCPixelSmoothEdge (int iBlock) : m_iBlock(FMax(1,iBlock)) {}
  3542. private:
  3543. int m_iBlock ; // >=1
  3544. private:
  3545. virtual bool ValidateColorBits (const FCObjImage* pImg)
  3546. {
  3547. return pImg->IsValidImage() && (pImg->ColorBits() == 32) ;
  3548. }
  3549. static void RecordHaloPoint (const FCObjImage& imgAlpha, std::deque<POINT>& listHalo)
  3550. {
  3551. // expand edge to search easily
  3552. FCObjImage imgSearch (imgAlpha.Width()+2, imgAlpha.Height()+2, imgAlpha.ColorBits()) ;
  3553. imgSearch.CoverBlock (imgAlpha, 1, 1) ;
  3554. // record halo point
  3555. FCObjImage imgRecord (imgSearch.Width(), imgSearch.Height(), 8) ;
  3556. POINT nDirect[4] = {{0,-1}, {0,1}, {-1,0}, {1,0}} ; // up-down-left-right
  3557. for (int y=1 ; y < imgSearch.Height()-1 ; y++)
  3558. for (int x=1 ; x < imgSearch.Width()-1 ; x++)
  3559. {
  3560. BYTE * p = imgSearch.GetBits(x,y) ;
  3561. for (int i=0 ; i < 4 ; i++)
  3562. {
  3563. // direction
  3564. int nDX = x + nDirect[i].x,
  3565. nDY = y + nDirect[i].y ;
  3566. BYTE * pTmp = imgSearch.GetBits (nDX, nDY) ;
  3567. if (*pTmp == *p)
  3568. continue ;
  3569. // draw halo at smaller alpha
  3570. POINT pt ;
  3571. if (*pTmp < *p)
  3572. {
  3573. pt.x=nDX ; pt.y=nDY ;
  3574. }
  3575. else
  3576. {
  3577. pt.x=x ; pt.y=y ;
  3578. }
  3579. *imgRecord.GetBits (pt.x, pt.y) = 0xFF ;
  3580. }
  3581. }
  3582. // halo point
  3583. listHalo.clear() ;
  3584. {
  3585. for (int y=0 ; y < imgRecord.Height() ; y++)
  3586. for (int x=0 ; x < imgRecord.Width() ; x++)
  3587. if (*imgRecord.GetBits(x,y) == 0xFF)
  3588. {
  3589. POINT pt = {x-1, y-1} ; // remember -1
  3590. listHalo.push_back (pt) ;
  3591. }
  3592. }
  3593. }
  3594. void DrawHalo (FCObjImage& imgDest, FCObjImage& imgAlpha, FCObjImage& imgHalo, POINT ptCenter)
  3595. {
  3596. int nLT = (imgHalo.Width()-1) / 2 ;
  3597. RECT rcHalo = {ptCenter.x-nLT, ptCenter.y-nLT, ptCenter.x+nLT+1, ptCenter.y+nLT+1},
  3598. rcAlpha = {0,0,imgAlpha.Width(),imgAlpha.Height()}, rcDest ;
  3599. if (::IntersectRect (&rcDest, &rcHalo, &rcAlpha) == 0)
  3600. return ;
  3601. int nCenter = 0 ;
  3602. if (imgAlpha.IsInside (ptCenter.x, ptCenter.y))
  3603. nCenter = *imgAlpha.GetBits (ptCenter.x, ptCenter.y) ;
  3604. for (int y=rcDest.top ; y < rcDest.bottom ; y++)
  3605. for (int x=rcDest.left ; x < rcDest.right ; x++)
  3606. {
  3607. BYTE * pDest = imgDest.GetBits (x, y),
  3608. * pAlpha = imgAlpha.GetBits (x, y),
  3609. * pHalo = imgHalo.GetBits (x-rcHalo.left, y-rcHalo.top) ;
  3610. // calculate percentage
  3611. int nNew = FMax (nCenter, *pAlpha * *pHalo / 0xFF) ;
  3612. if (nNew < *pDest)
  3613. *pDest = nNew ;
  3614. }
  3615. }
  3616. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3617. {
  3618. // get alpha channel
  3619. FCObjImage imgAlpha ;
  3620. pImg->GetAlphaChannel (&imgAlpha) ;
  3621. // get draw halo point
  3622. std::deque<POINT> listHalo ;
  3623. RecordHaloPoint (imgAlpha, listHalo) ;
  3624. if (listHalo.empty())
  3625. return ;
  3626. // create halo image
  3627. FCObjImage imgHalo ;
  3628. FCPixelCreateHalo aCmdCreateHalo(m_iBlock, 0, 0xFF) ;
  3629. imgHalo.SinglePixelProcessProc (aCmdCreateHalo) ;
  3630. // make alpha image
  3631. FCObjImage imgDest = imgAlpha ;
  3632. for (size_t i=0 ; i < listHalo.size() ; i++)
  3633. {
  3634. DrawHalo (imgDest, imgAlpha, imgHalo, listHalo[i]) ;
  3635. if (pProgress)
  3636. pProgress->SetProgress (100*i/listHalo.size()) ;
  3637. }
  3638. pImg->AppendAlphaChannel (imgDest) ;
  3639. }
  3640. private:
  3641. class FCPixelCreateHalo : public FCSinglePixelProcessBase
  3642. {
  3643. public:
  3644. FCPixelCreateHalo (int nRadius, int crCenter, int crEdge) : m_crCenter(crCenter), m_crEdge(crEdge)
  3645. {
  3646. m_fRadius = FMax (1, nRadius) ;
  3647. m_fRadius += 1.0 ;
  3648. m_ptCenter.x = (int)m_fRadius ; m_ptCenter.y = (int)m_fRadius ;
  3649. }
  3650. private:
  3651. virtual bool ValidateColorBits (const FCObjImage* pImg) {return true;}
  3652. virtual void OnEnterProcess (FCObjImage* pImg)
  3653. {
  3654. int nWidth = (int)(2*m_fRadius + 1) ;
  3655. pImg->Create (nWidth, nWidth, 8) ;
  3656. }
  3657. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  3658. {
  3659. double fDist = FHypot((double)(x-m_ptCenter.x), (double)(y-m_ptCenter.y)) ;
  3660. if (fDist <= m_fRadius)
  3661. *pPixel = FRound (m_crCenter + (m_crEdge-m_crCenter)*fDist/m_fRadius) ;
  3662. else
  3663. *pPixel = m_crEdge ;
  3664. }
  3665. double m_fRadius ;
  3666. int m_crCenter, m_crEdge ;
  3667. POINT m_ptCenter ;
  3668. };
  3669. };
  3670. //=============================================================================
  3671. /// Calculate optimized image's rect.
  3672. class FCPixelGetOptimizedRect : public FCSinglePixelProcessBase
  3673. {
  3674. public:
  3675. FCPixelGetOptimizedRect()
  3676. {
  3677. memset (&m_rcOptimized, 0, sizeof(m_rcOptimized)) ;
  3678. m_bFirst = true ;
  3679. }
  3680. virtual bool ValidateColorBits (const FCObjImage* pImg)
  3681. {
  3682. return pImg->IsValidImage() && (pImg->ColorBits() == 32) ;
  3683. }
  3684. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  3685. {
  3686. if (PCL_A(pPixel))
  3687. if (m_bFirst)
  3688. {
  3689. m_rcOptimized.left = x ;
  3690. m_rcOptimized.right = x+1 ;
  3691. m_rcOptimized.top = y ;
  3692. m_rcOptimized.bottom = y+1 ;
  3693. m_bFirst = false ;
  3694. }
  3695. else
  3696. {
  3697. if (x < m_rcOptimized.left) m_rcOptimized.left = x ;
  3698. if (x+1 > m_rcOptimized.right) m_rcOptimized.right = x+1 ;
  3699. if (y < m_rcOptimized.top) m_rcOptimized.top = y ;
  3700. if (y+1 > m_rcOptimized.bottom) m_rcOptimized.bottom = y+1 ;
  3701. }
  3702. }
  3703. public:
  3704. RECT m_rcOptimized ;
  3705. bool m_bFirst ;
  3706. };
  3707. //=============================================================================
  3708. /**
  3709. * Add shadow (32 bit).
  3710. @verbatim
  3711. example:
  3712. SHADOWDATA ShData ;
  3713. ShData.crShadow = FCColor::crWhite() ;
  3714. ShData.nAlpha = 75 ;
  3715. ShData.nSmooth = 10 ;
  3716. ShData.nOffsetX = 5 ;
  3717. ShData.nOffsetY = 5 ;
  3718. FCPixelAddShadow aCmd (ShData) ;
  3719. img.SinglePixelProcessProc (aCmd) ;
  3720. @endverbatim
  3721. */
  3722. class FCPixelAddShadow : public FCPixelWholeImageBase
  3723. {
  3724. public:
  3725. FCPixelAddShadow (SHADOWDATA ShData)
  3726. {
  3727. m_ShadowData = ShData ;
  3728. m_ShadowData.nSmooth = FMax (2, (int)m_ShadowData.nSmooth) ;
  3729. m_ShadowData.nAlpha = FClamp ((int)m_ShadowData.nAlpha, 1, 100) ;
  3730. }
  3731. private:
  3732. virtual bool ValidateColorBits (const FCObjImage* pImg)
  3733. {
  3734. return pImg->IsValidImage() && (pImg->ColorBits() == 32) ;
  3735. }
  3736. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3737. {
  3738. // backup image
  3739. const FCObjImage imgOld(*pImg) ;
  3740. // calculate new image size
  3741. RECT rcImg = {0, 0, pImg->Width(), pImg->Height()},
  3742. rcShadowOffset = rcImg ;
  3743. ::OffsetRect (&rcShadowOffset, m_ShadowData.nOffsetX, m_ShadowData.nOffsetY) ;
  3744. RECT rcShadow = rcShadowOffset ;
  3745. ::InflateRect (&rcShadow, m_ShadowData.nSmooth, m_ShadowData.nSmooth) ;
  3746. RECT rcResult ;
  3747. ::UnionRect (&rcResult, &rcImg, &rcShadow) ;
  3748. // create shadow background and box-blur it
  3749. pImg->Create (RECTWIDTH(rcResult), RECTHEIGHT(rcResult), 32) ;
  3750. int nStartX = rcShadowOffset.left - rcResult.left,
  3751. nStartY = rcShadowOffset.top - rcResult.top ;
  3752. for (int y=0 ; y < imgOld.Height() ; y++)
  3753. for (int x=0 ; x < imgOld.Width() ; x++)
  3754. {
  3755. RGBQUAD cr = m_ShadowData.crShadow ;
  3756. PCL_A(&cr) = PCL_A(imgOld.GetBits(x,y)) * m_ShadowData.nAlpha / 100 ;
  3757. *(RGBQUAD*)pImg->GetBits (nStartX + x, nStartY + y) = cr ;
  3758. }
  3759. // box-blur alpha-channel
  3760. FCPixelBlur_Box cmdSmooth (m_ShadowData.nSmooth, false) ;
  3761. pImg->SinglePixelProcessProc (cmdSmooth, pProgress) ;
  3762. // combine origin image
  3763. pImg->CombineImage (imgOld, rcImg.left-rcResult.left, rcImg.top-rcResult.top) ;
  3764. // adjust new img's position
  3765. pImg->SetGraphObjPos (imgOld.GetGraphObjPos().x - rcImg.left + rcResult.left,
  3766. imgOld.GetGraphObjPos().y - rcImg.top + rcResult.top) ;
  3767. }
  3768. private:
  3769. SHADOWDATA m_ShadowData ;
  3770. };
  3771. //=============================================================================
  3772. // inline Implement
  3773. //=============================================================================
  3774. #endif