pngimage.pas 178 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825
  1. {Portable Network Graphics Delphi 1.564 (31 July 2006) }
  2. {This is a full, open sourced implementation of png in Delphi }
  3. {It has native support for most of png features including the }
  4. {partial transparency, gamma and more. }
  5. {For the latest version, please be sure to check my website }
  6. {http://pngdelphi.sourceforge.net }
  7. {Gustavo Huffenbacher Daud (gustavo.daud@terra.com.br) }
  8. {
  9. Version 1.564
  10. 2006-07-25 BUG 1 - There was one GDI Palette object leak
  11. when assigning from other PNG (fixed)
  12. BUG 2 - Loosing color information when assigning png
  13. to bmp on lower screen depth system
  14. BUG 3 - There was a bug in TStream.GetSize
  15. (fixed thanks to Vladimir Panteleev)
  16. IMPROVE 1 - When assigning png to bmp now alpha information
  17. is drawn (simulated into a white background)
  18. Version 1.563
  19. 2006-07-25 BUG 1 - There was a memory bug in the main component
  20. destructor (fixed thanks to Steven L Brenner)
  21. BUG 2 - The packages name contained spaces which was
  22. causing some strange bugs in Delphi
  23. (fixed thanks to Martijn Saly)
  24. BUG 3 - Lots of fixes when handling palettes
  25. (bugs implemented in the last version)
  26. Fixed thanks to Gabriel Corneanu!!!
  27. BUG 4 - CreateAlpha was raising an error because it did
  28. not resized the palette chunk it created;
  29. Fixed thanks to Miha Sokolov
  30. IMPROVE 1 - Renamed the pngzlib.pas unit to zlibpas.pas
  31. as a tentative to all libraries use the same
  32. shared zlib implementation and to avoid including
  33. two or three times the same P-Code.
  34. (Gabriel Corneanu idea)
  35. Version 1.561
  36. 2006-05-17 BUG 1 - There was a bug in the method that draws semi
  37. transparent images (a memory leak). fixed.
  38. Version 1.56
  39. 2006-05-09 - IMPROVE 1 - Delphi standard TCanvas support is now implemented
  40. IMPROVE 2 - The PNG files may now be resized and created from
  41. scratch using CreateBlank, Resize, Width and Height
  42. BUG 1 - Fixed some bugs on handling tRNS transparencies
  43. BUG 2 - Fixed bugs related to palette handling
  44. Version 1.535
  45. 2006-04-21 - IMPROVE 1 - Now the library uses the latest ZLIB release (1.2.3)
  46. (thanks to: Roberto Della Pasqua
  47. http://www.dellapasqua.com/delphizlib/)
  48. Version 1.53
  49. 2006-04-14 -
  50. BUG 1 - Remove transparency was not working for
  51. RGB Alpha and Grayscale alpha. fixed
  52. BUG 2 - There was a bug were compressed text chunks no keyword
  53. name could not be read
  54. IMPROVE 1 - Add classes and methods to work with the pHYs chunk
  55. (including TPNGObject.DrawUsingPixelInformation)
  56. IMPROVE 3 - Included a property Version to return the library
  57. version
  58. IMPROVE 4 - New polish translation (thanks to Piotr Domanski)
  59. IMPROVE 5 - Now packages for delphi 5, 6, 7, 2005 and 2006
  60. Also Martijn Saly (thany) made some improvements in the library:
  61. IMPROVE 1 - SetPixel now works with grayscale
  62. IMPROVE 2 - Palette property now can be written using a
  63. windows handle
  64. Thanks !!
  65. Version 1.5
  66. 2005-06-29 - Fixed a lot of bugs using tips from mails that I´ve
  67. being receiving for some time
  68. BUG 1 - Loosing palette when assigning to TBitmap. fixed
  69. BUG 2 - SetPixels and GetPixels worked only with
  70. parameters in range 0..255. fixed
  71. BUG 3 - Force type address off using directive
  72. BUG 4 - TChunkzTXt contained an error
  73. BUG 5 - MaxIdatSize was not working correctly (fixed thanks
  74. to Gabriel Corneanu
  75. BUG 6 - Corrected german translation (thanks to Mael Horz)
  76. And the following improvements:
  77. IMPROVE 1 - Create ImageHandleValue properties as public in
  78. TChunkIHDR to get access to this handle
  79. IMPROVE 2 - Using SetStretchBltMode to improve stretch quality
  80. IMPROVE 3 - Scale is now working for alpha transparent images
  81. IMPROVE 4 - GammaTable propery is now public to support an
  82. article in the help file
  83. Version 1.4361
  84. 2003-03-04 - Fixed important bug for simple transparency when using
  85. RGB, Grayscale color modes
  86. Version 1.436
  87. 2003-03-04 - * NEW * Property Pixels for direct access to pixels
  88. * IMPROVED * Palette property (TPngObject) (read only)
  89. Slovenian traslation for the component (Miha Petelin)
  90. Help file update (scanline article/png->jpg example)
  91. Version 1.435
  92. 2003-11-03 - * NEW * New chunk implementation zTXt (method AddzTXt)
  93. * NEW * New compiler flags to store the extra 8 bits
  94. from 16 bits samples (when saving it is ignored), the
  95. extra data may be acessed using ExtraScanline property
  96. * Fixed * a bug on tIMe chunk
  97. French translation included (Thanks to IBE Software)
  98. Bugs fixed
  99. Version 1.432
  100. 2002-08-24 - * NEW * A new method, CreateAlpha will transform the
  101. current image into partial transparency.
  102. Help file updated with a new article on how to handle
  103. partial transparency.
  104. Version 1.431
  105. 2002-08-14 - Fixed and tested to work on:
  106. C++ Builder 3
  107. C++ Builder 5
  108. Delphi 3
  109. There was an error when setting TransparentColor, fixed
  110. New method, RemoveTransparency to remove image
  111. BIT TRANSPARENCY
  112. Version 1.43
  113. 2002-08-01 - * NEW * Support for Delphi 3 and C++ Builder 3
  114. Implements mostly some things that were missing,
  115. a few tweaks and fixes.
  116. Version 1.428
  117. 2002-07-24 - More minor fixes (thanks to Ian Boyd)
  118. Bit transparency fixes
  119. * NEW * Finally support to bit transparency
  120. (palette / rgb / grayscale -> all)
  121. Version 1.427
  122. 2002-07-19 - Lots of bugs and leaks fixed
  123. * NEW * method to easy adding text comments, AddtEXt
  124. * NEW * property for setting bit transparency,
  125. TransparentColor
  126. Version 1.426
  127. 2002-07-18 - Clipboard finally fixed and working
  128. Changed UseDelphi trigger to UseDelphi
  129. * NEW * Support for bit transparency bitmaps
  130. when assigning from/to TBitmap objects
  131. Altough it does not support drawing transparent
  132. parts of bit transparency pngs (only partial)
  133. it is closer than ever
  134. Version 1.425
  135. 2002-07-01 - Clipboard methods implemented
  136. Lots of bugs fixed
  137. Version 1.424
  138. 2002-05-16 - Scanline and AlphaScanline are now working correctly.
  139. New methods for handling the clipboard
  140. Version 1.423
  141. 2002-05-16 - * NEW * Partial transparency for 1, 2, 4 and 8 bits is
  142. also supported using the tRNS chunk (for palette and
  143. grayscaling).
  144. New bug fixes (Peter Haas).
  145. Version 1.422
  146. 2002-05-14 - Fixed some critical leaks, thanks to Peter Haas tips.
  147. New translation for German (Peter Haas).
  148. Version 1.421
  149. 2002-05-06 - Now uses new ZLIB version, 1.1.4 with some security
  150. fixes.
  151. LoadFromResourceID and LoadFromResourceName added and
  152. help file updated for that.
  153. The resources strings are now located in pnglang.pas.
  154. New translation for Brazilian Portuguese.
  155. Bugs fixed.
  156. IMPORTANT: As always I´m looking for bugs on the library. If
  157. anyone has found one, please send me an email and
  158. I will fix asap. Thanks for all the help and ideas
  159. I'm receiving so far.}
  160. {My email is : gustavo.daud@terra.com.br}
  161. {Website link : http://pngdelphi.sourceforge.net}
  162. {Gustavo Huffenbacher Daud}
  163. unit pngimage;
  164. interface
  165. {Triggers avaliable (edit the fields bellow)}
  166. {$TYPEDADDRESS OFF}
  167. {$DEFINE UseDelphi} //Disable fat vcl units(perfect for small apps)
  168. {$DEFINE ErrorOnUnknownCritical} //Error when finds an unknown critical chunk
  169. {$DEFINE CheckCRC} //Enables CRC checking
  170. {$DEFINE RegisterGraphic} //Registers TPNGObject to use with TPicture
  171. {$DEFINE PartialTransparentDraw} //Draws partial transparent images
  172. {$DEFINE Store16bits} //Stores the extra 8 bits from 16bits/sample
  173. {$RANGECHECKS OFF} {$J+}
  174. uses
  175. Windows {$IFDEF UseDelphi}, Classes, Graphics, SysUtils{$ENDIF},
  176. zlibpas, pnglang;
  177. const
  178. LibraryVersion = '1.564';
  179. {$IFNDEF UseDelphi}
  180. const
  181. soFromBeginning = 0;
  182. soFromCurrent = 1;
  183. soFromEnd = 2;
  184. {$ENDIF}
  185. const
  186. {ZLIB constants}
  187. ZLIBErrors: Array[-6..2] of string = ('incompatible version (-6)',
  188. 'buffer error (-5)', 'insufficient memory (-4)', 'data error (-3)',
  189. 'stream error (-2)', 'file error (-1)', '(0)', 'stream end (1)',
  190. 'need dictionary (2)');
  191. Z_NO_FLUSH = 0;
  192. Z_FINISH = 4;
  193. Z_STREAM_END = 1;
  194. {Avaliable PNG filters for mode 0}
  195. FILTER_NONE = 0;
  196. FILTER_SUB = 1;
  197. FILTER_UP = 2;
  198. FILTER_AVERAGE = 3;
  199. FILTER_PAETH = 4;
  200. {Avaliable color modes for PNG}
  201. COLOR_GRAYSCALE = 0;
  202. COLOR_RGB = 2;
  203. COLOR_PALETTE = 3;
  204. COLOR_GRAYSCALEALPHA = 4;
  205. COLOR_RGBALPHA = 6;
  206. type
  207. {$IFNDEF UseDelphi}
  208. {Custom exception handler}
  209. Exception = class(TObject)
  210. constructor Create(Msg: String);
  211. end;
  212. ExceptClass = class of Exception;
  213. TColor = ColorRef;
  214. {$ENDIF}
  215. {Error types}
  216. EPNGOutMemory = class(Exception);
  217. EPngError = class(Exception);
  218. EPngUnexpectedEnd = class(Exception);
  219. EPngInvalidCRC = class(Exception);
  220. EPngInvalidIHDR = class(Exception);
  221. EPNGMissingMultipleIDAT = class(Exception);
  222. EPNGZLIBError = class(Exception);
  223. EPNGInvalidPalette = class(Exception);
  224. EPNGInvalidFileHeader = class(Exception);
  225. EPNGIHDRNotFirst = class(Exception);
  226. EPNGNotExists = class(Exception);
  227. EPNGSizeExceeds = class(Exception);
  228. EPNGMissingPalette = class(Exception);
  229. EPNGUnknownCriticalChunk = class(Exception);
  230. EPNGUnknownCompression = class(Exception);
  231. EPNGUnknownInterlace = class(Exception);
  232. EPNGNoImageData = class(Exception);
  233. EPNGCouldNotLoadResource = class(Exception);
  234. EPNGCannotChangeTransparent = class(Exception);
  235. EPNGHeaderNotPresent = class(Exception);
  236. EPNGInvalidNewSize = class(Exception);
  237. EPNGInvalidSpec = class(Exception);
  238. type
  239. {Direct access to pixels using R,G,B}
  240. TRGBLine = array[word] of TRGBTriple;
  241. pRGBLine = ^TRGBLine;
  242. {Same as TBitmapInfo but with allocated space for}
  243. {palette entries}
  244. TMAXBITMAPINFO = packed record
  245. bmiHeader: TBitmapInfoHeader;
  246. bmiColors: packed array[0..255] of TRGBQuad;
  247. end;
  248. {Transparency mode for pngs}
  249. TPNGTransparencyMode = (ptmNone, ptmBit, ptmPartial);
  250. {Pointer to a cardinal type}
  251. pCardinal = ^Cardinal;
  252. {Access to a rgb pixel}
  253. pRGBPixel = ^TRGBPixel;
  254. TRGBPixel = packed record
  255. B, G, R: Byte;
  256. end;
  257. {Pointer to an array of bytes type}
  258. TByteArray = Array[Word] of Byte;
  259. pByteArray = ^TByteArray;
  260. {Forward}
  261. TPNGObject = class;
  262. pPointerArray = ^TPointerArray;
  263. TPointerArray = Array[Word] of Pointer;
  264. {Contains a list of objects}
  265. TPNGPointerList = class
  266. private
  267. fOwner: TPNGObject;
  268. fCount : Cardinal;
  269. fMemory: pPointerArray;
  270. function GetItem(Index: Cardinal): Pointer;
  271. procedure SetItem(Index: Cardinal; const Value: Pointer);
  272. protected
  273. {Removes an item}
  274. function Remove(Value: Pointer): Pointer; virtual;
  275. {Inserts an item}
  276. procedure Insert(Value: Pointer; Position: Cardinal);
  277. {Add a new item}
  278. procedure Add(Value: Pointer);
  279. {Returns an item}
  280. property Item[Index: Cardinal]: Pointer read GetItem write SetItem;
  281. {Set the size of the list}
  282. procedure SetSize(const Size: Cardinal);
  283. {Returns owner}
  284. property Owner: TPNGObject read fOwner;
  285. public
  286. {Returns number of items}
  287. property Count: Cardinal read fCount write SetSize;
  288. {Object being either created or destroyed}
  289. constructor Create(AOwner: TPNGObject);
  290. destructor Destroy; override;
  291. end;
  292. {Forward declaration}
  293. TChunk = class;
  294. TChunkClass = class of TChunk;
  295. {Same as TPNGPointerList but providing typecasted values}
  296. TPNGList = class(TPNGPointerList)
  297. private
  298. {Used with property Item}
  299. function GetItem(Index: Cardinal): TChunk;
  300. public
  301. {Finds the first item with this class}
  302. function FindChunk(ChunkClass: TChunkClass): TChunk;
  303. {Removes an item}
  304. procedure RemoveChunk(Chunk: TChunk); overload;
  305. {Add a new chunk using the class from the parameter}
  306. function Add(ChunkClass: TChunkClass): TChunk;
  307. {Returns pointer to the first chunk of class}
  308. function ItemFromClass(ChunkClass: TChunkClass): TChunk;
  309. {Returns a chunk item from the list}
  310. property Item[Index: Cardinal]: TChunk read GetItem;
  311. end;
  312. {$IFNDEF UseDelphi}
  313. {The STREAMs bellow are only needed in case delphi provided ones is not}
  314. {avaliable (UseDelphi trigger not set)}
  315. {Object becomes handles}
  316. TCanvas = THandle;
  317. TBitmap = HBitmap;
  318. {Trick to work}
  319. TPersistent = TObject;
  320. {Base class for all streams}
  321. TStream = class
  322. protected
  323. {Returning/setting size}
  324. function GetSize: Longint; virtual;
  325. procedure SetSize(const Value: Longint); virtual; abstract;
  326. {Returns/set position}
  327. function GetPosition: Longint; virtual;
  328. procedure SetPosition(const Value: Longint); virtual;
  329. public
  330. {Returns/sets current position}
  331. property Position: Longint read GetPosition write SetPosition;
  332. {Property returns/sets size}
  333. property Size: Longint read GetSize write SetSize;
  334. {Allows reading/writing data}
  335. function Read(var Buffer; Count: Longint): Cardinal; virtual; abstract;
  336. function Write(const Buffer; Count: Longint): Cardinal; virtual; abstract;
  337. {Copies from another Stream}
  338. function CopyFrom(Source: TStream;
  339. Count: Cardinal): Cardinal; virtual;
  340. {Seeks a stream position}
  341. function Seek(Offset: Longint; Origin: Word): Longint; virtual; abstract;
  342. end;
  343. {File stream modes}
  344. TFileStreamMode = (fsmRead, fsmWrite, fsmCreate);
  345. TFileStreamModeSet = set of TFileStreamMode;
  346. {File stream for reading from files}
  347. TFileStream = class(TStream)
  348. private
  349. {Opened mode}
  350. Filemode: TFileStreamModeSet;
  351. {Handle}
  352. fHandle: THandle;
  353. protected
  354. {Set the size of the file}
  355. procedure SetSize(const Value: Longint); override;
  356. public
  357. {Seeks a file position}
  358. function Seek(Offset: Longint; Origin: Word): Longint; override;
  359. {Reads/writes data from/to the file}
  360. function Read(var Buffer; Count: Longint): Cardinal; override;
  361. function Write(const Buffer; Count: Longint): Cardinal; override;
  362. {Stream being created and destroy}
  363. constructor Create(Filename: String; Mode: TFileStreamModeSet);
  364. destructor Destroy; override;
  365. end;
  366. {Stream for reading from resources}
  367. TResourceStream = class(TStream)
  368. constructor Create(Instance: HInst; const ResName: String; ResType:PChar);
  369. private
  370. {Variables for reading}
  371. Size: Integer;
  372. Memory: Pointer;
  373. Position: Integer;
  374. protected
  375. {Set the size of the file}
  376. procedure SetSize(const Value: Longint); override;
  377. public
  378. {Stream processing}
  379. function Read(var Buffer; Count: Integer): Cardinal; override;
  380. function Seek(Offset: Integer; Origin: Word): Longint; override;
  381. function Write(const Buffer; Count: Longint): Cardinal; override;
  382. end;
  383. {$ENDIF}
  384. {Forward}
  385. TChunkIHDR = class;
  386. TChunkpHYs = class;
  387. {Interlace method}
  388. TInterlaceMethod = (imNone, imAdam7);
  389. {Compression level type}
  390. TCompressionLevel = 0..9;
  391. {Filters type}
  392. TFilter = (pfNone, pfSub, pfUp, pfAverage, pfPaeth);
  393. TFilters = set of TFilter;
  394. {Png implementation object}
  395. TPngObject = class{$IFDEF UseDelphi}(TGraphic){$ENDIF}
  396. protected
  397. {Inverse gamma table values}
  398. InverseGamma: Array[Byte] of Byte;
  399. procedure InitializeGamma;
  400. private
  401. {Canvas}
  402. {$IFDEF UseDelphi}fCanvas: TCanvas;{$ENDIF}
  403. {Filters to test to encode}
  404. fFilters: TFilters;
  405. {Compression level for ZLIB}
  406. fCompressionLevel: TCompressionLevel;
  407. {Maximum size for IDAT chunks}
  408. fMaxIdatSize: Integer;
  409. {Returns if image is interlaced}
  410. fInterlaceMethod: TInterlaceMethod;
  411. {Chunks object}
  412. fChunkList: TPngList;
  413. {Clear all chunks in the list}
  414. procedure ClearChunks;
  415. {Returns if header is present}
  416. function HeaderPresent: Boolean;
  417. procedure GetPixelInfo(var LineSize, Offset: Cardinal);
  418. {Returns linesize and byte offset for pixels}
  419. procedure SetMaxIdatSize(const Value: Integer);
  420. function GetAlphaScanline(const LineIndex: Integer): pByteArray;
  421. function GetScanline(const LineIndex: Integer): Pointer;
  422. {$IFDEF Store16bits}
  423. function GetExtraScanline(const LineIndex: Integer): Pointer;
  424. {$ENDIF}
  425. function GetPixelInformation: TChunkpHYs;
  426. function GetTransparencyMode: TPNGTransparencyMode;
  427. function GetTransparentColor: TColor;
  428. procedure SetTransparentColor(const Value: TColor);
  429. {Returns the version}
  430. function GetLibraryVersion: String;
  431. protected
  432. {Being created}
  433. BeingCreated: Boolean;
  434. {Returns / set the image palette}
  435. function GetPalette: HPALETTE; {$IFDEF UseDelphi}override;{$ENDIF}
  436. procedure SetPalette(Value: HPALETTE); {$IFDEF UseDelphi}override;{$ENDIF}
  437. procedure DoSetPalette(Value: HPALETTE; const UpdateColors: Boolean);
  438. {Returns/sets image width and height}
  439. function GetWidth: Integer; {$IFDEF UseDelphi}override;{$ENDIF}
  440. function GetHeight: Integer; {$IFDEF UseDelphi}override; {$ENDIF}
  441. procedure SetWidth(Value: Integer); {$IFDEF UseDelphi}override; {$ENDIF}
  442. procedure SetHeight(Value: Integer); {$IFDEF UseDelphi}override;{$ENDIF}
  443. {Assigns from another TPNGObject}
  444. procedure AssignPNG(Source: TPNGObject);
  445. {Returns if the image is empty}
  446. function GetEmpty: Boolean; {$IFDEF UseDelphi}override; {$ENDIF}
  447. {Used with property Header}
  448. function GetHeader: TChunkIHDR;
  449. {Draws using partial transparency}
  450. procedure DrawPartialTrans(DC: HDC; Rect: TRect);
  451. {$IFDEF UseDelphi}
  452. {Returns if the image is transparent}
  453. function GetTransparent: Boolean; override;
  454. {$ENDIF}
  455. {Returns a pixel}
  456. function GetPixels(const X, Y: Integer): TColor; virtual;
  457. procedure SetPixels(const X, Y: Integer; const Value: TColor); virtual;
  458. public
  459. {Gamma table array}
  460. GammaTable: Array[Byte] of Byte;
  461. {Resizes the PNG image}
  462. procedure Resize(const CX, CY: Integer);
  463. {Generates alpha information}
  464. procedure CreateAlpha;
  465. {Removes the image transparency}
  466. procedure RemoveTransparency;
  467. {Transparent color}
  468. property TransparentColor: TColor read GetTransparentColor write
  469. SetTransparentColor;
  470. {Add text chunk, TChunkTEXT, TChunkzTXT}
  471. procedure AddtEXt(const Keyword, Text: String);
  472. procedure AddzTXt(const Keyword, Text: String);
  473. {$IFDEF UseDelphi}
  474. {Saves to clipboard format (thanks to Antoine Pottern)}
  475. procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
  476. var APalette: HPalette); override;
  477. procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle;
  478. APalette: HPalette); override;
  479. {$ENDIF}
  480. {Calling errors}
  481. procedure RaiseError(ExceptionClass: ExceptClass; Text: String);
  482. {Returns a scanline from png}
  483. property Scanline[const Index: Integer]: Pointer read GetScanline;
  484. {$IFDEF Store16bits}
  485. property ExtraScanline[const Index: Integer]: Pointer read GetExtraScanline;
  486. {$ENDIF}
  487. {Used to return pixel information}
  488. function HasPixelInformation: Boolean;
  489. property PixelInformation: TChunkpHYs read GetPixelInformation;
  490. property AlphaScanline[const Index: Integer]: pByteArray read
  491. GetAlphaScanline;
  492. procedure DrawUsingPixelInformation(Canvas: TCanvas; Point: TPoint);
  493. {Canvas}
  494. {$IFDEF UseDelphi}property Canvas: TCanvas read fCanvas;{$ENDIF}
  495. {Returns pointer to the header}
  496. property Header: TChunkIHDR read GetHeader;
  497. {Returns the transparency mode used by this png}
  498. property TransparencyMode: TPNGTransparencyMode read GetTransparencyMode;
  499. {Assigns from another object}
  500. procedure Assign(Source: TPersistent);{$IFDEF UseDelphi}override;{$ENDIF}
  501. {Assigns to another object}
  502. procedure AssignTo(Dest: TPersistent);{$IFDEF UseDelphi}override;{$ENDIF}
  503. {Assigns from a windows bitmap handle}
  504. procedure AssignHandle(Handle: HBitmap; Transparent: Boolean;
  505. TransparentColor: ColorRef);
  506. {Draws the image into a canvas}
  507. procedure Draw(ACanvas: TCanvas; const Rect: TRect);
  508. {$IFDEF UseDelphi}override;{$ENDIF}
  509. {Width and height properties}
  510. property Width: Integer read GetWidth;
  511. property Height: Integer read GetHeight;
  512. {Returns if the image is interlaced}
  513. property InterlaceMethod: TInterlaceMethod read fInterlaceMethod
  514. write fInterlaceMethod;
  515. {Filters to test to encode}
  516. property Filters: TFilters read fFilters write fFilters;
  517. {Maximum size for IDAT chunks, default and minimum is 65536}
  518. property MaxIdatSize: Integer read fMaxIdatSize write SetMaxIdatSize;
  519. {Property to return if the image is empty or not}
  520. property Empty: Boolean read GetEmpty;
  521. {Compression level}
  522. property CompressionLevel: TCompressionLevel read fCompressionLevel
  523. write fCompressionLevel;
  524. {Access to the chunk list}
  525. property Chunks: TPngList read fChunkList;
  526. {Object being created and destroyed}
  527. constructor Create; {$IFDEF UseDelphi}override;{$ENDIF}
  528. constructor CreateBlank(ColorType, Bitdepth: Cardinal; cx, cy: Integer);
  529. destructor Destroy; override;
  530. {$IFNDEF UseDelphi}procedure LoadFromFile(const Filename: String);{$ENDIF}
  531. {$IFNDEF UseDelphi}procedure SaveToFile(const Filename: String);{$ENDIF}
  532. procedure LoadFromStream(Stream: TStream);
  533. {$IFDEF UseDelphi}override;{$ENDIF}
  534. procedure SaveToStream(Stream: TStream); {$IFDEF UseDelphi}override;{$ENDIF}
  535. {Loading the image from resources}
  536. procedure LoadFromResourceName(Instance: HInst; const Name: String);
  537. procedure LoadFromResourceID(Instance: HInst; ResID: Integer);
  538. {Access to the png pixels}
  539. property Pixels[const X, Y: Integer]: TColor read GetPixels write SetPixels;
  540. {Palette property}
  541. {$IFNDEF UseDelphi}property Palette: HPalette read GetPalette write
  542. SetPalette;{$ENDIF}
  543. {Returns the version}
  544. property Version: String read GetLibraryVersion;
  545. end;
  546. {Chunk name object}
  547. TChunkName = Array[0..3] of Char;
  548. {Global chunk object}
  549. TChunk = class
  550. private
  551. {Contains data}
  552. fData: Pointer;
  553. fDataSize: Cardinal;
  554. {Stores owner}
  555. fOwner: TPngObject;
  556. {Stores the chunk name}
  557. fName: TChunkName;
  558. {Returns pointer to the TChunkIHDR}
  559. function GetHeader: TChunkIHDR;
  560. {Used with property index}
  561. function GetIndex: Integer;
  562. {Should return chunk class/name}
  563. class function GetName: String; virtual;
  564. {Returns the chunk name}
  565. function GetChunkName: String;
  566. public
  567. {Returns index from list}
  568. property Index: Integer read GetIndex;
  569. {Returns pointer to the TChunkIHDR}
  570. property Header: TChunkIHDR read GetHeader;
  571. {Resize the data}
  572. procedure ResizeData(const NewSize: Cardinal);
  573. {Returns data and size}
  574. property Data: Pointer read fData;
  575. property DataSize: Cardinal read fDataSize;
  576. {Assigns from another TChunk}
  577. procedure Assign(Source: TChunk); virtual;
  578. {Returns owner}
  579. property Owner: TPngObject read fOwner;
  580. {Being destroyed/created}
  581. constructor Create(Owner: TPngObject); virtual;
  582. destructor Destroy; override;
  583. {Returns chunk class/name}
  584. property Name: String read GetChunkName;
  585. {Loads the chunk from a stream}
  586. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  587. Size: Integer): Boolean; virtual;
  588. {Saves the chunk to a stream}
  589. function SaveData(Stream: TStream): Boolean;
  590. function SaveToStream(Stream: TStream): Boolean; virtual;
  591. end;
  592. {Chunk classes}
  593. TChunkIEND = class(TChunk); {End chunk}
  594. {IHDR data}
  595. pIHDRData = ^TIHDRData;
  596. TIHDRData = packed record
  597. Width, Height: Cardinal;
  598. BitDepth,
  599. ColorType,
  600. CompressionMethod,
  601. FilterMethod,
  602. InterlaceMethod: Byte;
  603. end;
  604. {Information header chunk}
  605. TChunkIHDR = class(TChunk)
  606. private
  607. {Current image}
  608. ImageHandle: HBitmap;
  609. ImageDC: HDC;
  610. ImagePalette: HPalette;
  611. {Output windows bitmap}
  612. HasPalette: Boolean;
  613. BitmapInfo: TMaxBitmapInfo;
  614. {Stores the image bytes}
  615. {$IFDEF Store16bits}ExtraImageData: Pointer;{$ENDIF}
  616. ImageData: pointer;
  617. ImageAlpha: Pointer;
  618. {Contains all the ihdr data}
  619. IHDRData: TIHDRData;
  620. protected
  621. BytesPerRow: Integer;
  622. {Creates a grayscale palette}
  623. function CreateGrayscalePalette(Bitdepth: Integer): HPalette;
  624. {Copies the palette to the Device Independent bitmap header}
  625. procedure PaletteToDIB(Palette: HPalette);
  626. {Resizes the image data to fill the color type, bit depth, }
  627. {width and height parameters}
  628. procedure PrepareImageData;
  629. {Release allocated ImageData memory}
  630. procedure FreeImageData;
  631. public
  632. {Access to ImageHandle}
  633. property ImageHandleValue: HBitmap read ImageHandle;
  634. {Properties}
  635. property Width: Cardinal read IHDRData.Width write IHDRData.Width;
  636. property Height: Cardinal read IHDRData.Height write IHDRData.Height;
  637. property BitDepth: Byte read IHDRData.BitDepth write IHDRData.BitDepth;
  638. property ColorType: Byte read IHDRData.ColorType write IHDRData.ColorType;
  639. property CompressionMethod: Byte read IHDRData.CompressionMethod
  640. write IHDRData.CompressionMethod;
  641. property FilterMethod: Byte read IHDRData.FilterMethod
  642. write IHDRData.FilterMethod;
  643. property InterlaceMethod: Byte read IHDRData.InterlaceMethod
  644. write IHDRData.InterlaceMethod;
  645. {Loads the chunk from a stream}
  646. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  647. Size: Integer): Boolean; override;
  648. {Saves the chunk to a stream}
  649. function SaveToStream(Stream: TStream): Boolean; override;
  650. {Destructor/constructor}
  651. constructor Create(Owner: TPngObject); override;
  652. destructor Destroy; override;
  653. {Assigns from another TChunk}
  654. procedure Assign(Source: TChunk); override;
  655. end;
  656. {pHYs chunk}
  657. pUnitType = ^TUnitType;
  658. TUnitType = (utUnknownType{utUnknown}, utMeter);
  659. TChunkpHYs = class(TChunk)
  660. private
  661. fPPUnitX, fPPUnitY: Cardinal;
  662. fUnit: TUnitType;
  663. public
  664. {Returns the properties}
  665. property PPUnitX: Cardinal read fPPUnitX write fPPUnitX;
  666. property PPUnitY: Cardinal read fPPUnitY write fPPUnitY;
  667. property UnitType: TUnitType read fUnit write fUnit;
  668. {Loads the chunk from a stream}
  669. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  670. Size: Integer): Boolean; override;
  671. {Saves the chunk to a stream}
  672. function SaveToStream(Stream: TStream): Boolean; override;
  673. {Assigns from another TChunk}
  674. procedure Assign(Source: TChunk); override;
  675. end;
  676. {Gamma chunk}
  677. TChunkgAMA = class(TChunk)
  678. private
  679. {Returns/sets the value for the gamma chunk}
  680. function GetValue: Cardinal;
  681. procedure SetValue(const Value: Cardinal);
  682. public
  683. {Returns/sets gamma value}
  684. property Gamma: Cardinal read GetValue write SetValue;
  685. {Loading the chunk from a stream}
  686. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  687. Size: Integer): Boolean; override;
  688. {Being created}
  689. constructor Create(Owner: TPngObject); override;
  690. {Assigns from another TChunk}
  691. procedure Assign(Source: TChunk); override;
  692. end;
  693. {ZLIB Decompression extra information}
  694. TZStreamRec2 = packed record
  695. {From ZLIB}
  696. ZLIB: TZStreamRec;
  697. {Additional info}
  698. Data: Pointer;
  699. fStream : TStream;
  700. end;
  701. {Palette chunk}
  702. TChunkPLTE = class(TChunk)
  703. protected
  704. {Number of items in the palette}
  705. fCount: Integer;
  706. private
  707. {Contains the palette handle}
  708. function GetPaletteItem(Index: Byte): TRGBQuad;
  709. public
  710. {Returns the color for each item in the palette}
  711. property Item[Index: Byte]: TRGBQuad read GetPaletteItem;
  712. {Returns the number of items in the palette}
  713. property Count: Integer read fCount;
  714. {Loads the chunk from a stream}
  715. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  716. Size: Integer): Boolean; override;
  717. {Saves the chunk to a stream}
  718. function SaveToStream(Stream: TStream): Boolean; override;
  719. {Assigns from another TChunk}
  720. procedure Assign(Source: TChunk); override;
  721. end;
  722. {Transparency information}
  723. TChunktRNS = class(TChunk)
  724. private
  725. fBitTransparency: Boolean;
  726. function GetTransparentColor: ColorRef;
  727. {Returns the transparent color}
  728. procedure SetTransparentColor(const Value: ColorRef);
  729. public
  730. {Palette values for transparency}
  731. PaletteValues: Array[Byte] of Byte;
  732. {Returns if it uses bit transparency}
  733. property BitTransparency: Boolean read fBitTransparency;
  734. {Returns the transparent color}
  735. property TransparentColor: ColorRef read GetTransparentColor write
  736. SetTransparentColor;
  737. {Loads/saves the chunk from/to a stream}
  738. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  739. Size: Integer): Boolean; override;
  740. function SaveToStream(Stream: TStream): Boolean; override;
  741. {Assigns from another TChunk}
  742. procedure Assign(Source: TChunk); override;
  743. end;
  744. {Actual image information}
  745. TChunkIDAT = class(TChunk)
  746. private
  747. {Holds another pointer to the TChunkIHDR}
  748. Header: TChunkIHDR;
  749. {Stores temporary image width and height}
  750. ImageWidth, ImageHeight: Integer;
  751. {Size in bytes of each line and offset}
  752. Row_Bytes, Offset : Cardinal;
  753. {Contains data for the lines}
  754. Encode_Buffer: Array[0..5] of pByteArray;
  755. Row_Buffer: Array[Boolean] of pByteArray;
  756. {Variable to invert the Row_Buffer used}
  757. RowUsed: Boolean;
  758. {Ending position for the current IDAT chunk}
  759. EndPos: Integer;
  760. {Filter the current line}
  761. procedure FilterRow;
  762. {Filter to encode and returns the best filter}
  763. function FilterToEncode: Byte;
  764. {Reads ZLIB compressed data}
  765. function IDATZlibRead(var ZLIBStream: TZStreamRec2; Buffer: Pointer;
  766. Count: Integer; var EndPos: Integer; var crcfile: Cardinal): Integer;
  767. {Compress and writes IDAT data}
  768. procedure IDATZlibWrite(var ZLIBStream: TZStreamRec2; Buffer: Pointer;
  769. const Length: Cardinal);
  770. procedure FinishIDATZlib(var ZLIBStream: TZStreamRec2);
  771. {Prepares the palette}
  772. procedure PreparePalette;
  773. protected
  774. {Decode interlaced image}
  775. procedure DecodeInterlacedAdam7(Stream: TStream;
  776. var ZLIBStream: TZStreamRec2; const Size: Integer; var crcfile: Cardinal);
  777. {Decode non interlaced imaged}
  778. procedure DecodeNonInterlaced(Stream: TStream;
  779. var ZLIBStream: TZStreamRec2; const Size: Integer;
  780. var crcfile: Cardinal);
  781. protected
  782. {Encode non interlaced images}
  783. procedure EncodeNonInterlaced(Stream: TStream;
  784. var ZLIBStream: TZStreamRec2);
  785. {Encode interlaced images}
  786. procedure EncodeInterlacedAdam7(Stream: TStream;
  787. var ZLIBStream: TZStreamRec2);
  788. protected
  789. {Memory copy methods to decode}
  790. procedure CopyNonInterlacedRGB8(
  791. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  792. procedure CopyNonInterlacedRGB16(
  793. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  794. procedure CopyNonInterlacedPalette148(
  795. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  796. procedure CopyNonInterlacedPalette2(
  797. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  798. procedure CopyNonInterlacedGray2(
  799. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  800. procedure CopyNonInterlacedGrayscale16(
  801. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  802. procedure CopyNonInterlacedRGBAlpha8(
  803. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  804. procedure CopyNonInterlacedRGBAlpha16(
  805. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  806. procedure CopyNonInterlacedGrayscaleAlpha8(
  807. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  808. procedure CopyNonInterlacedGrayscaleAlpha16(
  809. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  810. procedure CopyInterlacedRGB8(const Pass: Byte;
  811. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  812. procedure CopyInterlacedRGB16(const Pass: Byte;
  813. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  814. procedure CopyInterlacedPalette148(const Pass: Byte;
  815. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  816. procedure CopyInterlacedPalette2(const Pass: Byte;
  817. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  818. procedure CopyInterlacedGray2(const Pass: Byte;
  819. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  820. procedure CopyInterlacedGrayscale16(const Pass: Byte;
  821. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  822. procedure CopyInterlacedRGBAlpha8(const Pass: Byte;
  823. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  824. procedure CopyInterlacedRGBAlpha16(const Pass: Byte;
  825. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  826. procedure CopyInterlacedGrayscaleAlpha8(const Pass: Byte;
  827. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  828. procedure CopyInterlacedGrayscaleAlpha16(const Pass: Byte;
  829. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  830. protected
  831. {Memory copy methods to encode}
  832. procedure EncodeNonInterlacedRGB8(Src, Dest, Trans: pChar);
  833. procedure EncodeNonInterlacedRGB16(Src, Dest, Trans: pChar);
  834. procedure EncodeNonInterlacedGrayscale16(Src, Dest, Trans: pChar);
  835. procedure EncodeNonInterlacedPalette148(Src, Dest, Trans: pChar);
  836. procedure EncodeNonInterlacedRGBAlpha8(Src, Dest, Trans: pChar);
  837. procedure EncodeNonInterlacedRGBAlpha16(Src, Dest, Trans: pChar);
  838. procedure EncodeNonInterlacedGrayscaleAlpha8(Src, Dest, Trans: pChar);
  839. procedure EncodeNonInterlacedGrayscaleAlpha16(Src, Dest, Trans: pChar);
  840. procedure EncodeInterlacedRGB8(const Pass: Byte; Src, Dest, Trans: pChar);
  841. procedure EncodeInterlacedRGB16(const Pass: Byte; Src, Dest, Trans: pChar);
  842. procedure EncodeInterlacedPalette148(const Pass: Byte;
  843. Src, Dest, Trans: pChar);
  844. procedure EncodeInterlacedGrayscale16(const Pass: Byte;
  845. Src, Dest, Trans: pChar);
  846. procedure EncodeInterlacedRGBAlpha8(const Pass: Byte;
  847. Src, Dest, Trans: pChar);
  848. procedure EncodeInterlacedRGBAlpha16(const Pass: Byte;
  849. Src, Dest, Trans: pChar);
  850. procedure EncodeInterlacedGrayscaleAlpha8(const Pass: Byte;
  851. Src, Dest, Trans: pChar);
  852. procedure EncodeInterlacedGrayscaleAlpha16(const Pass: Byte;
  853. Src, Dest, Trans: pChar);
  854. public
  855. {Loads the chunk from a stream}
  856. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  857. Size: Integer): Boolean; override;
  858. {Saves the chunk to a stream}
  859. function SaveToStream(Stream: TStream): Boolean; override;
  860. end;
  861. {Image last modification chunk}
  862. TChunktIME = class(TChunk)
  863. private
  864. {Holds the variables}
  865. fYear: Word;
  866. fMonth, fDay, fHour, fMinute, fSecond: Byte;
  867. public
  868. {Returns/sets variables}
  869. property Year: Word read fYear write fYear;
  870. property Month: Byte read fMonth write fMonth;
  871. property Day: Byte read fDay write fDay;
  872. property Hour: Byte read fHour write fHour;
  873. property Minute: Byte read fMinute write fMinute;
  874. property Second: Byte read fSecond write fSecond;
  875. {Loads the chunk from a stream}
  876. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  877. Size: Integer): Boolean; override;
  878. {Saves the chunk to a stream}
  879. function SaveToStream(Stream: TStream): Boolean; override;
  880. {Assigns from another TChunk}
  881. procedure Assign(Source: TChunk); override;
  882. end;
  883. {Textual data}
  884. TChunktEXt = class(TChunk)
  885. private
  886. fKeyword, fText: String;
  887. public
  888. {Keyword and text}
  889. property Keyword: String read fKeyword write fKeyword;
  890. property Text: String read fText write fText;
  891. {Loads the chunk from a stream}
  892. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  893. Size: Integer): Boolean; override;
  894. {Saves the chunk to a stream}
  895. function SaveToStream(Stream: TStream): Boolean; override;
  896. {Assigns from another TChunk}
  897. procedure Assign(Source: TChunk); override;
  898. end;
  899. {zTXT chunk}
  900. TChunkzTXt = class(TChunktEXt)
  901. {Loads the chunk from a stream}
  902. function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  903. Size: Integer): Boolean; override;
  904. {Saves the chunk to a stream}
  905. function SaveToStream(Stream: TStream): Boolean; override;
  906. end;
  907. {Here we test if it's c++ builder or delphi version 3 or less}
  908. {$IFDEF VER110}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  909. {$IFDEF VER100}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  910. {$IFDEF VER93}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  911. {$IFDEF VER90}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  912. {$IFDEF VER80}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  913. {Registers a new chunk class}
  914. procedure RegisterChunk(ChunkClass: TChunkClass);
  915. {Calculates crc}
  916. function update_crc(crc: {$IFNDEF DelphiBuilder3Less}Cardinal{$ELSE}Integer
  917. {$ENDIF}; buf: pByteArray; len: Integer): Cardinal;
  918. {Invert bytes using assembly}
  919. function ByteSwap(const a: integer): integer;
  920. implementation
  921. var
  922. ChunkClasses: TPngPointerList;
  923. {Table of CRCs of all 8-bit messages}
  924. crc_table: Array[0..255] of Cardinal;
  925. {Flag: has the table been computed? Initially false}
  926. crc_table_computed: Boolean;
  927. {Draw transparent image using transparent color}
  928. procedure DrawTransparentBitmap(dc: HDC; srcBits: Pointer;
  929. var srcHeader: TBitmapInfoHeader;
  930. srcBitmapInfo: pBitmapInfo; Rect: TRect; cTransparentColor: COLORREF);
  931. var
  932. cColor: COLORREF;
  933. bmAndBack, bmAndObject, bmAndMem: HBITMAP;
  934. bmBackOld, bmObjectOld, bmMemOld: HBITMAP;
  935. hdcMem, hdcBack, hdcObject, hdcTemp: HDC;
  936. ptSize, orgSize: TPOINT;
  937. OldBitmap, DrawBitmap: HBITMAP;
  938. begin
  939. hdcTemp := CreateCompatibleDC(dc);
  940. {Select the bitmap}
  941. DrawBitmap := CreateDIBitmap(dc, srcHeader, CBM_INIT, srcBits, srcBitmapInfo^,
  942. DIB_RGB_COLORS);
  943. OldBitmap := SelectObject(hdcTemp, DrawBitmap);
  944. {Get sizes}
  945. OrgSize.x := abs(srcHeader.biWidth);
  946. OrgSize.y := abs(srcHeader.biHeight);
  947. ptSize.x := Rect.Right - Rect.Left; // Get width of bitmap
  948. ptSize.y := Rect.Bottom - Rect.Top; // Get height of bitmap
  949. {Create some DCs to hold temporary data}
  950. hdcBack := CreateCompatibleDC(dc);
  951. hdcObject := CreateCompatibleDC(dc);
  952. hdcMem := CreateCompatibleDC(dc);
  953. // Create a bitmap for each DC. DCs are required for a number of
  954. // GDI functions.
  955. // Monochrome DCs
  956. bmAndBack := CreateBitmap(ptSize.x, ptSize.y, 1, 1, nil);
  957. bmAndObject := CreateBitmap(ptSize.x, ptSize.y, 1, 1, nil);
  958. bmAndMem := CreateCompatibleBitmap(dc, ptSize.x, ptSize.y);
  959. // Each DC must select a bitmap object to store pixel data.
  960. bmBackOld := SelectObject(hdcBack, bmAndBack);
  961. bmObjectOld := SelectObject(hdcObject, bmAndObject);
  962. bmMemOld := SelectObject(hdcMem, bmAndMem);
  963. // Set the background color of the source DC to the color.
  964. // contained in the parts of the bitmap that should be transparent
  965. cColor := SetBkColor(hdcTemp, cTransparentColor);
  966. // Create the object mask for the bitmap by performing a BitBlt
  967. // from the source bitmap to a monochrome bitmap.
  968. StretchBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
  969. orgSize.x, orgSize.y, SRCCOPY);
  970. // Set the background color of the source DC back to the original
  971. // color.
  972. SetBkColor(hdcTemp, cColor);
  973. // Create the inverse of the object mask.
  974. BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,
  975. NOTSRCCOPY);
  976. // Copy the background of the main DC to the destination.
  977. BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, dc, Rect.Left, Rect.Top,
  978. SRCCOPY);
  979. // Mask out the places where the bitmap will be placed.
  980. BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
  981. // Mask out the transparent colored pixels on the bitmap.
  982. // BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
  983. StretchBlt(hdcTemp, 0, 0, OrgSize.x, OrgSize.y, hdcBack, 0, 0,
  984. PtSize.x, PtSize.y, SRCAND);
  985. // XOR the bitmap with the background on the destination DC.
  986. StretchBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
  987. OrgSize.x, OrgSize.y, SRCPAINT);
  988. // Copy the destination to the screen.
  989. BitBlt(dc, Rect.Left, Rect.Top, ptSize.x, ptSize.y, hdcMem, 0, 0,
  990. SRCCOPY);
  991. // Delete the memory bitmaps.
  992. DeleteObject(SelectObject(hdcBack, bmBackOld));
  993. DeleteObject(SelectObject(hdcObject, bmObjectOld));
  994. DeleteObject(SelectObject(hdcMem, bmMemOld));
  995. DeleteObject(SelectObject(hdcTemp, OldBitmap));
  996. // Delete the memory DCs.
  997. DeleteDC(hdcMem);
  998. DeleteDC(hdcBack);
  999. DeleteDC(hdcObject);
  1000. DeleteDC(hdcTemp);
  1001. end;
  1002. {Make the table for a fast CRC.}
  1003. procedure make_crc_table;
  1004. var
  1005. c: Cardinal;
  1006. n, k: Integer;
  1007. begin
  1008. {fill the crc table}
  1009. for n := 0 to 255 do
  1010. begin
  1011. c := Cardinal(n);
  1012. for k := 0 to 7 do
  1013. begin
  1014. if Boolean(c and 1) then
  1015. c := $edb88320 xor (c shr 1)
  1016. else
  1017. c := c shr 1;
  1018. end;
  1019. crc_table[n] := c;
  1020. end;
  1021. {The table has already being computated}
  1022. crc_table_computed := true;
  1023. end;
  1024. {Update a running CRC with the bytes buf[0..len-1]--the CRC
  1025. should be initialized to all 1's, and the transmitted value
  1026. is the 1's complement of the final running CRC (see the
  1027. crc() routine below)).}
  1028. function update_crc(crc: {$IFNDEF DelphiBuilder3Less}Cardinal{$ELSE}Integer
  1029. {$ENDIF}; buf: pByteArray; len: Integer): Cardinal;
  1030. var
  1031. c: Cardinal;
  1032. n: Integer;
  1033. begin
  1034. c := crc;
  1035. {Create the crc table in case it has not being computed yet}
  1036. if not crc_table_computed then make_crc_table;
  1037. {Update}
  1038. for n := 0 to len - 1 do
  1039. c := crc_table[(c XOR buf^[n]) and $FF] XOR (c shr 8);
  1040. {Returns}
  1041. Result := c;
  1042. end;
  1043. {$IFNDEF UseDelphi}
  1044. function FileExists(Filename: String): Boolean;
  1045. var
  1046. FindFile: THandle;
  1047. FindData: TWin32FindData;
  1048. begin
  1049. FindFile := FindFirstFile(PChar(Filename), FindData);
  1050. Result := FindFile <> INVALID_HANDLE_VALUE;
  1051. if Result then Windows.FindClose(FindFile);
  1052. end;
  1053. {$ENDIF}
  1054. {$IFNDEF UseDelphi}
  1055. {Exception implementation}
  1056. constructor Exception.Create(Msg: String);
  1057. begin
  1058. end;
  1059. {$ENDIF}
  1060. {Calculates the paeth predictor}
  1061. function PaethPredictor(a, b, c: Byte): Byte;
  1062. var
  1063. pa, pb, pc: Integer;
  1064. begin
  1065. { a = left, b = above, c = upper left }
  1066. pa := abs(b - c); { distances to a, b, c }
  1067. pb := abs(a - c);
  1068. pc := abs(a + b - c * 2);
  1069. { return nearest of a, b, c, breaking ties in order a, b, c }
  1070. if (pa <= pb) and (pa <= pc) then
  1071. Result := a
  1072. else
  1073. if pb <= pc then
  1074. Result := b
  1075. else
  1076. Result := c;
  1077. end;
  1078. {Invert bytes using assembly}
  1079. function ByteSwap(const a: integer): integer;
  1080. asm
  1081. bswap eax
  1082. end;
  1083. function ByteSwap16(inp:word): word;
  1084. asm
  1085. bswap eax
  1086. shr eax, 16
  1087. end;
  1088. {Calculates number of bytes for the number of pixels using the}
  1089. {color mode in the paramenter}
  1090. function BytesForPixels(const Pixels: Integer; const ColorType,
  1091. BitDepth: Byte): Integer;
  1092. begin
  1093. case ColorType of
  1094. {Palette and grayscale contains a single value, for palette}
  1095. {an value of size 2^bitdepth pointing to the palette index}
  1096. {and grayscale the value from 0 to 2^bitdepth with color intesity}
  1097. COLOR_GRAYSCALE, COLOR_PALETTE:
  1098. Result := (Pixels * BitDepth + 7) div 8;
  1099. {RGB contains 3 values R, G, B with size 2^bitdepth each}
  1100. COLOR_RGB:
  1101. Result := (Pixels * BitDepth * 3) div 8;
  1102. {Contains one value followed by alpha value booth size 2^bitdepth}
  1103. COLOR_GRAYSCALEALPHA:
  1104. Result := (Pixels * BitDepth * 2) div 8;
  1105. {Contains four values size 2^bitdepth, Red, Green, Blue and alpha}
  1106. COLOR_RGBALPHA:
  1107. Result := (Pixels * BitDepth * 4) div 8;
  1108. else
  1109. Result := 0;
  1110. end {case ColorType}
  1111. end;
  1112. type
  1113. pChunkClassInfo = ^TChunkClassInfo;
  1114. TChunkClassInfo = record
  1115. ClassName: TChunkClass;
  1116. end;
  1117. {Register a chunk type}
  1118. procedure RegisterChunk(ChunkClass: TChunkClass);
  1119. var
  1120. NewClass: pChunkClassInfo;
  1121. begin
  1122. {In case the list object has not being created yet}
  1123. if ChunkClasses = nil then ChunkClasses := TPngPointerList.Create(nil);
  1124. {Add this new class}
  1125. new(NewClass);
  1126. NewClass^.ClassName := ChunkClass;
  1127. ChunkClasses.Add(NewClass);
  1128. end;
  1129. {Free chunk class list}
  1130. procedure FreeChunkClassList;
  1131. var
  1132. i: Integer;
  1133. begin
  1134. if (ChunkClasses <> nil) then
  1135. begin
  1136. FOR i := 0 TO ChunkClasses.Count - 1 do
  1137. Dispose(pChunkClassInfo(ChunkClasses.Item[i]));
  1138. ChunkClasses.Free;
  1139. end;
  1140. end;
  1141. {Registering of common chunk classes}
  1142. procedure RegisterCommonChunks;
  1143. begin
  1144. {Important chunks}
  1145. RegisterChunk(TChunkIEND);
  1146. RegisterChunk(TChunkIHDR);
  1147. RegisterChunk(TChunkIDAT);
  1148. RegisterChunk(TChunkPLTE);
  1149. RegisterChunk(TChunkgAMA);
  1150. RegisterChunk(TChunktRNS);
  1151. {Not so important chunks}
  1152. RegisterChunk(TChunkpHYs);
  1153. RegisterChunk(TChunktIME);
  1154. RegisterChunk(TChunktEXt);
  1155. RegisterChunk(TChunkzTXt);
  1156. end;
  1157. {Creates a new chunk of this class}
  1158. function CreateClassChunk(Owner: TPngObject; Name: TChunkName): TChunk;
  1159. var
  1160. i : Integer;
  1161. NewChunk: TChunkClass;
  1162. begin
  1163. {Looks for this chunk}
  1164. NewChunk := TChunk; {In case there is no registered class for this}
  1165. {Looks for this class in all registered chunks}
  1166. if Assigned(ChunkClasses) then
  1167. FOR i := 0 TO ChunkClasses.Count - 1 DO
  1168. begin
  1169. if pChunkClassInfo(ChunkClasses.Item[i])^.ClassName.GetName = Name then
  1170. begin
  1171. NewChunk := pChunkClassInfo(ChunkClasses.Item[i])^.ClassName;
  1172. break;
  1173. end;
  1174. end;
  1175. {Returns chunk class}
  1176. Result := NewChunk.Create(Owner);
  1177. Result.fName := Name;
  1178. end;
  1179. {ZLIB support}
  1180. const
  1181. ZLIBAllocate = High(Word);
  1182. {Initializes ZLIB for decompression}
  1183. function ZLIBInitInflate(Stream: TStream): TZStreamRec2;
  1184. begin
  1185. {Fill record}
  1186. Fillchar(Result, SIZEOF(TZStreamRec2), #0);
  1187. {Set internal record information}
  1188. with Result do
  1189. begin
  1190. GetMem(Data, ZLIBAllocate);
  1191. fStream := Stream;
  1192. end;
  1193. {Init decompression}
  1194. InflateInit_(Result.zlib, zlib_version, SIZEOF(TZStreamRec));
  1195. end;
  1196. {Initializes ZLIB for compression}
  1197. function ZLIBInitDeflate(Stream: TStream;
  1198. Level: TCompressionlevel; Size: Cardinal): TZStreamRec2;
  1199. begin
  1200. {Fill record}
  1201. Fillchar(Result, SIZEOF(TZStreamRec2), #0);
  1202. {Set internal record information}
  1203. with Result, ZLIB do
  1204. begin
  1205. GetMem(Data, Size);
  1206. fStream := Stream;
  1207. next_out := Data;
  1208. avail_out := Size;
  1209. end;
  1210. {Inits compression}
  1211. deflateInit_(Result.zlib, Level, zlib_version, sizeof(TZStreamRec));
  1212. end;
  1213. {Terminates ZLIB for compression}
  1214. procedure ZLIBTerminateDeflate(var ZLIBStream: TZStreamRec2);
  1215. begin
  1216. {Terminates decompression}
  1217. DeflateEnd(ZLIBStream.zlib);
  1218. {Free internal record}
  1219. FreeMem(ZLIBStream.Data, ZLIBAllocate);
  1220. end;
  1221. {Terminates ZLIB for decompression}
  1222. procedure ZLIBTerminateInflate(var ZLIBStream: TZStreamRec2);
  1223. begin
  1224. {Terminates decompression}
  1225. InflateEnd(ZLIBStream.zlib);
  1226. {Free internal record}
  1227. FreeMem(ZLIBStream.Data, ZLIBAllocate);
  1228. end;
  1229. {Decompresses ZLIB into a memory address}
  1230. function DecompressZLIB(const Input: Pointer; InputSize: Integer;
  1231. var Output: Pointer; var OutputSize: Integer;
  1232. var ErrorOutput: String): Boolean;
  1233. var
  1234. StreamRec : TZStreamRec;
  1235. Buffer : Array[Byte] of Byte;
  1236. InflateRet: Integer;
  1237. begin
  1238. with StreamRec do
  1239. begin
  1240. {Initializes}
  1241. Result := True;
  1242. OutputSize := 0;
  1243. {Prepares the data to decompress}
  1244. FillChar(StreamRec, SizeOf(TZStreamRec), #0);
  1245. InflateInit_(StreamRec, zlib_version, SIZEOF(TZStreamRec));
  1246. next_in := Input;
  1247. avail_in := InputSize;
  1248. {Decodes data}
  1249. repeat
  1250. {In case it needs an output buffer}
  1251. if (avail_out = 0) then
  1252. begin
  1253. next_out := @Buffer;
  1254. avail_out := SizeOf(Buffer);
  1255. end {if (avail_out = 0)};
  1256. {Decompress and put in output}
  1257. InflateRet := inflate(StreamRec, 0);
  1258. if (InflateRet = Z_STREAM_END) or (InflateRet = 0) then
  1259. begin
  1260. {Reallocates output buffer}
  1261. inc(OutputSize, total_out);
  1262. if Output = nil then
  1263. GetMem(Output, OutputSize) else ReallocMem(Output, OutputSize);
  1264. {Copies the new data}
  1265. CopyMemory(Ptr(Longint(Output) + OutputSize - total_out),
  1266. @Buffer, total_out);
  1267. end {if (InflateRet = Z_STREAM_END) or (InflateRet = 0)}
  1268. {Now tests for errors}
  1269. else if InflateRet < 0 then
  1270. begin
  1271. Result := False;
  1272. ErrorOutput := StreamRec.msg;
  1273. InflateEnd(StreamRec);
  1274. Exit;
  1275. end {if InflateRet < 0}
  1276. until InflateRet = Z_STREAM_END;
  1277. {Terminates decompression}
  1278. InflateEnd(StreamRec);
  1279. end {with StreamRec}
  1280. end;
  1281. {Compresses ZLIB into a memory address}
  1282. function CompressZLIB(Input: Pointer; InputSize, CompressionLevel: Integer;
  1283. var Output: Pointer; var OutputSize: Integer;
  1284. var ErrorOutput: String): Boolean;
  1285. var
  1286. StreamRec : TZStreamRec;
  1287. Buffer : Array[Byte] of Byte;
  1288. DeflateRet: Integer;
  1289. begin
  1290. with StreamRec do
  1291. begin
  1292. Result := True; {By default returns TRUE as everything might have gone ok}
  1293. OutputSize := 0; {Initialize}
  1294. {Prepares the data to compress}
  1295. FillChar(StreamRec, SizeOf(TZStreamRec), #0);
  1296. DeflateInit_(StreamRec, CompressionLevel,zlib_version, SIZEOF(TZStreamRec));
  1297. next_in := Input;
  1298. avail_in := InputSize;
  1299. while avail_in > 0 do
  1300. begin
  1301. {When it needs new buffer to stores the compressed data}
  1302. if avail_out = 0 then
  1303. begin
  1304. {Restore buffer}
  1305. next_out := @Buffer;
  1306. avail_out := SizeOf(Buffer);
  1307. end {if avail_out = 0};
  1308. {Compresses}
  1309. DeflateRet := deflate(StreamRec, Z_FINISH);
  1310. if (DeflateRet = Z_STREAM_END) or (DeflateRet = 0) then
  1311. begin
  1312. {Updates the output memory}
  1313. inc(OutputSize, total_out);
  1314. if Output = nil then
  1315. GetMem(Output, OutputSize) else ReallocMem(Output, OutputSize);
  1316. {Copies the new data}
  1317. CopyMemory(Ptr(Longint(Output) + OutputSize - total_out),
  1318. @Buffer, total_out);
  1319. end {if (InflateRet = Z_STREAM_END) or (InflateRet = 0)}
  1320. {Now tests for errors}
  1321. else if DeflateRet < 0 then
  1322. begin
  1323. Result := False;
  1324. ErrorOutput := StreamRec.msg;
  1325. DeflateEnd(StreamRec);
  1326. Exit;
  1327. end {if InflateRet < 0}
  1328. end {while avail_in > 0};
  1329. {Finishes compressing}
  1330. DeflateEnd(StreamRec);
  1331. end {with StreamRec}
  1332. end;
  1333. {TPngPointerList implementation}
  1334. {Object being created}
  1335. constructor TPngPointerList.Create(AOwner: TPNGObject);
  1336. begin
  1337. inherited Create; {Let ancestor work}
  1338. {Holds owner}
  1339. fOwner := AOwner;
  1340. {Memory pointer not being used yet}
  1341. fMemory := nil;
  1342. {No items yet}
  1343. fCount := 0;
  1344. end;
  1345. {Removes value from the list}
  1346. function TPngPointerList.Remove(Value: Pointer): Pointer;
  1347. var
  1348. I, Position: Integer;
  1349. begin
  1350. {Gets item position}
  1351. Position := -1;
  1352. FOR I := 0 TO Count - 1 DO
  1353. if Value = Item[I] then Position := I;
  1354. {In case a match was found}
  1355. if Position >= 0 then
  1356. begin
  1357. Result := Item[Position]; {Returns pointer}
  1358. {Remove item and move memory}
  1359. Dec(fCount);
  1360. if Position < Integer(FCount) then
  1361. System.Move(fMemory^[Position + 1], fMemory^[Position],
  1362. (Integer(fCount) - Position) * SizeOf(Pointer));
  1363. end {if Position >= 0} else Result := nil
  1364. end;
  1365. {Add a new value in the list}
  1366. procedure TPngPointerList.Add(Value: Pointer);
  1367. begin
  1368. Count := Count + 1;
  1369. Item[Count - 1] := Value;
  1370. end;
  1371. {Object being destroyed}
  1372. destructor TPngPointerList.Destroy;
  1373. begin
  1374. {Release memory if needed}
  1375. if fMemory <> nil then
  1376. FreeMem(fMemory, fCount * sizeof(Pointer));
  1377. {Free things}
  1378. inherited Destroy;
  1379. end;
  1380. {Returns one item from the list}
  1381. function TPngPointerList.GetItem(Index: Cardinal): Pointer;
  1382. begin
  1383. if (Index <= Count - 1) then
  1384. Result := fMemory[Index]
  1385. else
  1386. {In case it's out of bounds}
  1387. Result := nil;
  1388. end;
  1389. {Inserts a new item in the list}
  1390. procedure TPngPointerList.Insert(Value: Pointer; Position: Cardinal);
  1391. begin
  1392. if (Position < Count) or (Count = 0) then
  1393. begin
  1394. {Increase item count}
  1395. SetSize(Count + 1);
  1396. {Move other pointers}
  1397. if Position < Count then
  1398. System.Move(fMemory^[Position], fMemory^[Position + 1],
  1399. (Count - Position - 1) * SizeOf(Pointer));
  1400. {Sets item}
  1401. Item[Position] := Value;
  1402. end;
  1403. end;
  1404. {Sets one item from the list}
  1405. procedure TPngPointerList.SetItem(Index: Cardinal; const Value: Pointer);
  1406. begin
  1407. {If index is in bounds, set value}
  1408. if (Index <= Count - 1) then
  1409. fMemory[Index] := Value
  1410. end;
  1411. {This method resizes the list}
  1412. procedure TPngPointerList.SetSize(const Size: Cardinal);
  1413. begin
  1414. {Sets the size}
  1415. if (fMemory = nil) and (Size > 0) then
  1416. GetMem(fMemory, Size * SIZEOF(Pointer))
  1417. else
  1418. if Size > 0 then {Only realloc if the new size is greater than 0}
  1419. ReallocMem(fMemory, Size * SIZEOF(Pointer))
  1420. else
  1421. {In case user is resize to 0 items}
  1422. begin
  1423. FreeMem(fMemory);
  1424. fMemory := nil;
  1425. end;
  1426. {Update count}
  1427. fCount := Size;
  1428. end;
  1429. {TPNGList implementation}
  1430. {Finds the first chunk of this class}
  1431. function TPNGList.FindChunk(ChunkClass: TChunkClass): TChunk;
  1432. var
  1433. i: Integer;
  1434. begin
  1435. Result := nil;
  1436. for i := 0 to Count - 1 do
  1437. if Item[i] is ChunkClass then
  1438. begin
  1439. Result := Item[i];
  1440. Break
  1441. end
  1442. end;
  1443. {Removes an item}
  1444. procedure TPNGList.RemoveChunk(Chunk: TChunk);
  1445. begin
  1446. Remove(Chunk);
  1447. Chunk.Free
  1448. end;
  1449. {Add a new item}
  1450. function TPNGList.Add(ChunkClass: TChunkClass): TChunk;
  1451. var
  1452. IHDR: TChunkIHDR;
  1453. IEND: TChunkIEND;
  1454. IDAT: TChunkIDAT;
  1455. PLTE: TChunkPLTE;
  1456. begin
  1457. Result := nil; {Default result}
  1458. {Adding these is not allowed}
  1459. if ((ChunkClass = TChunkIHDR) or (ChunkClass = TChunkIDAT) or
  1460. (ChunkClass = TChunkPLTE) or (ChunkClass = TChunkIEND)) and not
  1461. (Owner.BeingCreated) then
  1462. fOwner.RaiseError(EPngError, EPNGCannotAddChunkText)
  1463. {Two of these is not allowed}
  1464. else if ((ChunkClass = TChunkgAMA) and (ItemFromClass(TChunkgAMA) <> nil)) or
  1465. ((ChunkClass = TChunktRNS) and (ItemFromClass(TChunktRNS) <> nil)) or
  1466. ((ChunkClass = TChunkpHYs) and (ItemFromClass(TChunkpHYs) <> nil)) then
  1467. fOwner.RaiseError(EPngError, EPNGCannotAddChunkText)
  1468. {There must have an IEND and IHDR chunk}
  1469. else if ((ItemFromClass(TChunkIEND) = nil) or
  1470. (ItemFromClass(TChunkIHDR) = nil)) and not Owner.BeingCreated then
  1471. fOwner.RaiseError(EPngError, EPNGCannotAddInvalidImageText)
  1472. else
  1473. begin
  1474. {Get common chunks}
  1475. IHDR := ItemFromClass(TChunkIHDR) as TChunkIHDR;
  1476. IEND := ItemFromClass(TChunkIEND) as TChunkIEND;
  1477. {Create new chunk}
  1478. Result := ChunkClass.Create(Owner);
  1479. {Add to the list}
  1480. if (ChunkClass = TChunkgAMA) or (ChunkClass = TChunkpHYs) or
  1481. (ChunkClass = TChunkPLTE) then
  1482. Insert(Result, IHDR.Index + 1)
  1483. {Header and end}
  1484. else if (ChunkClass = TChunkIEND) then
  1485. Insert(Result, Count)
  1486. else if (ChunkClass = TChunkIHDR) then
  1487. Insert(Result, 0)
  1488. {Transparency chunk (fix by Ian Boyd)}
  1489. else if (ChunkClass = TChunktRNS) then
  1490. begin
  1491. {Transparecy chunk must be after PLTE; before IDAT}
  1492. IDAT := ItemFromClass(TChunkIDAT) as TChunkIDAT;
  1493. PLTE := ItemFromClass(TChunkPLTE) as TChunkPLTE;
  1494. if Assigned(PLTE) then
  1495. Insert(Result, PLTE.Index + 1)
  1496. else if Assigned(IDAT) then
  1497. Insert(Result, IDAT.Index)
  1498. else
  1499. Insert(Result, IHDR.Index + 1)
  1500. end
  1501. else {All other chunks}
  1502. Insert(Result, IEND.Index);
  1503. end {if}
  1504. end;
  1505. {Returns item from the list}
  1506. function TPNGList.GetItem(Index: Cardinal): TChunk;
  1507. begin
  1508. Result := inherited GetItem(Index);
  1509. end;
  1510. {Returns first item from the list using the class from parameter}
  1511. function TPNGList.ItemFromClass(ChunkClass: TChunkClass): TChunk;
  1512. var
  1513. i: Integer;
  1514. begin
  1515. Result := nil; {Initial result}
  1516. FOR i := 0 TO Count - 1 DO
  1517. {Test if this item has the same class}
  1518. if Item[i] is ChunkClass then
  1519. begin
  1520. {Returns this item and exit}
  1521. Result := Item[i];
  1522. break;
  1523. end {if}
  1524. end;
  1525. {$IFNDEF UseDelphi}
  1526. {TStream implementation}
  1527. {Copies all from another stream}
  1528. function TStream.CopyFrom(Source: TStream; Count: Cardinal): Cardinal;
  1529. const
  1530. MaxBytes = $f000;
  1531. var
  1532. Buffer: PChar;
  1533. BufSize, N: Cardinal;
  1534. begin
  1535. {If count is zero, copy everything from Source}
  1536. if Count = 0 then
  1537. begin
  1538. Source.Seek(0, soFromBeginning);
  1539. Count := Source.Size;
  1540. end;
  1541. Result := Count; {Returns the number of bytes readed}
  1542. {Allocates memory}
  1543. if Count > MaxBytes then BufSize := MaxBytes else BufSize := Count;
  1544. GetMem(Buffer, BufSize);
  1545. {Copy memory}
  1546. while Count > 0 do
  1547. begin
  1548. if Count > BufSize then N := BufSize else N := Count;
  1549. Source.Read(Buffer^, N);
  1550. Write(Buffer^, N);
  1551. dec(Count, N);
  1552. end;
  1553. {Deallocates memory}
  1554. FreeMem(Buffer, BufSize);
  1555. end;
  1556. {Set current stream position}
  1557. procedure TStream.SetPosition(const Value: Longint);
  1558. begin
  1559. Seek(Value, soFromBeginning);
  1560. end;
  1561. {Returns position}
  1562. function TStream.GetPosition: Longint;
  1563. begin
  1564. Result := Seek(0, soFromCurrent);
  1565. end;
  1566. {Returns stream size}
  1567. function TStream.GetSize: Longint;
  1568. var
  1569. Pos: Cardinal;
  1570. begin
  1571. Pos := Seek(0, soFromCurrent);
  1572. Result := Seek(0, soFromEnd);
  1573. Seek(Pos, soFromBeginning);
  1574. end;
  1575. {TFileStream implementation}
  1576. {Filestream object being created}
  1577. constructor TFileStream.Create(Filename: String; Mode: TFileStreamModeSet);
  1578. {Makes file mode}
  1579. function OpenMode: DWORD;
  1580. begin
  1581. Result := 0;
  1582. if fsmRead in Mode then Result := GENERIC_READ;
  1583. if (fsmWrite in Mode) or (fsmCreate in Mode) then
  1584. Result := Result OR GENERIC_WRITE;
  1585. end;
  1586. const
  1587. IsCreate: Array[Boolean] of Integer = (OPEN_ALWAYS, CREATE_ALWAYS);
  1588. begin
  1589. {Call ancestor}
  1590. inherited Create;
  1591. {Create handle}
  1592. fHandle := CreateFile(PChar(Filename), OpenMode, FILE_SHARE_READ or
  1593. FILE_SHARE_WRITE, nil, IsCreate[fsmCreate in Mode], 0, 0);
  1594. {Store mode}
  1595. FileMode := Mode;
  1596. end;
  1597. {Filestream object being destroyed}
  1598. destructor TFileStream.Destroy;
  1599. begin
  1600. {Terminates file and close}
  1601. if FileMode = [fsmWrite] then
  1602. SetEndOfFile(fHandle);
  1603. CloseHandle(fHandle);
  1604. {Call ancestor}
  1605. inherited Destroy;
  1606. end;
  1607. {Writes data to the file}
  1608. function TFileStream.Write(const Buffer; Count: Longint): Cardinal;
  1609. begin
  1610. if not WriteFile(fHandle, Buffer, Count, Result, nil) then
  1611. Result := 0;
  1612. end;
  1613. {Reads data from the file}
  1614. function TFileStream.Read(var Buffer; Count: Longint): Cardinal;
  1615. begin
  1616. if not ReadFile(fHandle, Buffer, Count, Result, nil) then
  1617. Result := 0;
  1618. end;
  1619. {Seeks the file position}
  1620. function TFileStream.Seek(Offset: Integer; Origin: Word): Longint;
  1621. begin
  1622. Result := SetFilePointer(fHandle, Offset, nil, Origin);
  1623. end;
  1624. {Sets the size of the file}
  1625. procedure TFileStream.SetSize(const Value: Longint);
  1626. begin
  1627. Seek(Value, soFromBeginning);
  1628. SetEndOfFile(fHandle);
  1629. end;
  1630. {TResourceStream implementation}
  1631. {Creates the resource stream}
  1632. constructor TResourceStream.Create(Instance: HInst; const ResName: String;
  1633. ResType: PChar);
  1634. var
  1635. ResID: HRSRC;
  1636. ResGlobal: HGlobal;
  1637. begin
  1638. {Obtains the resource ID}
  1639. ResID := FindResource(hInstance, PChar(ResName), RT_RCDATA);
  1640. if ResID = 0 then raise EPNGError.Create('');
  1641. {Obtains memory and size}
  1642. ResGlobal := LoadResource(hInstance, ResID);
  1643. Size := SizeOfResource(hInstance, ResID);
  1644. Memory := LockResource(ResGlobal);
  1645. if (ResGlobal = 0) or (Memory = nil) then EPNGError.Create('');
  1646. end;
  1647. {Setting resource stream size is not supported}
  1648. procedure TResourceStream.SetSize(const Value: Integer);
  1649. begin
  1650. end;
  1651. {Writing into a resource stream is not supported}
  1652. function TResourceStream.Write(const Buffer; Count: Integer): Cardinal;
  1653. begin
  1654. Result := 0;
  1655. end;
  1656. {Reads data from the stream}
  1657. function TResourceStream.Read(var Buffer; Count: Integer): Cardinal;
  1658. begin
  1659. //Returns data
  1660. CopyMemory(@Buffer, Ptr(Longint(Memory) + Position), Count);
  1661. //Update position
  1662. inc(Position, Count);
  1663. //Returns
  1664. Result := Count;
  1665. end;
  1666. {Seeks data}
  1667. function TResourceStream.Seek(Offset: Integer; Origin: Word): Longint;
  1668. begin
  1669. {Move depending on the origin}
  1670. case Origin of
  1671. soFromBeginning: Position := Offset;
  1672. soFromCurrent: inc(Position, Offset);
  1673. soFromEnd: Position := Size + Offset;
  1674. end;
  1675. {Returns the current position}
  1676. Result := Position;
  1677. end;
  1678. {$ENDIF}
  1679. {TChunk implementation}
  1680. {Resizes the data}
  1681. procedure TChunk.ResizeData(const NewSize: Cardinal);
  1682. begin
  1683. fDataSize := NewSize;
  1684. ReallocMem(fData, NewSize + 1);
  1685. end;
  1686. {Returns index from list}
  1687. function TChunk.GetIndex: Integer;
  1688. var
  1689. i: Integer;
  1690. begin
  1691. Result := -1; {Avoiding warnings}
  1692. {Searches in the list}
  1693. FOR i := 0 TO Owner.Chunks.Count - 1 DO
  1694. if Owner.Chunks.Item[i] = Self then
  1695. begin
  1696. {Found match}
  1697. Result := i;
  1698. exit;
  1699. end {for i}
  1700. end;
  1701. {Returns pointer to the TChunkIHDR}
  1702. function TChunk.GetHeader: TChunkIHDR;
  1703. begin
  1704. Result := Owner.Chunks.Item[0] as TChunkIHDR;
  1705. end;
  1706. {Assigns from another TChunk}
  1707. procedure TChunk.Assign(Source: TChunk);
  1708. begin
  1709. {Copy properties}
  1710. fName := Source.fName;
  1711. {Set data size and realloc}
  1712. ResizeData(Source.fDataSize);
  1713. {Copy data (if there's any)}
  1714. if fDataSize > 0 then CopyMemory(fData, Source.fData, fDataSize);
  1715. end;
  1716. {Chunk being created}
  1717. constructor TChunk.Create(Owner: TPngObject);
  1718. var
  1719. ChunkName: String;
  1720. begin
  1721. {Ancestor create}
  1722. inherited Create;
  1723. {If it's a registered class, set the chunk name based on the class}
  1724. {name. For instance, if the class name is TChunkgAMA, the GAMA part}
  1725. {will become the chunk name}
  1726. ChunkName := Copy(ClassName, Length('TChunk') + 1, Length(ClassName));
  1727. if Length(ChunkName) = 4 then CopyMemory(@fName[0], @ChunkName[1], 4);
  1728. {Initialize data holder}
  1729. GetMem(fData, 1);
  1730. fDataSize := 0;
  1731. {Record owner}
  1732. fOwner := Owner;
  1733. end;
  1734. {Chunk being destroyed}
  1735. destructor TChunk.Destroy;
  1736. begin
  1737. {Free data holder}
  1738. FreeMem(fData, fDataSize + 1);
  1739. {Let ancestor destroy}
  1740. inherited Destroy;
  1741. end;
  1742. {Returns the chunk name 1}
  1743. function TChunk.GetChunkName: String;
  1744. begin
  1745. Result := fName
  1746. end;
  1747. {Returns the chunk name 2}
  1748. class function TChunk.GetName: String;
  1749. begin
  1750. {For avoid writing GetName for each TChunk descendent, by default for}
  1751. {classes which don't declare GetName, it will look for the class name}
  1752. {to extract the chunk kind. Example, if the class name is TChunkIEND }
  1753. {this method extracts and returns IEND}
  1754. Result := Copy(ClassName, Length('TChunk') + 1, Length(ClassName));
  1755. end;
  1756. {Saves the data to the stream}
  1757. function TChunk.SaveData(Stream: TStream): Boolean;
  1758. var
  1759. ChunkSize, ChunkCRC: Cardinal;
  1760. begin
  1761. {First, write the size for the following data in the chunk}
  1762. ChunkSize := ByteSwap(DataSize);
  1763. Stream.Write(ChunkSize, 4);
  1764. {The chunk name}
  1765. Stream.Write(fName, 4);
  1766. {If there is data for the chunk, write it}
  1767. if DataSize > 0 then Stream.Write(Data^, DataSize);
  1768. {Calculates and write CRC}
  1769. ChunkCRC := update_crc($ffffffff, @fName[0], 4);
  1770. ChunkCRC := Byteswap(update_crc(ChunkCRC, Data, DataSize) xor $ffffffff);
  1771. Stream.Write(ChunkCRC, 4);
  1772. {Returns that everything went ok}
  1773. Result := TRUE;
  1774. end;
  1775. {Saves the chunk to the stream}
  1776. function TChunk.SaveToStream(Stream: TStream): Boolean;
  1777. begin
  1778. Result := SaveData(Stream)
  1779. end;
  1780. {Loads the chunk from a stream}
  1781. function TChunk.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  1782. Size: Integer): Boolean;
  1783. var
  1784. CheckCRC: Cardinal;
  1785. {$IFDEF CheckCRC}RightCRC: Cardinal;{$ENDIF}
  1786. begin
  1787. {Copies data from source}
  1788. ResizeData(Size);
  1789. if Size > 0 then Stream.Read(fData^, Size);
  1790. {Reads CRC}
  1791. Stream.Read(CheckCRC, 4);
  1792. CheckCrc := ByteSwap(CheckCRC);
  1793. {Check if crc readed is valid}
  1794. {$IFDEF CheckCRC}
  1795. RightCRC := update_crc($ffffffff, @ChunkName[0], 4);
  1796. RightCRC := update_crc(RightCRC, fData, Size) xor $ffffffff;
  1797. Result := RightCRC = CheckCrc;
  1798. {Handle CRC error}
  1799. if not Result then
  1800. begin
  1801. {In case it coult not load chunk}
  1802. Owner.RaiseError(EPngInvalidCRC, EPngInvalidCRCText);
  1803. exit;
  1804. end
  1805. {$ELSE}Result := TRUE; {$ENDIF}
  1806. end;
  1807. {TChunktIME implementation}
  1808. {Chunk being loaded from a stream}
  1809. function TChunktIME.LoadFromStream(Stream: TStream;
  1810. const ChunkName: TChunkName; Size: Integer): Boolean;
  1811. begin
  1812. {Let ancestor load the data}
  1813. Result := inherited LoadFromStream(Stream, ChunkName, Size);
  1814. if not Result or (Size <> 7) then exit; {Size must be 7}
  1815. {Reads data}
  1816. fYear := ((pByte(Longint(Data) )^) * 256)+ (pByte(Longint(Data) + 1)^);
  1817. fMonth := pByte(Longint(Data) + 2)^;
  1818. fDay := pByte(Longint(Data) + 3)^;
  1819. fHour := pByte(Longint(Data) + 4)^;
  1820. fMinute := pByte(Longint(Data) + 5)^;
  1821. fSecond := pByte(Longint(Data) + 6)^;
  1822. end;
  1823. {Assigns from another TChunk}
  1824. procedure TChunktIME.Assign(Source: TChunk);
  1825. begin
  1826. fYear := TChunktIME(Source).fYear;
  1827. fMonth := TChunktIME(Source).fMonth;
  1828. fDay := TChunktIME(Source).fDay;
  1829. fHour := TChunktIME(Source).fHour;
  1830. fMinute := TChunktIME(Source).fMinute;
  1831. fSecond := TChunktIME(Source).fSecond;
  1832. end;
  1833. {Saving the chunk to a stream}
  1834. function TChunktIME.SaveToStream(Stream: TStream): Boolean;
  1835. begin
  1836. {Update data}
  1837. ResizeData(7); {Make sure the size is 7}
  1838. pWord(Data)^ := ByteSwap16(Year);
  1839. pByte(Longint(Data) + 2)^ := Month;
  1840. pByte(Longint(Data) + 3)^ := Day;
  1841. pByte(Longint(Data) + 4)^ := Hour;
  1842. pByte(Longint(Data) + 5)^ := Minute;
  1843. pByte(Longint(Data) + 6)^ := Second;
  1844. {Let inherited save data}
  1845. Result := inherited SaveToStream(Stream);
  1846. end;
  1847. {TChunkztXt implementation}
  1848. {Loading the chunk from a stream}
  1849. function TChunkzTXt.LoadFromStream(Stream: TStream;
  1850. const ChunkName: TChunkName; Size: Integer): Boolean;
  1851. var
  1852. ErrorOutput: String;
  1853. CompressionMethod: Byte;
  1854. Output: Pointer;
  1855. OutputSize: Integer;
  1856. begin
  1857. {Load data from stream and validate}
  1858. Result := inherited LoadFromStream(Stream, ChunkName, Size);
  1859. if not Result or (Size < 4) then exit;
  1860. fKeyword := PChar(Data); {Get keyword and compression method bellow}
  1861. if Longint(fKeyword) = 0 then
  1862. CompressionMethod := pByte(Data)^
  1863. else
  1864. CompressionMethod := pByte(Longint(fKeyword) + Length(fKeyword))^;
  1865. fText := '';
  1866. {In case the compression is 0 (only one accepted by specs), reads it}
  1867. if CompressionMethod = 0 then
  1868. begin
  1869. Output := nil;
  1870. if DecompressZLIB(PChar(Longint(Data) + Length(fKeyword) + 2),
  1871. Size - Length(fKeyword) - 2, Output, OutputSize, ErrorOutput) then
  1872. begin
  1873. SetLength(fText, OutputSize);
  1874. CopyMemory(@fText[1], Output, OutputSize);
  1875. end {if DecompressZLIB(...};
  1876. FreeMem(Output);
  1877. end {if CompressionMethod = 0}
  1878. end;
  1879. {Saving the chunk to a stream}
  1880. function TChunkztXt.SaveToStream(Stream: TStream): Boolean;
  1881. var
  1882. Output: Pointer;
  1883. OutputSize: Integer;
  1884. ErrorOutput: String;
  1885. begin
  1886. Output := nil; {Initializes output}
  1887. if fText = '' then fText := ' ';
  1888. {Compresses the data}
  1889. if CompressZLIB(@fText[1], Length(fText), Owner.CompressionLevel, Output,
  1890. OutputSize, ErrorOutput) then
  1891. begin
  1892. {Size is length from keyword, plus a null character to divide}
  1893. {plus the compression method, plus the length of the text (zlib compressed)}
  1894. ResizeData(Length(fKeyword) + 2 + OutputSize);
  1895. Fillchar(Data^, DataSize, #0);
  1896. {Copies the keyword data}
  1897. if Keyword <> '' then
  1898. CopyMemory(Data, @fKeyword[1], Length(Keyword));
  1899. {Compression method 0 (inflate/deflate)}
  1900. pByte(Ptr(Longint(Data) + Length(Keyword) + 1))^ := 0;
  1901. if OutputSize > 0 then
  1902. CopyMemory(Ptr(Longint(Data) + Length(Keyword) + 2), Output, OutputSize);
  1903. {Let ancestor calculate crc and save}
  1904. Result := SaveData(Stream);
  1905. end {if CompressZLIB(...} else Result := False;
  1906. {Frees output}
  1907. if Output <> nil then FreeMem(Output)
  1908. end;
  1909. {TChunktEXt implementation}
  1910. {Assigns from another text chunk}
  1911. procedure TChunktEXt.Assign(Source: TChunk);
  1912. begin
  1913. fKeyword := TChunktEXt(Source).fKeyword;
  1914. fText := TChunktEXt(Source).fText;
  1915. end;
  1916. {Loading the chunk from a stream}
  1917. function TChunktEXt.LoadFromStream(Stream: TStream;
  1918. const ChunkName: TChunkName; Size: Integer): Boolean;
  1919. begin
  1920. {Load data from stream and validate}
  1921. Result := inherited LoadFromStream(Stream, ChunkName, Size);
  1922. if not Result or (Size < 3) then exit;
  1923. {Get text}
  1924. fKeyword := PChar(Data);
  1925. SetLength(fText, Size - Length(fKeyword) - 1);
  1926. CopyMemory(@fText[1], Ptr(Longint(Data) + Length(fKeyword) + 1),
  1927. Length(fText));
  1928. end;
  1929. {Saving the chunk to a stream}
  1930. function TChunktEXt.SaveToStream(Stream: TStream): Boolean;
  1931. begin
  1932. {Size is length from keyword, plus a null character to divide}
  1933. {plus the length of the text}
  1934. ResizeData(Length(fKeyword) + 1 + Length(fText));
  1935. Fillchar(Data^, DataSize, #0);
  1936. {Copy data}
  1937. if Keyword <> '' then
  1938. CopyMemory(Data, @fKeyword[1], Length(Keyword));
  1939. if Text <> '' then
  1940. CopyMemory(Ptr(Longint(Data) + Length(Keyword) + 1), @fText[1],
  1941. Length(Text));
  1942. {Let ancestor calculate crc and save}
  1943. Result := inherited SaveToStream(Stream);
  1944. end;
  1945. {TChunkIHDR implementation}
  1946. {Chunk being created}
  1947. constructor TChunkIHDR.Create(Owner: TPngObject);
  1948. begin
  1949. {Prepare pointers}
  1950. ImageHandle := 0;
  1951. ImagePalette := 0;
  1952. ImageDC := 0;
  1953. {Call inherited}
  1954. inherited Create(Owner);
  1955. end;
  1956. {Chunk being destroyed}
  1957. destructor TChunkIHDR.Destroy;
  1958. begin
  1959. {Free memory}
  1960. FreeImageData();
  1961. {Calls TChunk destroy}
  1962. inherited Destroy;
  1963. end;
  1964. {Copies the palette}
  1965. procedure CopyPalette(Source: HPALETTE; Destination: HPALETTE);
  1966. var
  1967. PaletteSize: Integer;
  1968. Entries: Array[Byte] of TPaletteEntry;
  1969. begin
  1970. PaletteSize := 0;
  1971. if GetObject(Source, SizeOf(PaletteSize), @PaletteSize) = 0 then Exit;
  1972. if PaletteSize = 0 then Exit;
  1973. ResizePalette(Destination, PaletteSize);
  1974. GetPaletteEntries(Source, 0, PaletteSize, Entries);
  1975. SetPaletteEntries(Destination, 0, PaletteSize, Entries);
  1976. end;
  1977. {Assigns from another IHDR chunk}
  1978. procedure TChunkIHDR.Assign(Source: TChunk);
  1979. begin
  1980. {Copy the IHDR data}
  1981. if Source is TChunkIHDR then
  1982. begin
  1983. {Copy IHDR values}
  1984. IHDRData := TChunkIHDR(Source).IHDRData;
  1985. {Prepare to hold data by filling BitmapInfo structure and}
  1986. {resizing ImageData and ImageAlpha memory allocations}
  1987. PrepareImageData();
  1988. {Copy image data}
  1989. CopyMemory(ImageData, TChunkIHDR(Source).ImageData,
  1990. BytesPerRow * Integer(Height));
  1991. CopyMemory(ImageAlpha, TChunkIHDR(Source).ImageAlpha,
  1992. Integer(Width) * Integer(Height));
  1993. {Copy palette colors}
  1994. BitmapInfo.bmiColors := TChunkIHDR(Source).BitmapInfo.bmiColors;
  1995. {Copy palette also}
  1996. CopyPalette(TChunkIHDR(Source).ImagePalette, ImagePalette);
  1997. end
  1998. else
  1999. Owner.RaiseError(EPNGError, EPNGCannotAssignChunkText);
  2000. end;
  2001. {Release allocated image data}
  2002. procedure TChunkIHDR.FreeImageData;
  2003. begin
  2004. {Free old image data}
  2005. if ImageHandle <> 0 then DeleteObject(ImageHandle);
  2006. if ImageDC <> 0 then DeleteDC(ImageDC);
  2007. if ImageAlpha <> nil then FreeMem(ImageAlpha);
  2008. if ImagePalette <> 0 then DeleteObject(ImagePalette);
  2009. {$IFDEF Store16bits}
  2010. if ExtraImageData <> nil then FreeMem(ExtraImageData);
  2011. {$ENDIF}
  2012. ImageHandle := 0; ImageDC := 0; ImageAlpha := nil; ImageData := nil;
  2013. ImagePalette := 0; ExtraImageData := nil;
  2014. end;
  2015. {Chunk being loaded from a stream}
  2016. function TChunkIHDR.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  2017. Size: Integer): Boolean;
  2018. begin
  2019. {Let TChunk load it}
  2020. Result := inherited LoadFromStream(Stream, ChunkName, Size);
  2021. if not Result then Exit;
  2022. {Now check values}
  2023. {Note: It's recommended by png specification to make sure that the size}
  2024. {must be 13 bytes to be valid, but some images with 14 bytes were found}
  2025. {which could be loaded by internet explorer and other tools}
  2026. if (fDataSize < SIZEOF(TIHdrData)) then
  2027. begin
  2028. {Ihdr must always have at least 13 bytes}
  2029. Result := False;
  2030. Owner.RaiseError(EPNGInvalidIHDR, EPNGInvalidIHDRText);
  2031. exit;
  2032. end;
  2033. {Everything ok, reads IHDR}
  2034. IHDRData := pIHDRData(fData)^;
  2035. IHDRData.Width := ByteSwap(IHDRData.Width);
  2036. IHDRData.Height := ByteSwap(IHDRData.Height);
  2037. {The width and height must not be larger than 65535 pixels}
  2038. if (IHDRData.Width > High(Word)) or (IHDRData.Height > High(Word)) then
  2039. begin
  2040. Result := False;
  2041. Owner.RaiseError(EPNGSizeExceeds, EPNGSizeExceedsText);
  2042. exit;
  2043. end {if IHDRData.Width > High(Word)};
  2044. {Compression method must be 0 (inflate/deflate)}
  2045. if (IHDRData.CompressionMethod <> 0) then
  2046. begin
  2047. Result := False;
  2048. Owner.RaiseError(EPNGUnknownCompression, EPNGUnknownCompressionText);
  2049. exit;
  2050. end;
  2051. {Interlace must be either 0 (none) or 7 (adam7)}
  2052. if (IHDRData.InterlaceMethod <> 0) and (IHDRData.InterlaceMethod <> 1) then
  2053. begin
  2054. Result := False;
  2055. Owner.RaiseError(EPNGUnknownInterlace, EPNGUnknownInterlaceText);
  2056. exit;
  2057. end;
  2058. {Updates owner properties}
  2059. Owner.InterlaceMethod := TInterlaceMethod(IHDRData.InterlaceMethod);
  2060. {Prepares data to hold image}
  2061. PrepareImageData();
  2062. end;
  2063. {Saving the IHDR chunk to a stream}
  2064. function TChunkIHDR.SaveToStream(Stream: TStream): Boolean;
  2065. begin
  2066. {Ignore 2 bits images}
  2067. if BitDepth = 2 then BitDepth := 4;
  2068. {It needs to do is update the data with the IHDR data}
  2069. {structure containing the write values}
  2070. ResizeData(SizeOf(TIHDRData));
  2071. pIHDRData(fData)^ := IHDRData;
  2072. {..byteswap 4 byte types}
  2073. pIHDRData(fData)^.Width := ByteSwap(pIHDRData(fData)^.Width);
  2074. pIHDRData(fData)^.Height := ByteSwap(pIHDRData(fData)^.Height);
  2075. {..update interlace method}
  2076. pIHDRData(fData)^.InterlaceMethod := Byte(Owner.InterlaceMethod);
  2077. {..and then let the ancestor SaveToStream do the hard work}
  2078. Result := inherited SaveToStream(Stream);
  2079. end;
  2080. {Creates a grayscale palette}
  2081. function TChunkIHDR.CreateGrayscalePalette(Bitdepth: Integer): HPalette;
  2082. var
  2083. j: Integer;
  2084. palEntries: TMaxLogPalette;
  2085. begin
  2086. {Prepares and fills the strucutre}
  2087. if Bitdepth = 16 then Bitdepth := 8;
  2088. fillchar(palEntries, sizeof(palEntries), 0);
  2089. palEntries.palVersion := $300;
  2090. palEntries.palNumEntries := 1 shl Bitdepth;
  2091. {Fill it with grayscale colors}
  2092. for j := 0 to palEntries.palNumEntries - 1 do
  2093. begin
  2094. palEntries.palPalEntry[j].peRed :=
  2095. fOwner.GammaTable[MulDiv(j, 255, palEntries.palNumEntries - 1)];
  2096. palEntries.palPalEntry[j].peGreen := palEntries.palPalEntry[j].peRed;
  2097. palEntries.palPalEntry[j].peBlue := palEntries.palPalEntry[j].peRed;
  2098. end;
  2099. {Creates and returns the palette}
  2100. Result := CreatePalette(pLogPalette(@palEntries)^);
  2101. end;
  2102. {Copies the palette to the Device Independent bitmap header}
  2103. procedure TChunkIHDR.PaletteToDIB(Palette: HPalette);
  2104. var
  2105. j: Integer;
  2106. palEntries: TMaxLogPalette;
  2107. begin
  2108. {Copy colors}
  2109. Fillchar(palEntries, sizeof(palEntries), #0);
  2110. BitmapInfo.bmiHeader.biClrUsed := GetPaletteEntries(Palette, 0, 256, palEntries.palPalEntry[0]);
  2111. for j := 0 to BitmapInfo.bmiHeader.biClrUsed - 1 do
  2112. begin
  2113. BitmapInfo.bmiColors[j].rgbBlue := palEntries.palPalEntry[j].peBlue;
  2114. BitmapInfo.bmiColors[j].rgbRed := palEntries.palPalEntry[j].peRed;
  2115. BitmapInfo.bmiColors[j].rgbGreen := palEntries.palPalEntry[j].peGreen;
  2116. end;
  2117. end;
  2118. {Resizes the image data to fill the color type, bit depth, }
  2119. {width and height parameters}
  2120. procedure TChunkIHDR.PrepareImageData();
  2121. {Set the bitmap info}
  2122. procedure SetInfo(const Bitdepth: Integer; const Palette: Boolean);
  2123. begin
  2124. {Copy if the bitmap contain palette entries}
  2125. HasPalette := Palette;
  2126. {Fill the strucutre}
  2127. with BitmapInfo.bmiHeader do
  2128. begin
  2129. biSize := sizeof(TBitmapInfoHeader);
  2130. biHeight := Height;
  2131. biWidth := Width;
  2132. biPlanes := 1;
  2133. biBitCount := BitDepth;
  2134. biCompression := BI_RGB;
  2135. end {with BitmapInfo.bmiHeader}
  2136. end;
  2137. begin
  2138. {Prepare bitmap info header}
  2139. Fillchar(BitmapInfo, sizeof(TMaxBitmapInfo), #0);
  2140. {Release old image data}
  2141. FreeImageData();
  2142. {Obtain number of bits for each pixel}
  2143. case ColorType of
  2144. COLOR_GRAYSCALE, COLOR_PALETTE, COLOR_GRAYSCALEALPHA:
  2145. case BitDepth of
  2146. {These are supported by windows}
  2147. 1, 4, 8: SetInfo(BitDepth, TRUE);
  2148. {2 bits for each pixel is not supported by windows bitmap}
  2149. 2 : SetInfo(4, TRUE);
  2150. {Also 16 bits (2 bytes) for each pixel is not supported}
  2151. {and should be transormed into a 8 bit grayscale}
  2152. 16 : SetInfo(8, TRUE);
  2153. end;
  2154. {Only 1 byte (8 bits) is supported}
  2155. COLOR_RGB, COLOR_RGBALPHA: SetInfo(24, FALSE);
  2156. end {case ColorType};
  2157. {Number of bytes for each scanline}
  2158. BytesPerRow := (((BitmapInfo.bmiHeader.biBitCount * Width) + 31)
  2159. and not 31) div 8;
  2160. {Build array for alpha information, if necessary}
  2161. if (ColorType = COLOR_RGBALPHA) or (ColorType = COLOR_GRAYSCALEALPHA) then
  2162. begin
  2163. GetMem(ImageAlpha, Integer(Width) * Integer(Height));
  2164. FillChar(ImageAlpha^, Integer(Width) * Integer(Height), #0);
  2165. end;
  2166. {Build array for extra byte information}
  2167. {$IFDEF Store16bits}
  2168. if (BitDepth = 16) then
  2169. begin
  2170. GetMem(ExtraImageData, BytesPerRow * Integer(Height));
  2171. FillChar(ExtraImageData^, BytesPerRow * Integer(Height), #0);
  2172. end;
  2173. {$ENDIF}
  2174. {Creates the image to hold the data, CreateDIBSection does a better}
  2175. {work in allocating necessary memory}
  2176. ImageDC := CreateCompatibleDC(0);
  2177. {$IFDEF UseDelphi}Self.Owner.Canvas.Handle := ImageDC;{$ENDIF}
  2178. {In case it is a palette image, create the palette}
  2179. if HasPalette then
  2180. begin
  2181. {Create a standard palette}
  2182. if ColorType = COLOR_PALETTE then
  2183. ImagePalette := CreateHalfTonePalette(ImageDC)
  2184. else
  2185. ImagePalette := CreateGrayscalePalette(Bitdepth);
  2186. ResizePalette(ImagePalette, 1 shl BitmapInfo.bmiHeader.biBitCount);
  2187. BitmapInfo.bmiHeader.biClrUsed := 1 shl BitmapInfo.bmiHeader.biBitCount;
  2188. SelectPalette(ImageDC, ImagePalette, False);
  2189. RealizePalette(ImageDC);
  2190. PaletteTODIB(ImagePalette);
  2191. end;
  2192. {Create the device independent bitmap}
  2193. ImageHandle := CreateDIBSection(ImageDC, pBitmapInfo(@BitmapInfo)^,
  2194. DIB_RGB_COLORS, ImageData, 0, 0);
  2195. SelectObject(ImageDC, ImageHandle);
  2196. {Build array and allocate bytes for each row}
  2197. fillchar(ImageData^, BytesPerRow * Integer(Height), 0);
  2198. end;
  2199. {TChunktRNS implementation}
  2200. {$IFNDEF UseDelphi}
  2201. function CompareMem(P1, P2: pByte; const Size: Integer): Boolean;
  2202. var i: Integer;
  2203. begin
  2204. Result := True;
  2205. for i := 1 to Size do
  2206. begin
  2207. if P1^ <> P2^ then Result := False;
  2208. inc(P1); inc(P2);
  2209. end {for i}
  2210. end;
  2211. {$ENDIF}
  2212. {Sets the transpararent color}
  2213. procedure TChunktRNS.SetTransparentColor(const Value: ColorRef);
  2214. var
  2215. i: Byte;
  2216. LookColor: TRGBQuad;
  2217. begin
  2218. {Clears the palette values}
  2219. Fillchar(PaletteValues, SizeOf(PaletteValues), #0);
  2220. {Sets that it uses bit transparency}
  2221. fBitTransparency := True;
  2222. {Depends on the color type}
  2223. with Header do
  2224. case ColorType of
  2225. COLOR_GRAYSCALE:
  2226. begin
  2227. Self.ResizeData(2);
  2228. pWord(@PaletteValues[0])^ := ByteSwap16(GetRValue(Value));
  2229. end;
  2230. COLOR_RGB:
  2231. begin
  2232. Self.ResizeData(6);
  2233. pWord(@PaletteValues[0])^ := ByteSwap16(GetRValue(Value));
  2234. pWord(@PaletteValues[2])^ := ByteSwap16(GetGValue(Value));
  2235. pWord(@PaletteValues[4])^ := ByteSwap16(GetBValue(Value));
  2236. end;
  2237. COLOR_PALETTE:
  2238. begin
  2239. {Creates a RGBQuad to search for the color}
  2240. LookColor.rgbRed := GetRValue(Value);
  2241. LookColor.rgbGreen := GetGValue(Value);
  2242. LookColor.rgbBlue := GetBValue(Value);
  2243. {Look in the table for the entry}
  2244. for i := 0 to BitmapInfo.bmiHeader.biClrUsed - 1 do
  2245. if CompareMem(@BitmapInfo.bmiColors[i], @LookColor, 3) then
  2246. Break;
  2247. {Fill the transparency table}
  2248. Fillchar(PaletteValues, i, 255);
  2249. Self.ResizeData(i + 1)
  2250. end
  2251. end {case / with};
  2252. end;
  2253. {Returns the transparent color for the image}
  2254. function TChunktRNS.GetTransparentColor: ColorRef;
  2255. var
  2256. PaletteChunk: TChunkPLTE;
  2257. i: Integer;
  2258. Value: Byte;
  2259. begin
  2260. Result := 0; {Default: Unknown transparent color}
  2261. {Depends on the color type}
  2262. with Header do
  2263. case ColorType of
  2264. COLOR_GRAYSCALE:
  2265. begin
  2266. Value := BitmapInfo.bmiColors[PaletteValues[1]].rgbRed;
  2267. Result := RGB(Value, Value, Value);
  2268. end;
  2269. COLOR_RGB:
  2270. Result := RGB(fOwner.GammaTable[PaletteValues[1]],
  2271. fOwner.GammaTable[PaletteValues[3]],
  2272. fOwner.GammaTable[PaletteValues[5]]);
  2273. COLOR_PALETTE:
  2274. begin
  2275. {Obtains the palette chunk}
  2276. PaletteChunk := Owner.Chunks.ItemFromClass(TChunkPLTE) as TChunkPLTE;
  2277. {Looks for an entry with 0 transparency meaning that it is the}
  2278. {full transparent entry}
  2279. for i := 0 to Self.DataSize - 1 do
  2280. if PaletteValues[i] = 0 then
  2281. with PaletteChunk.GetPaletteItem(i) do
  2282. begin
  2283. Result := RGB(rgbRed, rgbGreen, rgbBlue);
  2284. break
  2285. end
  2286. end {COLOR_PALETTE}
  2287. end {case Header.ColorType};
  2288. end;
  2289. {Saving the chunk to a stream}
  2290. function TChunktRNS.SaveToStream(Stream: TStream): Boolean;
  2291. begin
  2292. {Copy palette into data buffer}
  2293. if DataSize <= 256 then
  2294. CopyMemory(fData, @PaletteValues[0], DataSize);
  2295. Result := inherited SaveToStream(Stream);
  2296. end;
  2297. {Assigns from another chunk}
  2298. procedure TChunktRNS.Assign(Source: TChunk);
  2299. begin
  2300. CopyMemory(@PaletteValues[0], @TChunkTrns(Source).PaletteValues[0], 256);
  2301. fBitTransparency := TChunkTrns(Source).fBitTransparency;
  2302. inherited Assign(Source);
  2303. end;
  2304. {Loads the chunk from a stream}
  2305. function TChunktRNS.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  2306. Size: Integer): Boolean;
  2307. var
  2308. i, Differ255: Integer;
  2309. begin
  2310. {Let inherited load}
  2311. Result := inherited LoadFromStream(Stream, ChunkName, Size);
  2312. if not Result then Exit;
  2313. {Make sure size is correct}
  2314. if Size > 256 then Owner.RaiseError(EPNGInvalidPalette,
  2315. EPNGInvalidPaletteText);
  2316. {The unset items should have value 255}
  2317. Fillchar(PaletteValues[0], 256, 255);
  2318. {Copy the other values}
  2319. CopyMemory(@PaletteValues[0], fData, Size);
  2320. {Create the mask if needed}
  2321. case Header.ColorType of
  2322. {Mask for grayscale and RGB}
  2323. COLOR_RGB, COLOR_GRAYSCALE: fBitTransparency := True;
  2324. COLOR_PALETTE:
  2325. begin
  2326. Differ255 := 0; {Count the entries with a value different from 255}
  2327. {Tests if it uses bit transparency}
  2328. for i := 0 to Size - 1 do
  2329. if PaletteValues[i] <> 255 then inc(Differ255);
  2330. {If it has one value different from 255 it is a bit transparency}
  2331. fBitTransparency := (Differ255 = 1);
  2332. end {COLOR_PALETTE}
  2333. end {case Header.ColorType};
  2334. end;
  2335. {Prepares the image palette}
  2336. procedure TChunkIDAT.PreparePalette;
  2337. var
  2338. Entries: Word;
  2339. j : Integer;
  2340. palEntries: TMaxLogPalette;
  2341. begin
  2342. {In case the image uses grayscale, build a grayscale palette}
  2343. with Header do
  2344. if (ColorType = COLOR_GRAYSCALE) or (ColorType = COLOR_GRAYSCALEALPHA) then
  2345. begin
  2346. {Calculate total number of palette entries}
  2347. Entries := (1 shl Byte(BitmapInfo.bmiHeader.biBitCount));
  2348. Fillchar(palEntries, sizeof(palEntries), #0);
  2349. palEntries.palVersion := $300;
  2350. palEntries.palNumEntries := Entries;
  2351. FOR j := 0 TO Entries - 1 DO
  2352. with palEntries.palPalEntry[j] do
  2353. begin
  2354. {Calculate each palette entry}
  2355. peRed := fOwner.GammaTable[MulDiv(j, 255, Entries - 1)];
  2356. peGreen := peRed;
  2357. peBlue := peRed;
  2358. end {with BitmapInfo.bmiColors[j]};
  2359. Owner.SetPalette(CreatePalette(pLogPalette(@palEntries)^));
  2360. end {if ColorType = COLOR_GRAYSCALE..., with Header}
  2361. end;
  2362. {Reads from ZLIB}
  2363. function TChunkIDAT.IDATZlibRead(var ZLIBStream: TZStreamRec2;
  2364. Buffer: Pointer; Count: Integer; var EndPos: Integer;
  2365. var crcfile: Cardinal): Integer;
  2366. var
  2367. ProcResult : Integer;
  2368. IDATHeader : Array[0..3] of char;
  2369. IDATCRC : Cardinal;
  2370. begin
  2371. {Uses internal record pointed by ZLIBStream to gather information}
  2372. with ZLIBStream, ZLIBStream.zlib do
  2373. begin
  2374. {Set the buffer the zlib will read into}
  2375. next_out := Buffer;
  2376. avail_out := Count;
  2377. {Decode until it reach the Count variable}
  2378. while avail_out > 0 do
  2379. begin
  2380. {In case it needs more data and it's in the end of a IDAT chunk,}
  2381. {it means that there are more IDAT chunks}
  2382. if (fStream.Position = EndPos) and (avail_out > 0) and
  2383. (avail_in = 0) then
  2384. begin
  2385. {End this chunk by reading and testing the crc value}
  2386. fStream.Read(IDATCRC, 4);
  2387. {$IFDEF CheckCRC}
  2388. if crcfile xor $ffffffff <> Cardinal(ByteSwap(IDATCRC)) then
  2389. begin
  2390. Result := -1;
  2391. Owner.RaiseError(EPNGInvalidCRC, EPNGInvalidCRCText);
  2392. exit;
  2393. end;
  2394. {$ENDIF}
  2395. {Start reading the next chunk}
  2396. fStream.Read(EndPos, 4); {Reads next chunk size}
  2397. fStream.Read(IDATHeader[0], 4); {Next chunk header}
  2398. {It must be a IDAT chunk since image data is required and PNG}
  2399. {specification says that multiple IDAT chunks must be consecutive}
  2400. if IDATHeader <> 'IDAT' then
  2401. begin
  2402. Owner.RaiseError(EPNGMissingMultipleIDAT, EPNGMissingMultipleIDATText);
  2403. result := -1;
  2404. exit;
  2405. end;
  2406. {Calculate chunk name part of the crc}
  2407. {$IFDEF CheckCRC}
  2408. crcfile := update_crc($ffffffff, @IDATHeader[0], 4);
  2409. {$ENDIF}
  2410. EndPos := fStream.Position + ByteSwap(EndPos);
  2411. end;
  2412. {In case it needs compressed data to read from}
  2413. if avail_in = 0 then
  2414. begin
  2415. {In case it's trying to read more than it is avaliable}
  2416. if fStream.Position + ZLIBAllocate > EndPos then
  2417. avail_in := fStream.Read(Data^, EndPos - fStream.Position)
  2418. else
  2419. avail_in := fStream.Read(Data^, ZLIBAllocate);
  2420. {Update crc}
  2421. {$IFDEF CheckCRC}
  2422. crcfile := update_crc(crcfile, Data, avail_in);
  2423. {$ENDIF}
  2424. {In case there is no more compressed data to read from}
  2425. if avail_in = 0 then
  2426. begin
  2427. Result := Count - avail_out;
  2428. Exit;
  2429. end;
  2430. {Set next buffer to read and record current position}
  2431. next_in := Data;
  2432. end {if avail_in = 0};
  2433. ProcResult := inflate(zlib, 0);
  2434. {In case the result was not sucessfull}
  2435. if (ProcResult < 0) then
  2436. begin
  2437. Result := -1;
  2438. Owner.RaiseError(EPNGZLIBError,
  2439. EPNGZLIBErrorText + zliberrors[procresult]);
  2440. exit;
  2441. end;
  2442. end {while avail_out > 0};
  2443. end {with};
  2444. {If everything gone ok, it returns the count bytes}
  2445. Result := Count;
  2446. end;
  2447. {TChunkIDAT implementation}
  2448. const
  2449. {Adam 7 interlacing values}
  2450. RowStart: array[0..6] of Integer = (0, 0, 4, 0, 2, 0, 1);
  2451. ColumnStart: array[0..6] of Integer = (0, 4, 0, 2, 0, 1, 0);
  2452. RowIncrement: array[0..6] of Integer = (8, 8, 8, 4, 4, 2, 2);
  2453. ColumnIncrement: array[0..6] of Integer = (8, 8, 4, 4, 2, 2, 1);
  2454. {Copy interlaced images with 1 byte for R, G, B}
  2455. procedure TChunkIDAT.CopyInterlacedRGB8(const Pass: Byte;
  2456. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2457. var
  2458. Col: Integer;
  2459. begin
  2460. {Get first column and enter in loop}
  2461. Col := ColumnStart[Pass];
  2462. Dest := pChar(Longint(Dest) + Col * 3);
  2463. repeat
  2464. {Copy this row}
  2465. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2466. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Dest);
  2467. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) )^]; inc(Dest);
  2468. {Move to next column}
  2469. inc(Src, 3);
  2470. inc(Dest, ColumnIncrement[Pass] * 3 - 3);
  2471. inc(Col, ColumnIncrement[Pass]);
  2472. until Col >= ImageWidth;
  2473. end;
  2474. {Copy interlaced images with 2 bytes for R, G, B}
  2475. procedure TChunkIDAT.CopyInterlacedRGB16(const Pass: Byte;
  2476. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2477. var
  2478. Col: Integer;
  2479. begin
  2480. {Get first column and enter in loop}
  2481. Col := ColumnStart[Pass];
  2482. Dest := pChar(Longint(Dest) + Col * 3);
  2483. repeat
  2484. {Copy this row}
  2485. Byte(Dest^) := Owner.GammaTable[pByte(Longint(Src) + 4)^]; inc(Dest);
  2486. Byte(Dest^) := Owner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2487. Byte(Dest^) := Owner.GammaTable[pByte(Longint(Src) )^]; inc(Dest);
  2488. {$IFDEF Store16bits}
  2489. {Copy extra pixel values}
  2490. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 5)^]; inc(Extra);
  2491. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 3)^]; inc(Extra);
  2492. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Extra);
  2493. {$ENDIF}
  2494. {Move to next column}
  2495. inc(Src, 6);
  2496. inc(Dest, ColumnIncrement[Pass] * 3 - 3);
  2497. inc(Col, ColumnIncrement[Pass]);
  2498. until Col >= ImageWidth;
  2499. end;
  2500. {Copy ímages with palette using bit depths 1, 4 or 8}
  2501. procedure TChunkIDAT.CopyInterlacedPalette148(const Pass: Byte;
  2502. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2503. const
  2504. BitTable: Array[1..8] of Integer = ($1, $3, 0, $F, 0, 0, 0, $FF);
  2505. StartBit: Array[1..8] of Integer = (7 , 0 , 0, 4, 0, 0, 0, 0);
  2506. var
  2507. CurBit, Col: Integer;
  2508. Dest2: PChar;
  2509. begin
  2510. {Get first column and enter in loop}
  2511. Col := ColumnStart[Pass];
  2512. repeat
  2513. {Copy data}
  2514. CurBit := StartBit[Header.BitDepth];
  2515. repeat
  2516. {Adjust pointer to pixel byte bounds}
  2517. Dest2 := pChar(Longint(Dest) + (Header.BitDepth * Col) div 8);
  2518. {Copy data}
  2519. Byte(Dest2^) := Byte(Dest2^) or
  2520. ( ((Byte(Src^) shr CurBit) and BitTable[Header.BitDepth])
  2521. shl (StartBit[Header.BitDepth] - (Col * Header.BitDepth mod 8)));
  2522. {Move to next column}
  2523. inc(Col, ColumnIncrement[Pass]);
  2524. {Will read next bits}
  2525. dec(CurBit, Header.BitDepth);
  2526. until CurBit < 0;
  2527. {Move to next byte in source}
  2528. inc(Src);
  2529. until Col >= ImageWidth;
  2530. end;
  2531. {Copy ímages with palette using bit depth 2}
  2532. procedure TChunkIDAT.CopyInterlacedPalette2(const Pass: Byte; Src, Dest,
  2533. Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2534. var
  2535. CurBit, Col: Integer;
  2536. Dest2: PChar;
  2537. begin
  2538. {Get first column and enter in loop}
  2539. Col := ColumnStart[Pass];
  2540. repeat
  2541. {Copy data}
  2542. CurBit := 6;
  2543. repeat
  2544. {Adjust pointer to pixel byte bounds}
  2545. Dest2 := pChar(Longint(Dest) + Col div 2);
  2546. {Copy data}
  2547. Byte(Dest2^) := Byte(Dest2^) or (((Byte(Src^) shr CurBit) and $3)
  2548. shl (4 - (4 * Col) mod 8));
  2549. {Move to next column}
  2550. inc(Col, ColumnIncrement[Pass]);
  2551. {Will read next bits}
  2552. dec(CurBit, 2);
  2553. until CurBit < 0;
  2554. {Move to next byte in source}
  2555. inc(Src);
  2556. until Col >= ImageWidth;
  2557. end;
  2558. {Copy ímages with grayscale using bit depth 2}
  2559. procedure TChunkIDAT.CopyInterlacedGray2(const Pass: Byte;
  2560. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2561. var
  2562. CurBit, Col: Integer;
  2563. Dest2: PChar;
  2564. begin
  2565. {Get first column and enter in loop}
  2566. Col := ColumnStart[Pass];
  2567. repeat
  2568. {Copy data}
  2569. CurBit := 6;
  2570. repeat
  2571. {Adjust pointer to pixel byte bounds}
  2572. Dest2 := pChar(Longint(Dest) + Col div 2);
  2573. {Copy data}
  2574. Byte(Dest2^) := Byte(Dest2^) or ((((Byte(Src^) shr CurBit) shl 2) and $F)
  2575. shl (4 - (Col*4) mod 8));
  2576. {Move to next column}
  2577. inc(Col, ColumnIncrement[Pass]);
  2578. {Will read next bits}
  2579. dec(CurBit, 2);
  2580. until CurBit < 0;
  2581. {Move to next byte in source}
  2582. inc(Src);
  2583. until Col >= ImageWidth;
  2584. end;
  2585. {Copy ímages with palette using 2 bytes for each pixel}
  2586. procedure TChunkIDAT.CopyInterlacedGrayscale16(const Pass: Byte;
  2587. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2588. var
  2589. Col: Integer;
  2590. begin
  2591. {Get first column and enter in loop}
  2592. Col := ColumnStart[Pass];
  2593. Dest := pChar(Longint(Dest) + Col);
  2594. repeat
  2595. {Copy this row}
  2596. Dest^ := Src^; inc(Dest);
  2597. {$IFDEF Store16bits}
  2598. Extra^ := pChar(Longint(Src) + 1)^; inc(Extra);
  2599. {$ENDIF}
  2600. {Move to next column}
  2601. inc(Src, 2);
  2602. inc(Dest, ColumnIncrement[Pass] - 1);
  2603. inc(Col, ColumnIncrement[Pass]);
  2604. until Col >= ImageWidth;
  2605. end;
  2606. {Decodes interlaced RGB alpha with 1 byte for each sample}
  2607. procedure TChunkIDAT.CopyInterlacedRGBAlpha8(const Pass: Byte;
  2608. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2609. var
  2610. Col: Integer;
  2611. begin
  2612. {Get first column and enter in loop}
  2613. Col := ColumnStart[Pass];
  2614. Dest := pChar(Longint(Dest) + Col * 3);
  2615. Trans := pChar(Longint(Trans) + Col);
  2616. repeat
  2617. {Copy this row and alpha value}
  2618. Trans^ := pChar(Longint(Src) + 3)^;
  2619. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2620. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Dest);
  2621. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) )^]; inc(Dest);
  2622. {Move to next column}
  2623. inc(Src, 4);
  2624. inc(Dest, ColumnIncrement[Pass] * 3 - 3);
  2625. inc(Trans, ColumnIncrement[Pass]);
  2626. inc(Col, ColumnIncrement[Pass]);
  2627. until Col >= ImageWidth;
  2628. end;
  2629. {Decodes interlaced RGB alpha with 2 bytes for each sample}
  2630. procedure TChunkIDAT.CopyInterlacedRGBAlpha16(const Pass: Byte;
  2631. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2632. var
  2633. Col: Integer;
  2634. begin
  2635. {Get first column and enter in loop}
  2636. Col := ColumnStart[Pass];
  2637. Dest := pChar(Longint(Dest) + Col * 3);
  2638. Trans := pChar(Longint(Trans) + Col);
  2639. repeat
  2640. {Copy this row and alpha value}
  2641. Trans^ := pChar(Longint(Src) + 6)^;
  2642. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 4)^]; inc(Dest);
  2643. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2644. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) )^]; inc(Dest);
  2645. {$IFDEF Store16bits}
  2646. {Copy extra pixel values}
  2647. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 5)^]; inc(Extra);
  2648. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 3)^]; inc(Extra);
  2649. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Extra);
  2650. {$ENDIF}
  2651. {Move to next column}
  2652. inc(Src, 8);
  2653. inc(Dest, ColumnIncrement[Pass] * 3 - 3);
  2654. inc(Trans, ColumnIncrement[Pass]);
  2655. inc(Col, ColumnIncrement[Pass]);
  2656. until Col >= ImageWidth;
  2657. end;
  2658. {Decodes 8 bit grayscale image followed by an alpha sample}
  2659. procedure TChunkIDAT.CopyInterlacedGrayscaleAlpha8(const Pass: Byte;
  2660. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2661. var
  2662. Col: Integer;
  2663. begin
  2664. {Get first column, pointers to the data and enter in loop}
  2665. Col := ColumnStart[Pass];
  2666. Dest := pChar(Longint(Dest) + Col);
  2667. Trans := pChar(Longint(Trans) + Col);
  2668. repeat
  2669. {Copy this grayscale value and alpha}
  2670. Dest^ := Src^; inc(Src);
  2671. Trans^ := Src^; inc(Src);
  2672. {Move to next column}
  2673. inc(Dest, ColumnIncrement[Pass]);
  2674. inc(Trans, ColumnIncrement[Pass]);
  2675. inc(Col, ColumnIncrement[Pass]);
  2676. until Col >= ImageWidth;
  2677. end;
  2678. {Decodes 16 bit grayscale image followed by an alpha sample}
  2679. procedure TChunkIDAT.CopyInterlacedGrayscaleAlpha16(const Pass: Byte;
  2680. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2681. var
  2682. Col: Integer;
  2683. begin
  2684. {Get first column, pointers to the data and enter in loop}
  2685. Col := ColumnStart[Pass];
  2686. Dest := pChar(Longint(Dest) + Col);
  2687. Trans := pChar(Longint(Trans) + Col);
  2688. repeat
  2689. {$IFDEF Store16bits}
  2690. Extra^ := pChar(Longint(Src) + 1)^; inc(Extra);
  2691. {$ENDIF}
  2692. {Copy this grayscale value and alpha, transforming 16 bits into 8}
  2693. Dest^ := Src^; inc(Src, 2);
  2694. Trans^ := Src^; inc(Src, 2);
  2695. {Move to next column}
  2696. inc(Dest, ColumnIncrement[Pass]);
  2697. inc(Trans, ColumnIncrement[Pass]);
  2698. inc(Col, ColumnIncrement[Pass]);
  2699. until Col >= ImageWidth;
  2700. end;
  2701. {Decodes an interlaced image}
  2702. procedure TChunkIDAT.DecodeInterlacedAdam7(Stream: TStream;
  2703. var ZLIBStream: TZStreamRec2; const Size: Integer; var crcfile: Cardinal);
  2704. var
  2705. CurrentPass: Byte;
  2706. PixelsThisRow: Integer;
  2707. CurrentRow: Integer;
  2708. Trans, Data{$IFDEF Store16bits}, Extra{$ENDIF}: pChar;
  2709. CopyProc: procedure(const Pass: Byte; Src, Dest,
  2710. Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar) of object;
  2711. begin
  2712. CopyProc := nil; {Initialize}
  2713. {Determine method to copy the image data}
  2714. case Header.ColorType of
  2715. {R, G, B values for each pixel}
  2716. COLOR_RGB:
  2717. case Header.BitDepth of
  2718. 8: CopyProc := CopyInterlacedRGB8;
  2719. 16: CopyProc := CopyInterlacedRGB16;
  2720. end {case Header.BitDepth};
  2721. {Palette}
  2722. COLOR_PALETTE, COLOR_GRAYSCALE:
  2723. case Header.BitDepth of
  2724. 1, 4, 8: CopyProc := CopyInterlacedPalette148;
  2725. 2 : if Header.ColorType = COLOR_PALETTE then
  2726. CopyProc := CopyInterlacedPalette2
  2727. else
  2728. CopyProc := CopyInterlacedGray2;
  2729. 16 : CopyProc := CopyInterlacedGrayscale16;
  2730. end;
  2731. {RGB followed by alpha}
  2732. COLOR_RGBALPHA:
  2733. case Header.BitDepth of
  2734. 8: CopyProc := CopyInterlacedRGBAlpha8;
  2735. 16: CopyProc := CopyInterlacedRGBAlpha16;
  2736. end;
  2737. {Grayscale followed by alpha}
  2738. COLOR_GRAYSCALEALPHA:
  2739. case Header.BitDepth of
  2740. 8: CopyProc := CopyInterlacedGrayscaleAlpha8;
  2741. 16: CopyProc := CopyInterlacedGrayscaleAlpha16;
  2742. end;
  2743. end {case Header.ColorType};
  2744. {Adam7 method has 7 passes to make the final image}
  2745. FOR CurrentPass := 0 TO 6 DO
  2746. begin
  2747. {Calculates the number of pixels and bytes for this pass row}
  2748. PixelsThisRow := (ImageWidth - ColumnStart[CurrentPass] +
  2749. ColumnIncrement[CurrentPass] - 1) div ColumnIncrement[CurrentPass];
  2750. Row_Bytes := BytesForPixels(PixelsThisRow, Header.ColorType,
  2751. Header.BitDepth);
  2752. {Clear buffer for this pass}
  2753. ZeroMemory(Row_Buffer[not RowUsed], Row_Bytes);
  2754. {Get current row index}
  2755. CurrentRow := RowStart[CurrentPass];
  2756. {Get a pointer to the current row image data}
  2757. Data := Ptr(Longint(Header.ImageData) + Header.BytesPerRow *
  2758. (ImageHeight - 1 - CurrentRow));
  2759. Trans := Ptr(Longint(Header.ImageAlpha) + ImageWidth * CurrentRow);
  2760. {$IFDEF Store16bits}
  2761. Extra := Ptr(Longint(Header.ExtraImageData) + Header.BytesPerRow *
  2762. (ImageHeight - 1 - CurrentRow));
  2763. {$ENDIF}
  2764. if Row_Bytes > 0 then {There must have bytes for this interlaced pass}
  2765. while CurrentRow < ImageHeight do
  2766. begin
  2767. {Reads this line and filter}
  2768. if IDATZlibRead(ZLIBStream, @Row_Buffer[RowUsed][0], Row_Bytes + 1,
  2769. EndPos, CRCFile) = 0 then break;
  2770. FilterRow;
  2771. {Copy image data}
  2772. CopyProc(CurrentPass, @Row_Buffer[RowUsed][1], Data, Trans
  2773. {$IFDEF Store16bits}, Extra{$ENDIF});
  2774. {Use the other RowBuffer item}
  2775. RowUsed := not RowUsed;
  2776. {Move to the next row}
  2777. inc(CurrentRow, RowIncrement[CurrentPass]);
  2778. {Move pointer to the next line}
  2779. dec(Data, RowIncrement[CurrentPass] * Header.BytesPerRow);
  2780. inc(Trans, RowIncrement[CurrentPass] * ImageWidth);
  2781. {$IFDEF Store16bits}
  2782. dec(Extra, RowIncrement[CurrentPass] * Header.BytesPerRow);
  2783. {$ENDIF}
  2784. end {while CurrentRow < ImageHeight};
  2785. end {FOR CurrentPass};
  2786. end;
  2787. {Copy 8 bits RGB image}
  2788. procedure TChunkIDAT.CopyNonInterlacedRGB8(
  2789. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2790. var
  2791. I: Integer;
  2792. begin
  2793. FOR I := 1 TO ImageWidth DO
  2794. begin
  2795. {Copy pixel values}
  2796. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2797. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Dest);
  2798. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) )^]; inc(Dest);
  2799. {Move to next pixel}
  2800. inc(Src, 3);
  2801. end {for I}
  2802. end;
  2803. {Copy 16 bits RGB image}
  2804. procedure TChunkIDAT.CopyNonInterlacedRGB16(
  2805. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2806. var
  2807. I: Integer;
  2808. begin
  2809. FOR I := 1 TO ImageWidth DO
  2810. begin
  2811. //Since windows does not supports 2 bytes for
  2812. //each R, G, B value, the method will read only 1 byte from it
  2813. {Copy pixel values}
  2814. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 4)^]; inc(Dest);
  2815. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2816. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) )^]; inc(Dest);
  2817. {$IFDEF Store16bits}
  2818. {Copy extra pixel values}
  2819. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 5)^]; inc(Extra);
  2820. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 3)^]; inc(Extra);
  2821. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Extra);
  2822. {$ENDIF}
  2823. {Move to next pixel}
  2824. inc(Src, 6);
  2825. end {for I}
  2826. end;
  2827. {Copy types using palettes (1, 4 or 8 bits per pixel)}
  2828. procedure TChunkIDAT.CopyNonInterlacedPalette148(
  2829. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2830. begin
  2831. {It's simple as copying the data}
  2832. CopyMemory(Dest, Src, Row_Bytes);
  2833. end;
  2834. {Copy grayscale types using 2 bits for each pixel}
  2835. procedure TChunkIDAT.CopyNonInterlacedGray2(
  2836. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2837. var
  2838. i: Integer;
  2839. begin
  2840. {2 bits is not supported, this routine will converted into 4 bits}
  2841. FOR i := 1 TO Row_Bytes do
  2842. begin
  2843. Byte(Dest^) := ((Byte(Src^) shr 2) and $F) or ((Byte(Src^)) and $F0);
  2844. inc(Dest);
  2845. Byte(Dest^) := ((Byte(Src^) shl 2) and $F) or ((Byte(Src^) shl 4) and $F0);
  2846. inc(Dest);
  2847. inc(Src);
  2848. end {FOR i}
  2849. end;
  2850. {Copy types using palette with 2 bits for each pixel}
  2851. procedure TChunkIDAT.CopyNonInterlacedPalette2(
  2852. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2853. var
  2854. i: Integer;
  2855. begin
  2856. {2 bits is not supported, this routine will converted into 4 bits}
  2857. FOR i := 1 TO Row_Bytes do
  2858. begin
  2859. Byte(Dest^) := ((Byte(Src^) shr 4) and $3) or ((Byte(Src^) shr 2) and $30);
  2860. inc(Dest);
  2861. Byte(Dest^) := (Byte(Src^) and $3) or ((Byte(Src^) shl 2) and $30);
  2862. inc(Dest);
  2863. inc(Src);
  2864. end {FOR i}
  2865. end;
  2866. {Copy grayscale images with 16 bits}
  2867. procedure TChunkIDAT.CopyNonInterlacedGrayscale16(
  2868. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2869. var
  2870. I: Integer;
  2871. begin
  2872. FOR I := 1 TO ImageWidth DO
  2873. begin
  2874. {Windows does not supports 16 bits for each pixel in grayscale}
  2875. {mode, so reduce to 8}
  2876. Dest^ := Src^; inc(Dest);
  2877. {$IFDEF Store16bits}
  2878. Extra^ := pChar(Longint(Src) + 1)^; inc(Extra);
  2879. {$ENDIF}
  2880. {Move to next pixel}
  2881. inc(Src, 2);
  2882. end {for I}
  2883. end;
  2884. {Copy 8 bits per sample RGB images followed by an alpha byte}
  2885. procedure TChunkIDAT.CopyNonInterlacedRGBAlpha8(
  2886. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2887. var
  2888. i: Integer;
  2889. begin
  2890. FOR I := 1 TO ImageWidth DO
  2891. begin
  2892. {Copy pixel values and transparency}
  2893. Trans^ := pChar(Longint(Src) + 3)^;
  2894. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2895. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Dest);
  2896. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) )^]; inc(Dest);
  2897. {Move to next pixel}
  2898. inc(Src, 4); inc(Trans);
  2899. end {for I}
  2900. end;
  2901. {Copy 16 bits RGB image with alpha using 2 bytes for each sample}
  2902. procedure TChunkIDAT.CopyNonInterlacedRGBAlpha16(
  2903. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2904. var
  2905. I: Integer;
  2906. begin
  2907. FOR I := 1 TO ImageWidth DO
  2908. begin
  2909. //Copy rgb and alpha values (transforming from 16 bits to 8 bits)
  2910. {Copy pixel values}
  2911. Trans^ := pChar(Longint(Src) + 6)^;
  2912. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 4)^]; inc(Dest);
  2913. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2914. Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) )^]; inc(Dest);
  2915. {$IFDEF Store16bits}
  2916. {Copy extra pixel values}
  2917. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 5)^]; inc(Extra);
  2918. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 3)^]; inc(Extra);
  2919. Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Extra);
  2920. {$ENDIF}
  2921. {Move to next pixel}
  2922. inc(Src, 8); inc(Trans);
  2923. end {for I}
  2924. end;
  2925. {Copy 8 bits per sample grayscale followed by alpha}
  2926. procedure TChunkIDAT.CopyNonInterlacedGrayscaleAlpha8(
  2927. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2928. var
  2929. I: Integer;
  2930. begin
  2931. FOR I := 1 TO ImageWidth DO
  2932. begin
  2933. {Copy alpha value and then gray value}
  2934. Dest^ := Src^; inc(Src);
  2935. Trans^ := Src^; inc(Src);
  2936. inc(Dest); inc(Trans);
  2937. end;
  2938. end;
  2939. {Copy 16 bits per sample grayscale followed by alpha}
  2940. procedure TChunkIDAT.CopyNonInterlacedGrayscaleAlpha16(
  2941. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2942. var
  2943. I: Integer;
  2944. begin
  2945. FOR I := 1 TO ImageWidth DO
  2946. begin
  2947. {Copy alpha value and then gray value}
  2948. {$IFDEF Store16bits}
  2949. Extra^ := pChar(Longint(Src) + 1)^; inc(Extra);
  2950. {$ENDIF}
  2951. Dest^ := Src^; inc(Src, 2);
  2952. Trans^ := Src^; inc(Src, 2);
  2953. inc(Dest); inc(Trans);
  2954. end;
  2955. end;
  2956. {Decode non interlaced image}
  2957. procedure TChunkIDAT.DecodeNonInterlaced(Stream: TStream;
  2958. var ZLIBStream: TZStreamRec2; const Size: Integer; var crcfile: Cardinal);
  2959. var
  2960. j: Cardinal;
  2961. Trans, Data{$IFDEF Store16bits}, Extra{$ENDIF}: pChar;
  2962. CopyProc: procedure(
  2963. Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar) of object;
  2964. begin
  2965. CopyProc := nil; {Initialize}
  2966. {Determines the method to copy the image data}
  2967. case Header.ColorType of
  2968. {R, G, B values}
  2969. COLOR_RGB:
  2970. case Header.BitDepth of
  2971. 8: CopyProc := CopyNonInterlacedRGB8;
  2972. 16: CopyProc := CopyNonInterlacedRGB16;
  2973. end;
  2974. {Types using palettes}
  2975. COLOR_PALETTE, COLOR_GRAYSCALE:
  2976. case Header.BitDepth of
  2977. 1, 4, 8: CopyProc := CopyNonInterlacedPalette148;
  2978. 2 : if Header.ColorType = COLOR_PALETTE then
  2979. CopyProc := CopyNonInterlacedPalette2
  2980. else
  2981. CopyProc := CopyNonInterlacedGray2;
  2982. 16 : CopyProc := CopyNonInterlacedGrayscale16;
  2983. end;
  2984. {R, G, B followed by alpha}
  2985. COLOR_RGBALPHA:
  2986. case Header.BitDepth of
  2987. 8 : CopyProc := CopyNonInterlacedRGBAlpha8;
  2988. 16 : CopyProc := CopyNonInterlacedRGBAlpha16;
  2989. end;
  2990. {Grayscale followed by alpha}
  2991. COLOR_GRAYSCALEALPHA:
  2992. case Header.BitDepth of
  2993. 8 : CopyProc := CopyNonInterlacedGrayscaleAlpha8;
  2994. 16 : CopyProc := CopyNonInterlacedGrayscaleAlpha16;
  2995. end;
  2996. end;
  2997. {Get the image data pointer}
  2998. Longint(Data) := Longint(Header.ImageData) +
  2999. Header.BytesPerRow * (ImageHeight - 1);
  3000. Trans := Header.ImageAlpha;
  3001. {$IFDEF Store16bits}
  3002. Longint(Extra) := Longint(Header.ExtraImageData) +
  3003. Header.BytesPerRow * (ImageHeight - 1);
  3004. {$ENDIF}
  3005. {Reads each line}
  3006. FOR j := 0 to ImageHeight - 1 do
  3007. begin
  3008. {Read this line Row_Buffer[RowUsed][0] if the filter type for this line}
  3009. if IDATZlibRead(ZLIBStream, @Row_Buffer[RowUsed][0], Row_Bytes + 1, EndPos,
  3010. CRCFile) = 0 then break;
  3011. {Filter the current row}
  3012. FilterRow;
  3013. {Copies non interlaced row to image}
  3014. CopyProc(@Row_Buffer[RowUsed][1], Data, Trans{$IFDEF Store16bits}, Extra
  3015. {$ENDIF});
  3016. {Invert line used}
  3017. RowUsed := not RowUsed;
  3018. dec(Data, Header.BytesPerRow);
  3019. {$IFDEF Store16bits}dec(Extra, Header.BytesPerRow);{$ENDIF}
  3020. inc(Trans, ImageWidth);
  3021. end {for I};
  3022. end;
  3023. {Filter the current line}
  3024. procedure TChunkIDAT.FilterRow;
  3025. var
  3026. pp: Byte;
  3027. vv, left, above, aboveleft: Integer;
  3028. Col: Cardinal;
  3029. begin
  3030. {Test the filter}
  3031. case Row_Buffer[RowUsed]^[0] of
  3032. {No filtering for this line}
  3033. FILTER_NONE: begin end;
  3034. {AND 255 serves only to never let the result be larger than one byte}
  3035. {Sub filter}
  3036. FILTER_SUB:
  3037. FOR Col := Offset + 1 to Row_Bytes DO
  3038. Row_Buffer[RowUsed][Col] := (Row_Buffer[RowUsed][Col] +
  3039. Row_Buffer[RowUsed][Col - Offset]) and 255;
  3040. {Up filter}
  3041. FILTER_UP:
  3042. FOR Col := 1 to Row_Bytes DO
  3043. Row_Buffer[RowUsed][Col] := (Row_Buffer[RowUsed][Col] +
  3044. Row_Buffer[not RowUsed][Col]) and 255;
  3045. {Average filter}
  3046. FILTER_AVERAGE:
  3047. FOR Col := 1 to Row_Bytes DO
  3048. begin
  3049. {Obtains up and left pixels}
  3050. above := Row_Buffer[not RowUsed][Col];
  3051. if col - 1 < Offset then
  3052. left := 0
  3053. else
  3054. Left := Row_Buffer[RowUsed][Col - Offset];
  3055. {Calculates}
  3056. Row_Buffer[RowUsed][Col] := (Row_Buffer[RowUsed][Col] +
  3057. (left + above) div 2) and 255;
  3058. end;
  3059. {Paeth filter}
  3060. FILTER_PAETH:
  3061. begin
  3062. {Initialize}
  3063. left := 0;
  3064. aboveleft := 0;
  3065. {Test each byte}
  3066. FOR Col := 1 to Row_Bytes DO
  3067. begin
  3068. {Obtains above pixel}
  3069. above := Row_Buffer[not RowUsed][Col];
  3070. {Obtains left and top-left pixels}
  3071. if (col - 1 >= offset) Then
  3072. begin
  3073. left := row_buffer[RowUsed][col - offset];
  3074. aboveleft := row_buffer[not RowUsed][col - offset];
  3075. end;
  3076. {Obtains current pixel and paeth predictor}
  3077. vv := row_buffer[RowUsed][Col];
  3078. pp := PaethPredictor(left, above, aboveleft);
  3079. {Calculates}
  3080. Row_Buffer[RowUsed][Col] := (pp + vv) and $FF;
  3081. end {for};
  3082. end;
  3083. end {case};
  3084. end;
  3085. {Reads the image data from the stream}
  3086. function TChunkIDAT.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  3087. Size: Integer): Boolean;
  3088. var
  3089. ZLIBStream: TZStreamRec2;
  3090. CRCCheck,
  3091. CRCFile : Cardinal;
  3092. begin
  3093. {Get pointer to the header chunk}
  3094. Header := Owner.Chunks.Item[0] as TChunkIHDR;
  3095. {Build palette if necessary}
  3096. if Header.HasPalette then PreparePalette();
  3097. {Copy image width and height}
  3098. ImageWidth := Header.Width;
  3099. ImageHeight := Header.Height;
  3100. {Initialize to calculate CRC}
  3101. {$IFDEF CheckCRC}
  3102. CRCFile := update_crc($ffffffff, @ChunkName[0], 4);
  3103. {$ENDIF}
  3104. Owner.GetPixelInfo(Row_Bytes, Offset); {Obtain line information}
  3105. ZLIBStream := ZLIBInitInflate(Stream); {Initializes decompression}
  3106. {Calculate ending position for the current IDAT chunk}
  3107. EndPos := Stream.Position + Size;
  3108. {Allocate memory}
  3109. GetMem(Row_Buffer[false], Row_Bytes + 1);
  3110. GetMem(Row_Buffer[true], Row_Bytes + 1);
  3111. ZeroMemory(Row_Buffer[false], Row_bytes + 1);
  3112. {Set the variable to alternate the Row_Buffer item to use}
  3113. RowUsed := TRUE;
  3114. {Call special methods for the different interlace methods}
  3115. case Owner.InterlaceMethod of
  3116. imNone: DecodeNonInterlaced(stream, ZLIBStream, Size, crcfile);
  3117. imAdam7: DecodeInterlacedAdam7(stream, ZLIBStream, size, crcfile);
  3118. end;
  3119. {Free memory}
  3120. ZLIBTerminateInflate(ZLIBStream); {Terminates decompression}
  3121. FreeMem(Row_Buffer[False], Row_Bytes + 1);
  3122. FreeMem(Row_Buffer[True], Row_Bytes + 1);
  3123. {Now checks CRC}
  3124. Stream.Read(CRCCheck, 4);
  3125. {$IFDEF CheckCRC}
  3126. CRCFile := CRCFile xor $ffffffff;
  3127. CRCCheck := ByteSwap(CRCCheck);
  3128. Result := CRCCheck = CRCFile;
  3129. {Handle CRC error}
  3130. if not Result then
  3131. begin
  3132. {In case it coult not load chunk}
  3133. Owner.RaiseError(EPngInvalidCRC, EPngInvalidCRCText);
  3134. exit;
  3135. end;
  3136. {$ELSE}Result := TRUE; {$ENDIF}
  3137. end;
  3138. const
  3139. IDATHeader: Array[0..3] of char = ('I', 'D', 'A', 'T');
  3140. BUFFER = 5;
  3141. {Saves the IDAT chunk to a stream}
  3142. function TChunkIDAT.SaveToStream(Stream: TStream): Boolean;
  3143. var
  3144. ZLIBStream : TZStreamRec2;
  3145. begin
  3146. {Get pointer to the header chunk}
  3147. Header := Owner.Chunks.Item[0] as TChunkIHDR;
  3148. {Copy image width and height}
  3149. ImageWidth := Header.Width;
  3150. ImageHeight := Header.Height;
  3151. Owner.GetPixelInfo(Row_Bytes, Offset); {Obtain line information}
  3152. {Allocate memory}
  3153. GetMem(Encode_Buffer[BUFFER], Row_Bytes);
  3154. ZeroMemory(Encode_Buffer[BUFFER], Row_Bytes);
  3155. {Allocate buffers for the filters selected}
  3156. {Filter none will always be calculated to the other filters to work}
  3157. GetMem(Encode_Buffer[FILTER_NONE], Row_Bytes);
  3158. ZeroMemory(Encode_Buffer[FILTER_NONE], Row_Bytes);
  3159. if pfSub in Owner.Filters then
  3160. GetMem(Encode_Buffer[FILTER_SUB], Row_Bytes);
  3161. if pfUp in Owner.Filters then
  3162. GetMem(Encode_Buffer[FILTER_UP], Row_Bytes);
  3163. if pfAverage in Owner.Filters then
  3164. GetMem(Encode_Buffer[FILTER_AVERAGE], Row_Bytes);
  3165. if pfPaeth in Owner.Filters then
  3166. GetMem(Encode_Buffer[FILTER_PAETH], Row_Bytes);
  3167. {Initialize ZLIB}
  3168. ZLIBStream := ZLIBInitDeflate(Stream, Owner.fCompressionLevel,
  3169. Owner.MaxIdatSize);
  3170. {Write data depending on the interlace method}
  3171. case Owner.InterlaceMethod of
  3172. imNone: EncodeNonInterlaced(stream, ZLIBStream);
  3173. imAdam7: EncodeInterlacedAdam7(stream, ZLIBStream);
  3174. end;
  3175. {Terminates ZLIB}
  3176. ZLIBTerminateDeflate(ZLIBStream);
  3177. {Release allocated memory}
  3178. FreeMem(Encode_Buffer[BUFFER], Row_Bytes);
  3179. FreeMem(Encode_Buffer[FILTER_NONE], Row_Bytes);
  3180. if pfSub in Owner.Filters then
  3181. FreeMem(Encode_Buffer[FILTER_SUB], Row_Bytes);
  3182. if pfUp in Owner.Filters then
  3183. FreeMem(Encode_Buffer[FILTER_UP], Row_Bytes);
  3184. if pfAverage in Owner.Filters then
  3185. FreeMem(Encode_Buffer[FILTER_AVERAGE], Row_Bytes);
  3186. if pfPaeth in Owner.Filters then
  3187. FreeMem(Encode_Buffer[FILTER_PAETH], Row_Bytes);
  3188. {Everything went ok}
  3189. Result := True;
  3190. end;
  3191. {Writes the IDAT using the settings}
  3192. procedure WriteIDAT(Stream: TStream; Data: Pointer; const Length: Cardinal);
  3193. var
  3194. ChunkLen, CRC: Cardinal;
  3195. begin
  3196. {Writes IDAT header}
  3197. ChunkLen := ByteSwap(Length);
  3198. Stream.Write(ChunkLen, 4); {Chunk length}
  3199. Stream.Write(IDATHeader[0], 4); {Idat header}
  3200. CRC := update_crc($ffffffff, @IDATHeader[0], 4); {Crc part for header}
  3201. {Writes IDAT data and calculates CRC for data}
  3202. Stream.Write(Data^, Length);
  3203. CRC := Byteswap(update_crc(CRC, Data, Length) xor $ffffffff);
  3204. {Writes final CRC}
  3205. Stream.Write(CRC, 4);
  3206. end;
  3207. {Compress and writes IDAT chunk data}
  3208. procedure TChunkIDAT.IDATZlibWrite(var ZLIBStream: TZStreamRec2;
  3209. Buffer: Pointer; const Length: Cardinal);
  3210. begin
  3211. with ZLIBStream, ZLIBStream.ZLIB do
  3212. begin
  3213. {Set data to be compressed}
  3214. next_in := Buffer;
  3215. avail_in := Length;
  3216. {Compress all the data avaliable to compress}
  3217. while avail_in > 0 do
  3218. begin
  3219. deflate(ZLIB, Z_NO_FLUSH);
  3220. {The whole buffer was used, save data to stream and restore buffer}
  3221. if avail_out = 0 then
  3222. begin
  3223. {Writes this IDAT chunk}
  3224. WriteIDAT(fStream, Data, Owner.MaxIdatSize);
  3225. {Restore buffer}
  3226. next_out := Data;
  3227. avail_out := Owner.MaxIdatSize;
  3228. end {if avail_out = 0};
  3229. end {while avail_in};
  3230. end {with ZLIBStream, ZLIBStream.ZLIB}
  3231. end;
  3232. {Finishes compressing data to write IDAT chunk}
  3233. procedure TChunkIDAT.FinishIDATZlib(var ZLIBStream: TZStreamRec2);
  3234. begin
  3235. with ZLIBStream, ZLIBStream.ZLIB do
  3236. begin
  3237. {Set data to be compressed}
  3238. next_in := nil;
  3239. avail_in := 0;
  3240. while deflate(ZLIB,Z_FINISH) <> Z_STREAM_END do
  3241. begin
  3242. {Writes this IDAT chunk}
  3243. WriteIDAT(fStream, Data, Owner.MaxIdatSize - avail_out);
  3244. {Re-update buffer}
  3245. next_out := Data;
  3246. avail_out := Owner.MaxIdatSize;
  3247. end;
  3248. if avail_out < Owner.MaxIdatSize then
  3249. {Writes final IDAT}
  3250. WriteIDAT(fStream, Data, Owner.MaxIdatSize - avail_out);
  3251. end {with ZLIBStream, ZLIBStream.ZLIB};
  3252. end;
  3253. {Copy memory to encode RGB image with 1 byte for each color sample}
  3254. procedure TChunkIDAT.EncodeNonInterlacedRGB8(Src, Dest, Trans: pChar);
  3255. var
  3256. I: Integer;
  3257. begin
  3258. FOR I := 1 TO ImageWidth DO
  3259. begin
  3260. {Copy pixel values}
  3261. Byte(Dest^) := fOwner.InverseGamma[pByte(Longint(Src) + 2)^]; inc(Dest);
  3262. Byte(Dest^) := fOwner.InverseGamma[pByte(Longint(Src) + 1)^]; inc(Dest);
  3263. Byte(Dest^) := fOwner.InverseGamma[pByte(Longint(Src) )^]; inc(Dest);
  3264. {Move to next pixel}
  3265. inc(Src, 3);
  3266. end {for I}
  3267. end;
  3268. {Copy memory to encode RGB images with 16 bits for each color sample}
  3269. procedure TChunkIDAT.EncodeNonInterlacedRGB16(Src, Dest, Trans: pChar);
  3270. var
  3271. I: Integer;
  3272. begin
  3273. FOR I := 1 TO ImageWidth DO
  3274. begin
  3275. //Now we copy from 1 byte for each sample stored to a 2 bytes (or 1 word)
  3276. //for sample
  3277. {Copy pixel values}
  3278. pWORD(Dest)^ := fOwner.InverseGamma[pByte(Longint(Src) + 2)^]; inc(Dest, 2);
  3279. pWORD(Dest)^ := fOwner.InverseGamma[pByte(Longint(Src) + 1)^]; inc(Dest, 2);
  3280. pWORD(Dest)^ := fOwner.InverseGamma[pByte(Longint(Src) )^]; inc(Dest, 2);
  3281. {Move to next pixel}
  3282. inc(Src, 3);
  3283. end {for I}
  3284. end;
  3285. {Copy memory to encode types using palettes (1, 4 or 8 bits per pixel)}
  3286. procedure TChunkIDAT.EncodeNonInterlacedPalette148(Src, Dest, Trans: pChar);
  3287. begin
  3288. {It's simple as copying the data}
  3289. CopyMemory(Dest, Src, Row_Bytes);
  3290. end;
  3291. {Copy memory to encode grayscale images with 2 bytes for each sample}
  3292. procedure TChunkIDAT.EncodeNonInterlacedGrayscale16(Src, Dest, Trans: pChar);
  3293. var
  3294. I: Integer;
  3295. begin
  3296. FOR I := 1 TO ImageWidth DO
  3297. begin
  3298. //Now we copy from 1 byte for each sample stored to a 2 bytes (or 1 word)
  3299. //for sample
  3300. pWORD(Dest)^ := pByte(Longint(Src))^; inc(Dest, 2);
  3301. {Move to next pixel}
  3302. inc(Src);
  3303. end {for I}
  3304. end;
  3305. {Encode images using RGB followed by an alpha value using 1 byte for each}
  3306. procedure TChunkIDAT.EncodeNonInterlacedRGBAlpha8(Src, Dest, Trans: pChar);
  3307. var
  3308. i: Integer;
  3309. begin
  3310. {Copy the data to the destination, including data from Trans pointer}
  3311. FOR i := 1 TO ImageWidth do
  3312. begin
  3313. Byte(Dest^) := Owner.InverseGamma[PByte(Longint(Src) + 2)^]; inc(Dest);
  3314. Byte(Dest^) := Owner.InverseGamma[PByte(Longint(Src) + 1)^]; inc(Dest);
  3315. Byte(Dest^) := Owner.InverseGamma[PByte(Longint(Src) )^]; inc(Dest);
  3316. Dest^ := Trans^; inc(Dest);
  3317. inc(Src, 3); inc(Trans);
  3318. end {for i};
  3319. end;
  3320. {Encode images using RGB followed by an alpha value using 2 byte for each}
  3321. procedure TChunkIDAT.EncodeNonInterlacedRGBAlpha16(Src, Dest, Trans: pChar);
  3322. var
  3323. i: Integer;
  3324. begin
  3325. {Copy the data to the destination, including data from Trans pointer}
  3326. FOR i := 1 TO ImageWidth do
  3327. begin
  3328. pWord(Dest)^ := Owner.InverseGamma[PByte(Longint(Src) + 2)^]; inc(Dest, 2);
  3329. pWord(Dest)^ := Owner.InverseGamma[PByte(Longint(Src) + 1)^]; inc(Dest, 2);
  3330. pWord(Dest)^ := Owner.InverseGamma[PByte(Longint(Src) )^]; inc(Dest, 2);
  3331. pWord(Dest)^ := PByte(Longint(Trans) )^; inc(Dest, 2);
  3332. inc(Src, 3); inc(Trans);
  3333. end {for i};
  3334. end;
  3335. {Encode grayscale images followed by an alpha value using 1 byte for each}
  3336. procedure TChunkIDAT.EncodeNonInterlacedGrayscaleAlpha8(
  3337. Src, Dest, Trans: pChar);
  3338. var
  3339. i: Integer;
  3340. begin
  3341. {Copy the data to the destination, including data from Trans pointer}
  3342. FOR i := 1 TO ImageWidth do
  3343. begin
  3344. Dest^ := Src^; inc(Dest);
  3345. Dest^ := Trans^; inc(Dest);
  3346. inc(Src); inc(Trans);
  3347. end {for i};
  3348. end;
  3349. {Encode grayscale images followed by an alpha value using 2 byte for each}
  3350. procedure TChunkIDAT.EncodeNonInterlacedGrayscaleAlpha16(
  3351. Src, Dest, Trans: pChar);
  3352. var
  3353. i: Integer;
  3354. begin
  3355. {Copy the data to the destination, including data from Trans pointer}
  3356. FOR i := 1 TO ImageWidth do
  3357. begin
  3358. pWord(Dest)^ := pByte(Src)^; inc(Dest, 2);
  3359. pWord(Dest)^ := pByte(Trans)^; inc(Dest, 2);
  3360. inc(Src); inc(Trans);
  3361. end {for i};
  3362. end;
  3363. {Encode non interlaced images}
  3364. procedure TChunkIDAT.EncodeNonInterlaced(Stream: TStream;
  3365. var ZLIBStream: TZStreamRec2);
  3366. var
  3367. {Current line}
  3368. j: Cardinal;
  3369. {Pointers to image data}
  3370. Data, Trans: PChar;
  3371. {Filter used for this line}
  3372. Filter: Byte;
  3373. {Method which will copy the data into the buffer}
  3374. CopyProc: procedure(Src, Dest, Trans: pChar) of object;
  3375. begin
  3376. CopyProc := nil; {Initialize to avoid warnings}
  3377. {Defines the method to copy the data to the buffer depending on}
  3378. {the image parameters}
  3379. case Header.ColorType of
  3380. {R, G, B values}
  3381. COLOR_RGB:
  3382. case Header.BitDepth of
  3383. 8: CopyProc := EncodeNonInterlacedRGB8;
  3384. 16: CopyProc := EncodeNonInterlacedRGB16;
  3385. end;
  3386. {Palette and grayscale values}
  3387. COLOR_GRAYSCALE, COLOR_PALETTE:
  3388. case Header.BitDepth of
  3389. 1, 4, 8: CopyProc := EncodeNonInterlacedPalette148;
  3390. 16: CopyProc := EncodeNonInterlacedGrayscale16;
  3391. end;
  3392. {RGB with a following alpha value}
  3393. COLOR_RGBALPHA:
  3394. case Header.BitDepth of
  3395. 8: CopyProc := EncodeNonInterlacedRGBAlpha8;
  3396. 16: CopyProc := EncodeNonInterlacedRGBAlpha16;
  3397. end;
  3398. {Grayscale images followed by an alpha}
  3399. COLOR_GRAYSCALEALPHA:
  3400. case Header.BitDepth of
  3401. 8: CopyProc := EncodeNonInterlacedGrayscaleAlpha8;
  3402. 16: CopyProc := EncodeNonInterlacedGrayscaleAlpha16;
  3403. end;
  3404. end {case Header.ColorType};
  3405. {Get the image data pointer}
  3406. Longint(Data) := Longint(Header.ImageData) +
  3407. Header.BytesPerRow * (ImageHeight - 1);
  3408. Trans := Header.ImageAlpha;
  3409. {Writes each line}
  3410. FOR j := 0 to ImageHeight - 1 do
  3411. begin
  3412. {Copy data into buffer}
  3413. CopyProc(Data, @Encode_Buffer[BUFFER][0], Trans);
  3414. {Filter data}
  3415. Filter := FilterToEncode;
  3416. {Compress data}
  3417. IDATZlibWrite(ZLIBStream, @Filter, 1);
  3418. IDATZlibWrite(ZLIBStream, @Encode_Buffer[Filter][0], Row_Bytes);
  3419. {Adjust pointers to the actual image data}
  3420. dec(Data, Header.BytesPerRow);
  3421. inc(Trans, ImageWidth);
  3422. end;
  3423. {Compress and finishes copying the remaining data}
  3424. FinishIDATZlib(ZLIBStream);
  3425. end;
  3426. {Copy memory to encode interlaced images using RGB value with 1 byte for}
  3427. {each color sample}
  3428. procedure TChunkIDAT.EncodeInterlacedRGB8(const Pass: Byte;
  3429. Src, Dest, Trans: pChar);
  3430. var
  3431. Col: Integer;
  3432. begin
  3433. {Get first column and enter in loop}
  3434. Col := ColumnStart[Pass];
  3435. Src := pChar(Longint(Src) + Col * 3);
  3436. repeat
  3437. {Copy this row}
  3438. Byte(Dest^) := fOwner.InverseGamma[pByte(Longint(Src) + 2)^]; inc(Dest);
  3439. Byte(Dest^) := fOwner.InverseGamma[pByte(Longint(Src) + 1)^]; inc(Dest);
  3440. Byte(Dest^) := fOwner.InverseGamma[pByte(Longint(Src) )^]; inc(Dest);
  3441. {Move to next column}
  3442. inc(Src, ColumnIncrement[Pass] * 3);
  3443. inc(Col, ColumnIncrement[Pass]);
  3444. until Col >= ImageWidth;
  3445. end;
  3446. {Copy memory to encode interlaced RGB images with 2 bytes each color sample}
  3447. procedure TChunkIDAT.EncodeInterlacedRGB16(const Pass: Byte;
  3448. Src, Dest, Trans: pChar);
  3449. var
  3450. Col: Integer;
  3451. begin
  3452. {Get first column and enter in loop}
  3453. Col := ColumnStart[Pass];
  3454. Src := pChar(Longint(Src) + Col * 3);
  3455. repeat
  3456. {Copy this row}
  3457. pWord(Dest)^ := Owner.InverseGamma[pByte(Longint(Src) + 2)^]; inc(Dest, 2);
  3458. pWord(Dest)^ := Owner.InverseGamma[pByte(Longint(Src) + 1)^]; inc(Dest, 2);
  3459. pWord(Dest)^ := Owner.InverseGamma[pByte(Longint(Src) )^]; inc(Dest, 2);
  3460. {Move to next column}
  3461. inc(Src, ColumnIncrement[Pass] * 3);
  3462. inc(Col, ColumnIncrement[Pass]);
  3463. until Col >= ImageWidth;
  3464. end;
  3465. {Copy memory to encode interlaced images using palettes using bit depths}
  3466. {1, 4, 8 (each pixel in the image)}
  3467. procedure TChunkIDAT.EncodeInterlacedPalette148(const Pass: Byte;
  3468. Src, Dest, Trans: pChar);
  3469. const
  3470. BitTable: Array[1..8] of Integer = ($1, $3, 0, $F, 0, 0, 0, $FF);
  3471. StartBit: Array[1..8] of Integer = (7 , 0 , 0, 4, 0, 0, 0, 0);
  3472. var
  3473. CurBit, Col: Integer;
  3474. Src2: PChar;
  3475. begin
  3476. {Clean the line}
  3477. fillchar(Dest^, Row_Bytes, #0);
  3478. {Get first column and enter in loop}
  3479. Col := ColumnStart[Pass];
  3480. with Header.BitmapInfo.bmiHeader do
  3481. repeat
  3482. {Copy data}
  3483. CurBit := StartBit[biBitCount];
  3484. repeat
  3485. {Adjust pointer to pixel byte bounds}
  3486. Src2 := pChar(Longint(Src) + (biBitCount * Col) div 8);
  3487. {Copy data}
  3488. Byte(Dest^) := Byte(Dest^) or
  3489. (((Byte(Src2^) shr (StartBit[Header.BitDepth] - (biBitCount * Col)
  3490. mod 8))) and (BitTable[biBitCount])) shl CurBit;
  3491. {Move to next column}
  3492. inc(Col, ColumnIncrement[Pass]);
  3493. {Will read next bits}
  3494. dec(CurBit, biBitCount);
  3495. until CurBit < 0;
  3496. {Move to next byte in source}
  3497. inc(Dest);
  3498. until Col >= ImageWidth;
  3499. end;
  3500. {Copy to encode interlaced grayscale images using 16 bits for each sample}
  3501. procedure TChunkIDAT.EncodeInterlacedGrayscale16(const Pass: Byte;
  3502. Src, Dest, Trans: pChar);
  3503. var
  3504. Col: Integer;
  3505. begin
  3506. {Get first column and enter in loop}
  3507. Col := ColumnStart[Pass];
  3508. Src := pChar(Longint(Src) + Col);
  3509. repeat
  3510. {Copy this row}
  3511. pWord(Dest)^ := Byte(Src^); inc(Dest, 2);
  3512. {Move to next column}
  3513. inc(Src, ColumnIncrement[Pass]);
  3514. inc(Col, ColumnIncrement[Pass]);
  3515. until Col >= ImageWidth;
  3516. end;
  3517. {Copy to encode interlaced rgb images followed by an alpha value, all using}
  3518. {one byte for each sample}
  3519. procedure TChunkIDAT.EncodeInterlacedRGBAlpha8(const Pass: Byte;
  3520. Src, Dest, Trans: pChar);
  3521. var
  3522. Col: Integer;
  3523. begin
  3524. {Get first column and enter in loop}
  3525. Col := ColumnStart[Pass];
  3526. Src := pChar(Longint(Src) + Col * 3);
  3527. Trans := pChar(Longint(Trans) + Col);
  3528. repeat
  3529. {Copy this row}
  3530. Byte(Dest^) := Owner.InverseGamma[pByte(Longint(Src) + 2)^]; inc(Dest);
  3531. Byte(Dest^) := Owner.InverseGamma[pByte(Longint(Src) + 1)^]; inc(Dest);
  3532. Byte(Dest^) := Owner.InverseGamma[pByte(Longint(Src) )^]; inc(Dest);
  3533. Dest^ := Trans^; inc(Dest);
  3534. {Move to next column}
  3535. inc(Src, ColumnIncrement[Pass] * 3);
  3536. inc(Trans, ColumnIncrement[Pass]);
  3537. inc(Col, ColumnIncrement[Pass]);
  3538. until Col >= ImageWidth;
  3539. end;
  3540. {Copy to encode interlaced rgb images followed by an alpha value, all using}
  3541. {two byte for each sample}
  3542. procedure TChunkIDAT.EncodeInterlacedRGBAlpha16(const Pass: Byte;
  3543. Src, Dest, Trans: pChar);
  3544. var
  3545. Col: Integer;
  3546. begin
  3547. {Get first column and enter in loop}
  3548. Col := ColumnStart[Pass];
  3549. Src := pChar(Longint(Src) + Col * 3);
  3550. Trans := pChar(Longint(Trans) + Col);
  3551. repeat
  3552. {Copy this row}
  3553. pWord(Dest)^ := pByte(Longint(Src) + 2)^; inc(Dest, 2);
  3554. pWord(Dest)^ := pByte(Longint(Src) + 1)^; inc(Dest, 2);
  3555. pWord(Dest)^ := pByte(Longint(Src) )^; inc(Dest, 2);
  3556. pWord(Dest)^ := pByte(Trans)^; inc(Dest, 2);
  3557. {Move to next column}
  3558. inc(Src, ColumnIncrement[Pass] * 3);
  3559. inc(Trans, ColumnIncrement[Pass]);
  3560. inc(Col, ColumnIncrement[Pass]);
  3561. until Col >= ImageWidth;
  3562. end;
  3563. {Copy to encode grayscale interlaced images followed by an alpha value, all}
  3564. {using 1 byte for each sample}
  3565. procedure TChunkIDAT.EncodeInterlacedGrayscaleAlpha8(const Pass: Byte;
  3566. Src, Dest, Trans: pChar);
  3567. var
  3568. Col: Integer;
  3569. begin
  3570. {Get first column and enter in loop}
  3571. Col := ColumnStart[Pass];
  3572. Src := pChar(Longint(Src) + Col);
  3573. Trans := pChar(Longint(Trans) + Col);
  3574. repeat
  3575. {Copy this row}
  3576. Dest^ := Src^; inc(Dest);
  3577. Dest^ := Trans^; inc(Dest);
  3578. {Move to next column}
  3579. inc(Src, ColumnIncrement[Pass]);
  3580. inc(Trans, ColumnIncrement[Pass]);
  3581. inc(Col, ColumnIncrement[Pass]);
  3582. until Col >= ImageWidth;
  3583. end;
  3584. {Copy to encode grayscale interlaced images followed by an alpha value, all}
  3585. {using 2 bytes for each sample}
  3586. procedure TChunkIDAT.EncodeInterlacedGrayscaleAlpha16(const Pass: Byte;
  3587. Src, Dest, Trans: pChar);
  3588. var
  3589. Col: Integer;
  3590. begin
  3591. {Get first column and enter in loop}
  3592. Col := ColumnStart[Pass];
  3593. Src := pChar(Longint(Src) + Col);
  3594. Trans := pChar(Longint(Trans) + Col);
  3595. repeat
  3596. {Copy this row}
  3597. pWord(Dest)^ := pByte(Src)^; inc(Dest, 2);
  3598. pWord(Dest)^ := pByte(Trans)^; inc(Dest, 2);
  3599. {Move to next column}
  3600. inc(Src, ColumnIncrement[Pass]);
  3601. inc(Trans, ColumnIncrement[Pass]);
  3602. inc(Col, ColumnIncrement[Pass]);
  3603. until Col >= ImageWidth;
  3604. end;
  3605. {Encode interlaced images}
  3606. procedure TChunkIDAT.EncodeInterlacedAdam7(Stream: TStream;
  3607. var ZLIBStream: TZStreamRec2);
  3608. var
  3609. CurrentPass, Filter: Byte;
  3610. PixelsThisRow: Integer;
  3611. CurrentRow : Integer;
  3612. Trans, Data: pChar;
  3613. CopyProc: procedure(const Pass: Byte;
  3614. Src, Dest, Trans: pChar) of object;
  3615. begin
  3616. CopyProc := nil; {Initialize to avoid warnings}
  3617. {Defines the method to copy the data to the buffer depending on}
  3618. {the image parameters}
  3619. case Header.ColorType of
  3620. {R, G, B values}
  3621. COLOR_RGB:
  3622. case Header.BitDepth of
  3623. 8: CopyProc := EncodeInterlacedRGB8;
  3624. 16: CopyProc := EncodeInterlacedRGB16;
  3625. end;
  3626. {Grayscale and palette}
  3627. COLOR_PALETTE, COLOR_GRAYSCALE:
  3628. case Header.BitDepth of
  3629. 1, 4, 8: CopyProc := EncodeInterlacedPalette148;
  3630. 16: CopyProc := EncodeInterlacedGrayscale16;
  3631. end;
  3632. {RGB followed by alpha}
  3633. COLOR_RGBALPHA:
  3634. case Header.BitDepth of
  3635. 8: CopyProc := EncodeInterlacedRGBAlpha8;
  3636. 16: CopyProc := EncodeInterlacedRGBAlpha16;
  3637. end;
  3638. COLOR_GRAYSCALEALPHA:
  3639. {Grayscale followed by alpha}
  3640. case Header.BitDepth of
  3641. 8: CopyProc := EncodeInterlacedGrayscaleAlpha8;
  3642. 16: CopyProc := EncodeInterlacedGrayscaleAlpha16;
  3643. end;
  3644. end {case Header.ColorType};
  3645. {Compress the image using the seven passes for ADAM 7}
  3646. FOR CurrentPass := 0 TO 6 DO
  3647. begin
  3648. {Calculates the number of pixels and bytes for this pass row}
  3649. PixelsThisRow := (ImageWidth - ColumnStart[CurrentPass] +
  3650. ColumnIncrement[CurrentPass] - 1) div ColumnIncrement[CurrentPass];
  3651. Row_Bytes := BytesForPixels(PixelsThisRow, Header.ColorType,
  3652. Header.BitDepth);
  3653. ZeroMemory(Encode_Buffer[FILTER_NONE], Row_Bytes);
  3654. {Get current row index}
  3655. CurrentRow := RowStart[CurrentPass];
  3656. {Get a pointer to the current row image data}
  3657. Data := Ptr(Longint(Header.ImageData) + Header.BytesPerRow *
  3658. (ImageHeight - 1 - CurrentRow));
  3659. Trans := Ptr(Longint(Header.ImageAlpha) + ImageWidth * CurrentRow);
  3660. {Process all the image rows}
  3661. if Row_Bytes > 0 then
  3662. while CurrentRow < ImageHeight do
  3663. begin
  3664. {Copy data into buffer}
  3665. CopyProc(CurrentPass, Data, @Encode_Buffer[BUFFER][0], Trans);
  3666. {Filter data}
  3667. Filter := FilterToEncode;
  3668. {Compress data}
  3669. IDATZlibWrite(ZLIBStream, @Filter, 1);
  3670. IDATZlibWrite(ZLIBStream, @Encode_Buffer[Filter][0], Row_Bytes);
  3671. {Move to the next row}
  3672. inc(CurrentRow, RowIncrement[CurrentPass]);
  3673. {Move pointer to the next line}
  3674. dec(Data, RowIncrement[CurrentPass] * Header.BytesPerRow);
  3675. inc(Trans, RowIncrement[CurrentPass] * ImageWidth);
  3676. end {while CurrentRow < ImageHeight}
  3677. end {CurrentPass};
  3678. {Compress and finishes copying the remaining data}
  3679. FinishIDATZlib(ZLIBStream);
  3680. end;
  3681. {Filters the row to be encoded and returns the best filter}
  3682. function TChunkIDAT.FilterToEncode: Byte;
  3683. var
  3684. Run, LongestRun, ii, jj: Cardinal;
  3685. Last, Above, LastAbove: Byte;
  3686. begin
  3687. {Selecting more filters using the Filters property from TPngObject}
  3688. {increases the chances to the file be much smaller, but decreases}
  3689. {the performace}
  3690. {This method will creates the same line data using the different}
  3691. {filter methods and select the best}
  3692. {Sub-filter}
  3693. if pfSub in Owner.Filters then
  3694. for ii := 0 to Row_Bytes - 1 do
  3695. begin
  3696. {There is no previous pixel when it's on the first pixel, so}
  3697. {set last as zero when in the first}
  3698. if (ii >= Offset) then
  3699. last := Encode_Buffer[BUFFER]^[ii - Offset]
  3700. else
  3701. last := 0;
  3702. Encode_Buffer[FILTER_SUB]^[ii] := Encode_Buffer[BUFFER]^[ii] - last;
  3703. end;
  3704. {Up filter}
  3705. if pfUp in Owner.Filters then
  3706. for ii := 0 to Row_Bytes - 1 do
  3707. Encode_Buffer[FILTER_UP]^[ii] := Encode_Buffer[BUFFER]^[ii] -
  3708. Encode_Buffer[FILTER_NONE]^[ii];
  3709. {Average filter}
  3710. if pfAverage in Owner.Filters then
  3711. for ii := 0 to Row_Bytes - 1 do
  3712. begin
  3713. {Get the previous pixel, if the current pixel is the first, the}
  3714. {previous is considered to be 0}
  3715. if (ii >= Offset) then
  3716. last := Encode_Buffer[BUFFER]^[ii - Offset]
  3717. else
  3718. last := 0;
  3719. {Get the pixel above}
  3720. above := Encode_Buffer[FILTER_NONE]^[ii];
  3721. {Calculates formula to the average pixel}
  3722. Encode_Buffer[FILTER_AVERAGE]^[ii] := Encode_Buffer[BUFFER]^[ii] -
  3723. (above + last) div 2 ;
  3724. end;
  3725. {Paeth filter (the slower)}
  3726. if pfPaeth in Owner.Filters then
  3727. begin
  3728. {Initialize}
  3729. last := 0;
  3730. lastabove := 0;
  3731. for ii := 0 to Row_Bytes - 1 do
  3732. begin
  3733. {In case this pixel is not the first in the line obtains the}
  3734. {previous one and the one above the previous}
  3735. if (ii >= Offset) then
  3736. begin
  3737. last := Encode_Buffer[BUFFER]^[ii - Offset];
  3738. lastabove := Encode_Buffer[FILTER_NONE]^[ii - Offset];
  3739. end;
  3740. {Obtains the pixel above}
  3741. above := Encode_Buffer[FILTER_NONE]^[ii];
  3742. {Calculate paeth filter for this byte}
  3743. Encode_Buffer[FILTER_PAETH]^[ii] := Encode_Buffer[BUFFER]^[ii] -
  3744. PaethPredictor(last, above, lastabove);
  3745. end;
  3746. end;
  3747. {Now calculates the same line using no filter, which is necessary}
  3748. {in order to have data to the filters when the next line comes}
  3749. CopyMemory(@Encode_Buffer[FILTER_NONE]^[0],
  3750. @Encode_Buffer[BUFFER]^[0], Row_Bytes);
  3751. {If only filter none is selected in the filter list, we don't need}
  3752. {to proceed and further}
  3753. if (Owner.Filters = [pfNone]) or (Owner.Filters = []) then
  3754. begin
  3755. Result := FILTER_NONE;
  3756. exit;
  3757. end {if (Owner.Filters = [pfNone...};
  3758. {Check which filter is the best by checking which has the larger}
  3759. {sequence of the same byte, since they are best compressed}
  3760. LongestRun := 0; Result := FILTER_NONE;
  3761. for ii := FILTER_NONE TO FILTER_PAETH do
  3762. {Check if this filter was selected}
  3763. if TFilter(ii) in Owner.Filters then
  3764. begin
  3765. Run := 0;
  3766. {Check if it's the only filter}
  3767. if Owner.Filters = [TFilter(ii)] then
  3768. begin
  3769. Result := ii;
  3770. exit;
  3771. end;
  3772. {Check using a sequence of four bytes}
  3773. for jj := 2 to Row_Bytes - 1 do
  3774. if (Encode_Buffer[ii]^[jj] = Encode_Buffer [ii]^[jj-1]) or
  3775. (Encode_Buffer[ii]^[jj] = Encode_Buffer [ii]^[jj-2]) then
  3776. inc(Run); {Count the number of sequences}
  3777. {Check if this one is the best so far}
  3778. if (Run > LongestRun) then
  3779. begin
  3780. Result := ii;
  3781. LongestRun := Run;
  3782. end {if (Run > LongestRun)};
  3783. end {if TFilter(ii) in Owner.Filters};
  3784. end;
  3785. {TChunkPLTE implementation}
  3786. {Returns an item in the palette}
  3787. function TChunkPLTE.GetPaletteItem(Index: Byte): TRGBQuad;
  3788. begin
  3789. {Test if item is valid, if not raise error}
  3790. if Index > Count - 1 then
  3791. Owner.RaiseError(EPNGError, EPNGUnknownPalEntryText)
  3792. else
  3793. {Returns the item}
  3794. Result := Header.BitmapInfo.bmiColors[Index];
  3795. end;
  3796. {Loads the palette chunk from a stream}
  3797. function TChunkPLTE.LoadFromStream(Stream: TStream;
  3798. const ChunkName: TChunkName; Size: Integer): Boolean;
  3799. type
  3800. pPalEntry = ^PalEntry;
  3801. PalEntry = record
  3802. r, g, b: Byte;
  3803. end;
  3804. var
  3805. j : Integer; {For the FOR}
  3806. PalColor : pPalEntry;
  3807. palEntries: TMaxLogPalette;
  3808. begin
  3809. {Let ancestor load data and check CRC}
  3810. Result := inherited LoadFromStream(Stream, ChunkName, Size);
  3811. if not Result then exit;
  3812. {This chunk must be divisible by 3 in order to be valid}
  3813. if (Size mod 3 <> 0) or (Size div 3 > 256) then
  3814. begin
  3815. {Raise error}
  3816. Result := FALSE;
  3817. Owner.RaiseError(EPNGInvalidPalette, EPNGInvalidPaletteText);
  3818. exit;
  3819. end {if Size mod 3 <> 0};
  3820. {Fill array with the palette entries}
  3821. fCount := Size div 3;
  3822. Fillchar(palEntries, sizeof(palEntries), #0);
  3823. palEntries.palVersion := $300;
  3824. palEntries.palNumEntries := fCount;
  3825. PalColor := Data;
  3826. FOR j := 0 TO fCount - 1 DO
  3827. with palEntries.palPalEntry[j] do
  3828. begin
  3829. peRed := Owner.GammaTable[PalColor.r];
  3830. peGreen := Owner.GammaTable[PalColor.g];
  3831. peBlue := Owner.GammaTable[PalColor.b];
  3832. peFlags := 0;
  3833. {Move to next palette entry}
  3834. inc(PalColor);
  3835. end;
  3836. Owner.SetPalette(CreatePalette(pLogPalette(@palEntries)^));
  3837. end;
  3838. {Saves the PLTE chunk to a stream}
  3839. function TChunkPLTE.SaveToStream(Stream: TStream): Boolean;
  3840. var
  3841. J: Integer;
  3842. DataPtr: pByte;
  3843. BitmapInfo: TMAXBITMAPINFO;
  3844. palEntries: TMaxLogPalette;
  3845. begin
  3846. {Adjust size to hold all the palette items}
  3847. if fCount = 0 then fCount := Header.BitmapInfo.bmiHeader.biClrUsed;
  3848. ResizeData(fCount * 3);
  3849. {Get all the palette entries}
  3850. fillchar(palEntries, sizeof(palEntries), #0);
  3851. GetPaletteEntries(Header.ImagePalette, 0, 256, palEntries.palPalEntry[0]);
  3852. {Copy pointer to data}
  3853. DataPtr := fData;
  3854. {Copy palette items}
  3855. BitmapInfo := Header.BitmapInfo;
  3856. FOR j := 0 TO fCount - 1 DO
  3857. with palEntries.palPalEntry[j] do
  3858. begin
  3859. DataPtr^ := Owner.InverseGamma[peRed]; inc(DataPtr);
  3860. DataPtr^ := Owner.InverseGamma[peGreen]; inc(DataPtr);
  3861. DataPtr^ := Owner.InverseGamma[peBlue]; inc(DataPtr);
  3862. end {with BitmapInfo};
  3863. {Let ancestor do the rest of the work}
  3864. Result := inherited SaveToStream(Stream);
  3865. end;
  3866. {Assigns from another PLTE chunk}
  3867. procedure TChunkPLTE.Assign(Source: TChunk);
  3868. begin
  3869. {Copy the number of palette items}
  3870. if Source is TChunkPLTE then
  3871. fCount := TChunkPLTE(Source).fCount
  3872. else
  3873. Owner.RaiseError(EPNGError, EPNGCannotAssignChunkText);
  3874. end;
  3875. {TChunkgAMA implementation}
  3876. {Assigns from another chunk}
  3877. procedure TChunkgAMA.Assign(Source: TChunk);
  3878. begin
  3879. {Copy the gamma value}
  3880. if Source is TChunkgAMA then
  3881. Gamma := TChunkgAMA(Source).Gamma
  3882. else
  3883. Owner.RaiseError(EPNGError, EPNGCannotAssignChunkText);
  3884. end;
  3885. {Gamma chunk being created}
  3886. constructor TChunkgAMA.Create(Owner: TPngObject);
  3887. begin
  3888. {Call ancestor}
  3889. inherited Create(Owner);
  3890. Gamma := 1; {Initial value}
  3891. end;
  3892. {Returns gamma value}
  3893. function TChunkgAMA.GetValue: Cardinal;
  3894. begin
  3895. {Make sure that the size is four bytes}
  3896. if DataSize <> 4 then
  3897. begin
  3898. {Adjust size and returns 1}
  3899. ResizeData(4);
  3900. Result := 1;
  3901. end
  3902. {If it's right, read the value}
  3903. else Result := Cardinal(ByteSwap(pCardinal(Data)^))
  3904. end;
  3905. function Power(Base, Exponent: Extended): Extended;
  3906. begin
  3907. if Exponent = 0.0 then
  3908. Result := 1.0 {Math rule}
  3909. else if (Base = 0) or (Exponent = 0) then Result := 0
  3910. else
  3911. Result := Exp(Exponent * Ln(Base));
  3912. end;
  3913. {Loading the chunk from a stream}
  3914. function TChunkgAMA.LoadFromStream(Stream: TStream;
  3915. const ChunkName: TChunkName; Size: Integer): Boolean;
  3916. var
  3917. i: Integer;
  3918. Value: Cardinal;
  3919. begin
  3920. {Call ancestor and test if it went ok}
  3921. Result := inherited LoadFromStream(Stream, ChunkName, Size);
  3922. if not Result then exit;
  3923. Value := Gamma;
  3924. {Build gamma table and inverse table for saving}
  3925. if Value <> 0 then
  3926. with Owner do
  3927. FOR i := 0 TO 255 DO
  3928. begin
  3929. GammaTable[I] := Round(Power((I / 255), 1 /
  3930. (Value / 100000 * 2.2)) * 255);
  3931. InverseGamma[Round(Power((I / 255), 1 /
  3932. (Value / 100000 * 2.2)) * 255)] := I;
  3933. end
  3934. end;
  3935. {Sets the gamma value}
  3936. procedure TChunkgAMA.SetValue(const Value: Cardinal);
  3937. begin
  3938. {Make sure that the size is four bytes}
  3939. if DataSize <> 4 then ResizeData(4);
  3940. {If it's right, set the value}
  3941. pCardinal(Data)^ := ByteSwap(Value);
  3942. end;
  3943. {TPngObject implementation}
  3944. {Assigns from another object}
  3945. procedure TPngObject.Assign(Source: TPersistent);
  3946. begin
  3947. {Being cleared}
  3948. if Source = nil then
  3949. ClearChunks
  3950. {Assigns contents from another TPNGObject}
  3951. else if Source is TPNGObject then
  3952. AssignPNG(Source as TPNGObject)
  3953. {Copy contents from a TBitmap}
  3954. {$IFDEF UseDelphi}else if Source is TBitmap then
  3955. with Source as TBitmap do
  3956. AssignHandle(Handle, Transparent,
  3957. ColorToRGB(TransparentColor)){$ENDIF}
  3958. {Unknown source, let ancestor deal with it}
  3959. else
  3960. inherited;
  3961. end;
  3962. {Clear all the chunks in the list}
  3963. procedure TPngObject.ClearChunks;
  3964. var
  3965. i: Integer;
  3966. begin
  3967. {Initialize gamma}
  3968. InitializeGamma();
  3969. {Free all the objects and memory (0 chunks Bug fixed by Noel Sharpe)}
  3970. for i := 0 TO Integer(Chunks.Count) - 1 do
  3971. TChunk(Chunks.Item[i]).Free;
  3972. Chunks.Count := 0;
  3973. end;
  3974. {Portable Network Graphics object being created as a blank image}
  3975. constructor TPNGObject.CreateBlank(ColorType, BitDepth: Cardinal;
  3976. cx, cy: Integer);
  3977. var NewIHDR: TChunkIHDR;
  3978. begin
  3979. {Calls creator}
  3980. Create;
  3981. {Checks if the parameters are ok}
  3982. if not (ColorType in [COLOR_GRAYSCALE, COLOR_RGB, COLOR_PALETTE,
  3983. COLOR_GRAYSCALEALPHA, COLOR_RGBALPHA]) or not (BitDepth in
  3984. [1,2,4,8, 16]) or ((ColorType = COLOR_PALETTE) and (BitDepth = 16)) or
  3985. ((ColorType = COLOR_RGB) and (BitDepth < 8)) then
  3986. begin
  3987. RaiseError(EPNGInvalidSpec, EInvalidSpec);
  3988. exit;
  3989. end;
  3990. if Bitdepth = 2 then Bitdepth := 4;
  3991. {Add the basis chunks}
  3992. InitializeGamma;
  3993. BeingCreated := True;
  3994. Chunks.Add(TChunkIEND);
  3995. NewIHDR := Chunks.Add(TChunkIHDR) as TChunkIHDR;
  3996. NewIHDR.IHDRData.ColorType := ColorType;
  3997. NewIHDR.IHDRData.BitDepth := BitDepth;
  3998. NewIHDR.IHDRData.Width := cx;
  3999. NewIHDR.IHDRData.Height := cy;
  4000. NewIHDR.PrepareImageData;
  4001. if NewIHDR.HasPalette then
  4002. TChunkPLTE(Chunks.Add(TChunkPLTE)).fCount := 1 shl BitDepth;
  4003. Chunks.Add(TChunkIDAT);
  4004. BeingCreated := False;
  4005. end;
  4006. {Portable Network Graphics object being created}
  4007. constructor TPngObject.Create;
  4008. begin
  4009. {Let it be created}
  4010. inherited Create;
  4011. {Initial properties}
  4012. {$IFDEF UseDelphi}fCanvas := TCanvas.Create;{$ENDIF}
  4013. fFilters := [pfSub];
  4014. fCompressionLevel := 7;
  4015. fInterlaceMethod := imNone;
  4016. fMaxIdatSize := High(Word);
  4017. {Create chunklist object}
  4018. fChunkList := TPngList.Create(Self);
  4019. end;
  4020. {Portable Network Graphics object being destroyed}
  4021. destructor TPngObject.Destroy;
  4022. begin
  4023. {Free object list}
  4024. ClearChunks;
  4025. fChunkList.Free;
  4026. {$IFDEF UseDelphi}if fCanvas <> nil then
  4027. fCanvas.Free;{$ENDIF}
  4028. {Call ancestor destroy}
  4029. inherited Destroy;
  4030. end;
  4031. {Returns linesize and byte offset for pixels}
  4032. procedure TPngObject.GetPixelInfo(var LineSize, Offset: Cardinal);
  4033. begin
  4034. {There must be an Header chunk to calculate size}
  4035. if HeaderPresent then
  4036. begin
  4037. {Calculate number of bytes for each line}
  4038. LineSize := BytesForPixels(Header.Width, Header.ColorType, Header.BitDepth);
  4039. {Calculates byte offset}
  4040. Case Header.ColorType of
  4041. {Grayscale}
  4042. COLOR_GRAYSCALE:
  4043. If Header.BitDepth = 16 Then
  4044. Offset := 2
  4045. Else
  4046. Offset := 1 ;
  4047. {It always smaller or equal one byte, so it occupes one byte}
  4048. COLOR_PALETTE:
  4049. offset := 1;
  4050. {It might be 3 or 6 bytes}
  4051. COLOR_RGB:
  4052. offset := 3 * Header.BitDepth Div 8;
  4053. {It might be 2 or 4 bytes}
  4054. COLOR_GRAYSCALEALPHA:
  4055. offset := 2 * Header.BitDepth Div 8;
  4056. {4 or 8 bytes}
  4057. COLOR_RGBALPHA:
  4058. offset := 4 * Header.BitDepth Div 8;
  4059. else
  4060. Offset := 0;
  4061. End ;
  4062. end
  4063. else
  4064. begin
  4065. {In case if there isn't any Header chunk}
  4066. Offset := 0;
  4067. LineSize := 0;
  4068. end;
  4069. end;
  4070. {Returns image height}
  4071. function TPngObject.GetHeight: Integer;
  4072. begin
  4073. {There must be a Header chunk to get the size, otherwise returns 0}
  4074. if HeaderPresent then
  4075. Result := TChunkIHDR(Chunks.Item[0]).Height
  4076. else Result := 0;
  4077. end;
  4078. {Returns image width}
  4079. function TPngObject.GetWidth: Integer;
  4080. begin
  4081. {There must be a Header chunk to get the size, otherwise returns 0}
  4082. if HeaderPresent then
  4083. Result := Header.Width
  4084. else Result := 0;
  4085. end;
  4086. {Returns if the image is empty}
  4087. function TPngObject.GetEmpty: Boolean;
  4088. begin Result := (Chunks.Count = 0);
  4089. end;
  4090. {Raises an error}
  4091. procedure TPngObject.RaiseError(ExceptionClass: ExceptClass; Text: String);
  4092. begin
  4093. raise ExceptionClass.Create(Text);
  4094. end;
  4095. {Set the maximum size for IDAT chunk}
  4096. procedure TPngObject.SetMaxIdatSize(const Value: Integer);
  4097. begin
  4098. {Make sure the size is at least 65535}
  4099. if Value < High(Word) then
  4100. fMaxIdatSize := High(Word) else fMaxIdatSize := Value;
  4101. end;
  4102. {Draws the image using pixel information from TChunkpHYs}
  4103. procedure TPNGObject.DrawUsingPixelInformation(Canvas: TCanvas; Point: TPoint);
  4104. function Rect(Left, Top, Right, Bottom: Integer): TRect;
  4105. begin
  4106. Result.Left := Left;
  4107. Result.Top := Top;
  4108. Result.Right := Right;
  4109. Result.Bottom := Bottom;
  4110. end;
  4111. var
  4112. PPMeterY, PPMeterX: Double;
  4113. NewSizeX, NewSizeY: Integer;
  4114. DC: HDC;
  4115. begin
  4116. {Get system information}
  4117. DC := GetDC(0);
  4118. PPMeterY := GetDeviceCaps(DC, LOGPIXELSY) / 0.0254;
  4119. PPMeterX := GetDeviceCaps(DC, LOGPIXELSX) / 0.0254;
  4120. ReleaseDC(0, DC);
  4121. {In case it does not has pixel information}
  4122. if not HasPixelInformation then
  4123. Draw(Canvas, Rect(Point.X, Point.Y, Point.X + Width,
  4124. Point.Y + Height))
  4125. else
  4126. with PixelInformation do
  4127. begin
  4128. NewSizeX := Trunc(Self.Width / (PPUnitX / PPMeterX));
  4129. NewSizeY := Trunc(Self.Height / (PPUnitY / PPMeterY));
  4130. Draw(Canvas, Rect(Point.X, Point.Y, Point.X + NewSizeX,
  4131. Point.Y + NewSizeY));
  4132. end;
  4133. end;
  4134. {$IFNDEF UseDelphi}
  4135. {Creates a file stream reading from the filename in the parameter and load}
  4136. procedure TPngObject.LoadFromFile(const Filename: String);
  4137. var
  4138. FileStream: TFileStream;
  4139. begin
  4140. {Test if the file exists}
  4141. if not FileExists(Filename) then
  4142. begin
  4143. {In case it does not exists, raise error}
  4144. RaiseError(EPNGNotExists, EPNGNotExistsText);
  4145. exit;
  4146. end;
  4147. {Creates the file stream to read}
  4148. FileStream := TFileStream.Create(Filename, [fsmRead]);
  4149. LoadFromStream(FileStream); {Loads the data}
  4150. FileStream.Free; {Free file stream}
  4151. end;
  4152. {Saves the current png image to a file}
  4153. procedure TPngObject.SaveToFile(const Filename: String);
  4154. var
  4155. FileStream: TFileStream;
  4156. begin
  4157. {Creates the file stream to write}
  4158. FileStream := TFileStream.Create(Filename, [fsmWrite]);
  4159. SaveToStream(FileStream); {Saves the data}
  4160. FileStream.Free; {Free file stream}
  4161. end;
  4162. {$ENDIF}
  4163. {Returns if it has the pixel information chunk}
  4164. function TPngObject.HasPixelInformation: Boolean;
  4165. begin
  4166. Result := (Chunks.ItemFromClass(TChunkpHYs) as tChunkpHYs) <> nil;
  4167. end;
  4168. {Returns the pixel information chunk}
  4169. function TPngObject.GetPixelInformation: TChunkpHYs;
  4170. begin
  4171. Result := Chunks.ItemFromClass(TChunkpHYs) as tChunkpHYs;
  4172. if not Assigned(Result) then
  4173. begin
  4174. Result := Chunks.Add(tChunkpHYs) as tChunkpHYs;
  4175. Result.fUnit := utMeter;
  4176. end;
  4177. end;
  4178. {Returns pointer to the chunk TChunkIHDR which should be the first}
  4179. function TPngObject.GetHeader: TChunkIHDR;
  4180. begin
  4181. {If there is a TChunkIHDR returns it, otherwise returns nil}
  4182. if (Chunks.Count <> 0) and (Chunks.Item[0] is TChunkIHDR) then
  4183. Result := Chunks.Item[0] as TChunkIHDR
  4184. else
  4185. begin
  4186. {No header, throw error message}
  4187. RaiseError(EPNGHeaderNotPresent, EPNGHeaderNotPresentText);
  4188. Result := nil
  4189. end
  4190. end;
  4191. {Draws using partial transparency}
  4192. procedure TPngObject.DrawPartialTrans(DC: HDC; Rect: TRect);
  4193. {Adjust the rectangle structure}
  4194. procedure AdjustRect(var Rect: TRect);
  4195. var
  4196. t: Integer;
  4197. begin
  4198. if Rect.Right < Rect.Left then
  4199. begin
  4200. t := Rect.Right;
  4201. Rect.Right := Rect.Left;
  4202. Rect.Left := t;
  4203. end;
  4204. if Rect.Bottom < Rect.Top then
  4205. begin
  4206. t := Rect.Bottom;
  4207. Rect.Bottom := Rect.Top;
  4208. Rect.Top := t;
  4209. end
  4210. end;
  4211. type
  4212. {Access to pixels}
  4213. TPixelLine = Array[Word] of TRGBQuad;
  4214. pPixelLine = ^TPixelLine;
  4215. const
  4216. {Structure used to create the bitmap}
  4217. BitmapInfoHeader: TBitmapInfoHeader =
  4218. (biSize: sizeof(TBitmapInfoHeader);
  4219. biWidth: 100;
  4220. biHeight: 100;
  4221. biPlanes: 1;
  4222. biBitCount: 32;
  4223. biCompression: BI_RGB;
  4224. biSizeImage: 0;
  4225. biXPelsPerMeter: 0;
  4226. biYPelsPerMeter: 0;
  4227. biClrUsed: 0;
  4228. biClrImportant: 0);
  4229. var
  4230. {Buffer bitmap creation}
  4231. BitmapInfo : TBitmapInfo;
  4232. BufferDC : HDC;
  4233. BufferBits : Pointer;
  4234. OldBitmap,
  4235. BufferBitmap: HBitmap;
  4236. Header: TChunkIHDR;
  4237. {Transparency/palette chunks}
  4238. TransparencyChunk: TChunktRNS;
  4239. PaletteChunk: TChunkPLTE;
  4240. TransValue, PaletteIndex: Byte;
  4241. CurBit: Integer;
  4242. Data: PByte;
  4243. {Buffer bitmap modification}
  4244. BytesPerRowDest,
  4245. BytesPerRowSrc,
  4246. BytesPerRowAlpha: Integer;
  4247. ImageSource, ImageSourceOrg,
  4248. AlphaSource : pByteArray;
  4249. ImageData : pPixelLine;
  4250. i, j, i2, j2 : Integer;
  4251. {For bitmap stretching}
  4252. W, H : Cardinal;
  4253. Stretch : Boolean;
  4254. FactorX, FactorY: Double;
  4255. begin
  4256. {Prepares the rectangle structure to stretch draw}
  4257. if (Rect.Right = Rect.Left) or (Rect.Bottom = Rect.Top) then exit;
  4258. AdjustRect(Rect);
  4259. {Gets the width and height}
  4260. W := Rect.Right - Rect.Left;
  4261. H := Rect.Bottom - Rect.Top;
  4262. Header := Self.Header; {Fast access to header}
  4263. Stretch := (W <> Header.Width) or (H <> Header.Height);
  4264. if Stretch then FactorX := W / Header.Width else FactorX := 1;
  4265. if Stretch then FactorY := H / Header.Height else FactorY := 1;
  4266. {Prepare to create the bitmap}
  4267. Fillchar(BitmapInfo, sizeof(BitmapInfo), #0);
  4268. BitmapInfoHeader.biWidth := W;
  4269. BitmapInfoHeader.biHeight := -Integer(H);
  4270. BitmapInfo.bmiHeader := BitmapInfoHeader;
  4271. {Create the bitmap which will receive the background, the applied}
  4272. {alpha blending and then will be painted on the background}
  4273. BufferDC := CreateCompatibleDC(0);
  4274. {In case BufferDC could not be created}
  4275. if (BufferDC = 0) then RaiseError(EPNGOutMemory, EPNGOutMemoryText);
  4276. BufferBitmap := CreateDIBSection(BufferDC, BitmapInfo, DIB_RGB_COLORS,
  4277. BufferBits, 0, 0);
  4278. {In case buffer bitmap could not be created}
  4279. if (BufferBitmap = 0) or (BufferBits = Nil) then
  4280. begin
  4281. if BufferBitmap <> 0 then DeleteObject(BufferBitmap);
  4282. DeleteDC(BufferDC);
  4283. RaiseError(EPNGOutMemory, EPNGOutMemoryText);
  4284. end;
  4285. {Selects new bitmap and release old bitmap}
  4286. OldBitmap := SelectObject(BufferDC, BufferBitmap);
  4287. {Draws the background on the buffer image}
  4288. BitBlt(BufferDC, 0, 0, W, H, DC, Rect.Left, Rect.Top, SRCCOPY);
  4289. {Obtain number of bytes for each row}
  4290. BytesPerRowAlpha := Header.Width;
  4291. BytesPerRowDest := (((BitmapInfo.bmiHeader.biBitCount * W) + 31)
  4292. and not 31) div 8; {Number of bytes for each image row in destination}
  4293. BytesPerRowSrc := (((Header.BitmapInfo.bmiHeader.biBitCount * Header.Width) +
  4294. 31) and not 31) div 8; {Number of bytes for each image row in source}
  4295. {Obtains image pointers}
  4296. ImageData := BufferBits;
  4297. AlphaSource := Header.ImageAlpha;
  4298. Longint(ImageSource) := Longint(Header.ImageData) +
  4299. Header.BytesPerRow * Longint(Header.Height - 1);
  4300. ImageSourceOrg := ImageSource;
  4301. case Header.BitmapInfo.bmiHeader.biBitCount of
  4302. {R, G, B images}
  4303. 24:
  4304. FOR j := 1 TO H DO
  4305. begin
  4306. {Process all the pixels in this line}
  4307. FOR i := 0 TO W - 1 DO
  4308. begin
  4309. if Stretch then i2 := trunc(i / FactorX) else i2 := i;
  4310. {Optmize when we don´t have transparency}
  4311. if (AlphaSource[i2] <> 0) then
  4312. if (AlphaSource[i2] = 255) then
  4313. ImageData[i] := pRGBQuad(@ImageSource[i2 * 3])^
  4314. else
  4315. with ImageData[i] do
  4316. begin
  4317. rgbRed := (255+ImageSource[2+i2*3] * AlphaSource[i2] + rgbRed *
  4318. (not AlphaSource[i2])) shr 8;
  4319. rgbGreen := (255+ImageSource[1+i2*3] * AlphaSource[i2] +
  4320. rgbGreen * (not AlphaSource[i2])) shr 8;
  4321. rgbBlue := (255+ImageSource[i2*3] * AlphaSource[i2] + rgbBlue *
  4322. (not AlphaSource[i2])) shr 8;
  4323. end;
  4324. end;
  4325. {Move pointers}
  4326. inc(Longint(ImageData), BytesPerRowDest);
  4327. if Stretch then j2 := trunc(j / FactorY) else j2 := j;
  4328. Longint(ImageSource) := Longint(ImageSourceOrg) - BytesPerRowSrc * j2;
  4329. Longint(AlphaSource) := Longint(Header.ImageAlpha) +
  4330. BytesPerRowAlpha * j2;
  4331. end;
  4332. {Palette images with 1 byte for each pixel}
  4333. 1,4,8: if Header.ColorType = COLOR_GRAYSCALEALPHA then
  4334. FOR j := 1 TO H DO
  4335. begin
  4336. {Process all the pixels in this line}
  4337. FOR i := 0 TO W - 1 DO
  4338. with ImageData[i], Header.BitmapInfo do begin
  4339. if Stretch then i2 := trunc(i / FactorX) else i2 := i;
  4340. rgbRed := (255 + ImageSource[i2] * AlphaSource[i2] +
  4341. rgbRed * (255 - AlphaSource[i2])) shr 8;
  4342. rgbGreen := (255 + ImageSource[i2] * AlphaSource[i2] +
  4343. rgbGreen * (255 - AlphaSource[i2])) shr 8;
  4344. rgbBlue := (255 + ImageSource[i2] * AlphaSource[i2] +
  4345. rgbBlue * (255 - AlphaSource[i2])) shr 8;
  4346. end;
  4347. {Move pointers}
  4348. Longint(ImageData) := Longint(ImageData) + BytesPerRowDest;
  4349. if Stretch then j2 := trunc(j / FactorY) else j2 := j;
  4350. Longint(ImageSource) := Longint(ImageSourceOrg) - BytesPerRowSrc * j2;
  4351. Longint(AlphaSource) := Longint(Header.ImageAlpha) +
  4352. BytesPerRowAlpha * j2;
  4353. end
  4354. else {Palette images}
  4355. begin
  4356. {Obtain pointer to the transparency chunk}
  4357. TransparencyChunk := TChunktRNS(Chunks.ItemFromClass(TChunktRNS));
  4358. PaletteChunk := TChunkPLTE(Chunks.ItemFromClass(TChunkPLTE));
  4359. FOR j := 1 TO H DO
  4360. begin
  4361. {Process all the pixels in this line}
  4362. i := 0;
  4363. repeat
  4364. CurBit := 0;
  4365. if Stretch then i2 := trunc(i / FactorX) else i2 := i;
  4366. Data := @ImageSource[i2];
  4367. repeat
  4368. {Obtains the palette index}
  4369. case Header.BitDepth of
  4370. 1: PaletteIndex := (Data^ shr (7-(I Mod 8))) and 1;
  4371. 2,4: PaletteIndex := (Data^ shr ((1-(I Mod 2))*4)) and $0F;
  4372. else PaletteIndex := Data^;
  4373. end;
  4374. {Updates the image with the new pixel}
  4375. with ImageData[i] do
  4376. begin
  4377. TransValue := TransparencyChunk.PaletteValues[PaletteIndex];
  4378. rgbRed := (255 + PaletteChunk.Item[PaletteIndex].rgbRed *
  4379. TransValue + rgbRed * (255 - TransValue)) shr 8;
  4380. rgbGreen := (255 + PaletteChunk.Item[PaletteIndex].rgbGreen *
  4381. TransValue + rgbGreen * (255 - TransValue)) shr 8;
  4382. rgbBlue := (255 + PaletteChunk.Item[PaletteIndex].rgbBlue *
  4383. TransValue + rgbBlue * (255 - TransValue)) shr 8;
  4384. end;
  4385. {Move to next data}
  4386. inc(i); inc(CurBit, Header.BitmapInfo.bmiHeader.biBitCount);
  4387. until CurBit >= 8;
  4388. {Move to next source data}
  4389. //inc(Data);
  4390. until i >= Integer(W);
  4391. {Move pointers}
  4392. Longint(ImageData) := Longint(ImageData) + BytesPerRowDest;
  4393. if Stretch then j2 := trunc(j / FactorY) else j2 := j;
  4394. Longint(ImageSource) := Longint(ImageSourceOrg) - BytesPerRowSrc * j2;
  4395. end
  4396. end {Palette images}
  4397. end {case Header.BitmapInfo.bmiHeader.biBitCount};
  4398. {Draws the new bitmap on the foreground}
  4399. BitBlt(DC, Rect.Left, Rect.Top, W, H, BufferDC, 0, 0, SRCCOPY);
  4400. {Free bitmap}
  4401. SelectObject(BufferDC, OldBitmap);
  4402. DeleteObject(BufferBitmap);
  4403. DeleteDC(BufferDC);
  4404. end;
  4405. {Draws the image into a canvas}
  4406. procedure TPngObject.Draw(ACanvas: TCanvas; const Rect: TRect);
  4407. var
  4408. Header: TChunkIHDR;
  4409. begin
  4410. {Quit in case there is no header, otherwise obtain it}
  4411. if Empty then Exit;
  4412. Header := Chunks.GetItem(0) as TChunkIHDR;
  4413. {Copy the data to the canvas}
  4414. case Self.TransparencyMode of
  4415. {$IFDEF PartialTransparentDraw}
  4416. ptmPartial:
  4417. DrawPartialTrans(ACanvas{$IFDEF UseDelphi}.Handle{$ENDIF}, Rect);
  4418. {$ENDIF}
  4419. ptmBit: DrawTransparentBitmap(ACanvas{$IFDEF UseDelphi}.Handle{$ENDIF},
  4420. Header.ImageData, Header.BitmapInfo.bmiHeader,
  4421. pBitmapInfo(@Header.BitmapInfo), Rect,
  4422. {$IFDEF UseDelphi}ColorToRGB({$ENDIF}TransparentColor)
  4423. {$IFDEF UseDelphi}){$ENDIF}
  4424. else
  4425. begin
  4426. SetStretchBltMode(ACanvas{$IFDEF UseDelphi}.Handle{$ENDIF}, COLORONCOLOR);
  4427. StretchDiBits(ACanvas{$IFDEF UseDelphi}.Handle{$ENDIF}, Rect.Left,
  4428. Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top, 0, 0,
  4429. Header.Width, Header.Height, Header.ImageData,
  4430. pBitmapInfo(@Header.BitmapInfo)^, DIB_RGB_COLORS, SRCCOPY)
  4431. end
  4432. end {case}
  4433. end;
  4434. {Characters for the header}
  4435. const
  4436. PngHeader: Array[0..7] of Char = (#137, #80, #78, #71, #13, #10, #26, #10);
  4437. {Loads the image from a stream of data}
  4438. procedure TPngObject.LoadFromStream(Stream: TStream);
  4439. var
  4440. Header : Array[0..7] of Char;
  4441. HasIDAT : Boolean;
  4442. {Chunks reading}
  4443. ChunkCount : Cardinal;
  4444. ChunkLength: Cardinal;
  4445. ChunkName : TChunkName;
  4446. begin
  4447. {Initialize before start loading chunks}
  4448. ChunkCount := 0;
  4449. ClearChunks();
  4450. {Reads the header}
  4451. Stream.Read(Header[0], 8);
  4452. {Test if the header matches}
  4453. if Header <> PngHeader then
  4454. begin
  4455. RaiseError(EPNGInvalidFileHeader, EPNGInvalidFileHeaderText);
  4456. Exit;
  4457. end;
  4458. HasIDAT := FALSE;
  4459. Chunks.Count := 10;
  4460. {Load chunks}
  4461. repeat
  4462. inc(ChunkCount); {Increment number of chunks}
  4463. if Chunks.Count < ChunkCount then {Resize the chunks list if needed}
  4464. Chunks.Count := Chunks.Count + 10;
  4465. {Reads chunk length and invert since it is in network order}
  4466. {also checks the Read method return, if it returns 0, it}
  4467. {means that no bytes was readed, probably because it reached}
  4468. {the end of the file}
  4469. if Stream.Read(ChunkLength, 4) = 0 then
  4470. begin
  4471. {In case it found the end of the file here}
  4472. Chunks.Count := ChunkCount - 1;
  4473. RaiseError(EPNGUnexpectedEnd, EPNGUnexpectedEndText);
  4474. end;
  4475. ChunkLength := ByteSwap(ChunkLength);
  4476. {Reads chunk name}
  4477. Stream.Read(Chunkname, 4);
  4478. {Here we check if the first chunk is the Header which is necessary}
  4479. {to the file in order to be a valid Portable Network Graphics image}
  4480. if (ChunkCount = 1) and (ChunkName <> 'IHDR') then
  4481. begin
  4482. Chunks.Count := ChunkCount - 1;
  4483. RaiseError(EPNGIHDRNotFirst, EPNGIHDRNotFirstText);
  4484. exit;
  4485. end;
  4486. {Has a previous IDAT}
  4487. if (HasIDAT and (ChunkName = 'IDAT')) or (ChunkName = 'cHRM') then
  4488. begin
  4489. dec(ChunkCount);
  4490. Stream.Seek(ChunkLength + 4, soFromCurrent);
  4491. Continue;
  4492. end;
  4493. {Tell it has an IDAT chunk}
  4494. if ChunkName = 'IDAT' then HasIDAT := TRUE;
  4495. {Creates object for this chunk}
  4496. Chunks.SetItem(ChunkCount - 1, CreateClassChunk(Self, ChunkName));
  4497. {Check if the chunk is critical and unknown}
  4498. {$IFDEF ErrorOnUnknownCritical}
  4499. if (TChunk(Chunks.Item[ChunkCount - 1]).ClassType = TChunk) and
  4500. ((Byte(ChunkName[0]) AND $20) = 0) and (ChunkName <> '') then
  4501. begin
  4502. Chunks.Count := ChunkCount;
  4503. RaiseError(EPNGUnknownCriticalChunk, EPNGUnknownCriticalChunkText);
  4504. end;
  4505. {$ENDIF}
  4506. {Loads it}
  4507. try if not TChunk(Chunks.Item[ChunkCount - 1]).LoadFromStream(Stream,
  4508. ChunkName, ChunkLength) then break;
  4509. except
  4510. Chunks.Count := ChunkCount;
  4511. raise;
  4512. end;
  4513. {Terminates when it reaches the IEND chunk}
  4514. until (ChunkName = 'IEND');
  4515. {Resize the list to the appropriate size}
  4516. Chunks.Count := ChunkCount;
  4517. {Check if there is data}
  4518. if not HasIDAT then
  4519. RaiseError(EPNGNoImageData, EPNGNoImageDataText);
  4520. end;
  4521. {Changing height is not supported}
  4522. procedure TPngObject.SetHeight(Value: Integer);
  4523. begin
  4524. Resize(Width, Value)
  4525. end;
  4526. {Changing width is not supported}
  4527. procedure TPngObject.SetWidth(Value: Integer);
  4528. begin
  4529. Resize(Value, Height)
  4530. end;
  4531. {$IFDEF UseDelphi}
  4532. {Saves to clipboard format (thanks to Antoine Pottern)}
  4533. procedure TPNGObject.SaveToClipboardFormat(var AFormat: Word;
  4534. var AData: THandle; var APalette: HPalette);
  4535. begin
  4536. with TBitmap.Create do
  4537. try
  4538. Width := Self.Width;
  4539. Height := Self.Height;
  4540. Self.Draw(Canvas, Rect(0, 0, Width, Height));
  4541. SaveToClipboardFormat(AFormat, AData, APalette);
  4542. finally
  4543. Free;
  4544. end {try}
  4545. end;
  4546. {Loads data from clipboard}
  4547. procedure TPngObject.LoadFromClipboardFormat(AFormat: Word;
  4548. AData: THandle; APalette: HPalette);
  4549. begin
  4550. with TBitmap.Create do
  4551. try
  4552. LoadFromClipboardFormat(AFormat, AData, APalette);
  4553. Self.AssignHandle(Handle, False, 0);
  4554. finally
  4555. Free;
  4556. end {try}
  4557. end;
  4558. {Returns if the image is transparent}
  4559. function TPngObject.GetTransparent: Boolean;
  4560. begin
  4561. Result := (TransparencyMode <> ptmNone);
  4562. end;
  4563. {$ENDIF}
  4564. {Saving the PNG image to a stream of data}
  4565. procedure TPngObject.SaveToStream(Stream: TStream);
  4566. var
  4567. j: Integer;
  4568. begin
  4569. {Reads the header}
  4570. Stream.Write(PNGHeader[0], 8);
  4571. {Write each chunk}
  4572. FOR j := 0 TO Chunks.Count - 1 DO
  4573. Chunks.Item[j].SaveToStream(Stream)
  4574. end;
  4575. {Prepares the Header chunk}
  4576. procedure BuildHeader(Header: TChunkIHDR; Handle: HBitmap; Info: pBitmap);
  4577. var
  4578. DC: HDC;
  4579. begin
  4580. {Set width and height}
  4581. Header.Width := Info.bmWidth;
  4582. Header.Height := abs(Info.bmHeight);
  4583. {Set bit depth}
  4584. if Info.bmBitsPixel >= 16 then
  4585. Header.BitDepth := 8 else Header.BitDepth := Info.bmBitsPixel;
  4586. {Set color type}
  4587. if Info.bmBitsPixel >= 16 then
  4588. Header.ColorType := COLOR_RGB else Header.ColorType := COLOR_PALETTE;
  4589. {Set other info}
  4590. Header.CompressionMethod := 0; {deflate/inflate}
  4591. Header.InterlaceMethod := 0; {no interlace}
  4592. {Prepares bitmap headers to hold data}
  4593. Header.PrepareImageData();
  4594. {Copy image data}
  4595. DC := CreateCompatibleDC(0);
  4596. GetDIBits(DC, Handle, 0, Header.Height, Header.ImageData,
  4597. pBitmapInfo(@Header.BitmapInfo)^, DIB_RGB_COLORS);
  4598. DeleteDC(DC);
  4599. end;
  4600. {Loads the image from a resource}
  4601. procedure TPngObject.LoadFromResourceName(Instance: HInst;
  4602. const Name: String);
  4603. var
  4604. ResStream: TResourceStream;
  4605. begin
  4606. {Creates an especial stream to load from the resource}
  4607. try ResStream := TResourceStream.Create(Instance, Name, RT_RCDATA);
  4608. except RaiseError(EPNGCouldNotLoadResource, EPNGCouldNotLoadResourceText);
  4609. exit; end;
  4610. {Loads the png image from the resource}
  4611. try
  4612. LoadFromStream(ResStream);
  4613. finally
  4614. ResStream.Free;
  4615. end;
  4616. end;
  4617. {Loads the png from a resource ID}
  4618. procedure TPngObject.LoadFromResourceID(Instance: HInst; ResID: Integer);
  4619. begin
  4620. LoadFromResourceName(Instance, String(ResID));
  4621. end;
  4622. {Assigns this tpngobject to another object}
  4623. procedure TPngObject.AssignTo(Dest: TPersistent);
  4624. {$IFDEF UseDelphi}
  4625. function DetectPixelFormat: TPixelFormat;
  4626. begin
  4627. with Header do
  4628. begin
  4629. {Always use 24bits for partial transparency}
  4630. if TransparencyMode = ptmPartial then
  4631. DetectPixelFormat := pf24bit
  4632. else
  4633. case BitDepth of
  4634. {Only supported by COLOR_PALETTE}
  4635. 1: DetectPixelFormat := pf1bit;
  4636. 2, 4: DetectPixelFormat := pf4bit;
  4637. {8 may be palette or r, g, b values}
  4638. 8, 16:
  4639. case ColorType of
  4640. COLOR_RGB, COLOR_GRAYSCALE: DetectPixelFormat := pf24bit;
  4641. COLOR_PALETTE: DetectPixelFormat := pf8bit;
  4642. else raise Exception.Create('');
  4643. end {case ColorFormat of}
  4644. else raise Exception.Create('');
  4645. end {case BitDepth of}
  4646. end {with Header}
  4647. end;
  4648. var
  4649. TRNS: TChunkTRNS;
  4650. {$ENDIF}
  4651. begin
  4652. {If the destination is also a TPNGObject make it assign}
  4653. {this one}
  4654. if Dest is TPNGObject then
  4655. TPNGObject(Dest).AssignPNG(Self)
  4656. {$IFDEF UseDelphi}
  4657. {In case the destination is a bitmap}
  4658. else if (Dest is TBitmap) and HeaderPresent then
  4659. begin
  4660. {Copies the handle using CopyImage API}
  4661. TBitmap(Dest).PixelFormat := DetectPixelFormat;
  4662. TBitmap(Dest).Width := Width;
  4663. TBitmap(Dest).Height := Height;
  4664. TBitmap(Dest).Canvas.Draw(0, 0, Self);
  4665. {Copy transparency mode}
  4666. if (TransparencyMode = ptmBit) then
  4667. begin
  4668. TRNS := Chunks.ItemFromClass(TChunkTRNS) as TChunkTRNS;
  4669. TBitmap(Dest).TransparentColor := TRNS.TransparentColor;
  4670. TBitmap(Dest).Transparent := True
  4671. end {if (TransparencyMode = ptmBit)}
  4672. end
  4673. else
  4674. {Unknown destination kind}
  4675. inherited AssignTo(Dest);
  4676. {$ENDIF}
  4677. end;
  4678. {Assigns from a bitmap object}
  4679. procedure TPngObject.AssignHandle(Handle: HBitmap; Transparent: Boolean;
  4680. TransparentColor: ColorRef);
  4681. var
  4682. BitmapInfo: Windows.TBitmap;
  4683. {Chunks}
  4684. Header: TChunkIHDR;
  4685. PLTE: TChunkPLTE;
  4686. IDAT: TChunkIDAT;
  4687. IEND: TChunkIEND;
  4688. TRNS: TChunkTRNS;
  4689. i: Integer;
  4690. palEntries : TMaxLogPalette;
  4691. begin
  4692. {Obtain bitmap info}
  4693. GetObject(Handle, SizeOf(BitmapInfo), @BitmapInfo);
  4694. {Clear old chunks and prepare}
  4695. ClearChunks();
  4696. {Create the chunks}
  4697. Header := TChunkIHDR.Create(Self);
  4698. {This method will fill the Header chunk with bitmap information}
  4699. {and copy the image data}
  4700. BuildHeader(Header, Handle, @BitmapInfo);
  4701. if Header.HasPalette then PLTE := TChunkPLTE.Create(Self) else PLTE := nil;
  4702. if Transparent then TRNS := TChunkTRNS.Create(Self) else TRNS := nil;
  4703. IDAT := TChunkIDAT.Create(Self);
  4704. IEND := TChunkIEND.Create(Self);
  4705. {Add chunks}
  4706. TPNGPointerList(Chunks).Add(Header);
  4707. if Header.HasPalette then TPNGPointerList(Chunks).Add(PLTE);
  4708. if Transparent then TPNGPointerList(Chunks).Add(TRNS);
  4709. TPNGPointerList(Chunks).Add(IDAT);
  4710. TPNGPointerList(Chunks).Add(IEND);
  4711. {In case there is a image data, set the PLTE chunk fCount variable}
  4712. {to the actual number of palette colors which is 2^(Bits for each pixel)}
  4713. if Header.HasPalette then
  4714. begin
  4715. PLTE.fCount := 1 shl BitmapInfo.bmBitsPixel;
  4716. {Create and set palette}
  4717. fillchar(palEntries, sizeof(palEntries), 0);
  4718. palEntries.palVersion := $300;
  4719. palEntries.palNumEntries := 1 shl BitmapInfo.bmBitsPixel;
  4720. for i := 0 to palEntries.palNumEntries - 1 do
  4721. begin
  4722. palEntries.palPalEntry[i].peRed := Header.BitmapInfo.bmiColors[i].rgbRed;
  4723. palEntries.palPalEntry[i].peGreen := Header.BitmapInfo.bmiColors[i].rgbGreen;
  4724. palEntries.palPalEntry[i].peBlue := Header.BitmapInfo.bmiColors[i].rgbBlue;
  4725. end;
  4726. DoSetPalette(CreatePalette(pLogPalette(@palEntries)^), false);
  4727. end;
  4728. {In case it is a transparent bitmap, prepares it}
  4729. if Transparent then TRNS.TransparentColor := TransparentColor;
  4730. end;
  4731. {Assigns from another PNG}
  4732. procedure TPngObject.AssignPNG(Source: TPNGObject);
  4733. var
  4734. J: Integer;
  4735. begin
  4736. {Copy properties}
  4737. InterlaceMethod := Source.InterlaceMethod;
  4738. MaxIdatSize := Source.MaxIdatSize;
  4739. CompressionLevel := Source.CompressionLevel;
  4740. Filters := Source.Filters;
  4741. {Clear old chunks and prepare}
  4742. ClearChunks();
  4743. Chunks.Count := Source.Chunks.Count;
  4744. {Create chunks and makes a copy from the source}
  4745. FOR J := 0 TO Chunks.Count - 1 DO
  4746. with Source.Chunks do
  4747. begin
  4748. Chunks.SetItem(J, TChunkClass(TChunk(Item[J]).ClassType).Create(Self));
  4749. TChunk(Chunks.Item[J]).Assign(TChunk(Item[J]));
  4750. end {with};
  4751. end;
  4752. {Returns a alpha data scanline}
  4753. function TPngObject.GetAlphaScanline(const LineIndex: Integer): pByteArray;
  4754. begin
  4755. with Header do
  4756. if (ColorType = COLOR_RGBALPHA) or (ColorType = COLOR_GRAYSCALEALPHA) then
  4757. Longint(Result) := Longint(ImageAlpha) + (LineIndex * Longint(Width))
  4758. else Result := nil; {In case the image does not use alpha information}
  4759. end;
  4760. {$IFDEF Store16bits}
  4761. {Returns a png data extra scanline}
  4762. function TPngObject.GetExtraScanline(const LineIndex: Integer): Pointer;
  4763. begin
  4764. with Header do
  4765. Longint(Result) := (Longint(ExtraImageData) + ((Longint(Height) - 1) *
  4766. BytesPerRow)) - (LineIndex * BytesPerRow);
  4767. end;
  4768. {$ENDIF}
  4769. {Returns a png data scanline}
  4770. function TPngObject.GetScanline(const LineIndex: Integer): Pointer;
  4771. begin
  4772. with Header do
  4773. Longint(Result) := (Longint(ImageData) + ((Longint(Height) - 1) *
  4774. BytesPerRow)) - (LineIndex * BytesPerRow);
  4775. end;
  4776. {Initialize gamma table}
  4777. procedure TPngObject.InitializeGamma;
  4778. var
  4779. i: Integer;
  4780. begin
  4781. {Build gamma table as if there was no gamma}
  4782. FOR i := 0 to 255 do
  4783. begin
  4784. GammaTable[i] := i;
  4785. InverseGamma[i] := i;
  4786. end {for i}
  4787. end;
  4788. {Returns the transparency mode used by this png}
  4789. function TPngObject.GetTransparencyMode: TPNGTransparencyMode;
  4790. var
  4791. TRNS: TChunkTRNS;
  4792. begin
  4793. with Header do
  4794. begin
  4795. Result := ptmNone; {Default result}
  4796. {Gets the TRNS chunk pointer}
  4797. TRNS := Chunks.ItemFromClass(TChunkTRNS) as TChunkTRNS;
  4798. {Test depending on the color type}
  4799. case ColorType of
  4800. {This modes are always partial}
  4801. COLOR_RGBALPHA, COLOR_GRAYSCALEALPHA: Result := ptmPartial;
  4802. {This modes support bit transparency}
  4803. COLOR_RGB, COLOR_GRAYSCALE: if TRNS <> nil then Result := ptmBit;
  4804. {Supports booth translucid and bit}
  4805. COLOR_PALETTE:
  4806. {A TRNS chunk must be present, otherwise it won't support transparency}
  4807. if TRNS <> nil then
  4808. if TRNS.BitTransparency then
  4809. Result := ptmBit else Result := ptmPartial
  4810. end {case}
  4811. end {with Header}
  4812. end;
  4813. {Add a text chunk}
  4814. procedure TPngObject.AddtEXt(const Keyword, Text: String);
  4815. var
  4816. TextChunk: TChunkTEXT;
  4817. begin
  4818. TextChunk := Chunks.Add(TChunkText) as TChunkTEXT;
  4819. TextChunk.Keyword := Keyword;
  4820. TextChunk.Text := Text;
  4821. end;
  4822. {Add a text chunk}
  4823. procedure TPngObject.AddzTXt(const Keyword, Text: String);
  4824. var
  4825. TextChunk: TChunkzTXt;
  4826. begin
  4827. TextChunk := Chunks.Add(TChunkzTXt) as TChunkzTXt;
  4828. TextChunk.Keyword := Keyword;
  4829. TextChunk.Text := Text;
  4830. end;
  4831. {Removes the image transparency}
  4832. procedure TPngObject.RemoveTransparency;
  4833. var
  4834. TRNS: TChunkTRNS;
  4835. begin
  4836. {Removes depending on the color type}
  4837. with Header do
  4838. case ColorType of
  4839. {Palette uses the TChunktRNS to store alpha}
  4840. COLOR_PALETTE:
  4841. begin
  4842. TRNS := Chunks.ItemFromClass(TChunkTRNS) as TChunkTRNS;
  4843. if TRNS <> nil then Chunks.RemoveChunk(TRNS)
  4844. end;
  4845. {Png allocates different memory space to hold alpha information}
  4846. {for these types}
  4847. COLOR_GRAYSCALEALPHA, COLOR_RGBALPHA:
  4848. begin
  4849. {Transform into the appropriate color type}
  4850. if ColorType = COLOR_GRAYSCALEALPHA then
  4851. ColorType := COLOR_GRAYSCALE
  4852. else ColorType := COLOR_RGB;
  4853. {Free the pointer data}
  4854. if ImageAlpha <> nil then FreeMem(ImageAlpha);
  4855. ImageAlpha := nil
  4856. end
  4857. end
  4858. end;
  4859. {Generates alpha information}
  4860. procedure TPngObject.CreateAlpha;
  4861. var
  4862. TRNS: TChunkTRNS;
  4863. begin
  4864. {Generates depending on the color type}
  4865. with Header do
  4866. case ColorType of
  4867. {Png allocates different memory space to hold alpha information}
  4868. {for these types}
  4869. COLOR_GRAYSCALE, COLOR_RGB:
  4870. begin
  4871. {Transform into the appropriate color type}
  4872. if ColorType = COLOR_GRAYSCALE then
  4873. ColorType := COLOR_GRAYSCALEALPHA
  4874. else ColorType := COLOR_RGBALPHA;
  4875. {Allocates memory to hold alpha information}
  4876. GetMem(ImageAlpha, Integer(Width) * Integer(Height));
  4877. FillChar(ImageAlpha^, Integer(Width) * Integer(Height), #255);
  4878. end;
  4879. {Palette uses the TChunktRNS to store alpha}
  4880. COLOR_PALETTE:
  4881. begin
  4882. {Gets/creates TRNS chunk}
  4883. if Chunks.ItemFromClass(TChunkTRNS) = nil then
  4884. TRNS := Chunks.Add(TChunkTRNS) as TChunkTRNS
  4885. else
  4886. TRNS := Chunks.ItemFromClass(TChunkTRNS) as TChunkTRNS;
  4887. {Prepares the TRNS chunk}
  4888. with TRNS do
  4889. begin
  4890. ResizeData(256);
  4891. Fillchar(PaletteValues[0], 256, 255);
  4892. fDataSize := 1 shl Header.BitDepth;
  4893. fBitTransparency := False
  4894. end {with Chunks.Add};
  4895. end;
  4896. end {case Header.ColorType}
  4897. end;
  4898. {Returns transparent color}
  4899. function TPngObject.GetTransparentColor: TColor;
  4900. var
  4901. TRNS: TChunkTRNS;
  4902. begin
  4903. TRNS := Chunks.ItemFromClass(TChunkTRNS) as TChunkTRNS;
  4904. {Reads the transparency chunk to get this info}
  4905. if Assigned(TRNS) then Result := TRNS.TransparentColor
  4906. else Result := 0
  4907. end;
  4908. {$OPTIMIZATION OFF}
  4909. procedure TPngObject.SetTransparentColor(const Value: TColor);
  4910. var
  4911. TRNS: TChunkTRNS;
  4912. begin
  4913. if HeaderPresent then
  4914. {Tests the ColorType}
  4915. case Header.ColorType of
  4916. {Not allowed for this modes}
  4917. COLOR_RGBALPHA, COLOR_GRAYSCALEALPHA: Self.RaiseError(
  4918. EPNGCannotChangeTransparent, EPNGCannotChangeTransparentText);
  4919. {Allowed}
  4920. COLOR_PALETTE, COLOR_RGB, COLOR_GRAYSCALE:
  4921. begin
  4922. TRNS := Chunks.ItemFromClass(TChunkTRNS) as TChunkTRNS;
  4923. if not Assigned(TRNS) then TRNS := Chunks.Add(TChunkTRNS) as TChunkTRNS;
  4924. {Sets the transparency value from TRNS chunk}
  4925. TRNS.TransparentColor := {$IFDEF UseDelphi}ColorToRGB({$ENDIF}Value
  4926. {$IFDEF UseDelphi}){$ENDIF}
  4927. end {COLOR_PALETTE, COLOR_RGB, COLOR_GRAYSCALE)}
  4928. end {case}
  4929. end;
  4930. {Returns if header is present}
  4931. function TPngObject.HeaderPresent: Boolean;
  4932. begin
  4933. Result := ((Chunks.Count <> 0) and (Chunks.Item[0] is TChunkIHDR))
  4934. end;
  4935. {Returns pixel for png using palette and grayscale}
  4936. function GetByteArrayPixel(const png: TPngObject; const X, Y: Integer): TColor;
  4937. var
  4938. ByteData: Byte;
  4939. DataDepth: Byte;
  4940. begin
  4941. with png, Header do
  4942. begin
  4943. {Make sure the bitdepth is not greater than 8}
  4944. DataDepth := BitDepth;
  4945. if DataDepth > 8 then DataDepth := 8;
  4946. {Obtains the byte containing this pixel}
  4947. ByteData := pByteArray(png.Scanline[Y])^[X div (8 div DataDepth)];
  4948. {Moves the bits we need to the right}
  4949. ByteData := (ByteData shr ((8 - DataDepth) -
  4950. (X mod (8 div DataDepth)) * DataDepth));
  4951. {Discard the unwanted pixels}
  4952. ByteData:= ByteData and ($FF shr (8 - DataDepth));
  4953. {For palette mode map the palette entry and for grayscale convert and
  4954. returns the intensity}
  4955. case ColorType of
  4956. COLOR_PALETTE:
  4957. with TChunkPLTE(png.Chunks.ItemFromClass(TChunkPLTE)).Item[ByteData] do
  4958. Result := rgb(GammaTable[rgbRed], GammaTable[rgbGreen],
  4959. GammaTable[rgbBlue]);
  4960. COLOR_GRAYSCALE:
  4961. begin
  4962. if BitDepth = 1
  4963. then ByteData := GammaTable[Byte(ByteData * 255)]
  4964. else ByteData := GammaTable[Byte(ByteData * ((1 shl DataDepth) + 1))];
  4965. Result := rgb(ByteData, ByteData, ByteData);
  4966. end;
  4967. else Result := 0;
  4968. end {case};
  4969. end {with}
  4970. end;
  4971. {In case vcl units are not being used}
  4972. {$IFNDEF UseDelphi}
  4973. function ColorToRGB(const Color: TColor): COLORREF;
  4974. begin
  4975. Result := Color
  4976. end;
  4977. {$ENDIF}
  4978. {Sets a pixel for grayscale and palette pngs}
  4979. procedure SetByteArrayPixel(const png: TPngObject; const X, Y: Integer;
  4980. const Value: TColor);
  4981. const
  4982. ClearFlag: Array[1..8] of Integer = (1, 3, 0, 15, 0, 0, 0, $FF);
  4983. var
  4984. ByteData: pByte;
  4985. DataDepth: Byte;
  4986. ValEntry: Byte;
  4987. begin
  4988. with png.Header do
  4989. begin
  4990. {Map into a palette entry}
  4991. ValEntry := GetNearestPaletteIndex(Png.Palette, ColorToRGB(Value));
  4992. {16 bits grayscale extra bits are discarted}
  4993. DataDepth := BitDepth;
  4994. if DataDepth > 8 then DataDepth := 8;
  4995. {Gets a pointer to the byte we intend to change}
  4996. ByteData := @pByteArray(png.Scanline[Y])^[X div (8 div DataDepth)];
  4997. {Clears the old pixel data}
  4998. ByteData^ := ByteData^ and not (ClearFlag[DataDepth] shl ((8 - DataDepth) -
  4999. (X mod (8 div DataDepth)) * DataDepth));
  5000. {Setting the new pixel}
  5001. ByteData^ := ByteData^ or (ValEntry shl ((8 - DataDepth) -
  5002. (X mod (8 div DataDepth)) * DataDepth));
  5003. end {with png.Header}
  5004. end;
  5005. {Returns pixel when png uses RGB}
  5006. function GetRGBLinePixel(const png: TPngObject;
  5007. const X, Y: Integer): TColor;
  5008. begin
  5009. with pRGBLine(png.Scanline[Y])^[X] do
  5010. Result := RGB(rgbtRed, rgbtGreen, rgbtBlue)
  5011. end;
  5012. {Sets pixel when png uses RGB}
  5013. procedure SetRGBLinePixel(const png: TPngObject;
  5014. const X, Y: Integer; Value: TColor);
  5015. begin
  5016. with pRGBLine(png.Scanline[Y])^[X] do
  5017. begin
  5018. rgbtRed := GetRValue(Value);
  5019. rgbtGreen := GetGValue(Value);
  5020. rgbtBlue := GetBValue(Value)
  5021. end
  5022. end;
  5023. {Returns pixel when png uses grayscale}
  5024. function GetGrayLinePixel(const png: TPngObject;
  5025. const X, Y: Integer): TColor;
  5026. var
  5027. B: Byte;
  5028. begin
  5029. B := PByteArray(png.Scanline[Y])^[X];
  5030. Result := RGB(B, B, B);
  5031. end;
  5032. {Sets pixel when png uses grayscale}
  5033. procedure SetGrayLinePixel(const png: TPngObject;
  5034. const X, Y: Integer; Value: TColor);
  5035. begin
  5036. PByteArray(png.Scanline[Y])^[X] := GetRValue(Value);
  5037. end;
  5038. {Resizes the PNG image}
  5039. procedure TPngObject.Resize(const CX, CY: Integer);
  5040. function Min(const A, B: Integer): Integer;
  5041. begin
  5042. if A < B then Result := A else Result := B;
  5043. end;
  5044. var
  5045. Header: TChunkIHDR;
  5046. Line, NewBytesPerRow: Integer;
  5047. NewHandle: HBitmap;
  5048. NewDC: HDC;
  5049. NewImageData: Pointer;
  5050. NewImageAlpha: Pointer;
  5051. NewImageExtra: Pointer;
  5052. begin
  5053. if (CX > 0) and (CY > 0) then
  5054. begin
  5055. {Gets some actual information}
  5056. Header := Self.Header;
  5057. {Creates the new image}
  5058. NewDC := CreateCompatibleDC(Header.ImageDC);
  5059. Header.BitmapInfo.bmiHeader.biWidth := cx;
  5060. Header.BitmapInfo.bmiHeader.biHeight := cy;
  5061. NewHandle := CreateDIBSection(NewDC, pBitmapInfo(@Header.BitmapInfo)^,
  5062. DIB_RGB_COLORS, NewImageData, 0, 0);
  5063. SelectObject(NewDC, NewHandle);
  5064. {$IFDEF UseDelphi}Canvas.Handle := NewDC;{$ENDIF}
  5065. NewBytesPerRow := (((Header.BitmapInfo.bmiHeader.biBitCount * cx) + 31)
  5066. and not 31) div 8;
  5067. {Copies the image data}
  5068. for Line := 0 to Min(CY - 1, Height - 1) do
  5069. CopyMemory(Ptr(Longint(NewImageData) + (Longint(CY) - 1) *
  5070. NewBytesPerRow - (Line * NewBytesPerRow)), Scanline[Line],
  5071. Min(NewBytesPerRow, Header.BytesPerRow));
  5072. {Build array for alpha information, if necessary}
  5073. if (Header.ColorType = COLOR_RGBALPHA) or
  5074. (Header.ColorType = COLOR_GRAYSCALEALPHA) then
  5075. begin
  5076. GetMem(NewImageAlpha, CX * CY);
  5077. Fillchar(NewImageAlpha^, CX * CY, 255);
  5078. for Line := 0 to Min(CY - 1, Height - 1) do
  5079. CopyMemory(Ptr(Longint(NewImageAlpha) + (Line * CX)),
  5080. AlphaScanline[Line], Min(CX, Width));
  5081. FreeMem(Header.ImageAlpha);
  5082. Header.ImageAlpha := NewImageAlpha;
  5083. end;
  5084. {$IFDEF Store16bits}
  5085. if (Header.BitDepth = 16) then
  5086. begin
  5087. GetMem(NewImageExtra, CX * CY);
  5088. Fillchar(NewImageExtra^, CX * CY, 0);
  5089. for Line := 0 to Min(CY - 1, Height - 1) do
  5090. CopyMemory(Ptr(Longint(NewImageExtra) + (Line * CX)),
  5091. ExtraScanline[Line], Min(CX, Width));
  5092. FreeMem(Header.ExtraImageData);
  5093. Header.ExtraImageData := NewImageExtra;
  5094. end;
  5095. {$ENDIF}
  5096. {Deletes the old image}
  5097. DeleteObject(Header.ImageHandle);
  5098. DeleteDC(Header.ImageDC);
  5099. {Prepares the header to get the new image}
  5100. Header.BytesPerRow := NewBytesPerRow;
  5101. Header.IHDRData.Width := CX;
  5102. Header.IHDRData.Height := CY;
  5103. Header.ImageData := NewImageData;
  5104. {Replaces with the new image}
  5105. Header.ImageHandle := NewHandle;
  5106. Header.ImageDC := NewDC;
  5107. end
  5108. else
  5109. {The new size provided is invalid}
  5110. RaiseError(EPNGInvalidNewSize, EInvalidNewSize)
  5111. end;
  5112. {Sets a pixel}
  5113. procedure TPngObject.SetPixels(const X, Y: Integer; const Value: TColor);
  5114. begin
  5115. if ((X >= 0) and (X <= Width - 1)) and
  5116. ((Y >= 0) and (Y <= Height - 1)) then
  5117. with Header do
  5118. begin
  5119. if ColorType in [COLOR_GRAYSCALE, COLOR_PALETTE] then
  5120. SetByteArrayPixel(Self, X, Y, Value)
  5121. else if ColorType in [COLOR_GRAYSCALEALPHA] then
  5122. SetGrayLinePixel(Self, X, Y, Value)
  5123. else
  5124. SetRGBLinePixel(Self, X, Y, Value)
  5125. end {with}
  5126. end;
  5127. {Returns a pixel}
  5128. function TPngObject.GetPixels(const X, Y: Integer): TColor;
  5129. begin
  5130. if ((X >= 0) and (X <= Width - 1)) and
  5131. ((Y >= 0) and (Y <= Height - 1)) then
  5132. with Header do
  5133. begin
  5134. if ColorType in [COLOR_GRAYSCALE, COLOR_PALETTE] then
  5135. Result := GetByteArrayPixel(Self, X, Y)
  5136. else if ColorType in [COLOR_GRAYSCALEALPHA] then
  5137. Result := GetGrayLinePixel(Self, X, Y)
  5138. else
  5139. Result := GetRGBLinePixel(Self, X, Y)
  5140. end {with}
  5141. else Result := 0
  5142. end;
  5143. {Returns the image palette}
  5144. function TPngObject.GetPalette: HPALETTE;
  5145. begin
  5146. Result := Header.ImagePalette;
  5147. end;
  5148. {Assigns from another TChunk}
  5149. procedure TChunkpHYs.Assign(Source: TChunk);
  5150. begin
  5151. fPPUnitY := TChunkpHYs(Source).fPPUnitY;
  5152. fPPUnitX := TChunkpHYs(Source).fPPUnitX;
  5153. fUnit := TChunkpHYs(Source).fUnit;
  5154. end;
  5155. {Loads the chunk from a stream}
  5156. function TChunkpHYs.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  5157. Size: Integer): Boolean;
  5158. begin
  5159. {Let ancestor load the data}
  5160. Result := inherited LoadFromStream(Stream, ChunkName, Size);
  5161. if not Result or (Size <> 9) then exit; {Size must be 9}
  5162. {Reads data}
  5163. fPPUnitX := ByteSwap(pCardinal(Longint(Data))^);
  5164. fPPUnitY := ByteSwap(pCardinal(Longint(Data) + 4)^);
  5165. fUnit := pUnitType(Longint(Data) + 8)^;
  5166. end;
  5167. {Saves the chunk to a stream}
  5168. function TChunkpHYs.SaveToStream(Stream: TStream): Boolean;
  5169. begin
  5170. {Update data}
  5171. ResizeData(9); {Make sure the size is 9}
  5172. pCardinal(Data)^ := ByteSwap(fPPUnitX);
  5173. pCardinal(Longint(Data) + 4)^ := ByteSwap(fPPUnitY);
  5174. pUnitType(Longint(Data) + 8)^ := fUnit;
  5175. {Let inherited save data}
  5176. Result := inherited SaveToStream(Stream);
  5177. end;
  5178. procedure TPngObject.DoSetPalette(Value: HPALETTE; const UpdateColors: boolean);
  5179. begin
  5180. if (Header.HasPalette) then
  5181. begin
  5182. {Update the palette entries}
  5183. if UpdateColors then
  5184. Header.PaletteToDIB(Value);
  5185. {Resize the new palette}
  5186. SelectPalette(Header.ImageDC, Value, False);
  5187. RealizePalette(Header.ImageDC);
  5188. {Replaces}
  5189. DeleteObject(Header.ImagePalette);
  5190. Header.ImagePalette := Value;
  5191. end
  5192. end;
  5193. {Set palette based on a windows palette handle}
  5194. procedure TPngObject.SetPalette(Value: HPALETTE);
  5195. begin
  5196. DoSetPalette(Value, true);
  5197. end;
  5198. {Returns the library version}
  5199. function TPNGObject.GetLibraryVersion: String;
  5200. begin
  5201. Result := LibraryVersion
  5202. end;
  5203. initialization
  5204. {Initialize}
  5205. ChunkClasses := nil;
  5206. {crc table has not being computed yet}
  5207. crc_table_computed := FALSE;
  5208. {Register the necessary chunks for png}
  5209. RegisterCommonChunks;
  5210. {Registers TPNGObject to use with TPicture}
  5211. {$IFDEF UseDelphi}{$IFDEF RegisterGraphic}
  5212. TPicture.RegisterFileFormat('PNG', 'Portable Network Graphics', TPNGObject);
  5213. {$ENDIF}{$ENDIF}
  5214. finalization
  5215. {$IFDEF UseDelphi}{$IFDEF RegisterGraphic}
  5216. TPicture.UnregisterGraphicClass(TPNGObject);
  5217. {$ENDIF}{$ENDIF}
  5218. {Free chunk classes}
  5219. FreeChunkClassList;
  5220. end.