PixelProcessorBase.h 136 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025
  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. m_pFile = fopen (szFileName, "wb") ; assert(m_pFile);
  2799. char ch[95] =
  2800. {
  2801. ' ',
  2802. '`','1','2','3','4','5','6','7','8','9','0','-','=','\\',
  2803. 'q','w','e','r','t','y','u','i','o','p','[',']',
  2804. 'a','s','d','f','g','h','j','k','l',';','\'',
  2805. 'z','x','c','v','b','n','m',',','.','/',
  2806. '~','!','@','#','$','%','^','&','*','(',')','_','+','|',
  2807. 'Q','W','E','R','T','Y','U','I','O','P','{','}',
  2808. 'A','S','D','F','G','H','J','K','L',':','"',
  2809. 'Z','X','C','V','B','N','M','<','>','?'
  2810. };
  2811. int gr[95] =
  2812. {
  2813. 0,
  2814. 7,22,28,31,31,27,32,22,38,32,40, 6,12,20,38,32,26,20,24,40,
  2815. 29,24,28,38,32,32,26,22,34,24,44,33,32,32,24,16, 6,22,26,22,
  2816. 26,34,29,35,10, 6,20,14,22,47,42,34,40,10,35,21,22,22,16,14,
  2817. 26,40,39,29,38,22,28,36,22,36,30,22,22,36,26,36,25,34,38,24,
  2818. 36,22,12,12,26,30,30,34,39,42,41,18,18,22
  2819. };
  2820. // Bubble Sort
  2821. for (int i=0 ; i < 94 ; i++)
  2822. for (int j=i+1 ; j < 95 ; j++)
  2823. if (gr[i] > gr[j])
  2824. {
  2825. FSwap (ch[i], ch[j]) ;
  2826. FSwap (gr[i], gr[j]) ;
  2827. }
  2828. memcpy (m_chIndex, ch, 95*sizeof(char)) ;
  2829. memcpy (m_nGray, gr, 95*sizeof(int)) ;
  2830. }
  2831. virtual ~FCPixelExportAscII()
  2832. {
  2833. if (m_pFile)
  2834. fclose(m_pFile) ;
  2835. }
  2836. private:
  2837. virtual void OnEnterProcess (FCObjImage* pImg)
  2838. {
  2839. SetBackupImage (pImg) ;
  2840. }
  2841. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  2842. {
  2843. FCPixelInvert aCmd ; // most of image is brightness
  2844. GetBackupImage()->SinglePixelProcessProc (aCmd) ;
  2845. FCPixelConvertTo8BitGray aGray ;
  2846. GetBackupImage()->SinglePixelProcessProc (aGray) ;
  2847. const int nTransWidth = pImg->Width() / 8,
  2848. nTransHeight = pImg->Height() / 16 ;
  2849. for (int y=0 ; y < nTransHeight ; y++)
  2850. {
  2851. for (int x=0 ; x < nTransWidth ; x++)
  2852. {
  2853. int nGray = 0 ;
  2854. for (int k=0 ; k < 16 ; k++)
  2855. for(int h=0 ; h < 8 ; h++)
  2856. {
  2857. BYTE * pGray = GetBackupImage()->GetBits (8*x+h, y*16+k) ;
  2858. nGray += *pGray ;
  2859. }
  2860. nGray /= 16*8 ;
  2861. nGray = m_nGray[94] * nGray / 255 ;
  2862. int t = 0 ;
  2863. while (m_nGray[t+1] < nGray)
  2864. t++ ;
  2865. fwrite (&m_chIndex[t], 1, sizeof(char), m_pFile) ;
  2866. }
  2867. char tchar = (char)0x0D ;
  2868. fwrite (&tchar, 1, sizeof(char), m_pFile) ;
  2869. tchar = (char)0x0A ;
  2870. fwrite (&tchar, 1, sizeof(char), m_pFile) ;
  2871. }
  2872. }
  2873. char m_chIndex[95] ;
  2874. int m_nGray[95] ;
  2875. FILE * m_pFile ;
  2876. };
  2877. //=============================================================================
  2878. #ifdef PCL_3RD_LIBRARY_USE_FREEIMAGE
  2879. #include "../FreeImage_Helper.h"
  2880. /**
  2881. * Quantize image.
  2882. @verbatim
  2883. example:
  2884. FCPixelConvertQuantize aCmd (8) ;
  2885. img.SinglePixelProcessProc (aCmd) ;
  2886. @endverbatim
  2887. */
  2888. class FCPixelConvertQuantize : public FCPixelWholeImageBase
  2889. {
  2890. public:
  2891. /// Constructor (nBPP = 1 or 4 or 8).
  2892. FCPixelConvertQuantize (int nBPP) : m_nBPP(nBPP),m_nTransparency(-1) {}
  2893. int GetTransparencyIndex() {return m_nTransparency;}
  2894. private:
  2895. virtual bool ValidateColorBits (const FCObjImage* pImg)
  2896. {
  2897. if ((m_nBPP == 1) || (m_nBPP == 4) || (m_nBPP == 8))
  2898. return pImg->IsValidImage() ;
  2899. assert(false) ;
  2900. return false ;
  2901. }
  2902. virtual void OnEnterProcess (FCObjImage* pImg)
  2903. {
  2904. if (pImg->ColorBits() == 32)
  2905. {
  2906. // find a key color
  2907. FCPixelGetKeyColor aCmd ;
  2908. pImg->SinglePixelProcessProc (aCmd) ;
  2909. const RGBQUAD cr = aCmd.GetKeyColor() ;
  2910. // set pixel (alpha=0) key color
  2911. for (int y=0 ; y < pImg->Height() ; y++)
  2912. for (int x=0 ; x < pImg->Width() ; x++)
  2913. {
  2914. BYTE * p = pImg->GetBits(x,y) ;
  2915. if (PCL_A(p) == 0)
  2916. {
  2917. FCColor::CopyPixel (p, &cr, 3) ;
  2918. m_pt.x=x ; m_pt.y=y ;
  2919. m_nTransparency = 1 ;
  2920. }
  2921. }
  2922. }
  2923. SetBackupImage (pImg) ;
  2924. GetBackupImage()->ConvertTo24Bit() ; // easy to handle
  2925. }
  2926. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  2927. {
  2928. FIBITMAP * pFI = __pcl_AllocateFreeImage (*GetBackupImage()) ;
  2929. if (pFI)
  2930. {
  2931. FIBITMAP * pQu = FreeImage_ColorQuantizeEx (pFI, FIQ_NNQUANT, 1<<m_nBPP) ;
  2932. if (pQu)
  2933. {
  2934. __pcl_FreeImage_to_PCLImage (pQu, *pImg) ;
  2935. FreeImage_Unload (pQu) ;
  2936. }
  2937. FreeImage_Unload (pFI) ;
  2938. }
  2939. // set transparency
  2940. if (pImg->IsValidImage() && (m_nTransparency == 1) && pImg->IsInside(m_pt.x,m_pt.y))
  2941. {
  2942. m_nTransparency = (int)pImg->GetPixelData(m_pt.x,m_pt.y) ;
  2943. }
  2944. }
  2945. POINT m_pt ;
  2946. int m_nBPP ;
  2947. int m_nTransparency ;
  2948. };
  2949. #endif // PCL_3RD_LIBRARY_USE_FREEIMAGE
  2950. //=============================================================================
  2951. /**
  2952. * Glass tile (>=24 bit).
  2953. @verbatim
  2954. example:
  2955. FCPixelGlasstile aCmd (6, 6) ;
  2956. img.SinglePixelProcessProc (aCmd) ;
  2957. @endverbatim
  2958. */
  2959. class FCPixelGlasstile : public FCPixelWholeImageBase
  2960. {
  2961. public:
  2962. /// Constructor (account of X/Y tile).
  2963. FCPixelGlasstile (int nXTile, int nYTile)
  2964. {
  2965. m_nXTile = FMax(2, nXTile) ;
  2966. m_nYTile = FMax(2, nYTile) ;
  2967. }
  2968. private:
  2969. virtual void OnEnterProcess (FCObjImage* pImg)
  2970. {
  2971. SetBackupImage (pImg) ;
  2972. }
  2973. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  2974. {
  2975. int xhalv = m_nXTile / 2, yhalv = m_nYTile / 2 ;
  2976. int xplus = m_nXTile % 2, yplus = m_nYTile % 2 ;
  2977. int ymitt = 0, yoffs = 0 ;
  2978. for (int y=0 ; y < pImg->Height() ; y++)
  2979. {
  2980. int ypixel2 = FClamp (ymitt + yoffs*2, 0, pImg->Height()-1) ;
  2981. yoffs++ ;
  2982. if (yoffs == yhalv)
  2983. {
  2984. ymitt += m_nYTile ;
  2985. yoffs = -(yhalv + yplus) ;
  2986. }
  2987. int xmitt = 0, xoffs = 0 ;
  2988. for (int x=0 ; x < pImg->Width() ; x++)
  2989. {
  2990. int xpixel2 = FClamp (xmitt + xoffs*2, 0, pImg->Width()-1) ;
  2991. FCColor::CopyPixel (pImg->GetBits(x,y), GetBackupImage()->GetBits(xpixel2,ypixel2), pImg->ColorBits()/8) ;
  2992. xoffs++ ;
  2993. if (xoffs == xhalv)
  2994. {
  2995. xmitt += m_nXTile ;
  2996. xoffs = -(xhalv + xplus) ;
  2997. }
  2998. }
  2999. if (pProgress)
  3000. pProgress->SetProgress (100 * y / pImg->Height()) ;
  3001. }
  3002. }
  3003. int m_nXTile, m_nYTile ; // >=2
  3004. };
  3005. //=============================================================================
  3006. /**
  3007. * Box smooth (>=24 bit).
  3008. @verbatim
  3009. example:
  3010. FCPixelBlur_Box aCmd (5, true) ;
  3011. img.SinglePixelProcessProc (aCmd) ;
  3012. @endverbatim
  3013. */
  3014. class FCPixelBlur_Box : public FCPixelWholeImageBase
  3015. {
  3016. public:
  3017. /// Constructor.
  3018. FCPixelBlur_Box (int iBlockLen, bool bCopyEdge)
  3019. {
  3020. m_iBlock = FMax(2, iBlockLen) ;
  3021. m_bCopyEdge = bCopyEdge ;
  3022. }
  3023. private:
  3024. // if m_iBlock>200, the sum maybe exceed int32
  3025. void in_UpdateSum (int& R, int& G, int& B, int& A, const void* pAdd, const void* pSub)
  3026. {
  3027. int nAddA = (GetBackupImage()->ColorBits() == 32) ? PCL_A(pAdd) : 0xFF,
  3028. nSubA = (GetBackupImage()->ColorBits() == 32) ? PCL_A(pSub) : 0xFF ;
  3029. B = B + PCL_B(pAdd)*nAddA - PCL_B(pSub)*nSubA ;
  3030. G = G + PCL_G(pAdd)*nAddA - PCL_G(pSub)*nSubA ;
  3031. R = R + PCL_R(pAdd)*nAddA - PCL_R(pSub)*nSubA ;
  3032. A = A + nAddA - nSubA ;
  3033. }
  3034. void in_SetPixel (int R, int G, int B, int A, void* pPixel)
  3035. {
  3036. PCL_B(pPixel) = A ? (B/A) : 0 ;
  3037. PCL_G(pPixel) = A ? (G/A) : 0 ;
  3038. PCL_R(pPixel) = A ? (R/A) : 0 ;
  3039. if (GetBackupImage()->ColorBits() == 32)
  3040. PCL_A(pPixel) = A / FSquare(m_iBlock) ; // pixel number of block
  3041. }
  3042. virtual void OnEnterProcess (FCObjImage* pImg)
  3043. {
  3044. SetBackupImage (pImg) ;
  3045. // expand edge
  3046. int nLeftTop = m_iBlock/2, // left & top
  3047. nRightDown = nLeftTop; // right & bottom : -((m_iBlock % 2)^1)
  3048. GetBackupImage()->ExpandFrame (m_bCopyEdge, nLeftTop, nLeftTop, nRightDown, nRightDown) ;
  3049. }
  3050. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3051. {
  3052. // RGBA sum of every scanline start
  3053. int iFirstR=0, iFirstG=0, iFirstB=0, iFirstA=0 ;
  3054. for (int y=0 ; y < pImg->Height() ; y++)
  3055. {
  3056. if (y == 0) // first line
  3057. {
  3058. for (int ny=0 ; ny < m_iBlock ; ny++)
  3059. for (int nx=0 ; nx < m_iBlock ; nx++)
  3060. {
  3061. BYTE * pPixel = GetBackupImage()->GetBits (nx,ny) ;
  3062. int nA = (GetBackupImage()->ColorBits() == 32) ? PCL_A(pPixel) : 0xFF ;
  3063. iFirstB += PCL_B(pPixel) * nA ;
  3064. iFirstG += PCL_G(pPixel) * nA ;
  3065. iFirstR += PCL_R(pPixel) * nA ;
  3066. iFirstA += nA ;
  3067. }
  3068. }
  3069. else // Y move down
  3070. {
  3071. // sub up line & add down line
  3072. for (int i=0 ; i < m_iBlock ; i++)
  3073. in_UpdateSum (iFirstR, iFirstG, iFirstB, iFirstA,
  3074. GetBackupImage()->GetBits (i, y-1+m_iBlock),
  3075. GetBackupImage()->GetBits (i, y-1)) ;
  3076. }
  3077. // set first pixel per scanline
  3078. in_SetPixel (iFirstR, iFirstG, iFirstB, iFirstA, pImg->GetBits(y)) ;
  3079. // X move
  3080. int iCurrR=iFirstR, iCurrG=iFirstG, iCurrB=iFirstB, iCurrA=iFirstA ;
  3081. for (int x=1 ; x < pImg->Width() ; x++)
  3082. {
  3083. // sub left pixel & add right pixel
  3084. for (int i=0 ; i < m_iBlock ; i++)
  3085. in_UpdateSum (iCurrR, iCurrG, iCurrB, iCurrA,
  3086. GetBackupImage()->GetBits (x-1+m_iBlock, y+i),
  3087. GetBackupImage()->GetBits (x-1, y+i)) ;
  3088. in_SetPixel (iCurrR, iCurrG, iCurrB, iCurrA, pImg->GetBits(x,y)) ;
  3089. }
  3090. if (pProgress)
  3091. pProgress->SetProgress ((y+1) * 100 / pImg->Height()) ;
  3092. } // end of for(Y)
  3093. }
  3094. int m_iBlock ; // >=2
  3095. bool m_bCopyEdge ;
  3096. };
  3097. //=============================================================================
  3098. /**
  3099. * Blur zoom (>=24 bit).
  3100. @verbatim
  3101. example:
  3102. FCPixelBlur_Zoom aCmd (15) ;
  3103. img.SinglePixelProcessProc (aCmd) ;
  3104. @endverbatim
  3105. */
  3106. class FCPixelBlur_Zoom : public FCPixelWholeImageBase
  3107. {
  3108. public:
  3109. /// Constructor.
  3110. FCPixelBlur_Zoom (int nLength) : m_nLength(FMax(0,nLength)) {}
  3111. private:
  3112. virtual void OnEnterProcess (FCObjImage* pImg)
  3113. {
  3114. SetBackupImage (pImg) ;
  3115. }
  3116. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3117. {
  3118. for (int y=0 ; y < pImg->Height() ; y++)
  3119. {
  3120. for (int x=0 ; x < pImg->Width() ; x++)
  3121. {
  3122. // Stat.
  3123. int nSumB=0, nSumG=0, nSumR=0, nSumA=0,
  3124. i=0 ;
  3125. for (i=0 ; i < m_nLength ; i++)
  3126. {
  3127. int nCenX = pImg->Width()/2, nCenY = pImg->Height()/2,
  3128. xx = (int)(nCenX + (x-nCenX) * (1.0 + 0.02 * i)),
  3129. yy = (int)(nCenY + (y-nCenY) * (1.0 + 0.02 * i)) ;
  3130. if (!GetBackupImage()->IsInside(xx,yy))
  3131. break ;
  3132. BYTE * p = GetBackupImage()->GetBits (xx, yy) ;
  3133. int nA = (pImg->ColorBits() == 32) ? PCL_A(p) : 0xFF ;
  3134. nSumA += nA ;
  3135. nSumB += nA * PCL_B(p) ;
  3136. nSumG += nA * PCL_G(p) ;
  3137. nSumR += nA * PCL_R(p) ;
  3138. }
  3139. // set pixel
  3140. BYTE * pWrite = pImg->GetBits(x,y) ;
  3141. if (nSumA)
  3142. {
  3143. PCL_B(pWrite) = nSumB/nSumA ;
  3144. PCL_G(pWrite) = nSumG/nSumA ;
  3145. PCL_R(pWrite) = nSumR/nSumA ;
  3146. }
  3147. if ((pImg->ColorBits() == 32) && i)
  3148. PCL_A(pWrite) = nSumA/i ;
  3149. }
  3150. if (pProgress)
  3151. pProgress->SetProgress (100 * (y+1) / pImg->Height()) ;
  3152. }
  3153. }
  3154. int m_nLength ;
  3155. };
  3156. //=============================================================================
  3157. /**
  3158. * Blur radial (>=24 bit).
  3159. @verbatim
  3160. example:
  3161. FCPixelBlur_Radial aCmd (30) ;
  3162. img.SinglePixelProcessProc (aCmd) ;
  3163. @endverbatim
  3164. */
  3165. class FCPixelBlur_Radial : public FCPixelWholeImageBase
  3166. {
  3167. public:
  3168. /// Constructor.
  3169. FCPixelBlur_Radial (int nAngle) : m_nAngle(abs(nAngle) % 360) {}
  3170. private:
  3171. virtual void OnEnterProcess (FCObjImage* pImg)
  3172. {
  3173. SetBackupImage (pImg) ;
  3174. }
  3175. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3176. {
  3177. int nCenX = pImg->Width()/2, nCenY = pImg->Height()/2,
  3178. R = (int)FHypot ((double)FMax(nCenX,pImg->Width()-nCenX), (double)FMax(nCenY,pImg->Height()-nCenY)),
  3179. n = (int)(4 * AngleToRadian(m_nAngle) * sqrt((double)R) + 2) ;
  3180. PCL_array<double> ct(n),
  3181. st(n) ;
  3182. double theta = (double)AngleToRadian(m_nAngle) / ((double)(n - 1)),
  3183. offset = double(theta * (n - 1) / 2.0) ;
  3184. for (int i=0 ; i < n ; i++)
  3185. {
  3186. ct[i] = cos (theta * i - offset) ;
  3187. st[i] = sin (theta * i - offset) ;
  3188. }
  3189. for (int y=0 ; y < pImg->Height() ; y++)
  3190. {
  3191. for (int x=0 ; x < pImg->Width() ; x++)
  3192. {
  3193. int xr = x - nCenX, yr = y - nCenY,
  3194. r = (int)sqrt ((double)FSquare(xr) + (double)FSquare(yr)),
  3195. nStep ;
  3196. if (r == 0)
  3197. nStep = 1 ;
  3198. else
  3199. {
  3200. nStep = R/r ;
  3201. if (nStep == 0)
  3202. nStep = 1 ;
  3203. else
  3204. if (nStep > n-1)
  3205. nStep = n-1 ;
  3206. }
  3207. // Stat.
  3208. int nSumB=0, nSumG=0, nSumR=0, nSumA=0,
  3209. nCount = 0 ;
  3210. for (int i=0 ; i < n ; i += nStep)
  3211. {
  3212. int xx = (int)(nCenX + xr * ct[i] - yr * st[i]),
  3213. yy = (int)(nCenY + xr * st[i] + yr * ct[i]) ;
  3214. if (!GetBackupImage()->IsInside(xx,yy))
  3215. continue ;
  3216. nCount++ ;
  3217. BYTE * p = GetBackupImage()->GetBits (xx,yy) ;
  3218. int nA = (pImg->ColorBits() == 32) ? PCL_A(p) : 0xFF ;
  3219. nSumA += nA ;
  3220. nSumB += nA * PCL_B(p) ;
  3221. nSumG += nA * PCL_G(p) ;
  3222. nSumR += nA * PCL_R(p) ;
  3223. }
  3224. // set pixel
  3225. BYTE * pWrite = pImg->GetBits(x,y) ;
  3226. if (nSumA)
  3227. {
  3228. PCL_B(pWrite) = nSumB/nSumA ;
  3229. PCL_G(pWrite) = nSumG/nSumA ;
  3230. PCL_R(pWrite) = nSumR/nSumA ;
  3231. }
  3232. if ((pImg->ColorBits() == 32) && nCount)
  3233. PCL_A(pWrite) = nSumA/nCount ;
  3234. }
  3235. if (pProgress)
  3236. pProgress->SetProgress (100 * (y+1) / pImg->Height()) ;
  3237. }
  3238. }
  3239. int m_nAngle ; // [0, 360]
  3240. };
  3241. //=============================================================================
  3242. /**
  3243. * Blur motion (>=24 bit).
  3244. @verbatim
  3245. example:
  3246. FCPixelBlur_Motion aCmd (15, DIRECT_LEFT) ;
  3247. img.SinglePixelProcessProc (aCmd) ;
  3248. @endverbatim
  3249. */
  3250. class FCPixelBlur_Motion : public FCPixelWholeImageBase
  3251. {
  3252. public:
  3253. /// Constructor.
  3254. FCPixelBlur_Motion (int nStep, DIRECT_SYS Direct) : m_nStep(nStep), m_Direct(Direct) {}
  3255. private:
  3256. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3257. {
  3258. if (pImg->Width() < 5)
  3259. return ;
  3260. m_nStep = FClamp (m_nStep, 2, (int)pImg->Width()-2) ;
  3261. for (int y=0 ; y < pImg->Height() ; y++)
  3262. {
  3263. int nCurrX = 0,
  3264. nSpanX = 1 ;
  3265. RGBQUAD rgb ; // pixel at edge
  3266. switch (m_Direct)
  3267. {
  3268. case DIRECT_LEFT :
  3269. FCColor::CopyPixel (&rgb, pImg->GetBits(pImg->Width()-1, y), pImg->ColorBits()/8) ;
  3270. nCurrX = 0 ;
  3271. nSpanX = 1 ;
  3272. break ;
  3273. case DIRECT_RIGHT :
  3274. FCColor::CopyPixel (&rgb, pImg->GetBits(0, y), pImg->ColorBits()/8) ;
  3275. nCurrX = pImg->Width()-1 ;
  3276. nSpanX = -1 ;
  3277. break ;
  3278. }
  3279. // first block
  3280. int B=0, G=0, R=0, A=0, i=0 ;
  3281. for (i=0 ; i < m_nStep ; i++)
  3282. {
  3283. BYTE * p = pImg->GetBits (nCurrX + i*nSpanX, y) ;
  3284. B += PCL_B(p) ;
  3285. G += PCL_G(p) ;
  3286. R += PCL_R(p) ;
  3287. A += PCL_A(p) ;
  3288. }
  3289. // move block
  3290. for (i=0 ; i < pImg->Width() - 2 ; i++, nCurrX+=nSpanX) // leave 2 pixel edge
  3291. {
  3292. int newB = FClamp0255 (B / m_nStep), // don't set pixel current
  3293. newG = FClamp0255 (G / m_nStep),
  3294. newR = FClamp0255 (R / m_nStep),
  3295. newA = FClamp0255 (A / m_nStep) ;
  3296. BYTE * p = pImg->GetBits (nCurrX, y) ;
  3297. // step
  3298. if (i >= pImg->Width() - m_nStep) // edge
  3299. {
  3300. B = B - PCL_B(p) + PCL_B(&rgb) ;
  3301. G = G - PCL_G(p) + PCL_G(&rgb) ;
  3302. R = R - PCL_R(p) + PCL_R(&rgb) ;
  3303. if (pImg->ColorBits() == 32)
  3304. A = A - PCL_A(p) + PCL_A(&rgb) ;
  3305. }
  3306. else
  3307. {
  3308. BYTE * pA = pImg->GetBits (nCurrX + nSpanX*m_nStep, y) ;
  3309. B = B - PCL_B(p) + PCL_B(pA) ;
  3310. G = G - PCL_G(p) + PCL_G(pA) ;
  3311. R = R - PCL_R(p) + PCL_R(pA) ;
  3312. if (pImg->ColorBits() == 32)
  3313. A = A - PCL_A(p) + PCL_A(pA) ;
  3314. }
  3315. PCL_B(p) = newB ;
  3316. PCL_G(p) = newG ;
  3317. PCL_R(p) = newR ;
  3318. if (pImg->ColorBits() == 32)
  3319. PCL_A(p) = newA ;
  3320. }
  3321. if (pProgress)
  3322. pProgress->SetProgress ((y+1) * 100 / pImg->Height()) ;
  3323. }
  3324. }
  3325. DIRECT_SYS m_Direct ;
  3326. int m_nStep ; // (>= 2)
  3327. };
  3328. //=============================================================================
  3329. /**
  3330. * Blur IIR gauss (>=24 bit).
  3331. @verbatim
  3332. example:
  3333. FCPixelBlur_Gauss_IIR aCmd (10, 10) ;
  3334. img.SinglePixelProcessProc (aCmd) ;
  3335. @endverbatim
  3336. */
  3337. class FCPixelBlur_Gauss_IIR : public FCPixelWholeImageBase
  3338. {
  3339. public:
  3340. FCPixelBlur_Gauss_IIR (int nHorz, int nVert)
  3341. {
  3342. m_nHorz = FMax(1,nHorz) ;
  3343. m_nVert = FMax(1,nVert) ;
  3344. }
  3345. private:
  3346. 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)
  3347. {
  3348. // The constants used in the implemenation of a casual sequence
  3349. // using a 4th order approximation of the gaussian operator
  3350. const double div = sqrt(LIB_2PI) * std_dev ;
  3351. const double constants [8] =
  3352. {
  3353. -1.783/std_dev, -1.723/std_dev, 0.6318/std_dev, 1.997/std_dev,
  3354. 1.6803/div, 3.735/div, -0.6803/div, -0.2598/div
  3355. } ;
  3356. n_p[0] = constants[4] + constants[6] ;
  3357. 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])) ;
  3358. 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]))
  3359. + constants[6] * exp (2 * constants[0]) + constants[4] * exp (2 * constants[1]) ;
  3360. 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])) ;
  3361. n_p[4] = 0.0 ;
  3362. d_p[0] = 0.0 ;
  3363. d_p[1] = -2 * exp (constants[1]) * cos (constants[3]) - 2 * exp (constants[0]) * cos (constants[2]) ;
  3364. d_p[2] = 4 * cos (constants[3]) * cos (constants[2]) * exp (constants[0] + constants[1]) + exp (2 * constants[1]) + exp (2 * constants[0]) ;
  3365. d_p[3] = -2 * cos (constants[2]) * exp (constants[0] + 2 * constants[1]) - 2 * cos (constants[3]) * exp (constants[1] + 2 * constants[0]) ;
  3366. d_p[4] = exp (2 * constants[0] + 2 * constants[1]) ;
  3367. int i ;
  3368. for (i=0 ; i <= 4 ; i++)
  3369. {
  3370. d_m[i] = d_p[i] ;
  3371. }
  3372. n_m[0] = 0.0 ;
  3373. for (i=1 ; i <= 4 ; i++)
  3374. {
  3375. n_m[i] = n_p[i] - d_p[i] * n_p[0] ;
  3376. }
  3377. double sum_n_p=0.0, sum_n_m=0.0, sum_d=0.0 ;
  3378. for (i=0 ; i <= 4 ; i++)
  3379. {
  3380. sum_n_p += n_p[i] ;
  3381. sum_n_m += n_m[i] ;
  3382. sum_d += d_p[i] ;
  3383. }
  3384. const double a = sum_n_p / (1.0 + sum_d),
  3385. b = sum_n_m / (1.0 + sum_d) ;
  3386. for (i = 0; i <= 4; i++)
  3387. {
  3388. bd_p[i] = d_p[i] * a;
  3389. bd_m[i] = d_m[i] * b ;
  3390. }
  3391. }
  3392. void GaussIIRBlurImage (FCObjImage& img, int nLength, FCObjProgress* pProgress)
  3393. {
  3394. int i, j, b;
  3395. double n_p[5], n_m[5], d_p[5], d_m[5], bd_p[5], bd_m[5];
  3396. nLength = FMax (2, nLength + 1) ;
  3397. double std_dev = sqrt (-(nLength * nLength) / (2 * log (1.0 / 255.0)));
  3398. // derive the constants for calculating the gaussian from the std dev
  3399. find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);
  3400. FCObjImage imgOld(img) ;
  3401. int nSpan = img.ColorBits() / 8 ; // 3, 4
  3402. PCL_array<double> val_p(img.Width() * 3),
  3403. val_m(img.Width() * 3) ;
  3404. for (int y=0 ; y < img.Height() ; y++)
  3405. {
  3406. memset(val_p.get(), 0, val_p.GetArrayBytes());
  3407. memset(val_m.get(), 0, val_m.GetArrayBytes());
  3408. BYTE * sp_p = imgOld.GetBits(y) ;
  3409. BYTE * sp_m = imgOld.GetBits(img.Width()-1, y) ;
  3410. double * vp = val_p.get();
  3411. double * vm = val_m.get() + (img.Width() - 1) * 3;
  3412. // Set up the first vals
  3413. int initial_p[3], initial_m[3];
  3414. for (i = 0; i < 3; i++)
  3415. {
  3416. initial_p[i] = sp_p[i];
  3417. initial_m[i] = sp_m[i];
  3418. }
  3419. for (int x=0 ; x < img.Width() ; x++)
  3420. {
  3421. double *vpptr, *vmptr;
  3422. int terms = (x < 4) ? x : 4;
  3423. for (b = 0; b < 3; b++)
  3424. {
  3425. vpptr = vp + b; vmptr = vm + b;
  3426. for (i = 0; i <= terms; i++)
  3427. {
  3428. *vpptr += n_p[i] * sp_p[(-i * nSpan) + b] - d_p[i] * vp[(-i * 3) + b];
  3429. *vmptr += n_m[i] * sp_m[(i * nSpan) + b] - d_m[i] * vm[(i * 3) + b];
  3430. }
  3431. for (j = i; j <= 4; j++)
  3432. {
  3433. *vpptr += (n_p[j] - bd_p[j]) * initial_p[b];
  3434. *vmptr += (n_m[j] - bd_m[j]) * initial_m[b];
  3435. }
  3436. }
  3437. sp_p += nSpan ; sp_m -= nSpan ;
  3438. vp += 3 ; vm -= 3 ;
  3439. }
  3440. double * pTmp_p = val_p.get(), * pTmp_m = val_m.get() ;
  3441. for (int mm=0 ; mm < img.Width() ; mm++)
  3442. {
  3443. BYTE * p = img.GetBits (mm, y) ;
  3444. p[0] = FClamp0255 (int(*pTmp_p + *pTmp_m)) ; pTmp_p++ ; pTmp_m++ ;
  3445. p[1] = FClamp0255 (int(*pTmp_p + *pTmp_m)) ; pTmp_p++ ; pTmp_m++ ;
  3446. p[2] = FClamp0255 (int(*pTmp_p + *pTmp_m)) ; pTmp_p++ ; pTmp_m++ ;
  3447. }
  3448. if (pProgress)
  3449. pProgress->SetProgress ((y+1) * 100 / img.Height()) ;
  3450. }
  3451. }
  3452. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3453. {
  3454. GaussIIRBlurImage (*pImg, m_nHorz, 0) ;
  3455. FCPixelRotate90 aImg90 ;
  3456. pImg->SinglePixelProcessProc (aImg90) ;
  3457. GaussIIRBlurImage (*pImg, m_nVert, pProgress) ;
  3458. FCPixelRotate270 aImg270 ;
  3459. pImg->SinglePixelProcessProc (aImg270) ;
  3460. }
  3461. int m_nHorz, m_nVert ;
  3462. };
  3463. //=============================================================================
  3464. /**
  3465. * Add inner bevel frame (>=24 bit).
  3466. @verbatim
  3467. example:
  3468. FCPixelInnerBevel aCmd (20, 10) ;
  3469. img.SinglePixelProcessProc (aCmd) ;
  3470. @endverbatim
  3471. */
  3472. class FCPixelInnerBevel : public FCPixelWholeImageBase
  3473. {
  3474. public:
  3475. FCPixelInnerBevel (int nSize, int nSmooth)
  3476. {
  3477. m_nSize = FMax (1, nSize) ;
  3478. m_nSmooth = nSmooth ;
  3479. }
  3480. private:
  3481. // the temporary object adjust brightness
  3482. class __FCPixelFillInnerBevel : public FCSinglePixelProcessBase
  3483. {
  3484. public :
  3485. __FCPixelFillInnerBevel (FCObjImage* pImg) : m_pImgBright(pImg) {}
  3486. private:
  3487. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  3488. {
  3489. BYTE * p = m_pImgBright->GetBits(x,y) ;
  3490. PCL_B(pPixel) = FClamp0255 (PCL_B(pPixel) * PCL_A(p) / 100) ;
  3491. PCL_G(pPixel) = FClamp0255 (PCL_G(pPixel) * PCL_A(p) / 100) ;
  3492. PCL_R(pPixel) = FClamp0255 (PCL_R(pPixel) * PCL_A(p) / 100) ;
  3493. }
  3494. FCObjImage * m_pImgBright ;
  3495. };
  3496. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3497. {
  3498. // image brightness
  3499. const int nLeft=160, nTop=160,
  3500. nRight=40, nBottom=40 ;
  3501. FCObjImage imgBright (pImg->Width(), pImg->Height(), 32) ;
  3502. for (int y=0 ; y < imgBright.Height() ; y++)
  3503. for (int x=0 ; x < imgBright.Width() ; x++)
  3504. {
  3505. BYTE * p = imgBright.GetBits(x,y) ;
  3506. if ((x < m_nSize) && (y < imgBright.Height()-x) && (y > x))
  3507. PCL_A(p) = nLeft ;
  3508. else if ((y < m_nSize) && (x < imgBright.Width()-y) && (x > y))
  3509. PCL_A(p) = nTop ;
  3510. else if ((x > imgBright.Width()-m_nSize) && (y > imgBright.Width()-x) && (y < imgBright.Height()+x-imgBright.Width()))
  3511. PCL_A(p) = nRight ;
  3512. else if (y > imgBright.Height()-m_nSize)
  3513. PCL_A(p) = nBottom ;
  3514. else
  3515. PCL_A(p) = 100 ;
  3516. }
  3517. FCPixelBlur_Box cmdBlur (m_nSmooth, true) ;
  3518. imgBright.SinglePixelProcessProc (cmdBlur) ;
  3519. __FCPixelFillInnerBevel cmdBevel (&imgBright) ;
  3520. pImg->SinglePixelProcessProc (cmdBevel, pProgress) ;
  3521. }
  3522. int m_nSize, m_nSmooth ;
  3523. };
  3524. //=============================================================================
  3525. /**
  3526. * Smooth edge (32 bit).
  3527. @verbatim
  3528. example:
  3529. FCPixelSmoothEdge aCmd (15) ;
  3530. img.SinglePixelProcessProc (aCmd) ;
  3531. @endverbatim
  3532. */
  3533. class FCPixelSmoothEdge : public FCPixelWholeImageBase
  3534. {
  3535. public:
  3536. FCPixelSmoothEdge (int iBlock) : m_iBlock(FMax(1,iBlock)) {}
  3537. private:
  3538. int m_iBlock ; // >=1
  3539. private:
  3540. virtual bool ValidateColorBits (const FCObjImage* pImg)
  3541. {
  3542. return pImg->IsValidImage() && (pImg->ColorBits() == 32) ;
  3543. }
  3544. static void RecordHaloPoint (const FCObjImage& imgAlpha, std::deque<POINT>& listHalo)
  3545. {
  3546. // expand edge to search easily
  3547. FCObjImage imgSearch (imgAlpha.Width()+2, imgAlpha.Height()+2, imgAlpha.ColorBits()) ;
  3548. imgSearch.CoverBlock (imgAlpha, 1, 1) ;
  3549. // record halo point
  3550. FCObjImage imgRecord (imgSearch.Width(), imgSearch.Height(), 8) ;
  3551. POINT nDirect[4] = {{0,-1}, {0,1}, {-1,0}, {1,0}} ; // up-down-left-right
  3552. for (int y=1 ; y < imgSearch.Height()-1 ; y++)
  3553. for (int x=1 ; x < imgSearch.Width()-1 ; x++)
  3554. {
  3555. BYTE * p = imgSearch.GetBits(x,y) ;
  3556. for (int i=0 ; i < 4 ; i++)
  3557. {
  3558. // direction
  3559. int nDX = x + nDirect[i].x,
  3560. nDY = y + nDirect[i].y ;
  3561. BYTE * pTmp = imgSearch.GetBits (nDX, nDY) ;
  3562. if (*pTmp == *p)
  3563. continue ;
  3564. // draw halo at smaller alpha
  3565. POINT pt ;
  3566. if (*pTmp < *p)
  3567. {
  3568. pt.x=nDX ; pt.y=nDY ;
  3569. }
  3570. else
  3571. {
  3572. pt.x=x ; pt.y=y ;
  3573. }
  3574. *imgRecord.GetBits (pt.x, pt.y) = 0xFF ;
  3575. }
  3576. }
  3577. // halo point
  3578. listHalo.clear() ;
  3579. {
  3580. for (int y=0 ; y < imgRecord.Height() ; y++)
  3581. for (int x=0 ; x < imgRecord.Width() ; x++)
  3582. if (*imgRecord.GetBits(x,y) == 0xFF)
  3583. {
  3584. POINT pt = {x-1, y-1} ; // remember -1
  3585. listHalo.push_back (pt) ;
  3586. }
  3587. }
  3588. }
  3589. void DrawHalo (FCObjImage& imgDest, FCObjImage& imgAlpha, FCObjImage& imgHalo, POINT ptCenter)
  3590. {
  3591. int nLT = (imgHalo.Width()-1) / 2 ;
  3592. RECT rcHalo = {ptCenter.x-nLT, ptCenter.y-nLT, ptCenter.x+nLT+1, ptCenter.y+nLT+1},
  3593. rcAlpha = {0,0,imgAlpha.Width(),imgAlpha.Height()}, rcDest ;
  3594. if (::IntersectRect (&rcDest, &rcHalo, &rcAlpha) == 0)
  3595. return ;
  3596. int nCenter = 0 ;
  3597. if (imgAlpha.IsInside (ptCenter.x, ptCenter.y))
  3598. nCenter = *imgAlpha.GetBits (ptCenter.x, ptCenter.y) ;
  3599. for (int y=rcDest.top ; y < rcDest.bottom ; y++)
  3600. for (int x=rcDest.left ; x < rcDest.right ; x++)
  3601. {
  3602. BYTE * pDest = imgDest.GetBits (x, y),
  3603. * pAlpha = imgAlpha.GetBits (x, y),
  3604. * pHalo = imgHalo.GetBits (x-rcHalo.left, y-rcHalo.top) ;
  3605. // calculate percentage
  3606. int nNew = FMax (nCenter, *pAlpha * *pHalo / 0xFF) ;
  3607. if (nNew < *pDest)
  3608. *pDest = nNew ;
  3609. }
  3610. }
  3611. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3612. {
  3613. // get alpha channel
  3614. FCObjImage imgAlpha ;
  3615. pImg->GetAlphaChannel (&imgAlpha) ;
  3616. // get draw halo point
  3617. std::deque<POINT> listHalo ;
  3618. RecordHaloPoint (imgAlpha, listHalo) ;
  3619. if (listHalo.empty())
  3620. return ;
  3621. // create halo image
  3622. FCObjImage imgHalo ;
  3623. FCPixelCreateHalo aCmdCreateHalo(m_iBlock, 0, 0xFF) ;
  3624. imgHalo.SinglePixelProcessProc (aCmdCreateHalo) ;
  3625. // make alpha image
  3626. FCObjImage imgDest = imgAlpha ;
  3627. for (size_t i=0 ; i < listHalo.size() ; i++)
  3628. {
  3629. DrawHalo (imgDest, imgAlpha, imgHalo, listHalo[i]) ;
  3630. if (pProgress)
  3631. pProgress->SetProgress (100*i/listHalo.size()) ;
  3632. }
  3633. pImg->AppendAlphaChannel (imgDest) ;
  3634. }
  3635. private:
  3636. class FCPixelCreateHalo : public FCSinglePixelProcessBase
  3637. {
  3638. public:
  3639. FCPixelCreateHalo (int nRadius, int crCenter, int crEdge) : m_crCenter(crCenter), m_crEdge(crEdge)
  3640. {
  3641. m_fRadius = FMax (1, nRadius) ;
  3642. m_fRadius += 1.0 ;
  3643. m_ptCenter.x = (int)m_fRadius ; m_ptCenter.y = (int)m_fRadius ;
  3644. }
  3645. private:
  3646. virtual bool ValidateColorBits (const FCObjImage* pImg) {return true;}
  3647. virtual void OnEnterProcess (FCObjImage* pImg)
  3648. {
  3649. int nWidth = (int)(2*m_fRadius + 1) ;
  3650. pImg->Create (nWidth, nWidth, 8) ;
  3651. }
  3652. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  3653. {
  3654. double fDist = FHypot((double)(x-m_ptCenter.x), (double)(y-m_ptCenter.y)) ;
  3655. if (fDist <= m_fRadius)
  3656. *pPixel = FRound (m_crCenter + (m_crEdge-m_crCenter)*fDist/m_fRadius) ;
  3657. else
  3658. *pPixel = m_crEdge ;
  3659. }
  3660. double m_fRadius ;
  3661. int m_crCenter, m_crEdge ;
  3662. POINT m_ptCenter ;
  3663. };
  3664. };
  3665. //=============================================================================
  3666. /// Calculate optimized image's rect.
  3667. class FCPixelGetOptimizedRect : public FCSinglePixelProcessBase
  3668. {
  3669. public:
  3670. FCPixelGetOptimizedRect()
  3671. {
  3672. memset (&m_rcOptimized, 0, sizeof(m_rcOptimized)) ;
  3673. m_bFirst = true ;
  3674. }
  3675. virtual bool ValidateColorBits (const FCObjImage* pImg)
  3676. {
  3677. return pImg->IsValidImage() && (pImg->ColorBits() == 32) ;
  3678. }
  3679. virtual void ProcessPixel (FCObjImage* pImg, int x, int y, BYTE* pPixel)
  3680. {
  3681. if (PCL_A(pPixel))
  3682. if (m_bFirst)
  3683. {
  3684. m_rcOptimized.left = x ;
  3685. m_rcOptimized.right = x+1 ;
  3686. m_rcOptimized.top = y ;
  3687. m_rcOptimized.bottom = y+1 ;
  3688. m_bFirst = false ;
  3689. }
  3690. else
  3691. {
  3692. if (x < m_rcOptimized.left) m_rcOptimized.left = x ;
  3693. if (x+1 > m_rcOptimized.right) m_rcOptimized.right = x+1 ;
  3694. if (y < m_rcOptimized.top) m_rcOptimized.top = y ;
  3695. if (y+1 > m_rcOptimized.bottom) m_rcOptimized.bottom = y+1 ;
  3696. }
  3697. }
  3698. public:
  3699. RECT m_rcOptimized ;
  3700. bool m_bFirst ;
  3701. };
  3702. //=============================================================================
  3703. /**
  3704. * Add shadow (32 bit).
  3705. @verbatim
  3706. example:
  3707. SHADOWDATA ShData ;
  3708. ShData.crShadow = FCColor::crWhite() ;
  3709. ShData.nAlpha = 75 ;
  3710. ShData.nSmooth = 10 ;
  3711. ShData.nOffsetX = 5 ;
  3712. ShData.nOffsetY = 5 ;
  3713. FCPixelAddShadow aCmd (ShData) ;
  3714. img.SinglePixelProcessProc (aCmd) ;
  3715. @endverbatim
  3716. */
  3717. class FCPixelAddShadow : public FCPixelWholeImageBase
  3718. {
  3719. public:
  3720. FCPixelAddShadow (SHADOWDATA ShData)
  3721. {
  3722. m_ShadowData = ShData ;
  3723. m_ShadowData.nSmooth = FMax (2, (int)m_ShadowData.nSmooth) ;
  3724. m_ShadowData.nAlpha = FClamp ((int)m_ShadowData.nAlpha, 1, 100) ;
  3725. }
  3726. private:
  3727. virtual bool ValidateColorBits (const FCObjImage* pImg)
  3728. {
  3729. return pImg->IsValidImage() && (pImg->ColorBits() == 32) ;
  3730. }
  3731. virtual void ProcessWholeImage (FCObjImage* pImg, FCObjProgress* pProgress)
  3732. {
  3733. // backup image
  3734. const FCObjImage imgOld(*pImg) ;
  3735. // calculate new image size
  3736. RECT rcImg = {0, 0, pImg->Width(), pImg->Height()},
  3737. rcShadowOffset = rcImg ;
  3738. ::OffsetRect (&rcShadowOffset, m_ShadowData.nOffsetX, m_ShadowData.nOffsetY) ;
  3739. RECT rcShadow = rcShadowOffset ;
  3740. ::InflateRect (&rcShadow, m_ShadowData.nSmooth, m_ShadowData.nSmooth) ;
  3741. RECT rcResult ;
  3742. ::UnionRect (&rcResult, &rcImg, &rcShadow) ;
  3743. // create shadow background and box-blur it
  3744. pImg->Create (RECTWIDTH(rcResult), RECTHEIGHT(rcResult), 32) ;
  3745. int nStartX = rcShadowOffset.left - rcResult.left,
  3746. nStartY = rcShadowOffset.top - rcResult.top ;
  3747. for (int y=0 ; y < imgOld.Height() ; y++)
  3748. for (int x=0 ; x < imgOld.Width() ; x++)
  3749. {
  3750. RGBQUAD cr = m_ShadowData.crShadow ;
  3751. PCL_A(&cr) = PCL_A(imgOld.GetBits(x,y)) * m_ShadowData.nAlpha / 100 ;
  3752. *(RGBQUAD*)pImg->GetBits (nStartX + x, nStartY + y) = cr ;
  3753. }
  3754. // box-blur alpha-channel
  3755. FCPixelBlur_Box cmdSmooth (m_ShadowData.nSmooth, false) ;
  3756. pImg->SinglePixelProcessProc (cmdSmooth, pProgress) ;
  3757. // combine origin image
  3758. pImg->CombineImage (imgOld, rcImg.left-rcResult.left, rcImg.top-rcResult.top) ;
  3759. // adjust new img's position
  3760. pImg->SetGraphObjPos (imgOld.GetGraphObjPos().x - rcImg.left + rcResult.left,
  3761. imgOld.GetGraphObjPos().y - rcImg.top + rcResult.top) ;
  3762. }
  3763. private:
  3764. SHADOWDATA m_ShadowData ;
  3765. };
  3766. //=============================================================================
  3767. // inline Implement
  3768. //=============================================================================
  3769. #endif