fppdf.pp 186 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2014 by Michael Van Canneyt
  4. This unit generates PDF files, without dependencies on GUI libraries.
  5. (Based on original ideas from the fpGUI pdf generator by Jean-Marc Levecque
  6. <[email protected]>)
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. LOCALISATION NOTICE:
  13. Most of the string constants in this unit should NOT be localised,
  14. as they are specific constants used in the PDF Specification document.
  15. If you do localise anything, make sure you know what you are doing.
  16. **********************************************************************}
  17. unit fpPDF;
  18. {$mode objfpc}{$H+}
  19. { enable compiler define for extra console debug output }
  20. {.$define gdebug}
  21. interface
  22. uses
  23. Classes,
  24. SysUtils,
  25. StrUtils,
  26. contnrs,
  27. fpImage,
  28. FPReadJPEG, FPReadPNG, FPReadBMP, // these are required for auto image-handler functionality
  29. zstream,
  30. fpparsettf,
  31. fpTTFSubsetter,
  32. FPFontTextMapping;
  33. Const
  34. { Some popular predefined colors. Channel format is: RRGGBB }
  35. clBlack = $000000;
  36. clWhite = $FFFFFF;
  37. clBlue = $0000FF;
  38. clGreen = $008000;
  39. clRed = $FF0000;
  40. clAqua = $00FFFF;
  41. clMagenta = $FF00FF;
  42. clYellow = $FFFF00;
  43. clLtGray = $C0C0C0;
  44. clMaroon = $800000;
  45. clOlive = $808000;
  46. clDkGray = $808080;
  47. clTeal = $008080;
  48. clNavy = $000080;
  49. clPurple = $800080;
  50. clLime = $00FF00;
  51. clWaterMark = $F0F0F0;
  52. type
  53. TPDFPaperType = (ptCustom, ptA4, ptA5, ptLetter, ptLegal, ptExecutive, ptComm10, ptMonarch, ptDL, ptC5, ptB5);
  54. TPDFPaperOrientation = (ppoPortrait,ppoLandscape);
  55. TPDFPenStyle = (ppsSolid,ppsDash,ppsDot,ppsDashDot,ppsDashDotDot);
  56. TPDFLineCapStyle = (plcsButtCap, plcsRoundCap, plcsProjectingSquareCap);
  57. TPDFPageLayout = (lSingle, lTwo, lContinuous);
  58. TPDFUnitOfMeasure = (uomInches, uomMillimeters, uomCentimeters, uomPixels);
  59. TPDFOption = (poOutLine, poCompressText, poCompressFonts, poCompressImages, poUseRawJPEG, poNoEmbeddedFonts,
  60. poPageOriginAtTop, poSubsetFont, poMetadataEntry, poNoTrailerID, poUseImageTransparency,poUTF16info);
  61. TPDFOptions = set of TPDFOption;
  62. EPDF = Class(Exception);
  63. // forward declarations
  64. TPDFDocument = class;
  65. TPDFAnnotList = class;
  66. TPDFLineStyleDef = class;
  67. TPDFPage = class;
  68. TARGBColor = Cardinal;
  69. TPDFFloat = Single;
  70. {$IF FPC_FULLVERSION < 30000}
  71. RawByteString = type AnsiString;
  72. {$ENDIF}
  73. TPDFDimensions = record
  74. T,L,R,B: TPDFFloat;
  75. end;
  76. TPDFPaper = record
  77. H, W: integer;
  78. Printable: TPDFDimensions;
  79. end;
  80. TPDFCoord = record
  81. X,Y: TPDFFloat;
  82. end;
  83. TPDFCoordArray = array of TPDFCoord;
  84. { We use a special 3x3 matrix for transformations of coordinates. As the
  85. only allowed transformations are translations and scalations, we need a
  86. matrix with the following content ([x,y] is a variable):
  87. [0,0] 0 [2,0]
  88. 0 [1,1] [2,1]
  89. 0 0 1
  90. [0,0]: X scalation
  91. [2,0]: X translation
  92. [1,1]: Y scalation
  93. [2,1]: Y translation
  94. }
  95. TPDFMatrix = object
  96. _00, _20, _11, _21: TPDFFloat;
  97. function Transform(APoint: TPDFCoord): TPDFCoord; overload;
  98. function Transform(X, Y: TPDFFloat): TPDFCoord; overload;
  99. function ReverseTransform(APoint: TPDFCoord): TPDFCoord;
  100. procedure SetXScalation(const AValue: TPDFFloat);
  101. procedure SetYScalation(const AValue: TPDFFloat);
  102. procedure SetXTranslation(const AValue: TPDFFloat);
  103. procedure SetYTranslation(const AValue: TPDFFloat);
  104. end;
  105. // CharWidth array of standard PDF fonts
  106. TPDFFontWidthArray = array[0..255] of integer;
  107. TPDFObject = class(TObject)
  108. Protected
  109. Class Function FloatStr(F: TPDFFloat) : String;
  110. procedure Write(const AStream: TStream); virtual;
  111. Class procedure WriteString(const AValue: RawByteString; AStream: TStream);
  112. public
  113. Constructor Create(Const ADocument : TPDFDocument); virtual; overload;
  114. end;
  115. TPDFDocumentObject = Class(TPDFObject)
  116. Private
  117. FDocument : TPDFDocument;
  118. FLineCapStyle: TPDFLineCapStyle;
  119. Public
  120. Constructor Create(Const ADocument : TPDFDocument); override; overload;
  121. Procedure SetWidth(AWidth : TPDFFloat; AStream : TStream);
  122. Property Document : TPDFDocument Read FDocument ;
  123. end;
  124. TPDFBoolean = class(TPDFDocumentObject)
  125. private
  126. FValue: Boolean;
  127. protected
  128. procedure Write(const AStream: TStream); override;
  129. public
  130. constructor Create(Const ADocument : TPDFDocument; const AValue: Boolean);overload;
  131. end;
  132. TPDFMoveTo = class(TPDFDocumentObject)
  133. private
  134. FPos : TPDFCoord;
  135. protected
  136. procedure Write(const AStream: TStream); override;
  137. public
  138. class function Command(APos: TPDFCoord): String;
  139. class function Command(AX,AY: TPDFFloat): String;
  140. constructor Create(Const ADocument : TPDFDocument; const AX,AY : TPDFFloat);overload;
  141. constructor Create(Const ADocument : TPDFDocument; const APos : TPDFCoord);overload;
  142. end;
  143. TPDFResetPath = class(TPDFDocumentObject)
  144. protected
  145. procedure Write(const AStream: TStream); override;
  146. public
  147. class function Command: string;
  148. end;
  149. TPDFClosePath = class(TPDFDocumentObject)
  150. protected
  151. procedure Write(const AStream: TStream); override;
  152. public
  153. class function Command: string;
  154. end;
  155. TPDFStrokePath = class(TPDFDocumentObject)
  156. protected
  157. procedure Write(const AStream: TStream); override;
  158. public
  159. class function Command: string;
  160. end;
  161. { TPDFClipPath }
  162. TPDFClipPath = class(TPDFDocumentObject)
  163. protected
  164. procedure Write(const AStream: TStream); override;
  165. public
  166. class function Command: string;
  167. end;
  168. TPDFPushGraphicsStack = class(TPDFDocumentObject)
  169. protected
  170. procedure Write(const AStream: TStream); override;
  171. public
  172. class function Command: string;
  173. end;
  174. TPDFPopGraphicsStack = class(TPDFDocumentObject)
  175. protected
  176. procedure Write(const AStream: TStream); override;
  177. public
  178. class function Command: string;
  179. end;
  180. TPDFInteger = class(TPDFDocumentObject)
  181. private
  182. FInt: integer;
  183. protected
  184. procedure Inc;
  185. procedure Write(const AStream: TStream); override;
  186. public
  187. constructor Create(Const ADocument : TPDFDocument; const AValue: integer);overload;
  188. property Value: integer read FInt write FInt;
  189. end;
  190. TPDFReference = class(TPDFDocumentObject)
  191. private
  192. FValue: integer;
  193. protected
  194. procedure Write(const AStream: TStream); override;
  195. public
  196. constructor Create(Const ADocument : TPDFDocument; Const AValue: integer);overload;
  197. property Value: integer read FValue write FValue;
  198. end;
  199. TPDFName = class(TPDFDocumentObject)
  200. private
  201. FName : string;
  202. FMustEscape: boolean;
  203. function ConvertCharsToHex: string;
  204. protected
  205. procedure Write(const AStream: TStream); override;
  206. public
  207. constructor Create(Const ADocument : TPDFDocument; const AValue: string; const AMustEscape: boolean = True); overload;
  208. property Name : String read FName;
  209. property MustScape: boolean read FMustEscape;
  210. end;
  211. TPDFAbstractString = class(TPDFDocumentObject)
  212. protected
  213. FFontIndex: integer;
  214. // These symbols must be preceded by a backslash: "(", ")", "\"
  215. function InsertEscape(const AValue: string): string;
  216. public
  217. property FontIndex: integer read FFontIndex;
  218. end;
  219. TPDFString = class(TPDFAbstractString)
  220. private
  221. FValue: AnsiString;
  222. protected
  223. procedure Write(const AStream: TStream); override;
  224. public
  225. constructor Create(Const ADocument : TPDFDocument; const AValue: AnsiString); overload;
  226. property Value: AnsiString read FValue;
  227. end;
  228. TPDFUTF16String = class(TPDFAbstractString)
  229. private
  230. FValue: UnicodeString;
  231. protected
  232. procedure Write(const AStream: TStream); override;
  233. public
  234. constructor Create(Const ADocument : TPDFDocument; const AValue: UnicodeString; const AFontIndex : Integer); overload;
  235. property Value: UnicodeString read FValue;
  236. end;
  237. { TPDFRawHexString }
  238. TPDFRawHexString = class(TPDFDocumentObject)
  239. private
  240. FValue: String;
  241. protected
  242. procedure Write(const AStream: TStream); override;
  243. public
  244. constructor Create(Const ADocument : TPDFDocument; const AValue: String); overload;
  245. property Value: String read FValue;
  246. end;
  247. TPDFUTF8String = class(TPDFAbstractString)
  248. private
  249. FValue: UTF8String;
  250. { Remap each character to the equivalant dictionary character code }
  251. function RemapedText: AnsiString;
  252. protected
  253. procedure Write(const AStream: TStream); override;
  254. public
  255. constructor Create(Const ADocument : TPDFDocument; const AValue: UTF8String; const AFontIndex: integer); overload;
  256. property Value: UTF8String read FValue;
  257. end;
  258. { Is useful to populate an array with free-form space separated values. This
  259. class is similar to TPDFString, except it doesn't wrap the string content with
  260. '(' and ')' symbols and doesn't escape the content. }
  261. TPDFFreeFormString = class(TPDFAbstractString)
  262. private
  263. FValue: string;
  264. protected
  265. procedure Write(const AStream: TStream); override;
  266. public
  267. constructor Create(Const ADocument: TPDFDocument; const AValue: string); overload;
  268. property Value: string read FValue;
  269. end;
  270. TPDFArray = class(TPDFDocumentObject)
  271. private
  272. FArray: TFPObjectList;
  273. protected
  274. procedure Write(const AStream: TStream); override;
  275. procedure AddItem(const AValue: TPDFObject);
  276. // Add integers in S as TPDFInteger elements to the array
  277. Procedure AddIntArray(S : String);
  278. procedure AddFreeFormArrayValues(S: string);
  279. public
  280. constructor Create(Const ADocument : TPDFDocument); override;
  281. destructor Destroy; override;
  282. end;
  283. TPDFStream = class(TPDFDocumentObject)
  284. private
  285. FCompressionProhibited: Boolean;
  286. FItems: TFPObjectList;
  287. protected
  288. procedure Write(const AStream: TStream); override;
  289. procedure AddItem(const AValue: TPDFObject);
  290. public
  291. constructor Create(Const ADocument : TPDFDocument; OwnsObjects : Boolean = True); overload;
  292. destructor Destroy; override;
  293. property CompressionProhibited: Boolean read FCompressionProhibited write FCompressionProhibited;
  294. end;
  295. { TPDFMemoryStream }
  296. TPDFMemoryStream = class(TPDFDocumentObject)
  297. private
  298. FBuffer: TMemoryStream;
  299. protected
  300. procedure Write(const AStream: TStream); override;
  301. public
  302. constructor Create(Const ADocument : TPDFDocument; AStream: TStream); overload;
  303. destructor Destroy; override;
  304. end;
  305. TPDFEmbeddedFont = class(TPDFDocumentObject)
  306. private
  307. FTxtFont: integer;
  308. FTxtSize: string;
  309. FPage: TPDFPage;
  310. function GetPointSize: integer;
  311. protected
  312. procedure Write(const AStream: TStream); override;
  313. class function WriteEmbeddedFont(const ADocument: TPDFDocument; const Src: TMemoryStream; const AStream: TStream): int64;
  314. class function WriteEmbeddedSubsetFont(const ADocument: TPDFDocument; const AFontNum: integer; const AOutStream: TStream): int64;
  315. public
  316. constructor Create(const ADocument: TPDFDocument;const APage: TPDFPage; const AFont: integer; const ASize: string); overload;
  317. property FontIndex: integer read FTxtFont;
  318. property PointSize: integer read GetPointSize;
  319. property Page: TPDFPage read FPage;
  320. end;
  321. TPDFBaseText = class(TPDFDocumentObject)
  322. private
  323. FX: TPDFFloat;
  324. FY: TPDFFloat;
  325. FFont: TPDFEmbeddedFont;
  326. FDegrees: single;
  327. FUnderline: boolean;
  328. FColor: TARGBColor;
  329. FStrikeThrough: boolean;
  330. public
  331. constructor Create(const ADocument: TPDFDocument); override;
  332. property X: TPDFFloat read FX write FX;
  333. property Y: TPDFFloat read FY write FY;
  334. property Font: TPDFEmbeddedFont read FFont write FFont;
  335. property Degrees: single read FDegrees write FDegrees;
  336. property Underline: boolean read FUnderline write FUnderline;
  337. property Color: TARGBColor read FColor write FColor;
  338. property StrikeThrough: boolean read FStrikeThrough write FStrikeThrough;
  339. end;
  340. TPDFText = class(TPDFBaseText)
  341. private
  342. FString: TPDFString;
  343. function GetTextWidth: single;
  344. function GetTextHeight: single;
  345. protected
  346. procedure Write(const AStream: TStream); override;
  347. public
  348. constructor Create(const ADocument: TPDFDocument; const AX, AY: TPDFFloat; const AText: AnsiString; const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean); overload;
  349. destructor Destroy; override;
  350. property Text: TPDFString read FString;
  351. end;
  352. TPDFUTF8Text = class(TPDFBaseText)
  353. private
  354. FString: TPDFUTF8String;
  355. protected
  356. procedure Write(const AStream: TStream); override;
  357. public
  358. constructor Create(const ADocument: TPDFDocument; const AX, AY: TPDFFloat; const AText: UTF8String; const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean); overload;
  359. destructor Destroy; override;
  360. property Text: TPDFUTF8String read FString;
  361. end;
  362. TPDFUTF16Text = class(TPDFBaseText)
  363. private
  364. FString: TPDFUTF16String;
  365. protected
  366. procedure Write(const AStream: TStream); override;
  367. public
  368. constructor Create(const ADocument: TPDFDocument; const AX, AY: TPDFFloat; const AText: UnicodeString; const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean); overload;
  369. destructor Destroy; override;
  370. property Text: TPDFUTF16String read FString;
  371. end;
  372. TPDFLineSegment = class(TPDFDocumentObject)
  373. private
  374. FWidth: TPDFFloat;
  375. FStroke: boolean;
  376. P1, p2: TPDFCoord;
  377. protected
  378. procedure Write(const AStream: TStream); override;
  379. public
  380. Class Function Command(APos : TPDFCoord) : String; overload;
  381. Class Function Command(x1, y1 : TPDFFloat) : String; overload;
  382. Class Function Command(APos1, APos2 : TPDFCoord) : String; overload;
  383. constructor Create(Const ADocument : TPDFDocument; const AWidth, X1,Y1, X2,Y2: TPDFFloat; const AStroke: Boolean = True); overload;
  384. end;
  385. TPDFRectangle = class(TPDFDocumentObject)
  386. private
  387. FWidth: TPDFFloat;
  388. FTopLeft: TPDFCoord;
  389. FDimensions: TPDFCoord;
  390. FFill: Boolean;
  391. FStroke: Boolean;
  392. protected
  393. procedure Write(const AStream: TStream); override;
  394. public
  395. constructor Create(const ADocument: TPDFDocument; const APosX, APosY, AWidth, AHeight, ALineWidth: TPDFFloat; const AFill, AStroke: Boolean);overload;
  396. end;
  397. TPDFRoundedRectangle = class(TPDFDocumentObject)
  398. private
  399. FWidth: TPDFFloat;
  400. FBottomLeft: TPDFCoord;
  401. FDimensions: TPDFCoord;
  402. FFill: Boolean;
  403. FStroke: Boolean;
  404. FRadius: TPDFFloat;
  405. protected
  406. procedure Write(const AStream: TStream); override;
  407. public
  408. constructor Create(const ADocument: TPDFDocument; const APosX, APosY, AWidth, AHeight, ARadius, ALineWidth: TPDFFloat; const AFill, AStroke: Boolean);overload;
  409. end;
  410. TPDFCurveC = class(TPDFDocumentObject)
  411. private
  412. FCtrl1, FCtrl2, FTo: TPDFCoord;
  413. FWidth: TPDFFloat;
  414. FStroke: Boolean;
  415. protected
  416. procedure Write(const AStream: TStream); override;
  417. public
  418. Class Function Command(Const xCtrl1, yCtrl1, xCtrl2, yCtrl2, xTo, yTo: TPDFFloat): String; overload;
  419. Class Function Command(Const ACtrl1, ACtrl2, ATo3: TPDFCoord): String; overload;
  420. constructor Create(Const ADocument : TPDFDocument; const xCtrl1, yCtrl1, xCtrl2, yCtrl2, xTo, yTo, AWidth: TPDFFloat; AStroke: Boolean = True);overload;
  421. constructor Create(Const ADocument : TPDFDocument; const ACtrl1, ACtrl2, ATo3: TPDFCoord; AWidth: TPDFFloat; AStroke: Boolean = True);overload;
  422. end;
  423. TPDFCurveV = class(TPDFDocumentObject)
  424. private
  425. FP2,FP3: TPDFCoord;
  426. FWidth: TPDFFloat;
  427. FStroke : Boolean;
  428. protected
  429. procedure Write(const AStream: TStream); override;
  430. public
  431. constructor Create(Const ADocument : TPDFDocument; const X2,Y2,X3,Y3,AWidth : TPDFFloat;AStroke: Boolean = True);overload;
  432. constructor Create(Const ADocument : TPDFDocument; const AP2,AP3 : TPDFCoord; AWidth: TPDFFloat;AStroke: Boolean = True);overload;
  433. end;
  434. TPDFCurveY = class(TPDFDocumentObject)
  435. private
  436. FP1,FP3: TPDFCoord;
  437. FWidth: TPDFFloat;
  438. FStroke : Boolean;
  439. protected
  440. procedure Write(const AStream: TStream); override;
  441. public
  442. constructor Create(Const ADocument : TPDFDocument; const X1,Y1,X3,Y3,AWidth : TPDFFloat;AStroke: Boolean = True);overload;
  443. constructor Create(Const ADocument : TPDFDocument; const AP1,AP3 : TPDFCoord; AWidth: TPDFFloat;AStroke: Boolean = True);overload;
  444. end;
  445. TPDFEllipse = class(TPDFDocumentObject)
  446. private
  447. FCenter,
  448. FDimensions: TPDFCoord;
  449. FFill : Boolean;
  450. FStroke : Boolean;
  451. FLineWidth : TPDFFloat;
  452. protected
  453. procedure Write(const AStream: TStream); override;
  454. public
  455. constructor Create(Const ADocument : TPDFDocument; const APosX, APosY, AWidth, AHeight, ALineWidth: TPDFFloat; const AFill : Boolean = True; AStroke: Boolean = True);overload;
  456. end;
  457. TPDFSurface = class(TPDFDocumentObject)
  458. private
  459. FPoints: TPDFCoordArray;
  460. FFill : Boolean;
  461. FClose : Boolean;
  462. protected
  463. procedure Write(const AStream: TStream); override;
  464. public
  465. constructor Create(Const ADocument : TPDFDocument; const APoints: TPDFCoordArray; AClose : Boolean; AFill : Boolean = True); overload;
  466. end;
  467. TPDFImage = class(TPDFDocumentObject)
  468. private
  469. FNumber: integer;
  470. FPos: TPDFCoord;
  471. FSize: TPDFCoord;
  472. protected
  473. procedure Write(const AStream: TStream); override;
  474. public
  475. constructor Create(Const ADocument : TPDFDocument; const ALeft, ABottom, AWidth, AHeight: TPDFFloat; ANumber: integer); overload;
  476. end;
  477. TPDFLineStyle = class(TPDFDocumentObject)
  478. private
  479. FStyle: TPDFPenStyle;
  480. FPhase: integer;
  481. FLineWidth: TPDFFloat;
  482. protected
  483. procedure Write(const AStream: TStream);override;
  484. public
  485. constructor Create(Const ADocument : TPDFDocument; AStyle: TPDFPenStyle; APhase: integer; ALineWidth: TPDFFloat); overload;
  486. end;
  487. TPDFColor = class(TPDFDocumentObject)
  488. private
  489. FRed: string;
  490. FGreen: string;
  491. FBlue: string;
  492. FStroke: Boolean;
  493. FColor: TARGBColor;
  494. protected
  495. procedure Write(const AStream: TStream);override;
  496. public
  497. class function Command(const AStroke: boolean; const AColor: TARGBColor): string;
  498. constructor Create(Const ADocument : TPDFDocument; const AStroke: Boolean; AColor: TARGBColor); overload;
  499. property Color: TARGBColor read FColor;
  500. end;
  501. TPDFDictionaryItem = class(TPDFDocumentObject)
  502. private
  503. FKey: TPDFName;
  504. FObj: TPDFObject;
  505. protected
  506. procedure Write(const AStream: TStream);override;
  507. public
  508. constructor Create(Const ADocument : TPDFDocument; const AKey: string; const AValue: TPDFObject);
  509. destructor Destroy; override;
  510. Property Value : TPDFObject Read FObj;
  511. end;
  512. TPDFDictionary = class(TPDFDocumentObject)
  513. private
  514. FElements: TFPObjectList; // list of TPDFDictionaryItem
  515. function GetE(AIndex : Integer): TPDFDictionaryItem;
  516. function GetEC: Integer;
  517. function GetV(AIndex : Integer): TPDFObject;
  518. protected
  519. procedure AddElement(const AKey: string; const AValue: TPDFObject);
  520. procedure AddName(const AKey,AName : String; const AMustEscape: boolean = True);
  521. procedure AddInteger(const AKey : String; AInteger : Integer);
  522. procedure AddReference(const AKey : String; AReference : Integer);
  523. procedure AddString(const AKey, AString : String);
  524. procedure AddString(const AKey:string;const AString : UnicodeString);
  525. function IndexOfKey(const AValue: string): integer;
  526. procedure Write(const AStream: TStream); override;
  527. procedure WriteDictionary(const AObject: integer; const AStream: TStream);
  528. public
  529. constructor Create(Const ADocument : TPDFDocument); override;
  530. destructor Destroy; override;
  531. Function LastElement : TPDFDictionaryItem;
  532. Function LastValue : TPDFObject;
  533. Function FindElement(Const AKey : String) : TPDFDictionaryItem;
  534. Function FindValue(Const AKey : String) : TPDFObject;
  535. Function ElementByName(Const AKey : String) : TPDFDictionaryItem;
  536. Function ValueByName(Const AKey : String) : TPDFObject;
  537. Property Elements[AIndex : Integer] : TPDFDictionaryItem Read GetE;
  538. Property Values[AIndex : Integer] : TPDFObject Read GetV;
  539. Property ElementCount : Integer Read GetEC;
  540. end;
  541. TPDFXRef = class(TPDFDocumentObject)
  542. private
  543. FOffset: integer;
  544. FDict: TPDFDictionary;
  545. FStream: TPDFStream;
  546. protected
  547. procedure Write(const AStream: TStream);override;
  548. public
  549. constructor Create(Const ADocument : TPDFDocument); override;
  550. destructor Destroy; override;
  551. property Offset: integer read FOffset write FOffset;
  552. Property Dict : TPDFDictionary Read FDict;
  553. end;
  554. TPDFInfos = Class(TPersistent)
  555. private
  556. FApplicationName: String;
  557. FAuthor: String;
  558. FCreationDate: TDateTime;
  559. FProducer: String;
  560. FTitle: String;
  561. FKeywords: String;
  562. public
  563. constructor Create; virtual;
  564. Property Author : String Read FAuthor Write FAuthor;
  565. Property Title : String Read FTitle Write FTitle;
  566. Property ApplicationName : String Read FApplicationName Write FApplicationName;
  567. Property Producer : String Read FProducer Write FProducer;
  568. Property CreationDate : TDateTime Read FCreationDate Write FCreationDate;
  569. Property Keywords : String read FKeywords write FKeywords;
  570. end;
  571. { When the WriteXXX() and DrawXXX() methods specify coordinates, they do it as
  572. per the PDF specification, from the bottom-left. }
  573. { TPDFPage }
  574. TPDFPage = Class(TPDFDocumentObject)
  575. private
  576. FObjects : TObjectList;
  577. FOrientation: TPDFPaperOrientation;
  578. FPaper: TPDFPaper;
  579. FPaperType: TPDFPaperType;
  580. FUnitOfMeasure: TPDFUnitOfMeasure;
  581. FMatrix: TPDFMatrix;
  582. FAnnots: TPDFAnnotList;
  583. FLastFont: TPDFEmbeddedFont;
  584. FLastFontColor: TARGBColor;
  585. procedure CalcPaperSize;
  586. function GetO(AIndex : Integer): TPDFObject;
  587. function GetObjectCount: Integer;
  588. function CreateAnnotList: TPDFAnnotList; virtual;
  589. procedure SetOrientation(AValue: TPDFPaperOrientation);
  590. procedure SetPaperType(AValue: TPDFPaperType);
  591. procedure AddTextToLookupLists(AText: UTF8String);
  592. procedure SetUnitOfMeasure(AValue: TPDFUnitOfMeasure);
  593. protected
  594. procedure AdjustMatrix; virtual;
  595. procedure DoUnitConversion(var APoint: TPDFCoord); virtual;
  596. procedure CreateStdFontText(X, Y: TPDFFloat; AText: AnsiString; const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean); virtual;
  597. procedure CreateTTFFontText(X, Y: TPDFFloat; AText: UTF8String; const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean); virtual;
  598. Public
  599. Constructor Create(Const ADocument : TPDFDocument); override;
  600. Destructor Destroy; override;
  601. Procedure AddObject(AObject : TPDFObject);
  602. // Commands. These will create objects in the objects list of the page.
  603. Procedure SetFont(AFontIndex : Integer; AFontSize : Integer); virtual;
  604. // used for stroking and nonstroking colors - purpose determined by the AStroke parameter
  605. Procedure SetColor(AColor : TARGBColor; AStroke : Boolean = True); virtual;
  606. Procedure SetPenStyle(AStyle : TPDFPenStyle; const ALineWidth: TPDFFloat = 1.0); virtual;
  607. // Set color and pen style from line style
  608. Procedure SetLineStyle(AIndex : Integer; AStroke : Boolean = True); overload;
  609. Procedure SetLineStyle(S : TPDFLineStyleDef; AStroke : Boolean = True); overload;
  610. { output coordinate is the font baseline. }
  611. Procedure WriteText(X, Y: TPDFFloat; AText : UTF8String; const ADegrees: single = 0.0; const AUnderline: boolean = false; const AStrikethrough: boolean = false); overload;
  612. Procedure WriteText(APos: TPDFCoord; AText : UTF8String; const ADegrees: single = 0.0; const AUnderline: boolean = false; const AStrikethrough: boolean = false); overload;
  613. procedure DrawLine(X1, Y1, X2, Y2, ALineWidth : TPDFFloat; const AStroke: Boolean = True); overload;
  614. procedure DrawLine(APos1, APos2: TPDFCoord; ALineWidth: TPDFFloat; const AStroke: Boolean = True); overload;
  615. Procedure DrawLineStyle(X1, Y1, X2, Y2: TPDFFloat; AStyle: Integer); overload;
  616. Procedure DrawLineStyle(APos1, APos2: TPDFCoord; AStyle: Integer); overload;
  617. { X, Y coordinates are the bottom-left coordinate of the rectangle. The W and H parameters are in the UnitOfMeasure units. }
  618. Procedure DrawRect(const X, Y, W, H, ALineWidth: TPDFFloat; const AFill, AStroke : Boolean; const ADegrees: single = 0.0); overload;
  619. Procedure DrawRect(const APos: TPDFCoord; const W, H, ALineWidth: TPDFFloat; const AFill, AStroke : Boolean; const ADegrees: single = 0.0); overload;
  620. { X, Y coordinates are the bottom-left coordinate of the rectangle. The W and H parameters are in the UnitOfMeasure units. }
  621. procedure DrawRoundedRect(const X, Y, W, H, ARadius, ALineWidth: TPDFFloat; const AFill, AStroke : Boolean; const ADegrees: single = 0.0);
  622. { X, Y coordinates are the bottom-left coordinate of the image. AWidth and AHeight are in image pixels. }
  623. Procedure DrawImageRawSize(const X, Y: TPDFFloat; const APixelWidth, APixelHeight, ANumber: integer; const ADegrees: single = 0.0); overload;
  624. Procedure DrawImageRawSize(const APos: TPDFCoord; const APixelWidth, APixelHeight, ANumber: integer; const ADegrees: single = 0.0); overload;
  625. { X, Y coordinates are the bottom-left coordinate of the image. AWidth and AHeight are in UnitOfMeasure units. }
  626. Procedure DrawImage(const X, Y: TPDFFloat; const AWidth, AHeight: TPDFFloat; const ANumber: integer; const ADegrees: single = 0.0); overload;
  627. Procedure DrawImage(const APos: TPDFCoord; const AWidth, AHeight: TPDFFloat; const ANumber: integer; const ADegrees: single = 0.0); overload;
  628. { X, Y coordinates are the bottom-left coordinate of the boundry rectangle.
  629. The W and H parameters are in the UnitOfMeasure units. A negative AWidth will
  630. cause the ellpise to draw to the left of the origin point. }
  631. Procedure DrawEllipse(const APosX, APosY, AWidth, AHeight, ALineWidth: TPDFFloat; const AFill: Boolean = True; AStroke: Boolean = True; const ADegrees: single = 0.0); overload;
  632. Procedure DrawEllipse(const APos: TPDFCoord; const AWidth, AHeight, ALineWidth: TPDFFloat; const AFill: Boolean = True; AStroke: Boolean = True; const ADegrees: single = 0.0); overload;
  633. procedure DrawPolygon(const APoints: array of TPDFCoord; const ALineWidth: TPDFFloat);
  634. procedure DrawPolyLine(const APoints: array of TPDFCoord; const ALineWidth: TPDFFloat);
  635. { start a new subpath }
  636. procedure ResetPath;
  637. procedure ClipPath;
  638. { Close the current subpath by appending a straight line segment from the current point to the starting point of the subpath. }
  639. procedure ClosePath;
  640. procedure ClosePathStroke;
  641. { render the actual path }
  642. procedure StrokePath;
  643. { Fill using the nonzero winding number rule. }
  644. procedure FillStrokePath;
  645. { Fill using the Even-Odd rule. }
  646. procedure FillEvenOddStrokePath;
  647. { Graphic stack management }
  648. procedure PushGraphicsStack;
  649. procedure PopGraphicsStack;
  650. { Move the current drawing position to (x, y) }
  651. procedure MoveTo(x, y: TPDFFloat); overload;
  652. procedure MoveTo(APos: TPDFCoord); overload;
  653. { Append a cubic Bezier curve to the current path
  654. - The curve extends from the current point to the point (xTo, yTo),
  655. using (xCtrl1, yCtrl1) and (xCtrl2, yCtrl2) as the Bezier control points
  656. - The new current point is (xTo, yTo) }
  657. procedure CubicCurveTo(const xCtrl1, yCtrl1, xCtrl2, yCtrl2, xTo, yTo, ALineWidth: TPDFFloat; AStroke: Boolean = True); overload;
  658. procedure CubicCurveTo(ACtrl1, ACtrl2, ATo: TPDFCoord; const ALineWidth: TPDFFloat; AStroke: Boolean = True); overload;
  659. { Append a cubic Bezier curve to the current path
  660. - The curve extends from the current point to the point (xTo, yTo),
  661. using the current point and (xCtrl2, yCtrl2) as the Bezier control points
  662. - The new current point is (xTo, yTo) }
  663. procedure CubicCurveToV(xCtrl2, yCtrl2, xTo, yTo: TPDFFloat; const ALineWidth: TPDFFloat; AStroke: Boolean = True); overload;
  664. procedure CubicCurveToV(ACtrl2, ATo: TPDFCoord; const ALineWidth: TPDFFloat; AStroke: Boolean = True); overload;
  665. { Append a cubic Bezier curve to the current path
  666. - The curve extends from the current point to the point (xTo, yTo),
  667. using (xCtrl1, yCtrl1) and (xTo, yTo) as the Bezier control points
  668. - The new current point is (xTo, yTo) }
  669. procedure CubicCurveToY(xCtrl1, yCtrl1, xTo, yTo: TPDFFloat; const ALineWidth: TPDFFloat; AStroke: Boolean = True); overload;
  670. procedure CubicCurveToY(ACtrl1, ATo: TPDFCoord; const ALineWidth: TPDFFloat; AStroke: Boolean = True); overload;
  671. { Define a rectangle that becomes a clickable hotspot, referencing the URI argument. }
  672. Procedure AddExternalLink(const APosX, APosY, AWidth, AHeight: TPDFFloat; const AURI: string; ABorder: boolean = false);
  673. { This returns the paper height, converted to whatever UnitOfMeasure is set too }
  674. function GetPaperHeight: TPDFFloat;
  675. Function HasImages : Boolean;
  676. // Quick settings for Paper.
  677. Property PaperType : TPDFPaperType Read FPaperType Write SetPaperType default ptA4;
  678. Property Orientation : TPDFPaperOrientation Read FOrientation Write SetOrientation;
  679. // Set this if you want custom paper size. You must set this before setting PaperType = ptCustom.
  680. Property Paper : TPDFPaper Read FPaper Write FPaper;
  681. // Unit of Measure - how the PDF Page should convert the coordinates and dimensions
  682. property UnitOfMeasure: TPDFUnitOfMeasure read FUnitOfMeasure write SetUnitOfMeasure default uomMillimeters;
  683. Property ObjectCount: Integer Read GetObjectCount;
  684. Property Objects[AIndex : Integer] : TPDFObject Read GetO; default;
  685. // returns the last font object created by SetFont()
  686. property LastFont: TPDFEmbeddedFont read FLastFont;
  687. { A 3x3 matrix used to translate the PDF Cartesian coordinate system to an Image coordinate system. }
  688. property Matrix: TPDFMatrix read FMatrix write FMatrix;
  689. property Annots: TPDFAnnotList read FAnnots;
  690. end;
  691. TPDFPageClass = class of TPDFPage;
  692. TPDFSection = Class(TCollectionItem)
  693. private
  694. FTitle: String;
  695. FPages : TFPList; // not owned
  696. function GetP(AIndex : Integer): TPDFPage;
  697. function GetP: Integer;
  698. Public
  699. Destructor Destroy; override;
  700. Procedure AddPage(APage : TPDFPage);
  701. Property Title : String Read FTitle Write FTitle;
  702. Property Pages[AIndex : Integer] : TPDFPage Read GetP;
  703. Property PageCount : Integer Read GetP;
  704. end;
  705. TPDFSectionList = Class(TCollection)
  706. private
  707. function GetS(AIndex : Integer): TPDFSection;
  708. Public
  709. Function AddSection : TPDFSection;
  710. Property Section[AIndex : Integer] : TPDFSection Read GetS; Default;
  711. end;
  712. TPDFFont = class(TCollectionItem)
  713. private
  714. FIsStdFont: boolean;
  715. FName: String;
  716. FFontFilename: String;
  717. FTrueTypeFile: TTFFileInfo;
  718. { stores mapping of Char IDs to font Glyph IDs }
  719. FTextMappingList: TTextMappingList;
  720. FSubsetFont: TStream;
  721. procedure PrepareTextMapping;
  722. procedure SetFontFilename(AValue: string);
  723. procedure GenerateSubsetFont;
  724. public
  725. constructor Create(ACollection: TCollection); override;
  726. destructor Destroy; override;
  727. { Returns a string where each character is replaced with a glyph index value instead. }
  728. function GetGlyphIndices(const AText: UnicodeString): AnsiString;
  729. procedure AddTextToMappingList(const AText: UnicodeString);
  730. Property FontFile: string read FFontFilename write SetFontFilename;
  731. Property Name: String Read FName Write FName;
  732. property TextMapping: TTextMappingList read FTextMappingList;
  733. property IsStdFont: boolean read FIsStdFont write FIsStdFont;
  734. property SubsetFont: TStream read FSubsetFont;
  735. end;
  736. TPDFTrueTypeCharWidths = class(TPDFDocumentObject)
  737. private
  738. FEmbeddedFontNum: integer;
  739. FFontIndex: integer;
  740. protected
  741. procedure Write(const AStream: TStream);override;
  742. public
  743. constructor Create(const ADocument: TPDFDocument; const AEmbeddedFontNum: integer); overload;
  744. property EmbeddedFontNum: integer read FEmbeddedFontNum;
  745. property FontIndex: integer read FFontIndex write FFontIndex;
  746. end;
  747. { TPDFFontDefs }
  748. TPDFFontDefs = Class(TCollection)
  749. private
  750. function GetF(AIndex : Integer): TPDFFont;
  751. Public
  752. Function FindFont(const AName:string):integer;
  753. Function AddFontDef : TPDFFont;
  754. Property FontDefs[AIndex : Integer] : TPDFFont Read GetF; Default;
  755. end;
  756. TPDFPages = Class(TPDFDocumentObject)
  757. private
  758. FList: TFPObjectList;
  759. FPageClass: TPDFPageClass;
  760. function GetP(AIndex: Integer): TPDFPage;
  761. function GetPageCount: integer;
  762. public
  763. constructor Create(const ADocument: TPDFDocument); override; overload;
  764. destructor Destroy; override;
  765. function AddPage: TPDFPage;
  766. procedure Add(APage: TPDFPage);
  767. property Count: integer read GetPageCount;
  768. property Pages[AIndex: Integer]: TPDFPage read GetP; default;
  769. property PageClass: TPDFPageClass read FPageClass write FPageClass;
  770. end;
  771. TPDFAnnot = class(TPDFObject)
  772. private
  773. FLeft: TPDFFloat;
  774. FBottom: TPDFFloat;
  775. FWidth: TPDFFloat;
  776. FHeight: TPDFFloat;
  777. FURI: string;
  778. FBorder: boolean;
  779. public
  780. constructor Create(const ADocument: TPDFDocument); override; overload;
  781. constructor Create(const ADocument: TPDFDocument; const ALeft, ABottom, AWidth, AHeight: TPDFFloat; const AURI: String; const ABorder: Boolean = false); overload;
  782. end;
  783. TPDFAnnotList = class(TPDFDocumentObject)
  784. private
  785. FList: TFPObjectList;
  786. procedure CheckList;
  787. function GetAnnot(AIndex: integer): TPDFAnnot;
  788. public
  789. destructor Destroy; override;
  790. function AddAnnot: TPDFAnnot;
  791. function Count: integer;
  792. procedure Add(AAnnot: TPDFAnnot);
  793. property Annots[AIndex: integer]: TPDFAnnot read GetAnnot; default;
  794. end;
  795. TPDFImageCompression = (icNone, icDeflate, icJPEG);
  796. TPDFImageStreamOption = (isoCompressed,isoTransparent);
  797. TPDFImageStreamOptions = set of TPDFImageStreamOption;
  798. TPDFImageItem = Class(TCollectionItem)
  799. private
  800. FImage: TFPCustomImage;
  801. FOwnsImage: Boolean;
  802. FStreamed: TBytes;
  803. FCompression: TPDFImageCompression;
  804. FStreamedMask: TBytes;
  805. FCompressionMask: TPDFImageCompression;
  806. FWidth,FHeight : Integer;
  807. function GetHasMask: Boolean;
  808. function GetHeight: Integer;
  809. function GetStreamed: TBytes;
  810. function GetStreamedMask: TBytes;
  811. function GetWidth: Integer;
  812. procedure SetImage(AValue: TFPCustomImage);
  813. procedure SetStreamed(AValue: TBytes);
  814. Protected
  815. Function WriteStream(const AStreamedData: TBytes; AStream: TStream): int64; virtual;
  816. Public
  817. Destructor Destroy; override;
  818. Procedure CreateStreamedData(AUseCompression: Boolean); overload;
  819. Procedure CreateStreamedData(aOptions : TPDFImageStreamOptions); overload;
  820. Procedure DetachImage;
  821. procedure SetStreamedMask(const AValue: TBytes; const ACompression: TPDFImageCompression);
  822. Function WriteImageStream(AStream: TStream): int64;
  823. Function WriteMaskStream(AStream: TStream): int64;
  824. function Equals(AImage: TFPCustomImage): boolean; reintroduce;
  825. Property Image : TFPCustomImage Read FImage Write SetImage;
  826. Property StreamedData : TBytes Read GetStreamed Write SetStreamed;
  827. Property StreamedMask : TBytes Read GetStreamedMask;
  828. Property OwnsImage : Boolean Read FOwnsImage Write FOwnsImage;
  829. Property Width : Integer Read GetWidth;
  830. Property Height : Integer Read GetHeight;
  831. Property HasMask : Boolean read GetHasMask;
  832. end;
  833. TPDFImages = Class(TCollection)
  834. Private
  835. FOwner: TPDFDocument;
  836. function GetI(AIndex : Integer): TPDFImageItem;
  837. Protected
  838. function GetOwner: TPersistent; override;
  839. Public
  840. Constructor Create(AOwner: TPDFDocument; AItemClass : TCollectionItemClass);
  841. Function AddImageItem : TPDFImageItem;
  842. Function AddJPEGStream(Const AStream : TStream; Width,Height : Integer): Integer;
  843. Function AddFromStream(Const AStream : TStream; Handler : TFPCustomImageReaderClass;
  844. KeepImage : Boolean = False): Integer;
  845. Function AddFromFile(Const AFileName : String; KeepImage : Boolean = False): Integer;
  846. Property Images[AIndex : Integer] : TPDFImageItem Read GetI; default;
  847. Property Owner: TPDFDocument read FOwner;
  848. end;
  849. TXMPStream = class(TPDFDocumentObject)
  850. procedure Write(const AStream: TStream); override;
  851. end;
  852. TPDFFontNumBaseObject = class(TPDFDocumentObject)
  853. protected
  854. FFontNum: integer;
  855. public
  856. constructor Create(const ADocument: TPDFDocument; const AFontNum: integer); overload;
  857. property FontNum: integer read FFontNum;
  858. end;
  859. TPDFToUnicode = class(TPDFFontNumBaseObject)
  860. protected
  861. procedure Write(const AStream: TStream); override;
  862. end;
  863. TCIDToGIDMap = class(TPDFFontNumBaseObject)
  864. protected
  865. procedure Write(const AStream: TStream); override;
  866. end;
  867. TPDFCIDSet = class(TPDFFontNumBaseObject)
  868. protected
  869. procedure Write(const AStream: TStream); override;
  870. end;
  871. TPDFLineStyleDef = Class(TCollectionItem)
  872. private
  873. FColor: TARGBColor;
  874. FLineWidth: TPDFFloat;
  875. FPenStyle: TPDFPenStyle;
  876. Public
  877. Procedure Assign(Source : TPersistent); override;
  878. Published
  879. Property LineWidth : TPDFFloat Read FLineWidth Write FLineWidth;
  880. Property Color : TARGBColor Read FColor Write FColor Default clBlack;
  881. Property PenStyle : TPDFPenStyle Read FPenStyle Write FPenStyle Default ppsSolid;
  882. end;
  883. TPDFLineStyleDefs = Class(TCollection)
  884. private
  885. function GetI(AIndex : Integer): TPDFLineStyleDef;
  886. Public
  887. Function AddLineStyleDef : TPDFLineStyleDef;
  888. Property Defs[AIndex : Integer] : TPDFLineStyleDef Read GetI; Default;
  889. end;
  890. { TPDFDocument }
  891. TPDFDocument = class(TComponent)
  892. private
  893. FCatalogue: integer;
  894. FCurrentColor: string;
  895. FCurrentWidth: string;
  896. FLineCapStyle: TPDFLineCapStyle;
  897. FDefaultOrientation: TPDFPaperOrientation;
  898. FDefaultPaperType: TPDFPaperType;
  899. FFontDirectory: string;
  900. FFontFiles: TStrings;
  901. FFonts: TPDFFontDefs;
  902. FImages: TPDFImages;
  903. FInfos: TPDFInfos;
  904. FLineStyleDefs: TPDFLineStyleDefs;
  905. FObjectCount: Integer;
  906. FOptions: TPDFOptions;
  907. FPages: TPDFPages;
  908. FPreferences: Boolean;
  909. FPageLayout: TPDFPageLayout;
  910. FSections: TPDFSectionList;
  911. FTrailer: TPDFDictionary;
  912. FZoomValue: string;
  913. FGlobalXRefs: TFPObjectList; // list of TPDFXRef
  914. FUnitOfMeasure: TPDFUnitOfMeasure;
  915. function GetStdFontCharWidthsArray(const AFontName: string): TPDFFontWidthArray;
  916. function GetX(AIndex : Integer): TPDFXRef;
  917. function GetXC: Integer;
  918. function GetTotalAnnotsCount: integer;
  919. function GetFontNamePrefix(const AFontNum: Integer): string;
  920. procedure SetFontFiles(AValue: TStrings);
  921. procedure SetFonts(AValue: TPDFFontDefs);
  922. procedure SetInfos(AValue: TPDFInfos);
  923. procedure SetLineStyles(AValue: TPDFLineStyleDefs);
  924. Procedure SetOptions(aValue : TPDFOptions);
  925. protected
  926. // Create all kinds of things, virtual so they can be overridden to create descendents instead
  927. function CreatePDFPages: TPDFPages; virtual;
  928. function CreateLineStyles: TPDFLineStyleDefs; virtual;
  929. function CreateFontDefs: TPDFFontDefs; virtual;
  930. function CreatePDFImages: TPDFImages; virtual;
  931. function CreatePDFInfos: TPDFInfos; virtual;
  932. function CreateSectionList: TPDFSectionList; virtual;
  933. // Returns next prevoutline
  934. function CreateSectionOutLine(Const SectionIndex,OutLineRoot,ParentOutLine,NextSect,PrevSect : Integer): Integer; virtual;
  935. Function CreateSectionsOutLine : Integer; virtual;
  936. Function CreateSectionPageOutLine(Const S: TPDFSection; Const PageOutLine, PageIndex, NewPage, ParentOutline, NextOutline, PrevOutLine : Integer) : Integer;virtual;
  937. procedure AddFontNameToPages(const AName: String; ANum : Integer);
  938. procedure WriteXRefTable(const AStream: TStream);
  939. procedure WriteObject(const AObject: integer; const AStream: TStream);
  940. procedure CreateRefTable;virtual;
  941. procedure CreateTrailer;virtual;
  942. procedure CreateFontEntries; virtual;
  943. procedure CreateImageEntries; virtual;
  944. procedure CreateAnnotEntries(const APageNum: integer; const APageDict: TPDFDictionary); virtual;
  945. function CreateContentsEntry(const APageNum: integer): integer;virtual;
  946. function CreateCatalogEntry: integer;virtual;
  947. procedure CreateInfoEntry(UseUTF16 : Boolean);virtual;
  948. procedure CreateMetadataEntry;virtual;
  949. procedure CreateTrailerID;virtual;
  950. procedure CreatePreferencesEntry;virtual;
  951. function CreatePagesEntry(Parent: integer): integer;virtual;
  952. function CreatePageEntry(Parent, PageNum: integer): integer;virtual;
  953. function CreateOutlines: integer;virtual;
  954. function CreateOutlineEntry(Parent, SectNo, PageNo: integer; ATitle: string): integer;virtual;
  955. function LoadFont(AFont: TPDFFont): boolean;
  956. procedure CreateStdFont(EmbeddedFontName: string; EmbeddedFontNum: integer);virtual;
  957. procedure CreateTTFFont(const EmbeddedFontNum: integer);virtual;
  958. procedure CreateTTFDescendantFont(const EmbeddedFontNum: integer);virtual;
  959. procedure CreateTTFCIDSystemInfo;virtual;
  960. procedure CreateTp1Font(const EmbeddedFontNum: integer);virtual;
  961. procedure CreateFontDescriptor(const EmbeddedFontNum: integer);virtual;
  962. procedure CreateToUnicode(const AFontNum: integer);virtual;
  963. procedure CreateFontFileEntry(const AFontNum: integer);virtual;
  964. procedure CreateCIDSet(const AFontNum: integer); virtual;
  965. procedure CreateImageEntry(ImgWidth, ImgHeight, NumImg: integer;
  966. out ImageDict: TPDFDictionary);virtual;
  967. procedure CreateImageMaskEntry(ImgWidth, ImgHeight, NumImg: integer;
  968. ImageDict: TPDFDictionary);virtual;
  969. function CreateAnnotEntry(const APageNum, AnnotNum: integer): integer; virtual;
  970. function CreateCIDToGIDMap(const AFontNum: integer): integer; virtual;
  971. procedure CreatePageStream(APage : TPDFPage; PageNum: integer);
  972. Function CreateString(Const AValue : String) : TPDFString;
  973. Function CreateUTF16String(Const AValue : UnicodeString; const AFontIndex: integer) : TPDFUTF16String;
  974. Function CreateUTF8String(Const AValue : UTF8String; const AFontIndex: integer) : TPDFUTF8String;
  975. Function CreateGlobalXRef: TPDFXRef;
  976. Function AddGlobalXRef(AXRef : TPDFXRef) : Integer;
  977. function IndexOfGlobalXRef(const AValue: string): integer;
  978. Function FindGlobalXRef(Const AName : String) : TPDFXRef;
  979. Function GlobalXRefByName(Const AName : String) : TPDFXRef;
  980. Property GlobalXRefs[AIndex : Integer] : TPDFXRef Read GetX;
  981. Property GlobalXRefCount : Integer Read GetXC;
  982. Property CurrentColor: string Read FCurrentColor Write FCurrentColor;
  983. Property CurrentWidth: string Read FCurrentWidth Write FCurrentWidth;
  984. public
  985. constructor Create(AOwner : TComponent); override;
  986. destructor Destroy; override;
  987. procedure StartDocument;
  988. procedure Reset;
  989. procedure SaveToStream(const AStream: TStream); virtual;
  990. Procedure SaveToFile(Const AFileName : String);
  991. function IsStandardPDFFont(AFontName: string): boolean;
  992. // Create objects, owned by this document.
  993. Function CreateEmbeddedFont(const APage: TPDFPage; AFontIndex, AFontSize : Integer) : TPDFEmbeddedFont;
  994. Function CreateText(X,Y : TPDFFloat; AText : AnsiString; const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean) : TPDFText; overload;
  995. Function CreateText(X,Y : TPDFFloat; AText : UTF8String; const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean) : TPDFUTF8Text; overload;
  996. Function CreateText(X,Y : TPDFFloat; AText : UnicodeString; const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean) : TPDFUTF16Text; overload;
  997. Function CreateRectangle(const X,Y,W,H, ALineWidth: TPDFFloat; const AFill, AStroke: Boolean) : TPDFRectangle;
  998. function CreateRoundedRectangle(const X, Y, W, H, ARadius, ALineWidth: TPDFFloat; const AFill, AStroke: Boolean): TPDFRoundedRectangle;
  999. Function CreateColor(AColor : TARGBColor; AStroke : Boolean) : TPDFColor;
  1000. Function CreateBoolean(AValue : Boolean) : TPDFBoolean;
  1001. Function CreateInteger(AValue : Integer) : TPDFInteger;
  1002. Function CreateReference(AValue : Integer) : TPDFReference;
  1003. Function CreateLineStyle(APenStyle: TPDFPenStyle; const ALineWidth: TPDFFloat) : TPDFLineStyle;
  1004. Function CreateName(AValue : String; const AMustEscape: boolean = True) : TPDFName;
  1005. Function CreateStream(OwnsObjects : Boolean = True) : TPDFStream;
  1006. Function CreateDictionary : TPDFDictionary;
  1007. Function CreateXRef : TPDFXRef;
  1008. Function CreateArray : TPDFArray;
  1009. Function CreateImage(const ALeft, ABottom, AWidth, AHeight: TPDFFloat; ANumber: integer) : TPDFImage;
  1010. Function AddFont(AName : String) : Integer; overload;
  1011. Function AddFont(AFontFile: String; AName : String) : Integer; overload;
  1012. Function AddLineStyleDef(ALineWidth : TPDFFloat; AColor : TARGBColor = clBlack; APenStyle : TPDFPenStyle = ppsSolid) : Integer;
  1013. procedure AddOutputIntent(const Subtype, OutputConditionIdentifier, Info: string; ICCProfile: TStream);
  1014. procedure AddPDFA1sRGBOutputIntent;virtual;
  1015. Property Fonts : TPDFFontDefs Read FFonts Write SetFonts;
  1016. Property Pages : TPDFPages Read FPages;
  1017. Property Images : TPDFImages Read FImages;
  1018. Function ImageStreamOptions : TPDFImageStreamOptions;
  1019. Property Catalogue: integer Read FCatalogue;
  1020. Property Trailer: TPDFDictionary Read FTrailer;
  1021. Property FontFiles : TStrings Read FFontFiles Write SetFontFiles;
  1022. Property FontDirectory: string Read FFontDirectory Write FFontDirectory;
  1023. Property Sections : TPDFSectionList Read FSections;
  1024. Property ObjectCount : Integer Read FObjectCount;
  1025. Property LineCapStyle: TPDFLineCapStyle Read FLineCapStyle Write FLineCapStyle;
  1026. Published
  1027. Property Options : TPDFOptions Read FOptions Write SetOptions;
  1028. Property LineStyles : TPDFLineStyleDefs Read FLineStyleDefs Write SetLineStyles;
  1029. property PageLayout: TPDFPageLayout read FPageLayout write FPageLayout default lSingle;
  1030. Property Infos : TPDFInfos Read FInfos Write SetInfos;
  1031. Property DefaultPaperType : TPDFPaperTYpe Read FDefaultPaperType Write FDefaultPaperType;
  1032. Property DefaultOrientation : TPDFPaperOrientation Read FDefaultOrientation Write FDefaultOrientation;
  1033. property DefaultUnitOfMeasure: TPDFUnitOfMeasure read FUnitOfMeasure write FUnitOfMeasure default uomMillimeters;
  1034. end;
  1035. const
  1036. CRLF = #13#10;
  1037. PDF_VERSION = '%PDF-1.3';
  1038. PDF_BINARY_BLOB = '%'#$C3#$A4#$C3#$BC#$C3#$B6#$C3#$9F;
  1039. PDF_FILE_END = '%%EOF';
  1040. PDF_MAX_GEN_NUM = 65535;
  1041. PDF_UNICODE_HEADER = 'FEFF001B%s001B';
  1042. PDF_LANG_STRING = 'en';
  1043. PDF_NUMBER_MASK = '0.####';
  1044. { Info from http://www.papersizes.org/a-sizes-all-units.htm }
  1045. PDFPaperSizes : Array[TPDFPaperType,0..1] of Integer = (
  1046. // Height,Width (units in pixels (or Points))
  1047. (0,0), // ptCustom
  1048. (842,595), // ptA4
  1049. (595,420), // ptA5
  1050. (792,612), // ptLetter
  1051. (1008,612), // ptLegal
  1052. (756,522), // ptExecutive
  1053. (684,297), // ptComm10
  1054. (540,279), // ptMonarch
  1055. (624,312), // ptDL
  1056. (649,459), // ptC5
  1057. (709,499) // ptB5
  1058. );
  1059. PDFPaperPrintables : Array[TPDFPaperType,0..3] of Integer = (
  1060. // Top,Left,Right,Bottom (units in pixels)
  1061. (0,0,0,0), // ptCustom
  1062. (10,11,586,822), // ptA4
  1063. (10,11,407,588), // ptA5
  1064. (13,13,599,780), // ptLetter
  1065. (13,13,599,996), // ptLegal
  1066. (14,13,508,744), // ptExecutive
  1067. (13,13,284,672), // ptComm10
  1068. (13,13,266,528), // ptMonarch
  1069. (14,13,297,611), // ptDL
  1070. (13,13,446,637), // ptC5
  1071. (14,13,485,696) // ptB5
  1072. );
  1073. PageLayoutNames : Array[TPDFPageLayout] of String
  1074. = ('SinglePage','TwoColumnLeft','OneColumn');
  1075. // Helper procedures - made them global for unit testing purposes
  1076. procedure CompressStream(AFrom: TStream; ATo: TStream; ACompressLevel: TCompressionLevel = clDefault; ASkipHeader: boolean = False);
  1077. procedure CompressString(const AFrom: string; var ATo: string);
  1078. procedure DecompressStream(AFrom: TStream; ATo: TStream);
  1079. function mmToPDF(mm: single): TPDFFloat;
  1080. function PDFTomm(APixels : TPDFFloat) : Single;
  1081. function cmToPDF(cm: single): TPDFFloat;
  1082. function PDFtoCM(APixels: TPDFFloat): single;
  1083. function InchesToPDF(Inches: single): TPDFFloat;
  1084. function PDFtoInches(APixels: TPDFFloat): single;
  1085. function PDFCoord(x, y: TPDFFloat): TPDFCoord;
  1086. implementation
  1087. uses
  1088. math,
  1089. md5,
  1090. fpttf;
  1091. resourcestring
  1092. rsErrReportFontFileMissing = 'Font File "%s" does not exist.';
  1093. rsErrDictElementNotFound = 'Error: Dictionary element "%s" not found.';
  1094. rsErrInvalidSectionPage = 'Error: Invalid section page index.';
  1095. rsErrNoGlobalDict = 'Error: no global XRef named "%s".';
  1096. rsErrInvalidPageIndex = 'Invalid page index: %d';
  1097. rsErrInvalidAnnotIndex = 'Invalid annot index: %d';
  1098. rsErrNoFontDefined = 'No Font was set - please use SetFont() first.';
  1099. rsErrNoImageReader = 'Unsupported image format - no image reader available.';
  1100. rsErrUnknownStdFont = 'Unknown standard PDF font name <%s>.';
  1101. { Includes font metrics constant arrays for the standard PDF fonts. They are
  1102. not used at the moment, but in future we might want to do something with
  1103. them. }
  1104. {$I fontmetrics_stdpdf.inc }
  1105. type
  1106. // to get access to protected methods
  1107. TTTFFriendClass = class(TTFFileInfo)
  1108. end;
  1109. const
  1110. cInchToMM = 25.4;
  1111. cInchToCM = 2.54;
  1112. cDefaultDPI = 72;
  1113. // mm = (pixels * 25.4) / dpi
  1114. // pixels = (mm * dpi) / 25.4
  1115. // cm = ((pixels * 25.4) / dpi) / 10
  1116. // see http://paste.lisp.org/display/1105
  1117. BEZIER: single = 0.5522847498; // = 4/3 * (sqrt(2) - 1);
  1118. Var
  1119. PDFFormatSettings : TFormatSettings;
  1120. //Works correctly ony with Now (problem with DST depended on time)
  1121. //Is used only for CreationDate and it is usualy Now
  1122. function GetLocalTZD(ISO8601: Boolean): string;
  1123. var
  1124. i: Integer;
  1125. fmt: string;
  1126. begin
  1127. if ISO8601 then
  1128. fmt := '%.2d:%.2d'
  1129. else
  1130. fmt := '%.2d''%.2d''';
  1131. i := GetLocalTimeOffset; //min
  1132. if i < 0 then
  1133. Result := '+'
  1134. else if i = 0 then begin
  1135. Result := 'Z';
  1136. Exit;
  1137. end else
  1138. Result := '-';
  1139. i := Abs(i);
  1140. Result := Result + Format(fmt, [i div 60, i mod 60]);
  1141. end;
  1142. function DateToPdfDate(const ADate: TDateTime): string;
  1143. begin
  1144. Result:=FormatDateTime('"D:"yyyymmddhhnnss', ADate)+GetLocalTZD(False);
  1145. end;
  1146. function FormatPDFInt(const Value: integer; PadLen: integer): string;
  1147. begin
  1148. Result:=IntToStr(Value);
  1149. Dec(PadLen,Length(Result));
  1150. if PadLen>0 then
  1151. Result:=StringOfChar('0',Padlen)+Result;
  1152. end;
  1153. procedure CompressStream(AFrom: TStream; ATo: TStream; ACompressLevel: TCompressionLevel = clDefault; ASkipHeader: boolean = False);
  1154. var
  1155. c: TCompressionStream;
  1156. begin
  1157. if AFrom.Size = 0 then
  1158. begin
  1159. ATo.Size := 0;
  1160. Exit; //==>
  1161. end;
  1162. c := TCompressionStream.Create(ACompressLevel, ATo, ASkipHeader);
  1163. try
  1164. AFrom.Position := 0;
  1165. c.CopyFrom(AFrom, AFrom.Size);
  1166. //c.Flush; called in c.Free
  1167. finally
  1168. c.Free;
  1169. end;
  1170. end;
  1171. procedure CompressString(const AFrom: string; var ATo: string);
  1172. var
  1173. lStreamFrom : TStringStream;
  1174. lStreamTo : TStringStream;
  1175. begin
  1176. { TODO : Possible improvement would be to perform this compression directly on
  1177. the string as a buffer, and not go through the stream stage. }
  1178. lStreamFrom := TStringStream.Create(AFrom);
  1179. try
  1180. lStreamTo := TStringStream.Create('');
  1181. try
  1182. lStreamFrom.Position := 0;
  1183. lStreamTo.Size := 0;
  1184. CompressStream(lStreamFrom, lStreamTo);
  1185. ATo := lStreamTo.DataString;
  1186. finally
  1187. lStreamTo.Free;
  1188. end;
  1189. finally
  1190. lStreamFrom.Free;
  1191. end;
  1192. end;
  1193. procedure DecompressStream(AFrom: TStream; ATo: TStream);
  1194. {$IFDEF VER2_6}
  1195. {$DEFINE NOHEADERWORKADOUND}
  1196. {$ENDIF}
  1197. {$IFDEF VER3_0}
  1198. {$DEFINE NOHEADERWORKADOUND}
  1199. {$ENDIF}
  1200. Const
  1201. BufSize = 1024; // 1K
  1202. Type
  1203. TBuffer = Array[0..BufSize-1] of byte;
  1204. var
  1205. d: TDecompressionStream;
  1206. {$IFDEF NOHEADERWORKADOUND}
  1207. I: integer;
  1208. {$ENDIF}
  1209. Count : Integer;
  1210. Buffer : TBuffer;
  1211. begin
  1212. if AFrom.Size = 0 then
  1213. begin
  1214. ATo.Size := 0;
  1215. Exit; //==>
  1216. end;
  1217. FillMem(@Buffer, SizeOf(TBuffer), 0);
  1218. AFrom.Position := 0;
  1219. AFrom.Seek(0,soFromEnd);
  1220. {$IFDEF NOHEADERWORKADOUND}
  1221. // Work around a paszlib bug, FPC bugtracker 26827
  1222. I:=0;
  1223. AFrom.Write(I,SizeOf(I));
  1224. AFrom.Position:=0;
  1225. {$ENDIF}
  1226. D:=TDecompressionStream.Create(AFrom, False);
  1227. try
  1228. repeat
  1229. Count:=D.Read(Buffer,BufSize);
  1230. ATo.WriteBuffer(Buffer,Count);
  1231. until (Count<BufSize);
  1232. finally
  1233. d.Free;
  1234. end;
  1235. end;
  1236. function mmToPDF(mm: single): TPDFFloat;
  1237. begin
  1238. Result := mm * (cDefaultDPI / cInchToMM);
  1239. end;
  1240. function PDFTomm(APixels: TPDFFloat): Single;
  1241. begin
  1242. Result := (APixels * cInchToMM) / cDefaultDPI;
  1243. end;
  1244. function cmToPDF(cm: single): TPDFFloat;
  1245. begin
  1246. Result := cm *(cDefaultDPI / cInchToCM);
  1247. end;
  1248. function PDFtoCM(APixels: TPDFFloat): single;
  1249. begin
  1250. Result := (APixels * cInchToCM) / cDefaultDPI;
  1251. end;
  1252. function InchesToPDF(Inches: single): TPDFFloat;
  1253. begin
  1254. Result := Inches * cDefaultDPI;
  1255. end;
  1256. function PDFCoord(x, y: TPDFFloat): TPDFCoord;
  1257. begin
  1258. Result.x := x;
  1259. Result.y := y;
  1260. end;
  1261. function PDFtoInches(APixels: TPDFFloat): single;
  1262. begin
  1263. Result := APixels / cDefaultDPI;
  1264. end;
  1265. function XMLEscape(const Data: string): string;
  1266. var
  1267. iPos, i: Integer;
  1268. procedure Encode(const AStr: string);
  1269. begin
  1270. Move(AStr[1], result[iPos], Length(AStr) * SizeOf(Char));
  1271. Inc(iPos, Length(AStr));
  1272. end;
  1273. begin
  1274. SetLength(result, Length(Data) * 6);
  1275. iPos := 1;
  1276. for i := 1 to length(Data) do
  1277. case Data[i] of
  1278. '<': Encode('&lt;');
  1279. '>': Encode('&gt;');
  1280. '&': Encode('&amp;');
  1281. '"': Encode('&quot;');
  1282. else
  1283. result[iPos] := Data[i];
  1284. Inc(iPos);
  1285. end;
  1286. SetLength(result, iPos - 1);
  1287. end;
  1288. { TPDFMemoryStream }
  1289. procedure TPDFMemoryStream.Write(const AStream: TStream);
  1290. begin
  1291. FBuffer.Position := 0;
  1292. AStream.CopyFrom(FBuffer, FBuffer.Size);
  1293. end;
  1294. constructor TPDFMemoryStream.Create(const ADocument: TPDFDocument; AStream: TStream);
  1295. begin
  1296. FBuffer := TMemoryStream.Create;
  1297. FBuffer.LoadFromStream(AStream);
  1298. end;
  1299. destructor TPDFMemoryStream.Destroy;
  1300. begin
  1301. FreeAndNil(FBuffer);
  1302. inherited Destroy;
  1303. end;
  1304. { TXMPStream }
  1305. procedure TXMPStream.Write(const AStream: TStream);
  1306. procedure Add(const Tag, Value: string);
  1307. begin
  1308. WriteString('<'+Tag+'>', AStream);
  1309. WriteString(Value, AStream);
  1310. WriteString('</'+Tag+'>'+CRLF, AStream);
  1311. end;
  1312. function DateToISO8601Date(t: TDateTime): string;
  1313. begin
  1314. Result := FormatDateTime('yyyy-mm-dd"T"hh:nn:ss', t) + GetLocalTZD(True);
  1315. end;
  1316. var
  1317. i: integer;
  1318. const
  1319. NBSP: UnicodeChar = UnicodeChar($FEFF);
  1320. begin
  1321. WriteString('<?xpacket begin="'+UnicodeCharToString(@NBSP)+'" id="W5M0MpCehiHzreSzNTczkc9d"?>'+CRLF, AStream);
  1322. WriteString('<x:xmpmeta xmlns:x="adobe:ns:meta/">'+CRLF, AStream);
  1323. WriteString('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">'+CRLF, AStream);
  1324. WriteString('<rdf:Description rdf:about=""', AStream);
  1325. WriteString(' xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/"', AStream);
  1326. WriteString('>'+CRLF, AStream);
  1327. //PDF/A
  1328. Add('pdfaid:part', '1');
  1329. Add('pdfaid:conformance', 'B');
  1330. WriteString('</rdf:Description>'+CRLF, AStream);
  1331. WriteString('<rdf:Description rdf:about=""', AStream);
  1332. WriteString(' xmlns:pdf="http://ns.adobe.com/pdf/1.3/"', AStream);
  1333. WriteString('>'+CRLF, AStream);
  1334. Add('pdf:Producer', XMLEscape(Document.Infos.Producer));
  1335. if Document.Infos.Keywords <> '' then
  1336. Add('pdf:Keywords', XMLEscape(Document.Infos.Keywords));
  1337. WriteString('</rdf:Description>'+CRLF, AStream);
  1338. WriteString('<rdf:Description rdf:about=""', AStream);
  1339. WriteString(' xmlns:xmp="http://ns.adobe.com/xap/1.0/"', AStream);
  1340. WriteString('>'+CRLF, AStream);
  1341. if Document.Infos.ApplicationName <> '' then
  1342. Add('xmp:CreatorTool', XMLEscape(Document.Infos.ApplicationName));
  1343. if Document.Infos.CreationDate <> 0 then
  1344. Add('xmp:CreateDate', DateToISO8601Date(Document.Infos.CreationDate));
  1345. WriteString('</rdf:Description>'+CRLF, AStream);
  1346. if (Document.Infos.Title <> '') or (Document.Infos.Author <> '') then
  1347. begin
  1348. WriteString('<rdf:Description rdf:about=""', AStream);
  1349. WriteString(' xmlns:dc="http://purl.org/dc/elements/1.1/"', AStream);
  1350. WriteString('>'+CRLF, AStream);
  1351. if Document.Infos.Title <> '' then
  1352. Add('dc:title', '<rdf:Alt><rdf:li xml:lang="x-default">'+XMLEscape(Document.Infos.Title)+'</rdf:li></rdf:Alt>');
  1353. if Document.Infos.Author <> '' then
  1354. Add('dc:creator', '<rdf:Seq><rdf:li>'+ XMLEscape(Document.Infos.Author) + '</rdf:li></rdf:Seq>');
  1355. WriteString('</rdf:Description>'+CRLF, AStream);
  1356. end;
  1357. WriteString('</rdf:RDF>'+CRLF, AStream);
  1358. WriteString('</x:xmpmeta>'+CRLF, AStream);
  1359. //Recomended whitespace padding for inplace editing
  1360. for i := 1 to 21 do
  1361. WriteString(' '+CRLF, AStream);
  1362. WriteString('<?xpacket end="w"?>', AStream);
  1363. end;
  1364. { TPDFRawHexString }
  1365. procedure TPDFRawHexString.Write(const AStream: TStream);
  1366. begin
  1367. WriteString('<'+FValue+'>', AStream);
  1368. end;
  1369. constructor TPDFRawHexString.Create(const ADocument: TPDFDocument; const AValue: String);
  1370. begin
  1371. inherited Create(ADocument);
  1372. FValue := AValue;
  1373. end;
  1374. { TPDFMatrix }
  1375. function TPDFMatrix.Transform(APoint: TPDFCoord): TPDFCoord;
  1376. begin
  1377. Result.x := _00 * APoint.x + _20;
  1378. Result.y := _11 * APoint.y + _21;
  1379. end;
  1380. function TPDFMatrix.Transform(X, Y: TPDFFloat): TPDFCoord;
  1381. begin
  1382. Result.x := _00 * X + _20;
  1383. Result.y := _11 * Y + _21;
  1384. end;
  1385. function TPDFMatrix.ReverseTransform(APoint: TPDFCoord): TPDFCoord;
  1386. begin
  1387. Result.x := (APoint.x - _20) / _00;
  1388. Result.y := (APoint.y - _21) / _11;
  1389. end;
  1390. procedure TPDFMatrix.SetXScalation(const AValue: TPDFFloat);
  1391. begin
  1392. _00 := AValue;
  1393. end;
  1394. procedure TPDFMatrix.SetYScalation(const AValue: TPDFFloat);
  1395. begin
  1396. _11 := AValue;
  1397. end;
  1398. procedure TPDFMatrix.SetXTranslation(const AValue: TPDFFloat);
  1399. begin
  1400. _20 := AValue;
  1401. end;
  1402. procedure TPDFMatrix.SetYTranslation(const AValue: TPDFFloat);
  1403. begin
  1404. _21 := AValue;
  1405. end;
  1406. { TPDFFont }
  1407. procedure TPDFFont.PrepareTextMapping;
  1408. begin
  1409. if FFontFilename <> '' then
  1410. begin
  1411. // only create objects when needed
  1412. FTextMappingList := TTextMappingList.Create;
  1413. FTrueTypeFile := TTFFileInfo.Create;
  1414. FTrueTypeFile.LoadFromFile(FFontFilename);
  1415. FTrueTypeFile.PrepareFontDefinition('cp1252', True);
  1416. end;
  1417. end;
  1418. procedure TPDFFont.SetFontFilename(AValue: string);
  1419. begin
  1420. if FFontFilename = AValue then
  1421. Exit;
  1422. FFontFilename := AValue;
  1423. PrepareTextMapping;
  1424. end;
  1425. procedure TPDFFont.GenerateSubsetFont;
  1426. var
  1427. f: TFontSubsetter;
  1428. {$ifdef gdebug}
  1429. fs: TFileStream;
  1430. {$endif}
  1431. begin
  1432. if Assigned(FSubsetFont) then
  1433. FreeAndNil(FSubSetFont);
  1434. f := TFontSubsetter.Create(FTrueTypeFile, FTextMappingList);
  1435. try
  1436. FSubSetFont := TMemoryStream.Create;
  1437. f.SaveToStream(FSubsetFont);
  1438. {$ifdef gdebug}
  1439. fs := TFileStream.Create(FTrueTypeFile.PostScriptName + '-subset.ttf', fmCreate);
  1440. FSubSetFont.Position := 0;
  1441. TMemoryStream(FSubsetFont).SaveToStream(fs);
  1442. fs.Free;
  1443. {$endif}
  1444. finally
  1445. f.Free;
  1446. end;
  1447. end;
  1448. constructor TPDFFont.Create(ACollection: TCollection);
  1449. begin
  1450. inherited Create(ACollection);
  1451. FSubsetFont := nil;
  1452. end;
  1453. destructor TPDFFont.Destroy;
  1454. begin
  1455. FTextMappingList.Free;
  1456. FTrueTypeFile.Free;
  1457. FSubSetFont.Free;
  1458. inherited Destroy;
  1459. end;
  1460. function TPDFFont.GetGlyphIndices(const AText: UnicodeString): AnsiString;
  1461. var
  1462. i: integer;
  1463. c: word;
  1464. n: integer;
  1465. begin
  1466. Result := '';
  1467. if Length(AText) = 0 then
  1468. Exit;
  1469. for i := 1 to Length(AText) do
  1470. begin
  1471. c := Word(AText[i]);
  1472. for n := 0 to FTextMappingList.Count-1 do
  1473. begin
  1474. if FTextMappingList[n].CharID = c then
  1475. begin
  1476. result := Result + IntToHex(FTextMappingList[n].GlyphID, 4);
  1477. break;
  1478. end;
  1479. end;
  1480. end;
  1481. end;
  1482. procedure TPDFFont.AddTextToMappingList(const AText: UnicodeString);
  1483. var
  1484. i: integer;
  1485. c: uint16; // Unicode codepoint
  1486. gid: uint16;
  1487. begin
  1488. if AText = '' then
  1489. Exit;
  1490. for i := 1 to Length(AText) do
  1491. begin
  1492. c := uint16(AText[i]);
  1493. gid := FTrueTypeFile.GetGlyphIndex(c);
  1494. FTextMappingList.Add(c, gid);
  1495. end;
  1496. end;
  1497. { TPDFTrueTypeCharWidths }
  1498. // TODO: (optional improvement) CID -> Unicode mappings, use ranges to generate a smaller CMap
  1499. // See pdfbox's writeTo() method in ToUnicodeWriter.java
  1500. procedure TPDFTrueTypeCharWidths.Write(const AStream: TStream);
  1501. var
  1502. i: integer;
  1503. s: string;
  1504. lst: TTextMappingList;
  1505. lFont: TTFFileInfo;
  1506. lWidthIndex: integer;
  1507. begin
  1508. s := '';
  1509. lst := Document.Fonts[EmbeddedFontNum].TextMapping;
  1510. lst.Sort;
  1511. lFont := Document.Fonts[EmbeddedFontNum].FTrueTypeFile;
  1512. {$IFDEF gdebug}
  1513. System.WriteLn('****** isFixedPitch = ', BoolToStr(lFont.PostScript.isFixedPitch > 0, True));
  1514. System.WriteLn('****** Head.UnitsPerEm := ', lFont.Head.UnitsPerEm );
  1515. System.WriteLn('****** HHead.numberOfHMetrics := ', lFont.HHead.numberOfHMetrics );
  1516. {$ENDIF}
  1517. { NOTE: Monospaced fonts may not have a width for every glyph
  1518. the last one is for subsequent glyphs. }
  1519. for i := 0 to lst.Count-1 do
  1520. begin
  1521. if lst[i].GlyphID < lFont.HHead.numberOfHMetrics then
  1522. lWidthIndex := lst[i].GlyphID
  1523. else
  1524. lWidthIndex := lFont.HHead.numberOfHMetrics-1;
  1525. s := s + Format(' %d [%d]', [lst[i].GlyphID, TTTFFriendClass(lFont).ToNatural(lFont.Widths[lWidthIndex].AdvanceWidth)])
  1526. end;
  1527. WriteString(s, AStream);
  1528. end;
  1529. constructor TPDFTrueTypeCharWidths.Create(const ADocument: TPDFDocument; const AEmbeddedFontNum: integer);
  1530. begin
  1531. inherited Create(ADocument);
  1532. FEmbeddedFontNum := AEmbeddedFontNum;
  1533. end;
  1534. { TPDFMoveTo }
  1535. class function TPDFMoveTo.Command(APos: TPDFCoord): String;
  1536. begin
  1537. Result:=Command(APos.X,APos.Y);
  1538. end;
  1539. class function TPDFMoveTo.Command(AX, AY: TPDFFloat): String;
  1540. begin
  1541. Result:=FloatStr(AX)+' '+FloatStr(AY)+' m'+CRLF;
  1542. end;
  1543. procedure TPDFMoveTo.Write(const AStream: TStream);
  1544. begin
  1545. WriteString(Command(FPos),AStream);
  1546. end;
  1547. constructor TPDFMoveTo.Create(const ADocument: TPDFDocument; const AX,
  1548. AY: TPDFFloat);
  1549. begin
  1550. Inherited Create(ADocument);
  1551. FPos.X:=AX;
  1552. FPos.Y:=AY;
  1553. end;
  1554. constructor TPDFMoveTo.Create(const ADocument: TPDFDocument;
  1555. const APos: TPDFCoord);
  1556. begin
  1557. Inherited Create(ADocument);
  1558. FPos:=APos;
  1559. end;
  1560. { TPDFResetPath }
  1561. procedure TPDFResetPath.Write(const AStream: TStream);
  1562. begin
  1563. WriteString(Command, AStream);
  1564. end;
  1565. class function TPDFResetPath.Command: string;
  1566. begin
  1567. Result := 'n' + CRLF;
  1568. end;
  1569. { TPDFClosePath }
  1570. procedure TPDFClosePath.Write(const AStream: TStream);
  1571. begin
  1572. WriteString(Command, AStream);
  1573. end;
  1574. class function TPDFClosePath.Command: string;
  1575. begin
  1576. Result := 'h' + CRLF;
  1577. end;
  1578. { TPDFStrokePath }
  1579. procedure TPDFStrokePath.Write(const AStream: TStream);
  1580. begin
  1581. WriteString(Command, AStream);
  1582. end;
  1583. class function TPDFStrokePath.Command: string;
  1584. begin
  1585. Result := 'S' + CRLF;
  1586. end;
  1587. { TPDFClipPath }
  1588. procedure TPDFClipPath.Write(const AStream: TStream);
  1589. begin
  1590. WriteString(Command, AStream);
  1591. end;
  1592. class function TPDFClipPath.Command: string;
  1593. begin
  1594. Result := 'W n' + CRLF;
  1595. end;
  1596. { TPDFPushGraphicsStack }
  1597. procedure TPDFPushGraphicsStack.Write(const AStream: TStream);
  1598. begin
  1599. WriteString(Command, AStream);
  1600. end;
  1601. class function TPDFPushGraphicsStack.Command: string;
  1602. begin
  1603. Result := 'q'+CRLF;
  1604. end;
  1605. { TPDFPopGraphicsStack }
  1606. procedure TPDFPopGraphicsStack.Write(const AStream: TStream);
  1607. begin
  1608. WriteString(Command, AStream);
  1609. // disable cache
  1610. Self.Document.CurrentWidth:='';
  1611. Self.Document.CurrentColor:='';
  1612. end;
  1613. class function TPDFPopGraphicsStack.Command: string;
  1614. begin
  1615. Result := 'Q' + CRLF;
  1616. end;
  1617. { TPDFEllipse }
  1618. procedure TPDFEllipse.Write(const AStream: TStream);
  1619. Var
  1620. X,Y,W2,H2,WS,HS : TPDFFloat;
  1621. begin
  1622. if FStroke then
  1623. SetWidth(FLineWidth, AStream);
  1624. X:=FCenter.X;
  1625. Y:=FCenter.Y;
  1626. W2:=FDimensions.X/2;
  1627. H2:=FDimensions.Y/2;
  1628. WS:=W2*BEZIER;
  1629. HS:=H2*BEZIER;
  1630. // Starting point
  1631. WriteString(TPDFMoveTo.Command(X,Y+H2),AStream);
  1632. WriteString(TPDFCurveC.Command(X, Y+H2-HS, X+W2-WS, Y, X+W2, Y),AStream);
  1633. WriteString(TPDFCurveC.Command(X+W2+WS, Y, X+W2*2, Y+H2-HS, X+W2*2, Y+H2),AStream);
  1634. WriteString(TPDFCurveC.Command(X+W2*2, Y+H2+HS, X+W2+WS, Y+H2*2, X+W2, Y+H2*2),AStream);
  1635. WriteString(TPDFCurveC.Command(X+W2-WS, Y+H2*2, X, Y+H2+HS, X, Y+H2),AStream);
  1636. if FStroke and FFill then
  1637. WriteString('b'+CRLF, AStream)
  1638. else if FFill then
  1639. WriteString('f'+CRLF, AStream)
  1640. else if FStroke then
  1641. WriteString('S'+CRLF, AStream);
  1642. (*
  1643. // should we default to this if no stroking or filling is required?
  1644. else
  1645. WriteString('n'+CRLF, AStream); // see PDF 1.3 Specification document on page 152
  1646. *)
  1647. end;
  1648. constructor TPDFEllipse.Create(const ADocument: TPDFDocument; const APosX, APosY, AWidth, AHeight,
  1649. ALineWidth: TPDFFloat; const AFill: Boolean; AStroke: Boolean);
  1650. begin
  1651. Inherited Create(ADocument);
  1652. FLineWidth:=ALineWidth;
  1653. FCenter.X:=APosX;
  1654. FCenter.Y:=APosY;
  1655. FDimensions.X:=AWidth;
  1656. FDimensions.Y:=AHeight;
  1657. FFill:=AFill;
  1658. FStroke:=AStroke;
  1659. end;
  1660. { TPDFCurveY }
  1661. procedure TPDFCurveY.Write(const AStream: TStream);
  1662. begin
  1663. if FStroke then
  1664. SetWidth(FWidth,AStream);
  1665. WriteString(FloatStr(FP1.X)+' '+FloatStr(FP1.Y)+' '+
  1666. FloatStr(FP3.X)+' '+FloatStr(FP3.Y)+' y'+CRLF,AStream);
  1667. if FStroke then
  1668. WriteString('S'+CRLF, AStream);
  1669. end;
  1670. constructor TPDFCurveY.Create(const ADocument: TPDFDocument; const X1, Y1, X3,
  1671. Y3, AWidth: TPDFFloat; AStroke: Boolean);
  1672. begin
  1673. Inherited Create(ADocument);
  1674. FP1.X:=X1;
  1675. FP1.Y:=Y1;
  1676. FP3.X:=X3;
  1677. FP3.Y:=Y3;
  1678. FWidth:=AWidth;
  1679. FStroke:=AStroke;
  1680. end;
  1681. constructor TPDFCurveY.Create(const ADocument: TPDFDocument; const AP1,
  1682. AP3: TPDFCoord; AWidth: TPDFFloat; AStroke: Boolean);
  1683. begin
  1684. Inherited Create(ADocument);
  1685. FP1:=AP1;
  1686. FP3:=AP3;
  1687. FWidth:=AWidth;
  1688. FStroke:=AStroke;
  1689. end;
  1690. { TPDFCurveV }
  1691. procedure TPDFCurveV.Write(const AStream: TStream);
  1692. begin
  1693. if FStroke then
  1694. SetWidth(FWidth,AStream);
  1695. WriteString(FloatStr(FP2.X)+' '+FloatStr(FP2.Y)+' '+
  1696. FloatStr(FP3.X)+' '+FloatStr(FP3.Y)+' v'+CRLF,AStream);
  1697. if FStroke then
  1698. WriteString('S'+CRLF, AStream);
  1699. end;
  1700. constructor TPDFCurveV.Create(const ADocument: TPDFDocument; const X2, Y2, X3,
  1701. Y3, AWidth: TPDFFloat;AStroke: Boolean = True);
  1702. begin
  1703. Inherited Create(ADocument);
  1704. FP2.X:=X2;
  1705. FP2.Y:=Y2;
  1706. FP3.X:=X3;
  1707. FP3.Y:=Y3;
  1708. FWidth:=AWidth;
  1709. FStroke:=AStroke;
  1710. end;
  1711. constructor TPDFCurveV.Create(const ADocument: TPDFDocument; const AP2,
  1712. AP3: TPDFCoord; AWidth: TPDFFloat;AStroke: Boolean = True);
  1713. begin
  1714. Inherited Create(ADocument);
  1715. FP2:=AP2;
  1716. FP3:=AP3;
  1717. FWidth:=AWidth;
  1718. FStroke:=AStroke;
  1719. end;
  1720. { TPDFCurveC }
  1721. class function TPDFCurveC.Command(const xCtrl1, yCtrl1, xCtrl2, yCtrl2, xTo, yTo: TPDFFloat): String;
  1722. begin
  1723. Result:=FloatStr(xCtrl1)+' '+FloatStr(yCtrl1)+' '+
  1724. FloatStr(xCtrl2)+' '+FloatStr(yCtrl2)+' '+
  1725. FloatStr(xTo)+' '+FloatStr(yTo)+' c'+CRLF
  1726. end;
  1727. class function TPDFCurveC.Command(const ACtrl1, ACtrl2, ATo3: TPDFCoord): String;
  1728. begin
  1729. Result := Command(ACtrl1.X, ACtrl1.Y, ACtrl2.X, ACtrl2.Y, ATo3.X, ATo3.Y);
  1730. end;
  1731. procedure TPDFCurveC.Write(const AStream: TStream);
  1732. begin
  1733. if FStroke then
  1734. SetWidth(FWidth, AStream);
  1735. WriteString(Command(FCtrl1, FCtrl2, FTo), AStream);
  1736. if FStroke then
  1737. WriteString('S'+CRLF, AStream);
  1738. end;
  1739. constructor TPDFCurveC.Create(const ADocument: TPDFDocument; const xCtrl1, yCtrl1, xCtrl2, yCtrl2, xTo, yTo,
  1740. AWidth: TPDFFloat; AStroke: Boolean);
  1741. begin
  1742. Inherited Create(ADocument);
  1743. FCtrl1.X := xCtrl1;
  1744. FCtrl1.Y := yCtrl1;
  1745. FCtrl2.X := xCtrl2;
  1746. FCtrl2.Y := yCtrl2;
  1747. FTo.X := xTo;
  1748. FTo.Y := yTo;
  1749. FWidth := AWidth;
  1750. FStroke := AStroke;
  1751. end;
  1752. constructor TPDFCurveC.Create(const ADocument: TPDFDocument; const ACtrl1, ACtrl2, ATo3: TPDFCoord;
  1753. AWidth: TPDFFloat; AStroke: Boolean);
  1754. begin
  1755. Inherited Create(ADocument);
  1756. FCtrl1 := ACtrl1;
  1757. FCtrl2 := ACtrl2;
  1758. FTo := ATo3;
  1759. FWidth := AWidth;
  1760. FStroke := AStroke;
  1761. end;
  1762. { TPDFLineStyleDef }
  1763. Procedure TPDFLineStyleDef.Assign(Source : TPersistent);
  1764. Var
  1765. L : TPDFLineStyleDef;
  1766. begin
  1767. if Source is TPDFLineStyleDef then
  1768. begin
  1769. L:=Source as TPDFLineStyleDef;
  1770. LineWidth:=L.LineWidth;
  1771. Color:=L.Color;
  1772. PenStyle:=L.PenStyle;
  1773. end
  1774. else
  1775. Inherited;
  1776. end;
  1777. { TPDFLineStyleDefs }
  1778. function TPDFLineStyleDefs.GetI(AIndex : Integer): TPDFLineStyleDef;
  1779. begin
  1780. Result:=TPDFLineStyleDef(Items[AIndex]);
  1781. end;
  1782. function TPDFLineStyleDefs.AddLineStyleDef: TPDFLineStyleDef;
  1783. begin
  1784. Result:=Add as TPDFLineStyleDef;
  1785. end;
  1786. { TPDFPages }
  1787. function TPDFPages.GetP(AIndex : Integer): TPDFPage;
  1788. begin
  1789. if Assigned(Flist) then
  1790. Result:=TPDFPage(FList[Aindex])
  1791. else
  1792. Raise EListError.CreateFmt(rsErrInvalidPageIndex,[AIndex]);
  1793. end;
  1794. function TPDFPages.GetPageCount: integer;
  1795. begin
  1796. result := FList.Count;
  1797. end;
  1798. constructor TPDFPages.Create(const ADocument: TPDFDocument);
  1799. begin
  1800. inherited Create(ADocument);
  1801. FPageClass := TPDFPage;
  1802. end;
  1803. destructor TPDFPages.Destroy;
  1804. begin
  1805. FreeAndNil(FList);
  1806. inherited Destroy;
  1807. end;
  1808. function TPDFPages.AddPage: TPDFPage;
  1809. begin
  1810. if (FList=Nil) then
  1811. FList:=TFPObjectList.Create;
  1812. Result := PageClass.Create(Document);
  1813. FList.Add(Result);
  1814. end;
  1815. procedure TPDFPages.Add(APage: TPDFPage);
  1816. begin
  1817. if (FList = nil) then
  1818. FList := TFPObjectList.Create;
  1819. FList.Add(APage);
  1820. end;
  1821. { TPDFAnnot }
  1822. constructor TPDFAnnot.Create(const ADocument: TPDFDocument);
  1823. begin
  1824. inherited Create(ADocument);
  1825. end;
  1826. constructor TPDFAnnot.Create(const ADocument: TPDFDocument; const ALeft, ABottom, AWidth, AHeight: TPDFFloat;
  1827. const AURI: String; const ABorder: Boolean);
  1828. begin
  1829. Create(ADocument);
  1830. FLeft := ALeft;
  1831. FBottom := ABottom;
  1832. FWidth := AWidth;
  1833. FHeight := AHeight;
  1834. FURI := AURI;
  1835. FBorder := ABorder;
  1836. end;
  1837. { TPDFAnnotList }
  1838. procedure TPDFAnnotList.CheckList;
  1839. begin
  1840. if (FList = nil) then
  1841. FList := TFPObjectList.Create;
  1842. end;
  1843. function TPDFAnnotList.GetAnnot(AIndex: integer): TPDFAnnot;
  1844. begin
  1845. if Assigned(FList) then
  1846. Result := TPDFAnnot(FList[AIndex])
  1847. else
  1848. raise EListError.CreateFmt(rsErrInvalidAnnotIndex, [AIndex]);
  1849. end;
  1850. destructor TPDFAnnotList.Destroy;
  1851. begin
  1852. FreeAndNil(FList);
  1853. inherited Destroy;
  1854. end;
  1855. function TPDFAnnotList.AddAnnot: TPDFAnnot;
  1856. begin
  1857. CheckList;
  1858. Result := TPDFAnnot.Create(Document);
  1859. FList.Add(Result);
  1860. end;
  1861. function TPDFAnnotList.Count: integer;
  1862. begin
  1863. if Assigned(FList) then
  1864. result := FList.Count
  1865. else
  1866. result := 0;
  1867. end;
  1868. procedure TPDFAnnotList.Add(AAnnot: TPDFAnnot);
  1869. begin
  1870. CheckList;
  1871. FList.Add(AAnnot);
  1872. end;
  1873. { TPDFPage }
  1874. function TPDFPage.GetO(AIndex : Integer): TPDFObject;
  1875. begin
  1876. Result:=TPDFObject(FObjects[AIndex]);
  1877. end;
  1878. function TPDFPage.GetObjectCount: Integer;
  1879. begin
  1880. if FObjects=Nil then
  1881. Result:=0
  1882. else
  1883. Result:=FObjects.Count;
  1884. end;
  1885. function TPDFPage.CreateAnnotList: TPDFAnnotList;
  1886. begin
  1887. result := TPDFAnnotList.Create(Document);
  1888. end;
  1889. procedure TPDFPage.SetOrientation(AValue: TPDFPaperOrientation);
  1890. begin
  1891. if FOrientation=AValue then Exit;
  1892. FOrientation:=AValue;
  1893. CalcPaperSize;
  1894. AdjustMatrix;
  1895. end;
  1896. procedure TPDFPage.CalcPaperSize;
  1897. var
  1898. PP: TPDFPaper;
  1899. O1, O2: Integer;
  1900. begin
  1901. if PaperType = ptCustom then
  1902. Exit;
  1903. O1 := 0;
  1904. O2 := 1;
  1905. if Orientation = ppoLandScape then
  1906. begin
  1907. O1 := 1;
  1908. O2 := 0;
  1909. end;
  1910. PP.H:=PDFPaperSizes[PaperType][O1];
  1911. PP.W:=PDFPaperSizes[PaperType][O2];
  1912. PP.Printable.T:=PDFPaperPrintables[PaperType][O1];
  1913. PP.Printable.L:=PDFPaperPrintables[PaperType][O2];
  1914. PP.Printable.R:=PDFPaperPrintables[PaperType][2+O1];
  1915. PP.Printable.B:=PDFPaperPrintables[PaperType][2+O2];
  1916. Paper:=PP;
  1917. end;
  1918. procedure TPDFPage.SetPaperType(AValue: TPDFPaperType);
  1919. begin
  1920. if FPaperType=AValue then Exit;
  1921. FPaperType:=AValue;
  1922. CalcPaperSize;
  1923. AdjustMatrix;
  1924. end;
  1925. procedure TPDFPage.AddTextToLookupLists(AText: UTF8String);
  1926. var
  1927. str: UnicodeString;
  1928. begin
  1929. if AText = '' then
  1930. Exit;
  1931. str := UTF8Decode(AText);
  1932. Document.Fonts[FLastFont.FontIndex].AddTextToMappingList(str);
  1933. end;
  1934. procedure TPDFPage.DoUnitConversion(var APoint: TPDFCoord);
  1935. begin
  1936. case FUnitOfMeasure of
  1937. uomMillimeters:
  1938. begin
  1939. APoint.X := mmToPDF(APoint.X);
  1940. APoint.Y := mmToPDF(APoint.Y);
  1941. end;
  1942. uomCentimeters:
  1943. begin
  1944. APoint.X := cmToPDF(APoint.X);
  1945. APoint.Y := cmToPDF(APoint.Y);
  1946. end;
  1947. uomInches:
  1948. begin
  1949. APoint.X := InchesToPDF(APoint.X);
  1950. APoint.Y := InchesToPDF(APoint.Y);
  1951. end;
  1952. end;
  1953. end;
  1954. procedure TPDFPage.CreateStdFontText(X, Y: TPDFFloat; AText: AnsiString; const AFont: TPDFEmbeddedFont;
  1955. const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean);
  1956. var
  1957. T: TPDFText;
  1958. begin
  1959. T := Document.CreateText(X, Y, AText, AFont, ADegrees, AUnderline, AStrikeThrough);
  1960. AddObject(T);
  1961. end;
  1962. procedure TPDFPage.CreateTTFFontText(X, Y: TPDFFloat; AText: UTF8String; const AFont: TPDFEmbeddedFont;
  1963. const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean);
  1964. var
  1965. T: TPDFUTF8Text;
  1966. begin
  1967. AddTextToLookupLists(AText);
  1968. T := Document.CreateText(X, Y, AText, AFont, ADegrees, AUnderline, AStrikeThrough);
  1969. AddObject(T);
  1970. end;
  1971. procedure TPDFPage.SetUnitOfMeasure(AValue: TPDFUnitOfMeasure);
  1972. begin
  1973. if FUnitOfMeasure = AValue then
  1974. Exit;
  1975. FUnitOfMeasure := AValue;
  1976. AdjustMatrix;
  1977. end;
  1978. procedure TPDFPage.AdjustMatrix;
  1979. begin
  1980. if poPageOriginAtTop in Document.Options then
  1981. begin
  1982. FMatrix._11 := -1;
  1983. FMatrix._21 := GetPaperHeight;
  1984. end
  1985. else
  1986. begin
  1987. FMatrix._11 := 1;
  1988. FMatrix._21 := 0;
  1989. end;
  1990. end;
  1991. constructor TPDFPage.Create(const ADocument: TPDFDocument);
  1992. begin
  1993. inherited Create(ADocument);
  1994. FLastFont := nil;
  1995. FLastFontColor := clBlack;
  1996. FPaperType := ptA4;
  1997. FUnitOfMeasure := uomMillimeters;
  1998. CalcPaperSize;
  1999. If Assigned(ADocument) then
  2000. begin
  2001. PaperType := ADocument.DefaultPaperType;
  2002. Orientation := ADocument.DefaultOrientation;
  2003. FUnitOfMeasure:=ADocument.DefaultUnitOfMeasure;
  2004. end;
  2005. FMatrix._00 := 1;
  2006. FMatrix._20 := 0;
  2007. AdjustMatrix;
  2008. FAnnots := CreateAnnotList;
  2009. end;
  2010. destructor TPDFPage.Destroy;
  2011. begin
  2012. FreeAndNil(FObjects);
  2013. FreeAndNil(FAnnots);
  2014. inherited Destroy;
  2015. end;
  2016. procedure TPDFPage.AddObject(AObject: TPDFObject);
  2017. begin
  2018. if FObjects=Nil then
  2019. FObjects:=TObjectList.Create;
  2020. FObjects.Add(AObject);
  2021. end;
  2022. procedure TPDFPage.SetFont(AFontIndex: Integer; AFontSize: Integer);
  2023. Var
  2024. F : TPDFEmbeddedFont;
  2025. begin
  2026. F:=Document.CreateEmbeddedFont(self, AFontIndex, AFontSize);
  2027. AddObject(F);
  2028. FLastFont := F;
  2029. end;
  2030. procedure TPDFPage.SetColor(AColor: TARGBColor; AStroke : Boolean = True);
  2031. Var
  2032. C : TPDFColor;
  2033. begin
  2034. C:=Document.CreateColor(AColor,AStroke);
  2035. if not AStroke then
  2036. FLastFontColor := AColor;
  2037. AddObject(C);
  2038. end;
  2039. procedure TPDFPage.SetPenStyle(AStyle: TPDFPenStyle; const ALineWidth: TPDFFloat);
  2040. Var
  2041. L : TPDFLineStyle;
  2042. begin
  2043. L:=Document.CreateLineStyle(AStyle, ALineWidth);
  2044. AddObject(L);
  2045. end;
  2046. procedure TPDFPage.SetLineStyle(AIndex: Integer; AStroke : Boolean = True);
  2047. begin
  2048. SetLineStyle(Document.LineStyles[Aindex],AStroke);
  2049. end;
  2050. procedure TPDFPage.SetLineStyle(S: TPDFLineStyleDef; AStroke: Boolean = True);
  2051. begin
  2052. SetColor(S.Color,AStroke);
  2053. SetPenStyle(S.PenStyle,S.LineWidth);
  2054. end;
  2055. procedure TPDFPage.WriteText(X, Y: TPDFFloat; AText: UTF8String; const ADegrees: single;
  2056. const AUnderline: boolean; const AStrikethrough: boolean);
  2057. var
  2058. p: TPDFCoord;
  2059. begin
  2060. if not Assigned(FLastFont) then
  2061. raise EPDF.Create(rsErrNoFontDefined);
  2062. p := Matrix.Transform(X, Y);
  2063. DoUnitConversion(p);
  2064. if Document.Fonts[FLastFont.FontIndex].IsStdFont then
  2065. CreateStdFontText(p.X, p.Y, AText, FLastFont, ADegrees, AUnderline, AStrikeThrough)
  2066. else
  2067. CreateTTFFontText(p.X, p.Y, AText, FLastFont, ADegrees, AUnderline, AStrikeThrough);
  2068. end;
  2069. procedure TPDFPage.WriteText(APos: TPDFCoord; AText: UTF8String; const ADegrees: single;
  2070. const AUnderline: boolean; const AStrikethrough: boolean);
  2071. begin
  2072. WriteText(APos.X, APos.Y, AText, ADegrees, AUnderline, AStrikeThrough);
  2073. end;
  2074. procedure TPDFPage.DrawLine(X1, Y1, X2, Y2, ALineWidth: TPDFFloat; const AStroke: Boolean = True);
  2075. var
  2076. L : TPDFLineSegment;
  2077. p1, p2: TPDFCoord;
  2078. begin
  2079. p1 := Matrix.Transform(X1, Y1);
  2080. p2 := Matrix.Transform(X2, Y2);
  2081. DoUnitConversion(p1);
  2082. DoUnitConversion(p2);
  2083. L := TPDFLineSegment.Create(Document, ALineWidth, p1.X, p1.Y, p2.X, p2.Y, AStroke);
  2084. AddObject(L);
  2085. end;
  2086. procedure TPDFPage.DrawLine(APos1, APos2: TPDFCoord; ALineWidth: TPDFFloat;
  2087. const AStroke: Boolean);
  2088. begin
  2089. DrawLine(APos1.X, APos1.Y, APos2.X, APos2.Y, ALineWidth, AStroke);
  2090. end;
  2091. procedure TPDFPage.DrawLineStyle(X1, Y1, X2, Y2: TPDFFloat; AStyle: Integer);
  2092. var
  2093. S: TPDFLineStyleDef;
  2094. begin
  2095. S := Document.LineStyles[AStyle];
  2096. SetLineStyle(S);
  2097. DrawLine(X1, Y1, X2, Y2, S.LineWidth);
  2098. end;
  2099. procedure TPDFPage.DrawLineStyle(APos1, APos2: TPDFCoord; AStyle: Integer);
  2100. begin
  2101. DrawLineStyle(APos1.X, APos1.Y, APos2.X, APos2.Y, AStyle);
  2102. end;
  2103. procedure TPDFPage.DrawRect(const X, Y, W, H, ALineWidth: TPDFFloat; const AFill, AStroke: Boolean;
  2104. const ADegrees: single);
  2105. var
  2106. R: TPDFRectangle;
  2107. p1, p2: TPDFCoord;
  2108. t1, t2, t3: string;
  2109. rad: single;
  2110. begin
  2111. p1 := Matrix.Transform(X, Y);
  2112. DoUnitConversion(p1);
  2113. p2.X := W;
  2114. p2.Y := H;
  2115. DoUnitConversion(p2);
  2116. if ADegrees <> 0.0 then
  2117. begin
  2118. rad := DegToRad(-ADegrees);
  2119. t1 := FormatFloat(PDF_NUMBER_MASK, Cos(rad), PDFFormatSettings);
  2120. t2 := FormatFloat(PDF_NUMBER_MASK, -Sin(rad), PDFFormatSettings);
  2121. t3 := FormatFloat(PDF_NUMBER_MASK, Sin(rad), PDFFormatSettings);
  2122. AddObject(TPDFPushGraphicsStack.Create(Document));
  2123. // PDF v1.3 page 132 & 143
  2124. AddObject(TPDFFreeFormString.Create(Document, Format('%s %s %s %s %.4f %.4f cm',
  2125. [t1, t2, t3, t1, p1.X, p1.Y], PDFFormatSettings) + CRLF));
  2126. // co-ordinates are now based on the newly transformed matrix co-ordinates.
  2127. R := Document.CreateRectangle(0, 0, p2.X, p2.Y, ALineWidth, AFill, AStroke);
  2128. end
  2129. else
  2130. R := Document.CreateRectangle(p1.X, p1.Y, p2.X, p2.Y, ALineWidth, AFill, AStroke);
  2131. AddObject(R);
  2132. if ADegrees <> 0.0 then
  2133. AddObject(TPDFPopGraphicsStack.Create(Document));
  2134. end;
  2135. procedure TPDFPage.DrawRect(const APos: TPDFCoord; const W, H, ALineWidth: TPDFFloat; const AFill, AStroke: Boolean;
  2136. const ADegrees: single);
  2137. begin
  2138. DrawRect(APos.X, APos.Y, W, H, ALineWidth, AFill, AStroke, ADegrees);
  2139. end;
  2140. procedure TPDFPage.DrawRoundedRect(const X, Y, W, H, ARadius, ALineWidth: TPDFFloat; const AFill, AStroke: Boolean;
  2141. const ADegrees: single);
  2142. var
  2143. R: TPDFRoundedRectangle;
  2144. p1, p2, p3: TPDFCoord;
  2145. t1, t2, t3: string;
  2146. rad: single;
  2147. begin
  2148. p1 := Matrix.Transform(X, Y);
  2149. DoUnitConversion(p1);
  2150. p2.X := W;
  2151. p2.Y := H;
  2152. DoUnitConversion(p2);
  2153. p3.X := ARadius;
  2154. p3.Y := 0;
  2155. DoUnitConversion(p3);
  2156. if ADegrees <> 0.0 then
  2157. begin
  2158. rad := DegToRad(-ADegrees);
  2159. t1 := FormatFloat(PDF_NUMBER_MASK, Cos(rad), PDFFormatSettings);
  2160. t2 := FormatFloat(PDF_NUMBER_MASK, -Sin(rad), PDFFormatSettings);
  2161. t3 := FormatFloat(PDF_NUMBER_MASK, Sin(rad), PDFFormatSettings);
  2162. AddObject(TPDFPushGraphicsStack.Create(Document));
  2163. // PDF v1.3 page 132 & 143
  2164. AddObject(TPDFFreeFormString.Create(Document, Format('%s %s %s %s %.4f %.4f cm',
  2165. [t1, t2, t3, t1, p1.X, p1.Y], PDFFormatSettings) + CRLF));
  2166. // co-ordinates are now based on the newly transformed matrix co-ordinates.
  2167. R := Document.CreateRoundedRectangle(0, 0, p2.X, p2.Y, p3.X, ALineWidth, AFill, AStroke);
  2168. end
  2169. else
  2170. R := Document.CreateRoundedRectangle(p1.X, p1.Y, p2.X, p2.Y, p3.X, ALineWidth, AFill, AStroke);
  2171. AddObject(R);
  2172. if ADegrees <> 0.0 then
  2173. AddObject(TPDFPopGraphicsStack.Create(Document));
  2174. end;
  2175. procedure TPDFPage.DrawImageRawSize(const X, Y: TPDFFloat; const APixelWidth, APixelHeight, ANumber: integer;
  2176. const ADegrees: single);
  2177. var
  2178. p1: TPDFCoord;
  2179. t1, t2, t3: string;
  2180. rad: single;
  2181. begin
  2182. p1 := Matrix.Transform(X, Y);
  2183. DoUnitConversion(p1);
  2184. if ADegrees <> 0.0 then
  2185. begin
  2186. rad := DegToRad(-ADegrees);
  2187. t1 := FormatFloat(PDF_NUMBER_MASK, Cos(rad), PDFFormatSettings);
  2188. t2 := FormatFloat(PDF_NUMBER_MASK, -Sin(rad), PDFFormatSettings);
  2189. t3 := FormatFloat(PDF_NUMBER_MASK, Sin(rad), PDFFormatSettings);
  2190. AddObject(TPDFPushGraphicsStack.Create(Document));
  2191. // PDF v1.3 page 132 & 143
  2192. AddObject(TPDFFreeFormString.Create(Document, Format('%s %s %s %s %.4f %.4f cm',
  2193. [t1, t2, t3, t1, p1.X, p1.Y], PDFFormatSettings) + CRLF));
  2194. // co-ordinates are now based on the newly transformed matrix co-ordinates.
  2195. AddObject(Document.CreateImage(0, 0, APixelWidth, APixelHeight, ANumber));
  2196. end
  2197. else
  2198. AddObject(Document.CreateImage(p1.X, p1.Y, APixelWidth, APixelHeight, ANumber));
  2199. if ADegrees <> 0.0 then
  2200. AddObject(TPDFPopGraphicsStack.Create(Document));
  2201. end;
  2202. procedure TPDFPage.DrawImageRawSize(const APos: TPDFCoord; const APixelWidth, APixelHeight, ANumber: integer;
  2203. const ADegrees: single);
  2204. begin
  2205. DrawImage(APos.X, APos.Y, APixelWidth, APixelHeight, ANumber, ADegrees);
  2206. end;
  2207. procedure TPDFPage.DrawImage(const X, Y: TPDFFloat; const AWidth, AHeight: TPDFFloat; const ANumber: integer;
  2208. const ADegrees: single);
  2209. var
  2210. p1, p2: TPDFCoord;
  2211. t1, t2, t3: string;
  2212. rad: single;
  2213. begin
  2214. p1 := Matrix.Transform(X, Y);
  2215. DoUnitConversion(p1);
  2216. p2.X := AWidth;
  2217. p2.Y := AHeight;
  2218. DoUnitConversion(p2);
  2219. if ADegrees <> 0.0 then
  2220. begin
  2221. rad := DegToRad(-ADegrees);
  2222. t1 := FormatFloat(PDF_NUMBER_MASK, Cos(rad), PDFFormatSettings);
  2223. t2 := FormatFloat(PDF_NUMBER_MASK, -Sin(rad), PDFFormatSettings);
  2224. t3 := FormatFloat(PDF_NUMBER_MASK, Sin(rad), PDFFormatSettings);
  2225. AddObject(TPDFPushGraphicsStack.Create(Document));
  2226. // PDF v1.3 page 132 & 143
  2227. AddObject(TPDFFreeFormString.Create(Document, Format('%s %s %s %s %.4f %.4f cm',
  2228. [t1, t2, t3, t1, p1.X, p1.Y], PDFFormatSettings) + CRLF));
  2229. // co-ordinates are now based on the newly transformed matrix co-ordinates.
  2230. AddObject(Document.CreateImage(0, 0, p2.X, p2.Y, ANumber));
  2231. end
  2232. else
  2233. AddObject(Document.CreateImage(p1.X, p1.Y, p2.X, p2.Y, ANumber));
  2234. if ADegrees <> 0.0 then
  2235. AddObject(TPDFPopGraphicsStack.Create(Document));
  2236. end;
  2237. procedure TPDFPage.DrawImage(const APos: TPDFCoord; const AWidth, AHeight: TPDFFloat; const ANumber: integer;
  2238. const ADegrees: single);
  2239. begin
  2240. DrawImage(APos.X, APos.Y, AWidth, AHeight, ANumber, ADegrees);
  2241. end;
  2242. procedure TPDFPage.DrawEllipse(const APosX, APosY, AWidth, AHeight, ALineWidth: TPDFFloat; const AFill: Boolean;
  2243. AStroke: Boolean; const ADegrees: single);
  2244. var
  2245. p1, p2: TPDFCoord;
  2246. t1, t2, t3: string;
  2247. rad: single;
  2248. begin
  2249. p1 := Matrix.Transform(APosX, APosY);
  2250. DoUnitConversion(p1);
  2251. p2.X := AWidth;
  2252. p2.Y := AHeight;
  2253. DoUnitConversion(p2);
  2254. if ADegrees <> 0.0 then
  2255. begin
  2256. rad := DegToRad(-ADegrees);
  2257. t1 := FormatFloat(PDF_NUMBER_MASK, Cos(rad), PDFFormatSettings);
  2258. t2 := FormatFloat(PDF_NUMBER_MASK, -Sin(rad), PDFFormatSettings);
  2259. t3 := FormatFloat(PDF_NUMBER_MASK, Sin(rad), PDFFormatSettings);
  2260. AddObject(TPDFPushGraphicsStack.Create(Document));
  2261. // PDF v1.3 page 132 & 143
  2262. AddObject(TPDFFreeFormString.Create(Document, Format('%s %s %s %s %.4f %.4f cm',
  2263. [t1, t2, t3, t1, p1.X, p1.Y], PDFFormatSettings) + CRLF));
  2264. // co-ordinates are now based on the newly transformed matrix co-ordinates.
  2265. AddObject(TPDFEllipse.Create(Document, 0, 0, p2.X, p2.Y, ALineWidth, AFill, AStroke));
  2266. end
  2267. else
  2268. AddObject(TPDFEllipse.Create(Document, p1.X, p1.Y, p2.X, p2.Y, ALineWidth, AFill, AStroke));
  2269. if ADegrees <> 0.0 then
  2270. AddObject(TPDFPopGraphicsStack.Create(Document));
  2271. end;
  2272. procedure TPDFPage.DrawEllipse(const APos: TPDFCoord; const AWidth, AHeight, ALineWidth: TPDFFloat;
  2273. const AFill: Boolean; AStroke: Boolean; const ADegrees: single);
  2274. begin
  2275. DrawEllipse(APos.X, APos.Y, AWidth, AHeight, ALineWidth, AFill, AStroke, ADegrees);
  2276. end;
  2277. procedure TPDFPage.DrawPolygon(const APoints: array of TPDFCoord; const ALineWidth: TPDFFloat);
  2278. begin
  2279. DrawPolyLine(APoints, ALineWidth);
  2280. ClosePath;
  2281. end;
  2282. procedure TPDFPage.DrawPolyLine(const APoints: array of TPDFCoord; const ALineWidth: TPDFFloat);
  2283. var
  2284. i: integer;
  2285. begin
  2286. if Length(APoints) < 2 then
  2287. Exit; { not enough points to draw a line. Should this raise an exception? }
  2288. MoveTo(APoints[0].X, APoints[0].Y);
  2289. for i := Low(APoints)+1 to High(APoints) do
  2290. DrawLine(APoints[i-1].X, APoints[i-1].Y, APoints[i].X, APoints[i].Y, ALineWidth, False);
  2291. end;
  2292. procedure TPDFPage.ResetPath;
  2293. begin
  2294. AddObject(TPDFResetPath.Create(Document));
  2295. end;
  2296. procedure TPDFPage.ClipPath;
  2297. begin
  2298. AddObject(TPDFClipPath.Create(Document));
  2299. end;
  2300. procedure TPDFPage.ClosePath;
  2301. begin
  2302. AddObject(TPDFClosePath.Create(Document));
  2303. end;
  2304. procedure TPDFPage.ClosePathStroke;
  2305. begin
  2306. AddObject(TPDFFreeFormString.Create(Document, 's'+CRLF));
  2307. end;
  2308. procedure TPDFPage.StrokePath;
  2309. begin
  2310. AddObject(TPDFStrokePath.Create(Document));
  2311. end;
  2312. procedure TPDFPage.FillStrokePath;
  2313. begin
  2314. AddObject(TPDFFreeFormString.Create(Document, 'B'+CRLF));
  2315. end;
  2316. procedure TPDFPage.FillEvenOddStrokePath;
  2317. begin
  2318. AddObject(TPDFFreeFormString.Create(Document, 'B*'+CRLF));
  2319. end;
  2320. procedure TPDFPage.PushGraphicsStack;
  2321. begin
  2322. AddObject(TPDFPushGraphicsStack.Create(Document));
  2323. end;
  2324. procedure TPDFPage.PopGraphicsStack;
  2325. begin
  2326. AddObject(TPDFPopGraphicsStack.Create(Document));
  2327. end;
  2328. procedure TPDFPage.MoveTo(x, y: TPDFFloat);
  2329. var
  2330. p1: TPDFCoord;
  2331. begin
  2332. p1 := Matrix.Transform(x, y);
  2333. DoUnitConversion(p1);
  2334. AddObject(TPDFMoveTo.Create(Document, p1.x, p1.y));
  2335. end;
  2336. procedure TPDFPage.MoveTo(APos: TPDFCoord);
  2337. begin
  2338. MoveTo(APos.X, APos.Y);
  2339. end;
  2340. procedure TPDFPage.CubicCurveTo(const xCtrl1, yCtrl1, xCtrl2, yCtrl2, xTo, yTo, ALineWidth: TPDFFloat; AStroke: Boolean);
  2341. var
  2342. p1, p2, p3: TPDFCoord;
  2343. begin
  2344. p1 := Matrix.Transform(xCtrl1, yCtrl1);
  2345. DoUnitConversion(p1);
  2346. p2 := Matrix.Transform(xCtrl2, yCtrl2);
  2347. DoUnitConversion(p2);
  2348. p3 := Matrix.Transform(xTo, yTo);
  2349. DoUnitConversion(p3);
  2350. AddObject(TPDFCurveC.Create(Document, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, ALineWidth, AStroke));
  2351. end;
  2352. procedure TPDFPage.CubicCurveTo(ACtrl1, ACtrl2, ATo: TPDFCoord; const ALineWidth: TPDFFloat; AStroke: Boolean);
  2353. begin
  2354. CubicCurveTo(ACtrl1.X, ACtrl1.Y, ACtrl2.X, ACtrl2.Y, ATo.X, ATo.Y, ALineWidth, AStroke);
  2355. end;
  2356. procedure TPDFPage.CubicCurveToV(xCtrl2, yCtrl2, xTo, yTo: TPDFFloat; const ALineWidth: TPDFFloat; AStroke: Boolean);
  2357. var
  2358. p2, p3: TPDFCoord;
  2359. begin
  2360. p2 := Matrix.Transform(xCtrl2, yCtrl2);
  2361. DoUnitConversion(p2);
  2362. p3 := Matrix.Transform(xTo, yTo);
  2363. DoUnitConversion(p3);
  2364. AddObject(TPDFCurveV.Create(Document, p2.x, p2.y, p3.x, p3.y, ALineWidth, AStroke));
  2365. end;
  2366. procedure TPDFPage.CubicCurveToV(ACtrl2, ATo: TPDFCoord; const ALineWidth: TPDFFloat; AStroke: Boolean);
  2367. begin
  2368. CubicCurveToV(ACtrl2.X, ACtrl2.Y, ATo.X, ATo.Y, ALineWidth, AStroke);
  2369. end;
  2370. procedure TPDFPage.CubicCurveToY(xCtrl1, yCtrl1, xTo, yTo: TPDFFloat; const ALineWidth: TPDFFloat; AStroke: Boolean);
  2371. var
  2372. p1, p3: TPDFCoord;
  2373. begin
  2374. p1 := Matrix.Transform(xCtrl1, yCtrl1);
  2375. DoUnitConversion(p1);
  2376. p3 := Matrix.Transform(xTo, yTo);
  2377. DoUnitConversion(p3);
  2378. AddObject(TPDFCurveY.Create(Document, p1.x, p1.y, p3.x, p3.y, ALineWidth, AStroke));
  2379. end;
  2380. procedure TPDFPage.CubicCurveToY(ACtrl1, ATo: TPDFCoord; const ALineWidth: TPDFFloat; AStroke: Boolean);
  2381. begin
  2382. CubicCurveToY(ACtrl1.X, ACtrl1.Y, ATo.X, ATo.Y, ALineWidth, AStroke);
  2383. end;
  2384. procedure TPDFPage.AddExternalLink(const APosX, APosY, AWidth, AHeight: TPDFFloat;
  2385. const AURI: string; ABorder: boolean);
  2386. var
  2387. an: TPDFAnnot;
  2388. p1, p2: TPDFCoord;
  2389. begin
  2390. p1 := Matrix.Transform(APosX, APosY);
  2391. DoUnitConversion(p1);
  2392. p2.X := AWidth;
  2393. p2.Y := AHeight;
  2394. DoUnitConversion(p2);
  2395. an := TPDFAnnot.Create(Document, p1.X, p1.Y, p2.X, p2.Y, AURI, ABorder);
  2396. Annots.Add(an);
  2397. end;
  2398. function TPDFPage.GetPaperHeight: TPDFFloat;
  2399. begin
  2400. case FUnitOfMeasure of
  2401. uomMillimeters:
  2402. begin
  2403. Result := PDFtoMM(Paper.H);
  2404. end;
  2405. uomCentimeters:
  2406. begin
  2407. Result := PDFtoCM(Paper.H);
  2408. end;
  2409. uomInches:
  2410. begin
  2411. Result := PDFtoInches(Paper.H);
  2412. end;
  2413. uomPixels:
  2414. begin
  2415. Result := Paper.H;
  2416. end;
  2417. end;
  2418. end;
  2419. function TPDFPage.HasImages: Boolean;
  2420. Var
  2421. I,M : Integer;
  2422. begin
  2423. Result:=False;
  2424. M:=ObjectCount;
  2425. I:=0;
  2426. While (Not Result) and (I<M) do
  2427. begin
  2428. Result:=FObjects[i] is TPDFImage;
  2429. Inc(I);
  2430. end;
  2431. end;
  2432. { TPDFFontDefs }
  2433. function TPDFFontDefs.GetF(AIndex : Integer): TPDFFont;
  2434. begin
  2435. Result:=Items[AIndex] as TPDFFont;
  2436. end;
  2437. function TPDFFontDefs.FindFont(const AName: string): integer;
  2438. var
  2439. i:integer;
  2440. begin
  2441. Result:=-1;
  2442. for i := 0 to Count-1 do
  2443. begin
  2444. if GetF(i).Name = AName then
  2445. begin
  2446. Result := i;
  2447. Exit;
  2448. end;
  2449. end;
  2450. end;
  2451. function TPDFFontDefs.AddFontDef: TPDFFont;
  2452. begin
  2453. Result:=Add as TPDFFont;
  2454. end;
  2455. { TPDFSection }
  2456. function TPDFSection.GetP(AIndex : Integer): TPDFPage;
  2457. begin
  2458. If Assigned(FPages) then
  2459. Result:=TPDFPage(FPages[Aindex])
  2460. else
  2461. Raise EPDF.CreateFmt(rsErrInvalidSectionPage,[AIndex]);
  2462. end;
  2463. function TPDFSection.GetP: INteger;
  2464. begin
  2465. if Assigned(FPages) then
  2466. Result:=FPages.Count
  2467. else
  2468. Result:=0;
  2469. end;
  2470. destructor TPDFSection.Destroy;
  2471. begin
  2472. FreeAndNil(FPages);
  2473. inherited Destroy;
  2474. end;
  2475. procedure TPDFSection.AddPage(APage: TPDFPage);
  2476. begin
  2477. if Not Assigned(FPages) then
  2478. FPages:=TFPList.Create;
  2479. FPages.Add(APage);
  2480. end;
  2481. { TPDFSectionList }
  2482. function TPDFSectionList.GetS(AIndex : Integer): TPDFSection;
  2483. begin
  2484. Result:=Items[AIndex] as TPDFSection
  2485. end;
  2486. function TPDFSectionList.AddSection: TPDFSection;
  2487. begin
  2488. Result:=Add as TPDFSection;
  2489. end;
  2490. { TPDFDocumentObject }
  2491. constructor TPDFDocumentObject.Create(const ADocument: TPDFDocument);
  2492. begin
  2493. inherited Create(ADocument);
  2494. FDocument:=ADocument;
  2495. if Assigned(FDocument) then
  2496. FLineCapStyle := FDocument.LineCapStyle;
  2497. end;
  2498. procedure TPDFDocumentObject.SetWidth(AWidth: TPDFFloat; AStream : TStream);
  2499. Var
  2500. S : String;
  2501. begin
  2502. S:=FloatStr(AWidth)+' w'; // stroke width
  2503. if (S<>Document.CurrentWidth) then
  2504. begin
  2505. WriteString(IntToStr(Ord(FLineCapStyle))+' J'+CRLF, AStream); //set line cap
  2506. WriteString(S+CRLF, AStream);
  2507. Document.CurrentWidth:=S;
  2508. end;
  2509. end;
  2510. class procedure TPDFObject.WriteString(const AValue: RawByteString; AStream: TStream);
  2511. Var
  2512. L : Integer;
  2513. begin
  2514. L:=Length(AValue);
  2515. if L>0 then
  2516. AStream.Write(AValue[1],L);
  2517. end;
  2518. // Font=Name-Size:x:y
  2519. function ExtractBaseFontName(const AValue: string): string;
  2520. var
  2521. FontName, S1, S2: string;
  2522. P : Integer;
  2523. begin
  2524. P:=RPos('-', AValue);
  2525. if (P>0) then
  2526. FontName:=Copy(AValue,1,P-1)
  2527. else
  2528. FontName:='';
  2529. P:=Pos(':',AValue); // First attribute
  2530. if (P>0) then
  2531. begin
  2532. S1:=Copy(AValue,P+1,Length(AValue)-P);
  2533. S1:=Upcase(S1[1])+Copy(S1,2,Pred(Length(S1)));
  2534. P:=Pos(':',S1);
  2535. if (P>0) then
  2536. begin
  2537. S2:=Copy(S1,P+1,Length(S1)-P);
  2538. if Length(S2)>0 then
  2539. S2[1]:=Upcase(S2[1]);
  2540. S1:=Copy(S1,1,P-1);
  2541. if Length(S1)>0 then
  2542. S1[1]:=Upcase(S1[1]);
  2543. S1:=S1+S2;
  2544. end;
  2545. S1:='-'+S1;
  2546. end;
  2547. Result:=FontName+S1;
  2548. end;
  2549. { TPDFImageItem }
  2550. procedure TPDFImageItem.SetImage(AValue: TFPCustomImage);
  2551. begin
  2552. if FImage=AValue then Exit;
  2553. FImage:=AValue;
  2554. SetLength(FStreamed,0);
  2555. end;
  2556. function TPDFImageItem.GetStreamed: TBytes;
  2557. Var
  2558. Opts : TPDFImageStreamOptions;
  2559. begin
  2560. Opts:=[];
  2561. if Length(FStreamed)=0 then
  2562. begin
  2563. if Collection.Owner is TPDFDocument then
  2564. Opts:=TPDFDocument(Collection.Owner).ImageStreamOptions
  2565. else
  2566. Opts:=[isoCompressed,isoTransparent];
  2567. CreateStreamedData(Opts);
  2568. end;
  2569. Result:=FStreamed;
  2570. end;
  2571. function TPDFImageItem.GetStreamedMask: TBytes;
  2572. begin
  2573. GetStreamed; // calls CreateStreamedData
  2574. Result:=FStreamedMask;
  2575. end;
  2576. function TPDFImageItem.GetHeight: Integer;
  2577. begin
  2578. If Assigned(FImage) then
  2579. Result:=FImage.Height
  2580. else
  2581. Result:=FHeight;
  2582. end;
  2583. function TPDFImageItem.GetWidth: Integer;
  2584. begin
  2585. If Assigned(FImage) then
  2586. Result:=FImage.Width
  2587. else
  2588. Result:=FWidth;
  2589. end;
  2590. procedure TPDFImageItem.SetStreamed(AValue: TBytes);
  2591. begin
  2592. If AValue=FStreamed then exit;
  2593. SetLength(FStreamed,0);
  2594. FStreamed:=AValue;
  2595. end;
  2596. procedure TPDFImageItem.SetStreamedMask(const AValue: TBytes;
  2597. const ACompression: TPDFImageCompression);
  2598. begin
  2599. If AValue=FStreamedMask then exit;
  2600. SetLength(FStreamedMask,0);
  2601. FStreamedMask:=AValue;
  2602. FCompressionMask:=ACompression;
  2603. end;
  2604. function TPDFImageItem.WriteImageStream(AStream: TStream): int64;
  2605. begin
  2606. Result:=WriteStream(FStreamed, AStream);
  2607. end;
  2608. function TPDFImageItem.WriteMaskStream(AStream: TStream): int64;
  2609. begin
  2610. Result:=WriteStream(FStreamedMask, AStream);
  2611. end;
  2612. destructor TPDFImageItem.Destroy;
  2613. begin
  2614. if FOwnsImage then
  2615. FreeAndNil(FImage);
  2616. inherited Destroy;
  2617. end;
  2618. procedure TPDFImageItem.CreateStreamedData(AUseCompression: Boolean);
  2619. begin
  2620. CreateStreamedData([isoCompressed]);
  2621. end;
  2622. Procedure TPDFImageItem.CreateStreamedData(aOptions : TPDFImageStreamOptions);
  2623. function NeedsTransparency: Boolean;
  2624. var
  2625. Y, X: Integer;
  2626. begin
  2627. for Y:=0 to FHeight-1 do
  2628. for X:=0 to FWidth-1 do
  2629. begin
  2630. if Image.Colors[x,y].alpha < $FFFF then // has alpha channel
  2631. Exit(True);
  2632. end;
  2633. Result:=False;
  2634. end;
  2635. procedure CreateStream(out MS: TMemoryStream; out Str: TStream;
  2636. out Compression: TPDFImageCompression);
  2637. begin
  2638. MS := TMemoryStream.Create;
  2639. if (isoCompressed in aOptions) then
  2640. begin
  2641. Compression := icDeflate;
  2642. Str := Tcompressionstream.create(cldefault, MS);
  2643. end
  2644. else
  2645. begin
  2646. Compression := icNone;
  2647. Str := MS;
  2648. end;
  2649. end;
  2650. procedure StreamToBuffer(const MS: TMemoryStream; var Str: TStream; out Buffer: TBytes);
  2651. begin
  2652. if Str<>MS then
  2653. Str.Free;
  2654. Str := nil;
  2655. SetLength(Buffer, MS.Size);
  2656. MS.Position := 0;
  2657. if MS.Size>0 then
  2658. MS.ReadBuffer(Buffer[0], MS.Size);
  2659. end;
  2660. Var
  2661. X,Y : Integer;
  2662. C : TFPColor;
  2663. MS,MSMask : TMemoryStream;
  2664. Str,StrMask : TStream;
  2665. CWhite : TFPColor; // white color
  2666. CreateMask : Boolean;
  2667. begin
  2668. FillMem(@CWhite, SizeOf(CWhite), $FF);
  2669. FWidth:=Image.Width;
  2670. FHeight:=Image.Height;
  2671. CreateMask:=(isoTransparent in aOptions) and NeedsTransparency;
  2672. MS := nil;
  2673. Str := nil;
  2674. MSMask := nil;
  2675. StrMask := nil;
  2676. try
  2677. CreateStream(MS, Str, FCompression);
  2678. if CreateMask then
  2679. CreateStream(MSMask, StrMask, FCompressionMask);
  2680. for Y:=0 to FHeight-1 do
  2681. for X:=0 to FWidth-1 do
  2682. begin
  2683. C:=Image.Colors[x,y];
  2684. if CreateMask then
  2685. StrMask.WriteByte(C.Alpha shr 8)
  2686. else
  2687. if (C.alpha < $FFFF) then // remove alpha channel - assume white background
  2688. C := AlphaBlend(CWhite, C);
  2689. Str.WriteByte(C.Red shr 8);
  2690. Str.WriteByte(C.Green shr 8);
  2691. Str.WriteByte(C.Blue shr 8);
  2692. end;
  2693. StreamToBuffer(MS, Str, FStreamed);
  2694. if CreateMask then
  2695. StreamToBuffer(MSMask, StrMask, FStreamedMask);
  2696. finally
  2697. Str.Free;
  2698. StrMask.Free;
  2699. MS.Free;
  2700. MSMask.Free;
  2701. end;
  2702. end;
  2703. Procedure TPDFImageItem.DetachImage;
  2704. begin
  2705. FImage := nil;
  2706. end;
  2707. function TPDFImageItem.WriteStream(const AStreamedData: TBytes;
  2708. AStream: TStream): int64;
  2709. var
  2710. Img : TBytes;
  2711. begin
  2712. TPDFObject.WriteString(CRLF+'stream'+CRLF,AStream);
  2713. Img:=AStreamedData;
  2714. Result:=Length(Img);
  2715. AStream.WriteBuffer(Img[0],Result);
  2716. TPDFObject.WriteString(CRLF, AStream);
  2717. TPDFObject.WriteString('endstream', AStream);
  2718. end;
  2719. function TPDFImageItem.Equals(AImage: TFPCustomImage): boolean;
  2720. var
  2721. x, y: Integer;
  2722. begin
  2723. if AImage = nil then
  2724. begin
  2725. Result := False;
  2726. exit;
  2727. end;
  2728. { if dimensions don't match, we know we can exit early }
  2729. Result := (Image.Width = AImage.Width) and (Image.Height = AImage.Height);
  2730. if not Result then
  2731. Exit;
  2732. for x := 0 to Image.Width-1 do
  2733. for y := 0 to Image.Height-1 do
  2734. if Image.Colors[x, y] <> AImage.Colors[x, y] then
  2735. begin
  2736. Result := False;
  2737. Exit;
  2738. end;
  2739. end;
  2740. function TPDFImageItem.GetHasMask: Boolean;
  2741. begin
  2742. Result := Length(FStreamedMask)>0;
  2743. end;
  2744. { TPDFImages }
  2745. function TPDFImages.GetI(AIndex : Integer): TPDFImageItem;
  2746. begin
  2747. Result:=Items[AIndex] as TPDFImageItem;
  2748. end;
  2749. function TPDFImages.GetOwner: TPersistent;
  2750. begin
  2751. Result := FOwner;
  2752. end;
  2753. function TPDFImages.AddImageItem: TPDFImageItem;
  2754. begin
  2755. Result:=Add as TPDFImageItem;
  2756. end;
  2757. function TPDFImages.AddJPEGStream(const AStream: TStream; Width, Height: Integer
  2758. ): Integer;
  2759. Var
  2760. IP : TPDFImageItem;
  2761. begin
  2762. IP:=AddImageItem;
  2763. IP.FWidth := Width;
  2764. IP.FHeight := Height;
  2765. IP.FCompression := icJPEG;
  2766. SetLength(IP.FStreamed, AStream.Size-AStream.Position);
  2767. if Length(IP.FStreamed)>0 then
  2768. AStream.ReadBuffer(IP.FStreamed[0], Length(IP.FStreamed));
  2769. Result:=Count-1;
  2770. end;
  2771. constructor TPDFImages.Create(AOwner: TPDFDocument;
  2772. AItemClass: TCollectionItemClass);
  2773. begin
  2774. inherited Create(AItemClass);
  2775. FOwner := AOwner;
  2776. end;
  2777. function TPDFImages.AddFromFile(const AFileName: String; KeepImage: Boolean): Integer;
  2778. {$IF NOT (FPC_FULLVERSION >= 30101)}
  2779. function FindReaderFromExtension(extension: String): TFPCustomImageReaderClass;
  2780. var
  2781. s: string;
  2782. r: integer;
  2783. begin
  2784. extension := lowercase (extension);
  2785. if (extension <> '') and (extension[1] = '.') then
  2786. system.delete (extension,1,1);
  2787. with ImageHandlers do
  2788. begin
  2789. r := count-1;
  2790. s := extension + ';';
  2791. while (r >= 0) do
  2792. begin
  2793. Result := ImageReader[TypeNames[r]];
  2794. if (pos(s,{$if (FPC_FULLVERSION = 20604)}Extentions{$else}Extensions{$endif}[TypeNames[r]]+';') <> 0) then
  2795. Exit;
  2796. dec (r);
  2797. end;
  2798. end;
  2799. Result := nil;
  2800. end;
  2801. function FindReaderFromFileName(const filename: String): TFPCustomImageReaderClass;
  2802. begin
  2803. Result := FindReaderFromExtension(ExtractFileExt(filename));
  2804. end;
  2805. {$ENDIF}
  2806. var
  2807. FS: TFileStream;
  2808. begin
  2809. FS := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
  2810. try
  2811. Result := AddFromStream(FS,
  2812. {$IF (FPC_FULLVERSION >= 30101)}TFPCustomImage.{$ENDIF}FindReaderFromFileName(AFileName), KeepImage);
  2813. finally
  2814. FS.Free;
  2815. end;
  2816. end;
  2817. function TPDFImages.AddFromStream(const AStream: TStream;
  2818. Handler: TFPCustomImageReaderClass; KeepImage: Boolean): Integer;
  2819. Var
  2820. I : TFPMemoryImage;
  2821. IP : TPDFImageItem;
  2822. JPEG : TFPReaderJPEG;
  2823. Reader: TFPCustomImageReader;
  2824. {$IF (FPC_FULLVERSION >= 30101)}
  2825. Size : TPoint;
  2826. {$ELSE}
  2827. startPos: Int64;
  2828. {$ENDIF}
  2829. begin
  2830. if (poUseRawJPEG in Owner.Options) and Handler.InheritsFrom(TFPReaderJPEG) then
  2831. begin
  2832. JPEG := TFPReaderJPEG.Create;
  2833. try
  2834. {$IF (FPC_FULLVERSION >= 30101)}
  2835. Size := JPEG.ImageSize(AStream);
  2836. Result := AddJPEGStream(AStream, Size.X, Size.Y);
  2837. {$ELSE}
  2838. I:=TFPMemoryImage.Create(0,0);
  2839. try
  2840. startPos := AStream.Position;
  2841. I.LoadFromStream(AStream, JPEG);
  2842. AStream.Position := startPos;
  2843. Result := AddJPEGStream(AStream, I.Width, I.Height);
  2844. finally
  2845. I.Free;
  2846. end;
  2847. {$ENDIF}
  2848. finally
  2849. JPEG.Free;
  2850. end;
  2851. end else
  2852. begin
  2853. IP:=AddImageItem;
  2854. I:=TFPMemoryImage.Create(0,0);
  2855. if not Assigned(Handler) then
  2856. raise EPDF.Create(rsErrNoImageReader);
  2857. Reader := Handler.Create;
  2858. try
  2859. I.LoadFromStream(AStream, Reader);
  2860. finally
  2861. Reader.Free;
  2862. end;
  2863. IP.Image:=I;
  2864. if KeepImage then
  2865. IP.OwnsImage := True
  2866. else
  2867. begin
  2868. IP.CreateStreamedData(Owner.ImageStreamOptions);
  2869. IP.DetachImage; // not through property, that would clear the image
  2870. i.Free;
  2871. end;
  2872. end;
  2873. Result:=Count-1;
  2874. end;
  2875. { TPDFObject }
  2876. constructor TPDFObject.Create(const ADocument: TPDFDocument);
  2877. begin
  2878. If Assigned(ADocument) then
  2879. Inc(ADocument.FObjectCount);
  2880. end;
  2881. { We opted to use the Str() function instead of FormatFloat(), because it is
  2882. considerably faster. This also works around the problem of locale specific
  2883. DecimalSeparator causing float formatting problems in the generated PDF. }
  2884. class function TPDFObject.FloatStr(F: TPDFFloat): String;
  2885. begin
  2886. if ((Round(F*100) mod 100)=0) then
  2887. Str(F:4:0,Result)
  2888. else
  2889. Str(F:4:2,Result);
  2890. result := trim(Result);
  2891. end;
  2892. procedure TPDFObject.Write(const AStream: TStream);
  2893. begin
  2894. Assert(AStream<>Nil);
  2895. end;
  2896. procedure TPDFBoolean.Write(const AStream: TStream);
  2897. begin
  2898. if FValue then
  2899. WriteString('true', AStream)
  2900. else
  2901. WriteString('false', AStream);
  2902. end;
  2903. constructor TPDFBoolean.Create(Const ADocument : TPDFDocument; const AValue: Boolean);
  2904. begin
  2905. inherited Create(ADocument);
  2906. FValue:=AValue;
  2907. end;
  2908. procedure TPDFInteger.Write(const AStream: TStream);
  2909. begin
  2910. WriteString(IntToStr(FInt), AStream);
  2911. end;
  2912. procedure TPDFInteger.Inc;
  2913. begin
  2914. system.Inc(FInt);
  2915. end;
  2916. constructor TPDFInteger.Create(Const ADocument : TPDFDocument; const AValue: integer);
  2917. begin
  2918. inherited Create(ADocument);
  2919. FInt:=AValue;
  2920. end;
  2921. procedure TPDFReference.Write(const AStream: TStream);
  2922. begin
  2923. WriteString(IntToStr(FValue)+' 0 R', AStream);
  2924. end;
  2925. constructor TPDFReference.Create(Const ADocument : TPDFDocument; const AValue: integer);
  2926. begin
  2927. inherited Create(ADocument);
  2928. FValue:=AValue;
  2929. end;
  2930. procedure TPDFName.Write(const AStream: TStream);
  2931. begin
  2932. if FName <> '' then
  2933. if Pos('Length1', FName) > 0 then
  2934. WriteString('/Length1', AStream)
  2935. else
  2936. begin
  2937. if FMustEscape then
  2938. WriteString('/'+ConvertCharsToHex, AStream)
  2939. else
  2940. WriteString('/'+FName, AStream);
  2941. end;
  2942. end;
  2943. constructor TPDFName.Create(const ADocument: TPDFDocument; const AValue: string; const AMustEscape: boolean = True);
  2944. begin
  2945. inherited Create(ADocument);
  2946. FName:=AValue;
  2947. FMustEscape := AMustEscape;
  2948. end;
  2949. function TPDFName.ConvertCharsToHex: string;
  2950. var
  2951. s: string;
  2952. i: integer;
  2953. d: integer;
  2954. begin
  2955. s := '';
  2956. for i := 1 to Length(Name) do
  2957. begin
  2958. d := Ord(Name[i]);
  2959. if (d < 33) or (d > 126) then
  2960. s := s + '#' + IntToHex(d, 2)
  2961. else
  2962. s := s + Name[i];
  2963. end;
  2964. Result := s;
  2965. end;
  2966. { TPDFAbstractString }
  2967. function TPDFAbstractString.InsertEscape(const AValue: string): string;
  2968. var
  2969. S: string;
  2970. begin
  2971. Result:='';
  2972. S:=AValue;
  2973. if Pos('\', S) > 0 then
  2974. S:=AnsiReplaceStr(S, '\', '\\');
  2975. if Pos('(', S) > 0 then
  2976. S:=AnsiReplaceStr(S, '(', '\(');
  2977. if Pos(')', S) > 0 then
  2978. S:=AnsiReplaceStr(S, ')', '\)');
  2979. Result:=S;
  2980. end;
  2981. { TPDFString }
  2982. procedure TPDFString.Write(const AStream: TStream);
  2983. var
  2984. s: AnsiString;
  2985. begin
  2986. s := Utf8ToAnsi(FValue);
  2987. WriteString('('+s+')', AStream);
  2988. end;
  2989. constructor TPDFString.Create(Const ADocument : TPDFDocument; const AValue: string);
  2990. begin
  2991. inherited Create(ADocument);
  2992. FValue := AValue;
  2993. if (Pos('(', FValue) > 0) or (Pos(')', FValue) > 0) or (Pos('\', FValue) > 0) then
  2994. FValue := InsertEscape(FValue);
  2995. end;
  2996. { TPDFUTF16String }
  2997. constructor TPDFUTF16String.Create(Const ADocument : TPDFDocument; const AValue: Unicodestring; const AFontIndex : Integer);
  2998. begin
  2999. inherited Create(ADocument);
  3000. FValue := AValue;
  3001. FFontIndex:=aFontIndex;
  3002. end;
  3003. function oct_str(b:byte):string;
  3004. begin
  3005. Result:='';
  3006. repeat
  3007. Result:=IntToStr(b and $7)+Result;
  3008. b:=b shr 3;
  3009. until b=0;
  3010. end;
  3011. procedure TPDFUTF16String.Write(const AStream: TStream);
  3012. var
  3013. i:integer;
  3014. us:utf8string;
  3015. s:ansistring;
  3016. wv:word;
  3017. begin
  3018. us := Utf8Encode(FValue);
  3019. if (length(us)<>length(fValue)) then // quote
  3020. begin
  3021. s:='\376\377'; // UTF-16BE BOM
  3022. for i:=1 to length(fValue) do
  3023. begin
  3024. wv:=word(fValue[i]);
  3025. s:=s+'\'+oct_str(hi(wv));
  3026. s:=s+'\'+oct_str(lo(wv));
  3027. end;
  3028. end else
  3029. begin
  3030. if (Pos('(', FValue) > 0) or (Pos(')', FValue) > 0) or (Pos('\', FValue) > 0) then
  3031. s := InsertEscape(FValue)
  3032. else
  3033. s:=fValue;
  3034. end;
  3035. WriteString('('+s+')', AStream);
  3036. end;
  3037. { TPDFUTF8String }
  3038. function TPDFUTF8String.RemapedText: AnsiString;
  3039. var
  3040. s: UnicodeString;
  3041. begin
  3042. s := UTF8Decode(FValue);
  3043. Result := Document.Fonts[FontIndex].GetGlyphIndices(s);
  3044. end;
  3045. procedure TPDFUTF8String.Write(const AStream: TStream);
  3046. begin
  3047. WriteString('<'+RemapedText+'>', AStream);
  3048. end;
  3049. constructor TPDFUTF8String.Create(const ADocument: TPDFDocument; const AValue: UTF8String; const AFontIndex: integer);
  3050. begin
  3051. inherited Create(ADocument);
  3052. FValue := AValue;
  3053. FFontIndex := AFontIndex;
  3054. end;
  3055. { TPDFFreeFormString }
  3056. procedure TPDFFreeFormString.Write(const AStream: TStream);
  3057. var
  3058. s: AnsiString;
  3059. begin
  3060. s := Utf8ToAnsi(FValue);
  3061. WriteString(s, AStream);
  3062. end;
  3063. constructor TPDFFreeFormString.Create(const ADocument: TPDFDocument; const AValue: string);
  3064. begin
  3065. inherited Create(ADocument);
  3066. FValue := AValue;
  3067. end;
  3068. { TPDFArray }
  3069. procedure TPDFArray.Write(const AStream: TStream);
  3070. var
  3071. i: integer;
  3072. begin
  3073. WriteString('[', AStream);
  3074. for i:=0 to Pred(FArray.Count) do
  3075. begin
  3076. if i > 0 then
  3077. WriteString(' ', AStream);
  3078. TPDFObject(FArray[i]).Write(AStream);
  3079. end;
  3080. WriteString(']', AStream);
  3081. end;
  3082. procedure TPDFArray.AddItem(const AValue: TPDFObject);
  3083. begin
  3084. FArray.Add(AValue);
  3085. end;
  3086. procedure TPDFArray.AddIntArray(S: String);
  3087. Var
  3088. P : Integer;
  3089. begin
  3090. P:=Pos(' ',S);
  3091. while (P>0) do
  3092. begin
  3093. AddItem(Document.CreateInteger(StrToInt(Copy(S,1,Pred(P)))));
  3094. Delete(S,1,P);
  3095. P:=Pos(' ',S);
  3096. end;
  3097. if S <> '' then
  3098. AddItem(Document.CreateInteger(StrToInt(S)));
  3099. end;
  3100. procedure TPDFArray.AddFreeFormArrayValues(S: string);
  3101. begin
  3102. AddItem(TPDFFreeFormString.Create(nil, S));
  3103. end;
  3104. constructor TPDFArray.Create(const ADocument: TPDFDocument);
  3105. begin
  3106. inherited Create(ADocument);
  3107. FArray:=TFPObjectList.Create;
  3108. end;
  3109. destructor TPDFArray.Destroy;
  3110. begin
  3111. // TPDFInteger, TPDFReference, TPDFName
  3112. FreeAndNil(FArray);
  3113. inherited;
  3114. end;
  3115. procedure TPDFStream.Write(const AStream: TStream);
  3116. var
  3117. i: integer;
  3118. begin
  3119. for i:=0 to FItems.Count-1 do
  3120. TPDFObject(FItems[i]).Write(AStream);
  3121. end;
  3122. procedure TPDFStream.AddItem(const AValue: TPDFObject);
  3123. begin
  3124. FItems.Add(AValue);
  3125. end;
  3126. constructor TPDFStream.Create(Const ADocument : TPDFDocument; OwnsObjects : Boolean = True);
  3127. begin
  3128. inherited Create(ADocument);
  3129. FItems:=TFPObjectList.Create(OwnsObjects);
  3130. end;
  3131. destructor TPDFStream.Destroy;
  3132. begin
  3133. FreeAndNil(FItems);
  3134. inherited;
  3135. end;
  3136. function TPDFEmbeddedFont.GetPointSize: integer;
  3137. begin
  3138. Result := StrToInt(FTxtSize);
  3139. end;
  3140. procedure TPDFEmbeddedFont.Write(const AStream: TStream);
  3141. begin
  3142. WriteString('/F'+IntToStr(FTxtFont)+' '+FTxtSize+' Tf'+CRLF, AStream);
  3143. end;
  3144. Class function TPDFEmbeddedFont.WriteEmbeddedFont(const ADocument: TPDFDocument; const Src: TMemoryStream; const AStream: TStream): int64;
  3145. var
  3146. PS: int64;
  3147. CompressedStream: TMemoryStream;
  3148. begin
  3149. WriteString(CRLF+'stream'+CRLF, AStream);
  3150. PS:=AStream.Position;
  3151. if poCompressFonts in ADocument.Options then
  3152. begin
  3153. CompressedStream := TMemoryStream.Create;
  3154. CompressStream(Src, CompressedStream);
  3155. CompressedStream.Position := 0;
  3156. CompressedStream.SaveToStream(AStream);
  3157. CompressedStream.Free;
  3158. end
  3159. else
  3160. begin
  3161. Src.Position := 0;
  3162. Src.SaveToStream(AStream);
  3163. end;
  3164. Result:=AStream.Position-PS;
  3165. WriteString(CRLF, AStream);
  3166. WriteString('endstream', AStream);
  3167. end;
  3168. class function TPDFEmbeddedFont.WriteEmbeddedSubsetFont(const ADocument: TPDFDocument;
  3169. const AFontNum: integer; const AOutStream: TStream): int64;
  3170. var
  3171. PS: int64;
  3172. CompressedStream: TMemoryStream;
  3173. begin
  3174. if ADocument.Fonts[AFontNum].SubsetFont = nil then
  3175. raise Exception.Create('WriteEmbeddedSubsetFont: SubsetFont stream was not initialised.');
  3176. WriteString(CRLF+'stream'+CRLF, AOutStream);
  3177. PS := AOutStream.Position;
  3178. if poCompressFonts in ADocument.Options then
  3179. begin
  3180. CompressedStream := TMemoryStream.Create;
  3181. CompressStream(ADocument.Fonts[AFontNum].SubsetFont, CompressedStream);
  3182. CompressedStream.Position := 0;
  3183. CompressedStream.SaveToStream(AOutStream);
  3184. CompressedStream.Free;
  3185. end
  3186. else
  3187. begin
  3188. ADocument.Fonts[AFontNum].SubsetFont.Position := 0;
  3189. TMemoryStream(ADocument.Fonts[AFontNum].SubsetFont).SaveToStream(AOutStream);
  3190. end;
  3191. Result := AOutStream.Position-PS;
  3192. WriteString(CRLF, AOutStream);
  3193. WriteString('endstream', AOutStream);
  3194. end;
  3195. constructor TPDFEmbeddedFont.Create(const ADocument: TPDFDocument; const APage: TPDFPage; const AFont: integer;
  3196. const ASize: string);
  3197. begin
  3198. inherited Create(ADocument);
  3199. FTxtFont := AFont;
  3200. FTxtSize := ASize;
  3201. FPage := APage;
  3202. end;
  3203. { TPDFBaseText }
  3204. constructor TPDFBaseText.Create(const ADocument: TPDFDocument);
  3205. begin
  3206. inherited Create(ADocument);
  3207. FX := 0.0;
  3208. FY := 0.0;
  3209. FFont := nil;
  3210. FDegrees := 0.0;
  3211. FUnderline := False;
  3212. FColor := clBlack;
  3213. FStrikeThrough := False;
  3214. end;
  3215. { TPDFText }
  3216. function TPDFText.GetTextWidth: single;
  3217. var
  3218. i: integer;
  3219. lWidth: double;
  3220. lFontName: string;
  3221. begin
  3222. lFontName := Document.Fonts[Font.FontIndex].Name;
  3223. if not Document.IsStandardPDFFont(lFontName) then
  3224. raise EPDF.CreateFmt(rsErrUnknownStdFont, [lFontName]);
  3225. lWidth := 0;
  3226. for i := 1 to Length(FString.Value) do
  3227. lWidth := lWidth + Document.GetStdFontCharWidthsArray(lFontName)[Ord(FString.Value[i])];
  3228. Result := lWidth * Font.PointSize / 1540;
  3229. end;
  3230. function TPDFText.GetTextHeight: single;
  3231. var
  3232. lFontName: string;
  3233. begin
  3234. lFontName := Document.Fonts[Font.FontIndex].Name;
  3235. Result := 0;
  3236. case lFontName of
  3237. 'Courier': result := FONT_TIMES_COURIER_CAPHEIGHT;
  3238. 'Courier-Bold': result := FONT_TIMES_COURIER_CAPHEIGHT;
  3239. 'Courier-Oblique': result := FONT_TIMES_COURIER_CAPHEIGHT;
  3240. 'Courier-BoldOblique': result := FONT_TIMES_COURIER_CAPHEIGHT;
  3241. 'Helvetica': result := FONT_HELVETICA_ARIAL_CAPHEIGHT;
  3242. 'Helvetica-Bold': result := FONT_HELVETICA_ARIAL_BOLD_CAPHEIGHT;
  3243. 'Helvetica-Oblique': result := FONT_HELVETICA_ARIAL_ITALIC_CAPHEIGHT;
  3244. 'Helvetica-BoldOblique': result := FONT_HELVETICA_ARIAL_BOLD_ITALIC_CAPHEIGHT;
  3245. 'Times-Roman': result := FONT_TIMES_CAPHEIGHT;
  3246. 'Times-Bold': result := FONT_TIMES_BOLD_CAPHEIGHT;
  3247. 'Times-Italic': result := FONT_TIMES_ITALIC_CAPHEIGHT;
  3248. 'Times-BoldItalic': result := FONT_TIMES_BOLD_ITALIC_CAPHEIGHT;
  3249. 'Symbol': result := 300;
  3250. 'ZapfDingbats': result := 300;
  3251. else
  3252. raise EPDF.CreateFmt(rsErrUnknownStdFont, [lFontName]);
  3253. end;
  3254. Result := Result * Font.PointSize / 1540;
  3255. end;
  3256. procedure TPDFText.Write(const AStream: TStream);
  3257. var
  3258. t1, t2, t3: string;
  3259. rad: single;
  3260. lWidth: single;
  3261. lTextWidthInMM: single;
  3262. lHeight: single;
  3263. lTextHeightInMM: single;
  3264. lColor: string;
  3265. lLineWidth: string;
  3266. begin
  3267. inherited Write(AStream);
  3268. WriteString('BT'+CRLF, AStream);
  3269. if Degrees <> 0.0 then
  3270. begin
  3271. rad := DegToRad(-Degrees);
  3272. t1 := FloatStr(Cos(rad));
  3273. t2 := FloatStr(-Sin(rad));
  3274. t3 := FloatStr(Sin(rad));
  3275. WriteString(Format('%s %s %s %s %s %s Tm', [t1, t2, t3, t1, FloatStr(X), FloatStr(Y)]) + CRLF, AStream);
  3276. end
  3277. else
  3278. begin
  3279. WriteString(FloatStr(X)+' '+FloatStr(Y)+' TD'+CRLF, AStream);
  3280. end;
  3281. FString.Write(AStream);
  3282. WriteString(' Tj'+CRLF, AStream);
  3283. WriteString('ET'+CRLF, AStream);
  3284. if (not Underline) and (not StrikeThrough) then
  3285. Exit;
  3286. // result is in Font Units
  3287. lWidth := GetTextWidth;
  3288. lHeight := GetTextHeight;
  3289. { convert the Font Units to Millimeters. This is also because fontcache DPI (default 96) could differ from PDF DPI (72). }
  3290. lTextWidthInMM := (lWidth * cInchToMM) / gTTFontCache.DPI;
  3291. lTextHeightInMM := (lHeight * cInchToMM) / gTTFontCache.DPI;
  3292. if Degrees <> 0.0 then
  3293. // angled text
  3294. WriteString(Format('q %s %s %s %s %s %s cm', [t1, t2, t3, t1, FloatStr(X), FloatStr(Y)]) + CRLF, AStream)
  3295. else
  3296. // horizontal text
  3297. WriteString(Format('q 1 0 0 1 %s %s cm', [FloatStr(X), FloatStr(Y)]) + CRLF, AStream);
  3298. { set up a pen width and stroke color }
  3299. lColor := TPDFColor.Command(True, Color);
  3300. lLineWidth := FloatStr(mmToPDF(lTextHeightInMM / 12)) + ' w ';
  3301. WriteString(lLineWidth + lColor + CRLF, AStream);
  3302. { line segment is relative to matrix translation coordinate, set above }
  3303. if Underline then
  3304. WriteString(Format('0 -1.5 m %s -1.5 l S', [FloatStr(mmToPDF(lTextWidthInMM))]) + CRLF, AStream);
  3305. if StrikeThrough then
  3306. WriteString(Format('0 %s m %s %0:s l S', [FloatStr(mmToPDF(lTextHeightInMM) / 2), FloatStr(mmToPDF(lTextWidthInMM))]) + CRLF, AStream);
  3307. { restore graphics state to before the translation matrix adjustment }
  3308. WriteString('Q' + CRLF, AStream);
  3309. end;
  3310. constructor TPDFText.Create(const ADocument: TPDFDocument; const AX, AY: TPDFFloat; const AText: AnsiString;
  3311. const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean);
  3312. begin
  3313. inherited Create(ADocument);
  3314. X := AX;
  3315. Y := AY;
  3316. Font := AFont;
  3317. Degrees := ADegrees;
  3318. Underline := AUnderline;
  3319. StrikeThrough := AStrikeThrough;
  3320. if Assigned(AFont) and Assigned(AFont.Page) then
  3321. Color := AFont.Page.FLastFontColor;
  3322. FString := ADocument.CreateString(AText);
  3323. end;
  3324. destructor TPDFText.Destroy;
  3325. begin
  3326. FreeAndNil(FString);
  3327. inherited;
  3328. end;
  3329. { TPDFUTF8Text }
  3330. procedure TPDFUTF8Text.Write(const AStream: TStream);
  3331. var
  3332. t1, t2, t3: string;
  3333. rad: single;
  3334. lFC: TFPFontCacheItem;
  3335. lWidth: single;
  3336. lTextWidthInMM: single;
  3337. lHeight: single;
  3338. lTextHeightInMM: single;
  3339. lColor: string;
  3340. lLineWidth: string;
  3341. lDescender: single;
  3342. begin
  3343. inherited Write(AStream);
  3344. WriteString('BT'+CRLF, AStream);
  3345. if Degrees <> 0.0 then
  3346. begin
  3347. rad := DegToRad(-Degrees);
  3348. t1 := FloatStr(Cos(rad));
  3349. t2 := FloatStr(-Sin(rad));
  3350. t3 := FloatStr(Sin(rad));
  3351. WriteString(Format('%s %s %s %s %s %s Tm', [t1, t2, t3, t1, FloatStr(X), FloatStr(Y)]) + CRLF, AStream);
  3352. end
  3353. else
  3354. begin
  3355. WriteString(FloatStr(X)+' '+FloatStr(Y)+' TD'+CRLF, AStream);
  3356. end;
  3357. FString.Write(AStream);
  3358. WriteString(' Tj'+CRLF, AStream);
  3359. WriteString('ET'+CRLF, AStream);
  3360. if (not Underline) and (not StrikeThrough) then
  3361. Exit;
  3362. // implement Underline and Strikethrough here
  3363. lFC := gTTFontCache.Find(Document.Fonts[Font.FontIndex].Name);
  3364. if not Assigned(lFC) then
  3365. Exit; // we can't do anything further
  3366. // result is in Font Units
  3367. lWidth := lFC.TextWidth(FString.Value, Font.PointSize);
  3368. lHeight := lFC.TextHeight(FString.Value, Font.PointSize, lDescender);
  3369. { convert the Font Units to Millimeters. This is also because fontcache DPI (default 96) could differ from PDF DPI (72). }
  3370. lTextWidthInMM := (lWidth * cInchToMM) / gTTFontCache.DPI;
  3371. lTextHeightInMM := (lHeight * cInchToMM) / gTTFontCache.DPI;
  3372. if Degrees <> 0.0 then
  3373. // angled text
  3374. WriteString(Format('q %s %s %s %s %s %s cm', [t1, t2, t3, t1, FloatStr(X), FloatStr(Y)]) + CRLF, AStream)
  3375. else
  3376. // horizontal text
  3377. WriteString(Format('q 1 0 0 1 %s %s cm', [FloatStr(X), FloatStr(Y)]) + CRLF, AStream);
  3378. { set up a pen width and stroke color }
  3379. lColor := TPDFColor.Command(True, Color);
  3380. lLineWidth := FloatStr(mmToPDF(lTextHeightInMM / 12)) + ' w ';
  3381. WriteString(lLineWidth + lColor + CRLF, AStream);
  3382. { line segment is relative to matrix translation coordinate, set above }
  3383. if Underline then
  3384. WriteString(Format('0 -1.5 m %s -1.5 l S', [FloatStr(mmToPDF(lTextWidthInMM))]) + CRLF, AStream);
  3385. if StrikeThrough then
  3386. WriteString(Format('0 %s m %s %0:s l S', [FloatStr(mmToPDF(lTextHeightInMM) / 2), FloatStr(mmToPDF(lTextWidthInMM))]) + CRLF, AStream);
  3387. { restore graphics state to before the translation matrix adjustment }
  3388. WriteString('Q' + CRLF, AStream);
  3389. end;
  3390. constructor TPDFUTF8Text.Create(const ADocument: TPDFDocument; const AX, AY: TPDFFloat; const AText: UTF8String;
  3391. const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean);
  3392. begin
  3393. inherited Create(ADocument);
  3394. X := AX;
  3395. Y := AY;
  3396. Font := AFont;
  3397. Degrees := ADegrees;
  3398. Underline := AUnderline;
  3399. if Assigned(AFont) and Assigned(AFont.Page) then
  3400. Color := AFont.Page.FLastFontColor;
  3401. StrikeThrough := AStrikeThrough;
  3402. FString := ADocument.CreateUTF8String(AText, AFont.FontIndex);
  3403. end;
  3404. destructor TPDFUTF8Text.Destroy;
  3405. begin
  3406. FreeAndNil(FString);
  3407. inherited Destroy;
  3408. end;
  3409. { TPDFUTF16Text }
  3410. procedure TPDFUTF16Text.Write(const AStream: TStream);
  3411. var
  3412. t1, t2, t3: string;
  3413. rad: single;
  3414. lFC: TFPFontCacheItem;
  3415. lWidth: single;
  3416. lTextWidthInMM: single;
  3417. lHeight: single;
  3418. lTextHeightInMM: single;
  3419. lColor: string;
  3420. lLineWidth: string;
  3421. lDescender: single;
  3422. v : UTF8String;
  3423. begin
  3424. inherited Write(AStream);
  3425. WriteString('BT'+CRLF, AStream);
  3426. if Degrees <> 0.0 then
  3427. begin
  3428. rad := DegToRad(-Degrees);
  3429. t1 := FloatStr(Cos(rad));
  3430. t2 := FloatStr(-Sin(rad));
  3431. t3 := FloatStr(Sin(rad));
  3432. WriteString(Format('%s %s %s %s %s %s Tm', [t1, t2, t3, t1, FloatStr(X), FloatStr(Y)]) + CRLF, AStream);
  3433. end
  3434. else
  3435. begin
  3436. WriteString(FloatStr(X)+' '+FloatStr(Y)+' TD'+CRLF, AStream);
  3437. end;
  3438. FString.Write(AStream);
  3439. WriteString(' Tj'+CRLF, AStream);
  3440. WriteString('ET'+CRLF, AStream);
  3441. if (not Underline) and (not StrikeThrough) then
  3442. Exit;
  3443. // implement Underline and Strikethrough here
  3444. lFC := gTTFontCache.Find(Document.Fonts[Font.FontIndex].Name);
  3445. if not Assigned(lFC) then
  3446. Exit; // we can't do anything further
  3447. // result is in Font Units
  3448. v:=UTF8Encode(FString.Value);
  3449. lWidth := lFC.TextWidth(v, Font.PointSize);
  3450. lHeight := lFC.TextHeight(v, Font.PointSize, lDescender);
  3451. { convert the Font Units to Millimeters. This is also because fontcache DPI (default 96) could differ from PDF DPI (72). }
  3452. lTextWidthInMM := (lWidth * cInchToMM) / gTTFontCache.DPI;
  3453. lTextHeightInMM := (lHeight * cInchToMM) / gTTFontCache.DPI;
  3454. if Degrees <> 0.0 then
  3455. // angled text
  3456. WriteString(Format('q %s %s %s %s %s %s cm', [t1, t2, t3, t1, FloatStr(X), FloatStr(Y)]) + CRLF, AStream)
  3457. else
  3458. // horizontal text
  3459. WriteString(Format('q 1 0 0 1 %s %s cm', [FloatStr(X), FloatStr(Y)]) + CRLF, AStream);
  3460. { set up a pen width and stroke color }
  3461. lColor := TPDFColor.Command(True, Color);
  3462. lLineWidth := FloatStr(mmToPDF(lTextHeightInMM / 12)) + ' w ';
  3463. WriteString(lLineWidth + lColor + CRLF, AStream);
  3464. { line segment is relative to matrix translation coordinate, set above }
  3465. if Underline then
  3466. WriteString(Format('0 -1.5 m %s -1.5 l S', [FloatStr(mmToPDF(lTextWidthInMM))]) + CRLF, AStream);
  3467. if StrikeThrough then
  3468. WriteString(Format('0 %s m %s %0:s l S', [FloatStr(mmToPDF(lTextHeightInMM) / 2), FloatStr(mmToPDF(lTextWidthInMM))]) + CRLF, AStream);
  3469. { restore graphics state to before the translation matrix adjustment }
  3470. WriteString('Q' + CRLF, AStream);
  3471. end;
  3472. constructor TPDFUTF16Text.Create(const ADocument: TPDFDocument; const AX, AY: TPDFFloat; const AText: UnicodeString;
  3473. const AFont: TPDFEmbeddedFont; const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean);
  3474. begin
  3475. inherited Create(ADocument);
  3476. X := AX;
  3477. Y := AY;
  3478. Font := AFont;
  3479. Degrees := ADegrees;
  3480. Underline := AUnderline;
  3481. if Assigned(AFont) and Assigned(AFont.Page) then
  3482. Color := AFont.Page.FLastFontColor;
  3483. StrikeThrough := AStrikeThrough;
  3484. FString := ADocument.CreateUTF16String(AText, AFont.FontIndex);
  3485. end;
  3486. destructor TPDFUTF16Text.Destroy;
  3487. begin
  3488. FreeAndNil(FString);
  3489. inherited Destroy;
  3490. end;
  3491. { TPDFLineSegment }
  3492. procedure TPDFLineSegment.Write(const AStream: TStream);
  3493. begin
  3494. SetWidth(FWidth,AStream);
  3495. if FStroke then
  3496. WriteString(TPDFMoveTo.Command(P1), AStream);
  3497. WriteString(Command(P2),AStream);
  3498. if FStroke then
  3499. WriteString('S'+CRLF, AStream);
  3500. end;
  3501. class function TPDFLineSegment.Command(APos: TPDFCoord): String;
  3502. begin
  3503. Result:=FloatStr(APos.X)+' '+FloatStr(APos.Y)+' l'+CRLF
  3504. end;
  3505. class function TPDFLineSegment.Command(x1, y1: TPDFFloat): String;
  3506. begin
  3507. Result := FloatStr(x1)+' '+FloatStr(y1)+' l'+CRLF
  3508. end;
  3509. class function TPDFLineSegment.Command(APos1, APos2: TPDFCoord): String;
  3510. begin
  3511. Result:=TPDFMoveTo.Command(APos1)+Command(APos2);
  3512. end;
  3513. constructor TPDFLineSegment.Create(const ADocument: TPDFDocument; const AWidth, X1, Y1, X2, Y2: TPDFFloat;
  3514. const AStroke: Boolean);
  3515. begin
  3516. inherited Create(ADocument);
  3517. FWidth:=AWidth;
  3518. P1.X:=X1;
  3519. P1.Y:=Y1;
  3520. P2.X:=X2;
  3521. P2.Y:=Y2;
  3522. FStroke := AStroke;
  3523. end;
  3524. { TPDFRectangle }
  3525. procedure TPDFRectangle.Write(const AStream: TStream);
  3526. begin
  3527. if FStroke then
  3528. SetWidth(FWidth, AStream);
  3529. WriteString(FloatStr(FTopLeft.X)+' '+FloatStr(FTopLeft.Y)+' '+FloatStr(FDimensions.X)+' '+FloatStr(FDimensions.Y)+' re'+CRLF, AStream);
  3530. if FStroke and FFill then
  3531. WriteString('b'+CRLF, AStream)
  3532. else if FFill then
  3533. WriteString('f'+CRLF, AStream)
  3534. else if FStroke then
  3535. WriteString('S'+CRLF, AStream);
  3536. (*
  3537. // should we default to this if no stroking or filling is required?
  3538. else
  3539. WriteString('n'+CRLF, AStream); // see PDF 1.3 Specification document on page 152
  3540. *)
  3541. end;
  3542. constructor TPDFRectangle.Create(const ADocument: TPDFDocument; const APosX, APosY, AWidth, AHeight,
  3543. ALineWidth: TPDFFloat; const AFill, AStroke: Boolean);
  3544. begin
  3545. inherited Create(ADocument);
  3546. FTopLeft.X := APosX;
  3547. FTopLeft.Y := APosY;
  3548. FDimensions.X := AWidth;
  3549. FDimensions.Y := AHeight;
  3550. FWidth := ALineWidth;
  3551. FFill := AFill;
  3552. FStroke := AStroke;
  3553. end;
  3554. { TPDFRoundedRectangle }
  3555. procedure TPDFRoundedRectangle.Write(const AStream: TStream);
  3556. var
  3557. c: TPDFFloat;
  3558. x1, y1, x2, y2: TPDFFloat;
  3559. begin
  3560. if FStroke then
  3561. SetWidth(FWidth, AStream);
  3562. // bottom left
  3563. x1 := FBottomLeft.X;
  3564. y1 := FBottomLeft.Y;
  3565. // top right
  3566. x2 := FBottomLeft.X + FDimensions.X;
  3567. y2 := FBottomLeft.Y + FDimensions.Y;
  3568. // radius
  3569. c := FRadius;
  3570. // Starting point is bottom left, then drawing anti-clockwise
  3571. WriteString(TPDFMoveTo.Command(x1+c, y1), AStream);
  3572. WriteString(TPDFLineSegment.Command(x2-c, y1), AStream);
  3573. WriteString(TPDFCurveC.Command(x2-c+BEZIER*c, y1, x2, y1+c-BEZIER*c, x2, y1+c), AStream);
  3574. WriteString(TPDFLineSegment.Command(x2, y2-c), AStream);
  3575. WriteString(TPDFCurveC.Command(x2, y2-c+BEZIER*c, x2-c+BEZIER*c, y2, x2-c, y2), AStream);
  3576. WriteString(TPDFLineSegment.Command(x1+c, y2), AStream);
  3577. WriteString(TPDFCurveC.Command(x1+c-BEZIER*c, y2, x1, y2-c+BEZIER*c, x1, y2-c), AStream);
  3578. WriteString(TPDFLineSegment.Command(x1, y1+c), AStream);
  3579. WriteString(TPDFCurveC.Command(x1, y1+c-BEZIER*c, x1+c-BEZIER*c, y1, x1+c, y1), AStream);
  3580. WriteString('h'+CRLF, AStream);
  3581. if FStroke and FFill then
  3582. WriteString('b'+CRLF, AStream)
  3583. else if FFill then
  3584. WriteString('f'+CRLF, AStream)
  3585. else if FStroke then
  3586. WriteString('S'+CRLF, AStream);
  3587. end;
  3588. constructor TPDFRoundedRectangle.Create(const ADocument: TPDFDocument; const APosX, APosY, AWidth, AHeight, ARadius,
  3589. ALineWidth: TPDFFloat; const AFill, AStroke: Boolean);
  3590. begin
  3591. inherited Create(ADocument);
  3592. FBottomLeft.X := APosX;
  3593. FBottomLeft.Y := APosY;
  3594. FDimensions.X := AWidth;
  3595. FDimensions.Y := AHeight;
  3596. FWidth := ALineWidth;
  3597. FFill := AFill;
  3598. FStroke := AStroke;
  3599. FRadius := ARadius;
  3600. end;
  3601. { TPDFSurface }
  3602. procedure TPDFSurface.Write(const AStream: TStream);
  3603. var
  3604. i: integer;
  3605. begin
  3606. WriteString(TPDFMoveTo.Command(FPoints[0].X,FPoints[0].Y),AStream);
  3607. for i:=1 to Pred(Length(FPoints)) do
  3608. WriteString(FloatStr( FPoints[i].X)+' '+FloatStr( FPoints[i].Y)+' l'+CRLF, AStream);
  3609. if FClose then
  3610. WriteString('h'+CRLF, AStream);
  3611. if FFill then
  3612. WriteString('f'+CRLF, AStream);
  3613. end;
  3614. constructor TPDFSurface.Create(Const ADocument : TPDFDocument; const APoints: TPDFCoordArray; AClose : Boolean; AFill : Boolean = True);
  3615. begin
  3616. inherited Create(ADocument);
  3617. FPoints:=APoints;
  3618. FClose:=AClose;
  3619. FFill:=AFill;
  3620. end;
  3621. procedure TPDFImage.Write(const AStream: TStream);
  3622. begin
  3623. WriteString(TPDFPushGraphicsStack.Command, AStream); // save graphics state
  3624. WriteString(FloatStr(FSize.X)+' 0 0 '+FloatStr(FSize.Y)+' '+FloatStr( FPos.X)+' '+FloatStr( FPos.Y)+' cm'+CRLF, AStream);
  3625. WriteString('/I'+IntToStr(FNumber)+' Do'+CRLF, AStream);
  3626. WriteString(TPDFPopGraphicsStack.Command, AStream); // restore graphics state
  3627. end;
  3628. constructor TPDFImage.Create(const ADocument: TPDFDocument; const ALeft, ABottom, AWidth, AHeight: TPDFFloat; ANumber: integer);
  3629. begin
  3630. inherited Create(ADocument);
  3631. FNumber:=ANumber;
  3632. FPos.X:=ALeft;
  3633. FPos.Y:=ABottom;
  3634. FSize.X:=AWidth;
  3635. FSize.Y:=AHeight;
  3636. end;
  3637. // Dot = linewidth; Dash = (5 x linewidth); Gap = (3 x linewidth);
  3638. procedure TPDFLineStyle.Write(const AStream: TStream);
  3639. var
  3640. lMask: string;
  3641. w: TPDFFloat;
  3642. begin
  3643. w := FLineWidth;
  3644. case FStyle of
  3645. ppsSolid:
  3646. begin
  3647. lMask := '';
  3648. end;
  3649. ppsDash:
  3650. begin
  3651. lMask := FloatStr(5*w) + ' ' + FloatStr(5*w);
  3652. end;
  3653. ppsDot:
  3654. begin
  3655. lMask := FloatStr(0.8*w) + ' ' + FloatStr(4*w)
  3656. end;
  3657. ppsDashDot:
  3658. begin
  3659. lMask := FloatStr(5*w) + ' ' + FloatStr(3*w) + ' ' + FloatStr(0.8*w) + ' ' + FloatStr(3*w)
  3660. end;
  3661. ppsDashDotDot:
  3662. begin
  3663. lMask := FloatStr(5*w) + ' ' + FloatStr(3*w) + ' ' + FloatStr(0.8*w) + ' ' + FloatStr(3*w) + ' ' + FloatStr(0.8*w) + ' ' + FloatStr(3*w)
  3664. end;
  3665. end;
  3666. WriteString(Format('[%s] %d d'+CRLF,[lMask, FPhase]), AStream);
  3667. end;
  3668. constructor TPDFLineStyle.Create(const ADocument: TPDFDocument; AStyle: TPDFPenStyle; APhase: integer;
  3669. ALineWidth: TPDFFloat);
  3670. begin
  3671. inherited Create(ADocument);
  3672. FStyle := AStyle;
  3673. FPhase := APhase;
  3674. FLineWidth := ALineWidth;
  3675. end;
  3676. Function ARGBGetRed(AColor : TARGBColor) : Byte;
  3677. begin
  3678. Result:=((AColor shr 16) and $FF)
  3679. end;
  3680. Function ARGBGetGreen(AColor : TARGBColor) : Byte;
  3681. begin
  3682. Result:=((AColor shr 8) and $FF)
  3683. end;
  3684. Function ARGBGetBlue(AColor : TARGBColor) : Byte;
  3685. begin
  3686. Result:=AColor and $FF;
  3687. end;
  3688. Function ARGBGetAlpha(AColor : TARGBColor) : Byte;
  3689. begin
  3690. Result:=((AColor shr 24) and $FF)
  3691. end;
  3692. procedure TPDFColor.Write(const AStream: TStream);
  3693. var
  3694. S : String;
  3695. begin
  3696. S:=FRed+' '+FGreen+' '+FBlue;
  3697. if FStroke then
  3698. S:=S+' RG'
  3699. else
  3700. S:=S+' rg';
  3701. if (S<>Document.CurrentColor) then
  3702. begin
  3703. WriteString(S+CRLF, AStream);
  3704. Document.CurrentColor:=S;
  3705. end;
  3706. end;
  3707. class function TPDFColor.Command(const AStroke: boolean; const AColor: TARGBColor): string;
  3708. var
  3709. lR, lG, lB: string;
  3710. begin
  3711. lR := FloatStr(ARGBGetRed(AColor)/256);
  3712. lG := FloatStr(ARGBGetGreen(AColor)/256);
  3713. lB := FloatStr(ARGBGetBlue(AColor)/256);
  3714. result := lR+' '+lG+' '+lB+' ';
  3715. if AStroke then
  3716. result := result + 'RG'
  3717. else
  3718. result := result + 'rg'
  3719. end;
  3720. constructor TPDFColor.Create(Const ADocument : TPDFDocument; const AStroke: Boolean; AColor: TARGBColor);
  3721. begin
  3722. inherited Create(ADocument);
  3723. FColor := AColor;
  3724. FRed:=FloatStr( ARGBGetRed(AColor)/256);
  3725. FGreen:=FloatStr( ARGBGetGreen(AColor)/256);
  3726. FBlue:=FloatStr( ARGBGetBlue(AColor)/256);
  3727. FStroke:=AStroke;
  3728. end;
  3729. procedure TPDFDictionaryItem.Write(const AStream: TStream);
  3730. begin
  3731. FKey.Write(AStream);
  3732. TPDFObject.WriteString(' ', AStream);
  3733. FObj.Write(AStream);
  3734. TPDFObject.WriteString(CRLF, AStream);
  3735. end;
  3736. constructor TPDFDictionaryItem.Create(Const ADocument : TPDFDocument;const AKey: string; const AValue: TPDFObject);
  3737. begin
  3738. inherited Create(ADocument);
  3739. FKey:=ADocument.CreateName(AKey);
  3740. FObj:=AValue;
  3741. end;
  3742. destructor TPDFDictionaryItem.Destroy;
  3743. begin
  3744. FreeAndNil(FKey);
  3745. // TPDFBoolean,TPDFDictionary,TPDFInteger,TPDFName,TPDFReference,TPDFString,TPDFArray
  3746. FreeAndNil(FObj);
  3747. inherited;
  3748. end;
  3749. function TPDFDictionary.GetE(AIndex : Integer): TPDFDictionaryItem;
  3750. begin
  3751. Result:=TPDFDictionaryItem(FElements[AIndex]);
  3752. end;
  3753. function TPDFDictionary.GetEC: Integer;
  3754. begin
  3755. Result:=FElements.Count;
  3756. end;
  3757. function TPDFDictionary.GetV(AIndex : Integer): TPDFObject;
  3758. begin
  3759. Result:=Elements[AIndex].Value;
  3760. end;
  3761. procedure TPDFDictionary.AddElement(const AKey: string; const AValue: TPDFObject);
  3762. var
  3763. DicElement: TPDFDictionaryItem;
  3764. begin
  3765. DicElement:=TPDFDictionaryItem.Create(Document,AKey, AValue);
  3766. FElements.Add(DicElement);
  3767. end;
  3768. procedure TPDFDictionary.AddName(const AKey, AName: String; const AMustEscape: boolean = True);
  3769. begin
  3770. AddElement(AKey,Document.CreateName(AName, AMustEscape));
  3771. end;
  3772. procedure TPDFDictionary.AddInteger(const AKey: String; AInteger: Integer);
  3773. begin
  3774. AddElement(AKey,Document.CreateInteger(AInteger));
  3775. end;
  3776. procedure TPDFDictionary.AddReference(const AKey: String; AReference: Integer);
  3777. begin
  3778. AddElement(AKey,Document.CreateReference(AReference));
  3779. end;
  3780. procedure TPDFDictionary.AddString(const AKey, AString: String);
  3781. begin
  3782. AddElement(AKey,Document.CreateString(AString));
  3783. end;
  3784. procedure TPDFDictionary.AddString(const AKey:string;const AString: UnicodeString);
  3785. begin
  3786. AddElement(AKey,Document.CreateUTF16String(AString,-1));
  3787. end;
  3788. function TPDFDictionary.IndexOfKey(const AValue: string): integer;
  3789. var
  3790. i: integer;
  3791. begin
  3792. Result:=-1;
  3793. I:=0;
  3794. While (Result=-1) and (I<ElementCount) do
  3795. begin
  3796. if GetE(I).FKey.Name=AValue then
  3797. Result:=I;
  3798. Inc(I);
  3799. end;
  3800. end;
  3801. procedure TPDFDictionary.Write(const AStream: TStream);
  3802. begin
  3803. WriteDictionary(-1,AStream);
  3804. end;
  3805. procedure TPDFDictionary.WriteDictionary(const AObject: integer; const AStream: TStream);
  3806. var
  3807. ISize,i, NumImg, NumFnt, BufSize: integer;
  3808. Value: string;
  3809. M, Buf : TMemoryStream;
  3810. E : TPDFDictionaryItem;
  3811. D : TPDFDictionary;
  3812. begin
  3813. if GetE(0).FKey.Name='' then
  3814. GetE(0).Write(AStream) // write a charwidth array of a font
  3815. else
  3816. begin
  3817. WriteString('<<'+CRLF, AStream);
  3818. for i:=0 to ElementCount-1 do
  3819. GetE(I).Write(AStream);
  3820. NumImg:=-1;
  3821. NumFnt:=-1;
  3822. for i:=0 to ElementCount-1 do
  3823. begin
  3824. E:=GetE(i);
  3825. if AObject > -1 then
  3826. begin
  3827. if (E.FKey.Name='Name') then
  3828. begin
  3829. if (TPDFObject(E.Value) is TPDFName) and (TPDFName(E.Value).Name[1]='M') then
  3830. begin
  3831. NumImg:=StrToInt(Copy(TPDFName(E.Value).Name, 2, Length(TPDFName(E.Value).Name) - 1));
  3832. // write image stream length in xobject dictionary
  3833. ISize:=Length(Document.Images[NumImg].StreamedMask);
  3834. D:=Document.GlobalXRefs[AObject].Dict;
  3835. D.AddInteger('Length',ISize);
  3836. LastElement.Write(AStream);
  3837. case Document.Images[NumImg].FCompressionMask of
  3838. icJPEG: WriteString('/Filter /DCTDecode'+CRLF, AStream);
  3839. icDeflate: WriteString('/Filter /FlateDecode'+CRLF, AStream);
  3840. end;
  3841. WriteString('>>', AStream);
  3842. // write image stream in xobject dictionary
  3843. Document.Images[NumImg].WriteMaskStream(AStream);
  3844. end else
  3845. if (TPDFObject(E.Value) is TPDFName) and (TPDFName(E.Value).Name[1]='I') then
  3846. begin
  3847. NumImg:=StrToInt(Copy(TPDFName(E.Value).Name, 2, Length(TPDFName(E.Value).Name) - 1));
  3848. // write image stream length in xobject dictionary
  3849. ISize:=Length(Document.Images[NumImg].StreamedData);
  3850. D:=Document.GlobalXRefs[AObject].Dict;
  3851. D.AddInteger('Length',ISize);
  3852. LastElement.Write(AStream);
  3853. case Document.Images[NumImg].FCompression of
  3854. icJPEG: WriteString('/Filter /DCTDecode'+CRLF, AStream);
  3855. icDeflate: WriteString('/Filter /FlateDecode'+CRLF, AStream);
  3856. end;
  3857. WriteString('>>', AStream);
  3858. // write image stream in xobject dictionary
  3859. Document.Images[NumImg].WriteImageStream(AStream);
  3860. end;
  3861. end;
  3862. if Pos('Length1', E.FKey.Name) > 0 then
  3863. begin
  3864. Value:=E.FKey.Name;
  3865. NumFnt:=StrToInt(Copy(Value, Succ(Pos(' ', Value)), Length(Value) - Pos(' ', Value)));
  3866. if poSubsetFont in Document.Options then
  3867. begin
  3868. buf := TMemoryStream.Create;
  3869. try
  3870. // write fontfile stream (could be compressed or not) to a temporary buffer so we can get the size
  3871. BufSize := TPDFEmbeddedFont.WriteEmbeddedSubsetFont(Document, NumFnt, Buf);
  3872. Buf.Position := 0;
  3873. // write fontfile stream length in xobject dictionary
  3874. D := Document.GlobalXRefs[AObject].Dict;
  3875. D.AddInteger('Length', BufSize);
  3876. LastElement.Write(AStream);
  3877. WriteString('>>', AStream);
  3878. // write fontfile buffer stream in xobject dictionary
  3879. Buf.SaveToStream(AStream);
  3880. finally
  3881. Buf.Free;
  3882. end;
  3883. end
  3884. else
  3885. begin
  3886. M:=TMemoryStream.Create;
  3887. try
  3888. m.LoadFromFile(Document.FontFiles[NumFnt]);
  3889. Buf := TMemoryStream.Create;
  3890. try
  3891. // write fontfile stream (could be compressed or not) to a temporary buffer so we can get the size
  3892. BufSize := TPDFEmbeddedFont.WriteEmbeddedFont(Document, M, Buf);
  3893. Buf.Position := 0;
  3894. // write fontfile stream length in xobject dictionary
  3895. D := Document.GlobalXRefs[AObject].Dict;
  3896. D.AddInteger('Length', BufSize);
  3897. LastElement.Write(AStream);
  3898. WriteString('>>', AStream);
  3899. // write fontfile buffer stream in xobject dictionary
  3900. Buf.SaveToStream(AStream);
  3901. finally
  3902. Buf.Free;
  3903. end;
  3904. finally
  3905. M.Free;
  3906. end;
  3907. end;
  3908. end;
  3909. end;
  3910. end; { for i... }
  3911. end; { if FElement.Count... }
  3912. if (NumImg = -1) and (NumFnt = -1) then
  3913. WriteString('>>', AStream);
  3914. end; { if/else }
  3915. function TPDFDictionary.LastElement: TPDFDictionaryItem;
  3916. begin
  3917. if (ElementCount=0) then
  3918. Result:=Nil
  3919. else
  3920. Result:=GetE(ElementCount-1);
  3921. end;
  3922. function TPDFDictionary.LastValue: TPDFObject;
  3923. Var
  3924. DE : TPDFDictionaryItem;
  3925. begin
  3926. DE:=LastElement;
  3927. If Assigned(DE) then
  3928. Result:=DE.Value
  3929. else
  3930. Result:=Nil;
  3931. end;
  3932. function TPDFDictionary.FindElement(const AKey: String): TPDFDictionaryItem;
  3933. Var
  3934. I : integer;
  3935. begin
  3936. I:=IndexOfKey(AKey);
  3937. if I=-1 then
  3938. Result:=Nil
  3939. else
  3940. Result:=GetE(I);
  3941. end;
  3942. function TPDFDictionary.FindValue(const AKey: String): TPDFObject;
  3943. Var
  3944. DI : TPDFDictionaryItem;
  3945. begin
  3946. DI:=FindElement(AKey);
  3947. if Assigned(DI) then
  3948. Result:=DI.Value
  3949. else
  3950. Result:=Nil;
  3951. end;
  3952. function TPDFDictionary.ElementByName(const AKey: String): TPDFDictionaryItem;
  3953. begin
  3954. Result:=FindElement(AKey);
  3955. If (Result=Nil) then
  3956. Raise EPDF.CreateFmt(rsErrDictElementNotFound,[AKey]);
  3957. end;
  3958. function TPDFDictionary.ValueByName(const AKey: String): TPDFObject;
  3959. begin
  3960. Result:=ElementByName(AKey).Value;
  3961. end;
  3962. constructor TPDFDictionary.Create(const ADocument: TPDFDocument);
  3963. begin
  3964. inherited Create(ADocument);
  3965. FElements:=TFPObjectList.Create;
  3966. end;
  3967. destructor TPDFDictionary.Destroy;
  3968. begin
  3969. FreeAndNil(FElements);
  3970. inherited;
  3971. end;
  3972. procedure TPDFXRef.Write(const AStream: TStream);
  3973. begin
  3974. TPDFObject.WriteString(FormatPDFInt(FOffset, 10)+' '+FormatPDFInt(0, 5)+' n'+CRLF, AStream);
  3975. end;
  3976. constructor TPDFXRef.Create(Const ADocument : TPDFDocument);
  3977. begin
  3978. inherited Create;
  3979. FOffset:=0;
  3980. FDict:=ADocument.CreateDictionary;
  3981. FStream:=nil;
  3982. end;
  3983. destructor TPDFXRef.Destroy;
  3984. begin
  3985. FreeAndNil(FDict);
  3986. FreeAndNil(FStream);
  3987. inherited;
  3988. end;
  3989. { TPDFInfos }
  3990. constructor TPDFInfos.Create;
  3991. begin
  3992. inherited Create;
  3993. FProducer := 'fpGUI Toolkit 1.4';
  3994. FKeywords:= '';
  3995. end;
  3996. { TPDFFontNumBaseObject }
  3997. constructor TPDFFontNumBaseObject.Create(const ADocument: TPDFDocument; const AFontNum: integer);
  3998. begin
  3999. inherited Create(ADocument);
  4000. FFontNum := AFontNum;
  4001. end;
  4002. { TPDFToUnicode }
  4003. procedure TPDFToUnicode.Write(const AStream: TStream);
  4004. var
  4005. lst: TTextMappingList;
  4006. i: integer;
  4007. begin
  4008. lst := Document.Fonts[FontNum].TextMapping;
  4009. WriteString('/CIDInit /ProcSet findresource begin'+CRLF, AStream);
  4010. WriteString('12 dict begin'+CRLF, AStream);
  4011. WriteString('begincmap'+CRLF, AStream);
  4012. WriteString('/CIDSystemInfo'+CRLF, AStream);
  4013. WriteString('<</Registry (Adobe)'+CRLF, AStream);
  4014. if poSubsetFont in Document.Options then
  4015. WriteString('/Ordering (UCS)'+CRLF, AStream)
  4016. else
  4017. WriteString('/Ordering (Identity)'+CRLF, AStream);
  4018. WriteString('/Supplement 0'+CRLF, AStream);
  4019. WriteString('>> def'+CRLF, AStream);
  4020. if poSubsetFont in Document.Options then
  4021. WriteString('/CMapName /Adobe-Identity-UCS def'+CRLF, AStream)
  4022. else
  4023. WriteString(Format('/CMapName /%s def', [Document.Fonts[FontNum].FTrueTypeFile.PostScriptName])+CRLF, AStream);
  4024. WriteString('/CMapType 2 def'+CRLF, AStream); // 2 = ToUnicode
  4025. // ToUnicode always uses 16-bit CIDs
  4026. WriteString('1 begincodespacerange'+CRLF, AStream);
  4027. WriteString('<0000> <FFFF>'+CRLF, AStream);
  4028. WriteString('endcodespacerange'+CRLF, AStream);
  4029. if poSubsetFont in Document.Options then
  4030. begin
  4031. { TODO: Future Improvement - We can reduce the entries in the beginbfrange
  4032. by actually using ranges for consecutive numbers.
  4033. eg:
  4034. <0051> <0053> <006E>
  4035. vs
  4036. <0051> <0051> <006E>
  4037. <0052> <0052> <006F>
  4038. <0053> <0053> <0070>
  4039. }
  4040. // use hex values in the output
  4041. WriteString(Format('%d beginbfrange', [lst.Count-1])+CRLF, AStream);
  4042. for i := 1 to lst.Count-1 do
  4043. WriteString(Format('<%s> <%0:s> <%s>', [IntToHex(lst[i].GlyphID, 4), IntToHex(lst[i].CharID, 4)])+CRLF, AStream);
  4044. WriteString('endbfrange'+CRLF, AStream);
  4045. end
  4046. else
  4047. begin
  4048. WriteString(Format('%d beginbfchar', [lst.Count])+CRLF, AStream);
  4049. for i := 0 to lst.Count-1 do
  4050. WriteString(Format('<%s> <%s>', [IntToHex(lst[i].GlyphID, 4), IntToHex(lst[i].CharID, 4)])+CRLF, AStream);
  4051. WriteString('endbfchar'+CRLF, AStream);
  4052. end;
  4053. WriteString('endcmap'+CRLF, AStream);
  4054. WriteString('CMapName currentdict /CMap defineresource pop'+CRLF, AStream);
  4055. WriteString('end'+CRLF, AStream);
  4056. WriteString('end'+CRLF, AStream);
  4057. end;
  4058. { TCIDToGIDMap }
  4059. procedure TCIDToGIDMap.Write(const AStream: TStream);
  4060. var
  4061. lst: TTextMappingList;
  4062. i: integer;
  4063. cid, gid: uint16;
  4064. ba: TBytes;
  4065. lMaxCID: integer;
  4066. begin
  4067. lst := Document.Fonts[FontNum].TextMapping;
  4068. lst.Sort;
  4069. lMaxCID := lst.GetMaxGlyphID;
  4070. SetLength(ba, (lMaxCID + 1)*2);
  4071. // initialize array to 0's
  4072. for i := 0 to Length(ba)-1 do
  4073. ba[i] := 0;
  4074. for i := 0 to lst.Count-1 do
  4075. begin
  4076. cid := lst[i].GlyphID;
  4077. gid := lst[i].NewGlyphID;
  4078. ba[2*cid] := Hi(gid); // Byte((gid shr 8) and $FF); //Hi(gid);
  4079. ba[(2*cid)+1] := Lo(gid); //Byte(gid and $FF); //Lo(gid);
  4080. end;
  4081. AStream.WriteBuffer(ba[0], Length(ba));
  4082. //WriteString(CRLF, AStream);
  4083. SetLength(ba, 0);
  4084. end;
  4085. { TPDFCIDSet }
  4086. { CIDSet uses the bits of each byte for optimised storage. }
  4087. procedure TPDFCIDSet.Write(const AStream: TStream);
  4088. var
  4089. lst: TTextMappingList;
  4090. i: integer;
  4091. cid, gid: uint16;
  4092. ba: TBytes;
  4093. mask: uint8;
  4094. lSize: integer;
  4095. begin
  4096. lst := Document.Fonts[FontNum].TextMapping;
  4097. lst.Sort;
  4098. lSize := (lst.GetMaxGlyphID div 8) + 1;
  4099. SetLength(ba, lSize);
  4100. for i := 0 to lst.Count-1 do
  4101. begin
  4102. cid := lst[i].GlyphID;
  4103. mask := 1 shl (7 - (cid mod 8));
  4104. if cid = 0 then
  4105. gid := 0
  4106. else
  4107. gid := cid div 8;
  4108. ba[gid] := ba[gid] or mask;
  4109. end;
  4110. AStream.WriteBuffer(ba[0], Length(ba));
  4111. //WriteString(CRLF, AStream);
  4112. SetLength(ba, 0);
  4113. end;
  4114. { TPDFDocument }
  4115. procedure TPDFDocument.SetInfos(AValue: TPDFInfos);
  4116. begin
  4117. if FInfos=AValue then Exit;
  4118. FInfos.Assign(AValue);
  4119. end;
  4120. procedure TPDFDocument.SetOptions(aValue: TPDFOptions);
  4121. begin
  4122. if FOptions=AValue then Exit;
  4123. if (poNoEmbeddedFonts in aValue) then
  4124. Exclude(aValue,poSubsetFont);
  4125. FOptions:=aValue;
  4126. end;
  4127. procedure TPDFDocument.SetLineStyles(AValue: TPDFLineStyleDefs);
  4128. begin
  4129. if FLineStyleDefs=AValue then Exit;
  4130. FLineStyleDefs.Assign(AValue);
  4131. end;
  4132. procedure TPDFDocument.SetFonts(AValue: TPDFFontDefs);
  4133. begin
  4134. if FFonts=AValue then Exit;
  4135. FFonts:=AValue;
  4136. end;
  4137. procedure TPDFDocument.SetFontFiles(AValue: TStrings);
  4138. begin
  4139. if FFontFiles=AValue then Exit;
  4140. FFontFiles.Assign(AValue);
  4141. end;
  4142. function TPDFDocument.GetStdFontCharWidthsArray(const AFontName: string): TPDFFontWidthArray;
  4143. begin
  4144. case AFontName of
  4145. 'Courier': result := FONT_COURIER_FULL;
  4146. 'Courier-Bold': result := FONT_COURIER_FULL;
  4147. 'Courier-Oblique': result := FONT_COURIER_FULL;
  4148. 'Courier-BoldOblique': result := FONT_COURIER_FULL;
  4149. 'Helvetica': result := FONT_HELVETICA_ARIAL;
  4150. 'Helvetica-Bold': result := FONT_HELVETICA_ARIAL_BOLD;
  4151. 'Helvetica-Oblique': result := FONT_HELVETICA_ARIAL_ITALIC;
  4152. 'Helvetica-BoldOblique': result := FONT_HELVETICA_ARIAL_BOLD_ITALIC;
  4153. 'Times-Roman': result := FONT_TIMES;
  4154. 'Times-Bold': result := FONT_TIMES_BOLD;
  4155. 'Times-Italic': result := FONT_TIMES_ITALIC;
  4156. 'Times-BoldItalic': result := FONT_TIMES_BOLD_ITALIC;
  4157. 'Symbol': result := FONT_SYMBOL;
  4158. 'ZapfDingbats': result := FONT_ZAPFDINGBATS;
  4159. else
  4160. raise EPDF.CreateFmt(rsErrUnknownStdFont, [AFontName]);
  4161. end;
  4162. end;
  4163. function TPDFDocument.GetX(AIndex : Integer): TPDFXRef;
  4164. begin
  4165. Result:=FGlobalXRefs[Aindex] as TPDFXRef;
  4166. end;
  4167. function TPDFDocument.GetXC: Integer;
  4168. begin
  4169. Result:=FGlobalXRefs.Count;
  4170. end;
  4171. function TPDFDocument.GetTotalAnnotsCount: integer;
  4172. var
  4173. i: integer;
  4174. begin
  4175. Result := 0;
  4176. for i := 0 to Pages.Count-1 do
  4177. Result := Result + Pages[i].Annots.Count;
  4178. end;
  4179. function TPDFDocument.GetFontNamePrefix(const AFontNum: Integer): string;
  4180. begin
  4181. // TODO: it must be 6 uppercase characters - no numbers!
  4182. Result := 'GRAEA' + Char(65+AFontNum) + '+';
  4183. end;
  4184. function TPDFDocument.IndexOfGlobalXRef(const AValue: string): integer;
  4185. var
  4186. i: integer;
  4187. p : TPDFObject;
  4188. begin
  4189. Result:=-1;
  4190. I:=1;
  4191. While (Result=-1) and (I<FGlobalXRefs.Count) do
  4192. begin
  4193. p:=GetX(i).Dict.Elements[0].Value;
  4194. if (p is TPDFName) and (TPDFName(p).Name=AValue) then
  4195. Result:=i;
  4196. Inc(I);
  4197. end;
  4198. end;
  4199. function TPDFDocument.FindGlobalXRef(const AName: String): TPDFXRef;
  4200. Var
  4201. I : Integer;
  4202. begin
  4203. I:=IndexOfGlobalXRef(AName);
  4204. if I=-1 then
  4205. Result:=Nil
  4206. else
  4207. Result:=GlobalXRefs[i];
  4208. end;
  4209. procedure TPDFDocument.WriteXRefTable(const AStream: TStream);
  4210. var
  4211. i: integer;
  4212. begin
  4213. if FGlobalXRefs.Count > 1 then
  4214. for i:=1 to FGlobalXRefs.Count-1 do
  4215. GetX(i).Write(AStream);
  4216. end;
  4217. procedure TPDFDocument.WriteObject(const AObject: integer; const AStream: TStream);
  4218. var
  4219. M : TMemoryStream;
  4220. MCompressed: TMemoryStream;
  4221. X : TPDFXRef;
  4222. d: integer;
  4223. begin
  4224. TPDFObject.WriteString(IntToStr(AObject)+' 0 obj'+CRLF, AStream);
  4225. X:=GlobalXRefs[AObject];
  4226. if X.FStream = nil then
  4227. X.Dict.WriteDictionary(AObject, AStream)
  4228. else
  4229. begin
  4230. CurrentColor := '';
  4231. CurrentWidth := '';
  4232. M := TMemoryStream.Create;
  4233. X.FStream.Write(M);
  4234. d := M.Size;
  4235. if (poCompressText in Options) and not X.FStream.CompressionProhibited then
  4236. begin
  4237. MCompressed := TMemoryStream.Create;
  4238. CompressStream(M, MCompressed);
  4239. X.Dict.AddName('Filter', 'FlateDecode');
  4240. //X.Dict.AddInteger('Length1', MCompressed.Size); //Missing 'endstream' or incorrect stream length|stream Length incorrect
  4241. d := MCompressed.Size;
  4242. end;
  4243. X.Dict.AddInteger('Length', d);
  4244. X.Dict.Write(AStream);
  4245. // write stream in contents dictionary
  4246. CurrentColor:='';
  4247. CurrentWidth:='';
  4248. TPDFObject.WriteString(CRLF+'stream'+CRLF, AStream);
  4249. if (poCompressText in Options) and not X.FStream.CompressionProhibited then
  4250. begin
  4251. MCompressed.Position := 0;
  4252. MCompressed.SaveToStream(AStream);
  4253. MCompressed.Free;
  4254. end
  4255. else
  4256. begin
  4257. M.Position := 0;
  4258. m.SaveToStream(AStream);
  4259. // X.FStream.Write(AStream);
  4260. end;
  4261. M.Free;
  4262. TPDFObject.WriteString(CRLF, AStream);
  4263. TPDFObject.WriteString('endstream', AStream);
  4264. end;
  4265. TPDFObject.WriteString(CRLF+'endobj'+CRLF+CRLF, AStream);
  4266. end;
  4267. procedure TPDFDocument.CreateRefTable;
  4268. begin
  4269. FGlobalXRefs:=TFPObjectList.Create;
  4270. FGlobalXRefs.Add(CreateXRef);
  4271. end;
  4272. procedure TPDFDocument.CreateTrailer;
  4273. begin
  4274. FTrailer:=CreateDictionary;
  4275. Trailer.AddInteger('Size',GlobalXRefCount);
  4276. end;
  4277. function TPDFDocument.CreateCatalogEntry: integer;
  4278. var
  4279. CDict: TPDFDictionary;
  4280. begin
  4281. CDict:=CreateGlobalXRef.Dict;
  4282. Trailer.AddReference('Root',GlobalXRefCount-1);
  4283. CDict.AddName('Type','Catalog');
  4284. CDict.AddName('PageLayout', PageLayoutNames[FPageLayout]);
  4285. CDict.AddElement('OpenAction', CreateArray);
  4286. Result:=GlobalXRefCount-1;
  4287. end;
  4288. procedure TPDFDocument.CreateInfoEntry(UseUTF16 : Boolean);
  4289. var
  4290. IDict: TPDFDictionary;
  4291. Procedure DoEntry(aName, aValue : String; NoUnicode: boolean = false);
  4292. begin
  4293. if aValue='' then exit;
  4294. if UseUTF16 and not NoUnicode then
  4295. IDict.AddString(aName,utf8decode(aValue))
  4296. else
  4297. IDict.AddString(aName,aValue);
  4298. end;
  4299. begin
  4300. IDict:=CreateGlobalXRef.Dict;
  4301. Trailer.AddReference('Info', GLobalXRefCount-1);
  4302. (Trailer.ValueByName('Size') as TPDFInteger).Value:=GLobalXRefCount;
  4303. DoEntry('Title',Infos.Title);
  4304. DoEntry('Author',Infos.Author);
  4305. DoEntry('Creator',Infos.ApplicationName);
  4306. DoEntry('Producer',Infos.Producer);
  4307. DoEntry('CreationDate',DateToPdfDate(Infos.CreationDate),True);
  4308. DoEntry('Keywords',Infos.Keywords);
  4309. end;
  4310. procedure TPDFDocument.CreateMetadataEntry;
  4311. var
  4312. lXRef: TPDFXRef;
  4313. begin
  4314. lXRef := CreateGlobalXRef;
  4315. lXRef.Dict.AddName('Type','Metadata');
  4316. lXRef.Dict.AddName('Subtype', 'XML');
  4317. lXRef.FStream := CreateStream(True);
  4318. lXRef.FStream.AddItem(TXMPStream.Create(self));
  4319. lXRef.FStream.CompressionProhibited := True;
  4320. GlobalXRefs[Catalogue].Dict.AddReference('Metadata', GLobalXRefCount-1)
  4321. end;
  4322. procedure TPDFDocument.AddOutputIntent(const Subtype, OutputConditionIdentifier, Info: string; ICCProfile: TStream);
  4323. var
  4324. OutputIntents: TPDFObject;
  4325. OIDict: TPDFDictionary;
  4326. OIRef: Integer;
  4327. Profile: TPDFXRef;
  4328. begin
  4329. OIRef := GLobalXRefCount;
  4330. OIDict := CreateGlobalXRef.Dict;
  4331. OIDict.AddName('Type', 'OutputIntent');
  4332. OIDict.AddName('S', Subtype);
  4333. OIDict.AddString('OutputConditionIdentifier', OutputConditionIdentifier);
  4334. if Info <> '' then
  4335. OIDict.AddString('Info', Info);
  4336. if Assigned(ICCProfile) then begin
  4337. Profile := CreateGlobalXRef;
  4338. Profile.Dict.AddInteger('N', 3);
  4339. Profile.FStream := CreateStream(True);
  4340. Profile.FStream.AddItem(TPDFMemoryStream.Create(self, ICCProfile));
  4341. OIDict.AddReference('DestOutputProfile', GLobalXRefCount-1);
  4342. end;
  4343. OutputIntents := GlobalXRefs[Catalogue].Dict.FindValue('OutputIntents');
  4344. if not Assigned(OutputIntents) then begin
  4345. OutputIntents := CreateArray;
  4346. GlobalXRefs[Catalogue].Dict.AddElement('OutputIntents', OutputIntents);
  4347. end;
  4348. (OutputIntents as TPDFArray).AddItem(CreateReference(OIRef));
  4349. end;
  4350. {ICC v2 sRGB profile http://www.color.org/srgbprofiles.xalter
  4351. This profile is made available by the International Color Consortium, and may be copied, distributed, embedded, made,
  4352. used, and sold without restriction. Altered versions of this profile shall have the original identification and copyright
  4353. information removed and shall not be misrepresented as the original profile.}
  4354. const ICC_sRGB2014 : array [1..3024] of byte =
  4355. ($00,$00,$0B,$D0,$00,$00,$00,$00,$02,$00,$00,$00,$6D,$6E,$74,$72,$52,$47,$42,$20,$58,$59,$5A,$20,$07,$DF,$00,$02,$00,$0F,$00,$00,
  4356. $00,$00,$00,$00,$61,$63,$73,$70,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$00,$00,$00,
  4357. $00,$00,$00,$00,$00,$00,$F6,$D6,$00,$01,$00,$00,$00,$00,$D3,$2D,$00,$00,$00,$00,$3D,$0E,$B2,$DE,$AE,$93,$97,$BE,$9B,$67,$26,$CE,
  4358. $8C,$0A,$43,$CE,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  4359. $00,$00,$00,$10,$64,$65,$73,$63,$00,$00,$01,$44,$00,$00,$00,$63,$62,$58,$59,$5A,$00,$00,$01,$A8,$00,$00,$00,$14,$62,$54,$52,$43,
  4360. $00,$00,$01,$BC,$00,$00,$08,$0C,$67,$54,$52,$43,$00,$00,$01,$BC,$00,$00,$08,$0C,$72,$54,$52,$43,$00,$00,$01,$BC,$00,$00,$08,$0C,
  4361. $64,$6D,$64,$64,$00,$00,$09,$C8,$00,$00,$00,$88,$67,$58,$59,$5A,$00,$00,$0A,$50,$00,$00,$00,$14,$6C,$75,$6D,$69,$00,$00,$0A,$64,
  4362. $00,$00,$00,$14,$6D,$65,$61,$73,$00,$00,$0A,$78,$00,$00,$00,$24,$62,$6B,$70,$74,$00,$00,$0A,$9C,$00,$00,$00,$14,$72,$58,$59,$5A,
  4363. $00,$00,$0A,$B0,$00,$00,$00,$14,$74,$65,$63,$68,$00,$00,$0A,$C4,$00,$00,$00,$0C,$76,$75,$65,$64,$00,$00,$0A,$D0,$00,$00,$00,$87,
  4364. $77,$74,$70,$74,$00,$00,$0B,$58,$00,$00,$00,$14,$63,$70,$72,$74,$00,$00,$0B,$6C,$00,$00,$00,$37,$63,$68,$61,$64,$00,$00,$0B,$A4,
  4365. $00,$00,$00,$2C,$64,$65,$73,$63,$00,$00,$00,$00,$00,$00,$00,$09,$73,$52,$47,$42,$32,$30,$31,$34,$00,$00,$00,$00,$00,$00,$00,$00,
  4366. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  4367. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  4368. $00,$00,$00,$00,$00,$00,$00,$00,$58,$59,$5A,$20,$00,$00,$00,$00,$00,$00,$24,$A0,$00,$00,$0F,$84,$00,$00,$B6,$CF,$63,$75,$72,$76,
  4369. $00,$00,$00,$00,$00,$00,$04,$00,$00,$00,$00,$05,$00,$0A,$00,$0F,$00,$14,$00,$19,$00,$1E,$00,$23,$00,$28,$00,$2D,$00,$32,$00,$37,
  4370. $00,$3B,$00,$40,$00,$45,$00,$4A,$00,$4F,$00,$54,$00,$59,$00,$5E,$00,$63,$00,$68,$00,$6D,$00,$72,$00,$77,$00,$7C,$00,$81,$00,$86,
  4371. $00,$8B,$00,$90,$00,$95,$00,$9A,$00,$9F,$00,$A4,$00,$A9,$00,$AE,$00,$B2,$00,$B7,$00,$BC,$00,$C1,$00,$C6,$00,$CB,$00,$D0,$00,$D5,
  4372. $00,$DB,$00,$E0,$00,$E5,$00,$EB,$00,$F0,$00,$F6,$00,$FB,$01,$01,$01,$07,$01,$0D,$01,$13,$01,$19,$01,$1F,$01,$25,$01,$2B,$01,$32,
  4373. $01,$38,$01,$3E,$01,$45,$01,$4C,$01,$52,$01,$59,$01,$60,$01,$67,$01,$6E,$01,$75,$01,$7C,$01,$83,$01,$8B,$01,$92,$01,$9A,$01,$A1,
  4374. $01,$A9,$01,$B1,$01,$B9,$01,$C1,$01,$C9,$01,$D1,$01,$D9,$01,$E1,$01,$E9,$01,$F2,$01,$FA,$02,$03,$02,$0C,$02,$14,$02,$1D,$02,$26,
  4375. $02,$2F,$02,$38,$02,$41,$02,$4B,$02,$54,$02,$5D,$02,$67,$02,$71,$02,$7A,$02,$84,$02,$8E,$02,$98,$02,$A2,$02,$AC,$02,$B6,$02,$C1,
  4376. $02,$CB,$02,$D5,$02,$E0,$02,$EB,$02,$F5,$03,$00,$03,$0B,$03,$16,$03,$21,$03,$2D,$03,$38,$03,$43,$03,$4F,$03,$5A,$03,$66,$03,$72,
  4377. $03,$7E,$03,$8A,$03,$96,$03,$A2,$03,$AE,$03,$BA,$03,$C7,$03,$D3,$03,$E0,$03,$EC,$03,$F9,$04,$06,$04,$13,$04,$20,$04,$2D,$04,$3B,
  4378. $04,$48,$04,$55,$04,$63,$04,$71,$04,$7E,$04,$8C,$04,$9A,$04,$A8,$04,$B6,$04,$C4,$04,$D3,$04,$E1,$04,$F0,$04,$FE,$05,$0D,$05,$1C,
  4379. $05,$2B,$05,$3A,$05,$49,$05,$58,$05,$67,$05,$77,$05,$86,$05,$96,$05,$A6,$05,$B5,$05,$C5,$05,$D5,$05,$E5,$05,$F6,$06,$06,$06,$16,
  4380. $06,$27,$06,$37,$06,$48,$06,$59,$06,$6A,$06,$7B,$06,$8C,$06,$9D,$06,$AF,$06,$C0,$06,$D1,$06,$E3,$06,$F5,$07,$07,$07,$19,$07,$2B,
  4381. $07,$3D,$07,$4F,$07,$61,$07,$74,$07,$86,$07,$99,$07,$AC,$07,$BF,$07,$D2,$07,$E5,$07,$F8,$08,$0B,$08,$1F,$08,$32,$08,$46,$08,$5A,
  4382. $08,$6E,$08,$82,$08,$96,$08,$AA,$08,$BE,$08,$D2,$08,$E7,$08,$FB,$09,$10,$09,$25,$09,$3A,$09,$4F,$09,$64,$09,$79,$09,$8F,$09,$A4,
  4383. $09,$BA,$09,$CF,$09,$E5,$09,$FB,$0A,$11,$0A,$27,$0A,$3D,$0A,$54,$0A,$6A,$0A,$81,$0A,$98,$0A,$AE,$0A,$C5,$0A,$DC,$0A,$F3,$0B,$0B,
  4384. $0B,$22,$0B,$39,$0B,$51,$0B,$69,$0B,$80,$0B,$98,$0B,$B0,$0B,$C8,$0B,$E1,$0B,$F9,$0C,$12,$0C,$2A,$0C,$43,$0C,$5C,$0C,$75,$0C,$8E,
  4385. $0C,$A7,$0C,$C0,$0C,$D9,$0C,$F3,$0D,$0D,$0D,$26,$0D,$40,$0D,$5A,$0D,$74,$0D,$8E,$0D,$A9,$0D,$C3,$0D,$DE,$0D,$F8,$0E,$13,$0E,$2E,
  4386. $0E,$49,$0E,$64,$0E,$7F,$0E,$9B,$0E,$B6,$0E,$D2,$0E,$EE,$0F,$09,$0F,$25,$0F,$41,$0F,$5E,$0F,$7A,$0F,$96,$0F,$B3,$0F,$CF,$0F,$EC,
  4387. $10,$09,$10,$26,$10,$43,$10,$61,$10,$7E,$10,$9B,$10,$B9,$10,$D7,$10,$F5,$11,$13,$11,$31,$11,$4F,$11,$6D,$11,$8C,$11,$AA,$11,$C9,
  4388. $11,$E8,$12,$07,$12,$26,$12,$45,$12,$64,$12,$84,$12,$A3,$12,$C3,$12,$E3,$13,$03,$13,$23,$13,$43,$13,$63,$13,$83,$13,$A4,$13,$C5,
  4389. $13,$E5,$14,$06,$14,$27,$14,$49,$14,$6A,$14,$8B,$14,$AD,$14,$CE,$14,$F0,$15,$12,$15,$34,$15,$56,$15,$78,$15,$9B,$15,$BD,$15,$E0,
  4390. $16,$03,$16,$26,$16,$49,$16,$6C,$16,$8F,$16,$B2,$16,$D6,$16,$FA,$17,$1D,$17,$41,$17,$65,$17,$89,$17,$AE,$17,$D2,$17,$F7,$18,$1B,
  4391. $18,$40,$18,$65,$18,$8A,$18,$AF,$18,$D5,$18,$FA,$19,$20,$19,$45,$19,$6B,$19,$91,$19,$B7,$19,$DD,$1A,$04,$1A,$2A,$1A,$51,$1A,$77,
  4392. $1A,$9E,$1A,$C5,$1A,$EC,$1B,$14,$1B,$3B,$1B,$63,$1B,$8A,$1B,$B2,$1B,$DA,$1C,$02,$1C,$2A,$1C,$52,$1C,$7B,$1C,$A3,$1C,$CC,$1C,$F5,
  4393. $1D,$1E,$1D,$47,$1D,$70,$1D,$99,$1D,$C3,$1D,$EC,$1E,$16,$1E,$40,$1E,$6A,$1E,$94,$1E,$BE,$1E,$E9,$1F,$13,$1F,$3E,$1F,$69,$1F,$94,
  4394. $1F,$BF,$1F,$EA,$20,$15,$20,$41,$20,$6C,$20,$98,$20,$C4,$20,$F0,$21,$1C,$21,$48,$21,$75,$21,$A1,$21,$CE,$21,$FB,$22,$27,$22,$55,
  4395. $22,$82,$22,$AF,$22,$DD,$23,$0A,$23,$38,$23,$66,$23,$94,$23,$C2,$23,$F0,$24,$1F,$24,$4D,$24,$7C,$24,$AB,$24,$DA,$25,$09,$25,$38,
  4396. $25,$68,$25,$97,$25,$C7,$25,$F7,$26,$27,$26,$57,$26,$87,$26,$B7,$26,$E8,$27,$18,$27,$49,$27,$7A,$27,$AB,$27,$DC,$28,$0D,$28,$3F,
  4397. $28,$71,$28,$A2,$28,$D4,$29,$06,$29,$38,$29,$6B,$29,$9D,$29,$D0,$2A,$02,$2A,$35,$2A,$68,$2A,$9B,$2A,$CF,$2B,$02,$2B,$36,$2B,$69,
  4398. $2B,$9D,$2B,$D1,$2C,$05,$2C,$39,$2C,$6E,$2C,$A2,$2C,$D7,$2D,$0C,$2D,$41,$2D,$76,$2D,$AB,$2D,$E1,$2E,$16,$2E,$4C,$2E,$82,$2E,$B7,
  4399. $2E,$EE,$2F,$24,$2F,$5A,$2F,$91,$2F,$C7,$2F,$FE,$30,$35,$30,$6C,$30,$A4,$30,$DB,$31,$12,$31,$4A,$31,$82,$31,$BA,$31,$F2,$32,$2A,
  4400. $32,$63,$32,$9B,$32,$D4,$33,$0D,$33,$46,$33,$7F,$33,$B8,$33,$F1,$34,$2B,$34,$65,$34,$9E,$34,$D8,$35,$13,$35,$4D,$35,$87,$35,$C2,
  4401. $35,$FD,$36,$37,$36,$72,$36,$AE,$36,$E9,$37,$24,$37,$60,$37,$9C,$37,$D7,$38,$14,$38,$50,$38,$8C,$38,$C8,$39,$05,$39,$42,$39,$7F,
  4402. $39,$BC,$39,$F9,$3A,$36,$3A,$74,$3A,$B2,$3A,$EF,$3B,$2D,$3B,$6B,$3B,$AA,$3B,$E8,$3C,$27,$3C,$65,$3C,$A4,$3C,$E3,$3D,$22,$3D,$61,
  4403. $3D,$A1,$3D,$E0,$3E,$20,$3E,$60,$3E,$A0,$3E,$E0,$3F,$21,$3F,$61,$3F,$A2,$3F,$E2,$40,$23,$40,$64,$40,$A6,$40,$E7,$41,$29,$41,$6A,
  4404. $41,$AC,$41,$EE,$42,$30,$42,$72,$42,$B5,$42,$F7,$43,$3A,$43,$7D,$43,$C0,$44,$03,$44,$47,$44,$8A,$44,$CE,$45,$12,$45,$55,$45,$9A,
  4405. $45,$DE,$46,$22,$46,$67,$46,$AB,$46,$F0,$47,$35,$47,$7B,$47,$C0,$48,$05,$48,$4B,$48,$91,$48,$D7,$49,$1D,$49,$63,$49,$A9,$49,$F0,
  4406. $4A,$37,$4A,$7D,$4A,$C4,$4B,$0C,$4B,$53,$4B,$9A,$4B,$E2,$4C,$2A,$4C,$72,$4C,$BA,$4D,$02,$4D,$4A,$4D,$93,$4D,$DC,$4E,$25,$4E,$6E,
  4407. $4E,$B7,$4F,$00,$4F,$49,$4F,$93,$4F,$DD,$50,$27,$50,$71,$50,$BB,$51,$06,$51,$50,$51,$9B,$51,$E6,$52,$31,$52,$7C,$52,$C7,$53,$13,
  4408. $53,$5F,$53,$AA,$53,$F6,$54,$42,$54,$8F,$54,$DB,$55,$28,$55,$75,$55,$C2,$56,$0F,$56,$5C,$56,$A9,$56,$F7,$57,$44,$57,$92,$57,$E0,
  4409. $58,$2F,$58,$7D,$58,$CB,$59,$1A,$59,$69,$59,$B8,$5A,$07,$5A,$56,$5A,$A6,$5A,$F5,$5B,$45,$5B,$95,$5B,$E5,$5C,$35,$5C,$86,$5C,$D6,
  4410. $5D,$27,$5D,$78,$5D,$C9,$5E,$1A,$5E,$6C,$5E,$BD,$5F,$0F,$5F,$61,$5F,$B3,$60,$05,$60,$57,$60,$AA,$60,$FC,$61,$4F,$61,$A2,$61,$F5,
  4411. $62,$49,$62,$9C,$62,$F0,$63,$43,$63,$97,$63,$EB,$64,$40,$64,$94,$64,$E9,$65,$3D,$65,$92,$65,$E7,$66,$3D,$66,$92,$66,$E8,$67,$3D,
  4412. $67,$93,$67,$E9,$68,$3F,$68,$96,$68,$EC,$69,$43,$69,$9A,$69,$F1,$6A,$48,$6A,$9F,$6A,$F7,$6B,$4F,$6B,$A7,$6B,$FF,$6C,$57,$6C,$AF,
  4413. $6D,$08,$6D,$60,$6D,$B9,$6E,$12,$6E,$6B,$6E,$C4,$6F,$1E,$6F,$78,$6F,$D1,$70,$2B,$70,$86,$70,$E0,$71,$3A,$71,$95,$71,$F0,$72,$4B,
  4414. $72,$A6,$73,$01,$73,$5D,$73,$B8,$74,$14,$74,$70,$74,$CC,$75,$28,$75,$85,$75,$E1,$76,$3E,$76,$9B,$76,$F8,$77,$56,$77,$B3,$78,$11,
  4415. $78,$6E,$78,$CC,$79,$2A,$79,$89,$79,$E7,$7A,$46,$7A,$A5,$7B,$04,$7B,$63,$7B,$C2,$7C,$21,$7C,$81,$7C,$E1,$7D,$41,$7D,$A1,$7E,$01,
  4416. $7E,$62,$7E,$C2,$7F,$23,$7F,$84,$7F,$E5,$80,$47,$80,$A8,$81,$0A,$81,$6B,$81,$CD,$82,$30,$82,$92,$82,$F4,$83,$57,$83,$BA,$84,$1D,
  4417. $84,$80,$84,$E3,$85,$47,$85,$AB,$86,$0E,$86,$72,$86,$D7,$87,$3B,$87,$9F,$88,$04,$88,$69,$88,$CE,$89,$33,$89,$99,$89,$FE,$8A,$64,
  4418. $8A,$CA,$8B,$30,$8B,$96,$8B,$FC,$8C,$63,$8C,$CA,$8D,$31,$8D,$98,$8D,$FF,$8E,$66,$8E,$CE,$8F,$36,$8F,$9E,$90,$06,$90,$6E,$90,$D6,
  4419. $91,$3F,$91,$A8,$92,$11,$92,$7A,$92,$E3,$93,$4D,$93,$B6,$94,$20,$94,$8A,$94,$F4,$95,$5F,$95,$C9,$96,$34,$96,$9F,$97,$0A,$97,$75,
  4420. $97,$E0,$98,$4C,$98,$B8,$99,$24,$99,$90,$99,$FC,$9A,$68,$9A,$D5,$9B,$42,$9B,$AF,$9C,$1C,$9C,$89,$9C,$F7,$9D,$64,$9D,$D2,$9E,$40,
  4421. $9E,$AE,$9F,$1D,$9F,$8B,$9F,$FA,$A0,$69,$A0,$D8,$A1,$47,$A1,$B6,$A2,$26,$A2,$96,$A3,$06,$A3,$76,$A3,$E6,$A4,$56,$A4,$C7,$A5,$38,
  4422. $A5,$A9,$A6,$1A,$A6,$8B,$A6,$FD,$A7,$6E,$A7,$E0,$A8,$52,$A8,$C4,$A9,$37,$A9,$A9,$AA,$1C,$AA,$8F,$AB,$02,$AB,$75,$AB,$E9,$AC,$5C,
  4423. $AC,$D0,$AD,$44,$AD,$B8,$AE,$2D,$AE,$A1,$AF,$16,$AF,$8B,$B0,$00,$B0,$75,$B0,$EA,$B1,$60,$B1,$D6,$B2,$4B,$B2,$C2,$B3,$38,$B3,$AE,
  4424. $B4,$25,$B4,$9C,$B5,$13,$B5,$8A,$B6,$01,$B6,$79,$B6,$F0,$B7,$68,$B7,$E0,$B8,$59,$B8,$D1,$B9,$4A,$B9,$C2,$BA,$3B,$BA,$B5,$BB,$2E,
  4425. $BB,$A7,$BC,$21,$BC,$9B,$BD,$15,$BD,$8F,$BE,$0A,$BE,$84,$BE,$FF,$BF,$7A,$BF,$F5,$C0,$70,$C0,$EC,$C1,$67,$C1,$E3,$C2,$5F,$C2,$DB,
  4426. $C3,$58,$C3,$D4,$C4,$51,$C4,$CE,$C5,$4B,$C5,$C8,$C6,$46,$C6,$C3,$C7,$41,$C7,$BF,$C8,$3D,$C8,$BC,$C9,$3A,$C9,$B9,$CA,$38,$CA,$B7,
  4427. $CB,$36,$CB,$B6,$CC,$35,$CC,$B5,$CD,$35,$CD,$B5,$CE,$36,$CE,$B6,$CF,$37,$CF,$B8,$D0,$39,$D0,$BA,$D1,$3C,$D1,$BE,$D2,$3F,$D2,$C1,
  4428. $D3,$44,$D3,$C6,$D4,$49,$D4,$CB,$D5,$4E,$D5,$D1,$D6,$55,$D6,$D8,$D7,$5C,$D7,$E0,$D8,$64,$D8,$E8,$D9,$6C,$D9,$F1,$DA,$76,$DA,$FB,
  4429. $DB,$80,$DC,$05,$DC,$8A,$DD,$10,$DD,$96,$DE,$1C,$DE,$A2,$DF,$29,$DF,$AF,$E0,$36,$E0,$BD,$E1,$44,$E1,$CC,$E2,$53,$E2,$DB,$E3,$63,
  4430. $E3,$EB,$E4,$73,$E4,$FC,$E5,$84,$E6,$0D,$E6,$96,$E7,$1F,$E7,$A9,$E8,$32,$E8,$BC,$E9,$46,$E9,$D0,$EA,$5B,$EA,$E5,$EB,$70,$EB,$FB,
  4431. $EC,$86,$ED,$11,$ED,$9C,$EE,$28,$EE,$B4,$EF,$40,$EF,$CC,$F0,$58,$F0,$E5,$F1,$72,$F1,$FF,$F2,$8C,$F3,$19,$F3,$A7,$F4,$34,$F4,$C2,
  4432. $F5,$50,$F5,$DE,$F6,$6D,$F6,$FB,$F7,$8A,$F8,$19,$F8,$A8,$F9,$38,$F9,$C7,$FA,$57,$FA,$E7,$FB,$77,$FC,$07,$FC,$98,$FD,$29,$FD,$BA,
  4433. $FE,$4B,$FE,$DC,$FF,$6D,$FF,$FF,$64,$65,$73,$63,$00,$00,$00,$00,$00,$00,$00,$2E,$49,$45,$43,$20,$36,$31,$39,$36,$36,$2D,$32,$2D,
  4434. $31,$20,$44,$65,$66,$61,$75,$6C,$74,$20,$52,$47,$42,$20,$43,$6F,$6C,$6F,$75,$72,$20,$53,$70,$61,$63,$65,$20,$2D,$20,$73,$52,$47,
  4435. $42,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  4436. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  4437. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$58,$59,$5A,$20,$00,$00,$00,$00,$00,$00,$62,$99,$00,$00,$B7,$85,
  4438. $00,$00,$18,$DA,$58,$59,$5A,$20,$00,$00,$00,$00,$00,$00,$00,$00,$00,$50,$00,$00,$00,$00,$00,$00,$6D,$65,$61,$73,$00,$00,$00,$00,
  4439. $00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02,$58,$59,$5A,$20,
  4440. $00,$00,$00,$00,$00,$00,$00,$9E,$00,$00,$00,$A4,$00,$00,$00,$87,$58,$59,$5A,$20,$00,$00,$00,$00,$00,$00,$6F,$A2,$00,$00,$38,$F5,
  4441. $00,$00,$03,$90,$73,$69,$67,$20,$00,$00,$00,$00,$43,$52,$54,$20,$64,$65,$73,$63,$00,$00,$00,$00,$00,$00,$00,$2D,$52,$65,$66,$65,
  4442. $72,$65,$6E,$63,$65,$20,$56,$69,$65,$77,$69,$6E,$67,$20,$43,$6F,$6E,$64,$69,$74,$69,$6F,$6E,$20,$69,$6E,$20,$49,$45,$43,$20,$36,
  4443. $31,$39,$36,$36,$2D,$32,$2D,$31,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  4444. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
  4445. $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$58,$59,$5A,$20,$00,$00,$00,$00,
  4446. $00,$00,$F6,$D6,$00,$01,$00,$00,$00,$00,$D3,$2D,$74,$65,$78,$74,$00,$00,$00,$00,$43,$6F,$70,$79,$72,$69,$67,$68,$74,$20,$49,$6E,
  4447. $74,$65,$72,$6E,$61,$74,$69,$6F,$6E,$61,$6C,$20,$43,$6F,$6C,$6F,$72,$20,$43,$6F,$6E,$73,$6F,$72,$74,$69,$75,$6D,$2C,$20,$32,$30,
  4448. $31,$35,$00,$00,$73,$66,$33,$32,$00,$00,$00,$00,$00,$01,$0C,$44,$00,$00,$05,$DF,$FF,$FF,$F3,$26,$00,$00,$07,$94,$00,$00,$FD,$8F,
  4449. $FF,$FF,$FB,$A1,$FF,$FF,$FD,$A2,$00,$00,$03,$DB,$00,$00,$C0,$75);
  4450. procedure TPDFDocument.AddPDFA1sRGBOutputIntent;
  4451. var
  4452. st: TMemoryStream;
  4453. begin
  4454. st := TMemoryStream.Create;
  4455. try
  4456. st.SetSize(High(ICC_sRGB2014));
  4457. st.Write(ICC_sRGB2014[1], High(ICC_sRGB2014));
  4458. AddOutputIntent('GTS_PDFA1', 'Custom', 'sRGB', st); //GTS_PDFA1 required for PDF/A
  4459. finally
  4460. st.Free;
  4461. end;
  4462. end;
  4463. procedure TPDFDocument.CreateTrailerID;
  4464. var
  4465. s: string;
  4466. ID: TPDFArray;
  4467. begin
  4468. s := DateToPdfDate(Now) + IntToStr(GLobalXRefCount) +
  4469. Infos.Title + Infos.Author + Infos.ApplicationName + Infos.Producer + DateToPdfDate(Infos.CreationDate);
  4470. s := MD5Print(MD5String(s));
  4471. ID := CreateArray;
  4472. ID.AddItem(TPDFRawHexString.Create(Self, s));
  4473. ID.AddItem(TPDFRawHexString.Create(Self, s));
  4474. Trailer.AddElement('ID', ID);
  4475. end;
  4476. procedure TPDFDocument.CreatePreferencesEntry;
  4477. var
  4478. VDict: TPDFDictionary;
  4479. begin
  4480. VDict:=CreateGlobalXRef.Dict;
  4481. VDict.AddName('Type', 'ViewerPreferences');
  4482. VDict.AddElement('FitWindow', CreateBoolean(True));
  4483. VDict:=GlobalXRefByName('Catalog').Dict;
  4484. VDict.AddReference('ViewerPreferences',GLobalXRefCount-1);
  4485. end;
  4486. function TPDFDocument.CreatePagesEntry(Parent: integer): integer;
  4487. var
  4488. EDict,ADict: TPDFDictionary;
  4489. begin
  4490. EDict:=CreateGlobalXRef.Dict;
  4491. Result:=GLobalXRefCount-1;
  4492. EDict.AddName('Type','Pages');
  4493. EDict.AddElement('Kids',CreateArray);
  4494. EDict.AddInteger('Count',0);
  4495. if Parent=0 then
  4496. GlobalXRefByName('Catalog').Dict.AddReference('Pages',Result)
  4497. else
  4498. begin
  4499. EDict.AddReference('Parent',Parent);
  4500. ADict:=GlobalXRefs[Parent].Dict;
  4501. (ADict.ValueByName('Count') as TPDFInteger).Inc;
  4502. (ADict.ValueByName('Kids') as TPDFArray).AddItem(CreateReference(Result));
  4503. end;
  4504. end;
  4505. function TPDFDocument.CreatePageEntry(Parent, PageNum: integer): integer;
  4506. var
  4507. PDict,ADict: TPDFDictionary;
  4508. Arr : TPDFArray;
  4509. PP : TPDFPage;
  4510. begin
  4511. // add xref entry
  4512. PP:=Pages[PageNum];
  4513. PDict:=CreateGlobalXRef.Dict;
  4514. PDict.AddName('Type','Page');
  4515. PDict.AddReference('Parent',Parent);
  4516. ADict:=GlobalXRefs[Parent].Dict;
  4517. (ADict.ValueByName('Count') as TPDFInteger).Inc;
  4518. (ADict.ValueByName('Kids') as TPDFArray).AddItem(CreateReference(GlobalXRefCount-1));
  4519. Arr:=CreateArray;
  4520. Arr.AddItem(CreateInteger(0));
  4521. Arr.AddItem(CreateInteger(0));
  4522. Arr.AddItem(CreateInteger(PP.Paper.W));
  4523. Arr.AddItem(CreateInteger(PP.Paper.H));
  4524. PDict.AddElement('MediaBox',Arr);
  4525. CreateAnnotEntries(PageNum, PDict);
  4526. ADict:=CreateDictionary;
  4527. PDict.AddElement('Resources',ADict);
  4528. Arr:=CreateArray; // procset
  4529. ADict.AddElement('ProcSet',Arr);
  4530. Arr.AddItem(CreateName('PDF'));
  4531. Arr.AddItem(CreateName('Text'));
  4532. Arr.AddItem(CreateName('ImageC'));
  4533. if (Fonts.Count>0) then
  4534. ADict.AddElement('Font',CreateDictionary);
  4535. if PP.HasImages then
  4536. ADict.AddElement('XObject', CreateDictionary);
  4537. Result:=GlobalXRefCount-1;
  4538. end;
  4539. function TPDFDocument.CreateOutlines: integer;
  4540. var
  4541. ODict: TPDFDictionary;
  4542. begin
  4543. ODict:=CreateGlobalXRef.Dict;
  4544. ODict.AddName('Type','Outlines');
  4545. ODict.AddInteger('Count',0);
  4546. Result:=GLobalXRefCount-1;
  4547. end;
  4548. function TPDFDocument.CreateOutlineEntry(Parent, SectNo, PageNo: integer; ATitle: string): integer;
  4549. var
  4550. ODict: TPDFDictionary;
  4551. S: String;
  4552. begin
  4553. ODict:=CreateGlobalXRef.Dict;
  4554. S:=ATitle;
  4555. if (S='') then
  4556. S:='Section '+IntToStr(SectNo);
  4557. if (PageNo>-1) then
  4558. S:=S+' Page '+IntToStr(PageNo);
  4559. ODict.AddString('Title',S);
  4560. ODict.AddReference('Parent',Parent);
  4561. ODict.AddInteger('Count',0);
  4562. ODict.AddElement('Dest', CreateArray);
  4563. Result:=GLobalXRefCount-1;
  4564. end;
  4565. procedure TPDFDocument.AddFontNameToPages(const AName: String; ANum: Integer);
  4566. Var
  4567. i: integer;
  4568. ADict: TPDFDictionary;
  4569. begin
  4570. for i:=1 to GLobalXRefCount-1 do
  4571. begin
  4572. ADict:=GlobalXRefs[i].Dict;
  4573. if (ADict.ElementCount>0) then
  4574. if (ADict.Values[0] is TPDFName) and ((ADict.Values[0] as TPDFName).Name= 'Page') then
  4575. begin
  4576. ADict:=ADict.ValueByName('Resources') as TPDFDictionary;
  4577. ADict:=ADict.ValueByName('Font') as TPDFDictionary;
  4578. ADict.AddReference(AName,ANum);
  4579. end;
  4580. end;
  4581. end;
  4582. procedure TPDFDocument.CreateStdFont(EmbeddedFontName: string; EmbeddedFontNum: integer);
  4583. var
  4584. FDict: TPDFDictionary;
  4585. N: TPDFName;
  4586. lFontXRef: integer;
  4587. begin
  4588. lFontXRef := GlobalXRefCount; // will be used a few lines down in AddFontNameToPages()
  4589. // add xref entry
  4590. FDict := CreateGlobalXRef.Dict;
  4591. FDict.AddName('Type', 'Font');
  4592. FDict.AddName('Subtype', 'Type1');
  4593. FDict.AddName('Encoding', 'WinAnsiEncoding');
  4594. FDict.AddInteger('FirstChar', 32);
  4595. FDict.AddInteger('LastChar', 255);
  4596. FDict.AddName('BaseFont', EmbeddedFontName);
  4597. N := CreateName('F'+IntToStr(EmbeddedFontNum));
  4598. FDict.AddElement('Name',N);
  4599. // add font reference to global page dictionary
  4600. AddFontNameToPages(N.Name, lFontXRef);
  4601. FontFiles.Add('');
  4602. end;
  4603. function TPDFDocument.LoadFont(AFont: TPDFFont): boolean;
  4604. var
  4605. lFName: string;
  4606. s: string;
  4607. begin
  4608. Result := False;
  4609. if ExtractFilePath(AFont.FontFile) <> '' then
  4610. // assume AFont.FontFile is the full path to the TTF file
  4611. lFName := AFont.FontFile
  4612. else
  4613. // assume it's just a TTF filename
  4614. lFName := IncludeTrailingPathDelimiter(FontDirectory)+AFont.FontFile;
  4615. if FileExists(lFName) then
  4616. begin
  4617. s := LowerCase(ExtractFileExt(lFName));
  4618. Result := (s = '.ttf') or (s = '.otf');
  4619. end
  4620. else
  4621. Raise EPDF.CreateFmt(rsErrReportFontFileMissing, [lFName]);
  4622. end;
  4623. procedure TPDFDocument.CreateTTFFont(const EmbeddedFontNum: integer);
  4624. var
  4625. FDict: TPDFDictionary;
  4626. N: TPDFName;
  4627. Arr: TPDFArray;
  4628. lFontXRef: integer;
  4629. begin
  4630. lFontXRef := GlobalXRefCount; // will be used a few lines down in AddFontNameToPages()
  4631. // add xref entry
  4632. FDict := CreateGlobalXRef.Dict;
  4633. FDict.AddName('Type', 'Font');
  4634. FDict.AddName('Subtype', 'Type0');
  4635. if poSubsetFont in Options then
  4636. FDict.AddName('BaseFont', GetFontNamePrefix(EmbeddedFontNum) + Fonts[EmbeddedFontNum].Name)
  4637. else
  4638. FDict.AddName('BaseFont', Fonts[EmbeddedFontNum].Name);
  4639. FDict.AddName('Encoding', 'Identity-H');
  4640. // add name element to font dictionary
  4641. N:=CreateName('F'+IntToStr(EmbeddedFontNum));
  4642. FDict.AddElement('Name',N);
  4643. AddFontNameToPages(N.Name, lFontXRef);
  4644. Arr := CreateArray;
  4645. Arr.AddItem(TPDFReference.Create(self, GlobalXRefCount));
  4646. FDict.AddElement('DescendantFonts', Arr);
  4647. CreateTTFDescendantFont(EmbeddedFontNum);
  4648. if not (poNoEmbeddedFonts in Options) then
  4649. begin
  4650. FDict.AddReference('ToUnicode', GlobalXRefCount);
  4651. CreateToUnicode(EmbeddedFontNum);
  4652. end;
  4653. FontFiles.Add(Fonts[EmbeddedFontNum].FTrueTypeFile.Filename);
  4654. end;
  4655. procedure TPDFDocument.CreateTTFDescendantFont(const EmbeddedFontNum: integer);
  4656. var
  4657. FDict: TPDFDictionary;
  4658. Arr: TPDFArray;
  4659. begin
  4660. // add xref entry
  4661. FDict := CreateGlobalXRef.Dict;
  4662. FDict.AddName('Type', 'Font');
  4663. FDict.AddName('Subtype', 'CIDFontType2');
  4664. if poSubsetFont in Options then
  4665. FDict.AddName('BaseFont', GetFontNamePrefix(EmbeddedFontNum) + Fonts[EmbeddedFontNum].Name)
  4666. else
  4667. FDict.AddName('BaseFont', Fonts[EmbeddedFontNum].Name);
  4668. FDict.AddReference('CIDSystemInfo', GlobalXRefCount);
  4669. CreateTTFCIDSystemInfo;
  4670. // add fontdescriptor reference to font dictionary
  4671. FDict.AddReference('FontDescriptor',GlobalXRefCount);
  4672. CreateFontDescriptor(EmbeddedFontNum);
  4673. Arr := CreateArray;
  4674. FDict.AddElement('W',Arr);
  4675. Arr.AddItem(TPDFTrueTypeCharWidths.Create(self, EmbeddedFontNum));
  4676. // TODO: Implement CIDToGIDMap here
  4677. { It's an array of 256*256*2, loop through the CID values (from <xxx> Tj) and if
  4678. CID matches the loop variable, then populate the 2-byte data, otherwise write
  4679. $0 to the two bytes. Then stream the array as a PDF Reference Object and
  4680. use compression (if defined in PDFDocument.Options. }
  4681. if (poSubsetFont in Options) then
  4682. begin
  4683. FDict.AddReference('CIDToGIDMap', CreateCIDToGIDMap(EmbeddedFontNum));
  4684. end;
  4685. end;
  4686. procedure TPDFDocument.CreateTTFCIDSystemInfo;
  4687. var
  4688. FDict: TPDFDictionary;
  4689. begin
  4690. FDict := CreateGlobalXRef.Dict;
  4691. FDict.AddString('Registry', 'Adobe');
  4692. FDict.AddString('Ordering', 'Identity');
  4693. FDict.AddInteger('Supplement', 0);
  4694. end;
  4695. procedure TPDFDocument.CreateTp1Font(const EmbeddedFontNum: integer);
  4696. begin
  4697. Assert(EmbeddedFontNum<>-1);
  4698. end;
  4699. procedure TPDFDocument.CreateFontDescriptor(const EmbeddedFontNum: integer);
  4700. var
  4701. Arr: TPDFArray;
  4702. FDict: TPDFDictionary;
  4703. begin
  4704. FDict:=CreateGlobalXRef.Dict;
  4705. FDict.AddName('Type', 'FontDescriptor');
  4706. if poSubsetFont in Options then
  4707. begin
  4708. FDict.AddName('FontName', GetFontNamePrefix(EmbeddedFontNum) + Fonts[EmbeddedFontNum].Name);
  4709. FDict.AddInteger('Flags', 4);
  4710. end
  4711. else
  4712. begin
  4713. FDict.AddName('FontName', Fonts[EmbeddedFontNum].Name);
  4714. FDict.AddName('FontFamily', Fonts[EmbeddedFontNum].FTrueTypeFile.FamilyName);
  4715. FDict.AddInteger('Flags', 32);
  4716. end;
  4717. FDict.AddInteger('Ascent', Fonts[EmbeddedFontNum].FTrueTypeFile.Ascender);
  4718. FDict.AddInteger('Descent', Fonts[EmbeddedFontNum].FTrueTypeFile.Descender);
  4719. FDict.AddInteger('CapHeight', Fonts[EmbeddedFontNum].FTrueTypeFile.CapHeight);
  4720. Arr:=CreateArray;
  4721. FDict.AddElement('FontBBox',Arr);
  4722. Arr.AddIntArray(Fonts[EmbeddedFontNum].FTrueTypeFile.BBox);
  4723. FDict.AddInteger('ItalicAngle', trunc(Fonts[EmbeddedFontNum].FTrueTypeFile.ItalicAngle));
  4724. FDict.AddInteger('StemV', Fonts[EmbeddedFontNum].FTrueTypeFile.StemV);
  4725. FDict.AddInteger('MissingWidth', Fonts[EmbeddedFontNum].FTrueTypeFile.MissingWidth);
  4726. if not (poNoEmbeddedFonts in Options) then
  4727. begin
  4728. FDict.AddReference('FontFile2', GlobalXRefCount);
  4729. CreateFontFileEntry(EmbeddedFontNum);
  4730. if poSubsetFont in Options then
  4731. begin
  4732. // todo /CIDSet reference
  4733. FDict.AddReference('CIDSet', GlobalXRefCount);
  4734. CreateCIDSet(EmbeddedFontNum);
  4735. end;
  4736. end;
  4737. end;
  4738. procedure TPDFDocument.CreateToUnicode(const AFontNum: integer);
  4739. var
  4740. lXRef: TPDFXRef;
  4741. begin
  4742. lXRef := CreateGlobalXRef;
  4743. lXRef.FStream := CreateStream(True);
  4744. lXRef.FStream.AddItem(TPDFToUnicode.Create(self, AFontNum));
  4745. end;
  4746. procedure TPDFDocument.CreateFontFileEntry(const AFontNum: integer);
  4747. var
  4748. FDict: TPDFDictionary;
  4749. Len: Integer;
  4750. begin
  4751. FDict:=CreateGlobalXRef.Dict;
  4752. if poCompressFonts in Options then
  4753. FDict.AddName('Filter','FlateDecode');
  4754. if poSubsetFont in Options then
  4755. Len := Fonts[AFontNum].SubsetFont.Size
  4756. else
  4757. Len := Fonts[AFontNum].FTrueTypeFile.OriginalSize;
  4758. FDict.AddInteger('Length1 '+IntToStr(AFontNum), Len);
  4759. end;
  4760. procedure TPDFDocument.CreateCIDSet(const AFontNum: integer);
  4761. var
  4762. lXRef: TPDFXRef;
  4763. begin
  4764. lXRef := CreateGlobalXRef;
  4765. lXRef.FStream := CreateStream(True);
  4766. lXRef.FStream.AddItem(TPDFCIDSet.Create(self, AFontNum));
  4767. end;
  4768. procedure TPDFDocument.CreateImageEntry(ImgWidth, ImgHeight, NumImg: integer;
  4769. out ImageDict: TPDFDictionary);
  4770. var
  4771. N: TPDFName;
  4772. ADict: TPDFDictionary;
  4773. i: integer;
  4774. lXRef: integer;
  4775. begin
  4776. lXRef := GlobalXRefCount; // reference to be used later
  4777. ImageDict:=CreateGlobalXRef.Dict;
  4778. ImageDict.AddName('Type','XObject');
  4779. ImageDict.AddName('Subtype','Image');
  4780. ImageDict.AddInteger('Width',ImgWidth);
  4781. ImageDict.AddInteger('Height',ImgHeight);
  4782. ImageDict.AddName('ColorSpace','DeviceRGB');
  4783. ImageDict.AddInteger('BitsPerComponent',8);
  4784. N:=CreateName('I'+IntToStr(NumImg)); // Needed later
  4785. ImageDict.AddElement('Name',N);
  4786. // now find where we must add the image xref - we are looking for "Resources"
  4787. for i := 1 to GlobalXRefCount-1 do
  4788. begin
  4789. ADict:=GlobalXRefs[i].Dict;
  4790. if ADict.ElementCount > 0 then
  4791. begin
  4792. if (ADict.Values[0] is TPDFName) and ((ADict.Values[0] as TPDFName).Name='Page') then
  4793. begin
  4794. ADict:=ADict.ValueByName('Resources') as TPDFDictionary;
  4795. ADict:=TPDFDictionary(ADict.FindValue('XObject'));
  4796. if Assigned(ADict) then
  4797. begin
  4798. ADict.AddReference(N.Name, lXRef);
  4799. end;
  4800. end;
  4801. end;
  4802. end;
  4803. end;
  4804. procedure TPDFDocument.CreateImageMaskEntry(ImgWidth, ImgHeight,
  4805. NumImg: integer; ImageDict: TPDFDictionary);
  4806. var
  4807. N: TPDFName;
  4808. MDict: TPDFDictionary;
  4809. lXRef: integer;
  4810. begin
  4811. lXRef := GlobalXRefCount; // reference to be used later
  4812. MDict:=CreateGlobalXRef.Dict;
  4813. MDict.AddName('Type','XObject');
  4814. MDict.AddName('Subtype','Image');
  4815. MDict.AddInteger('Width',ImgWidth);
  4816. MDict.AddInteger('Height',ImgHeight);
  4817. MDict.AddName('ColorSpace','DeviceGray');
  4818. MDict.AddInteger('BitsPerComponent',8);
  4819. N:=CreateName('M'+IntToStr(NumImg)); // Needed later
  4820. MDict.AddElement('Name',N);
  4821. ImageDict.AddReference('SMask', lXRef);
  4822. end;
  4823. function TPDFDocument.CreateAnnotEntry(const APageNum, AnnotNum: integer): integer;
  4824. var
  4825. lDict, ADict: TPDFDictionary;
  4826. an: TPDFAnnot;
  4827. ar: TPDFArray;
  4828. lXRef: TPDFXRef;
  4829. s: string;
  4830. begin
  4831. an := Pages[APageNum].Annots[AnnotNum];
  4832. lXRef := CreateGlobalXRef;
  4833. lDict := lXRef.Dict;
  4834. lDict.AddName('Type', 'Annot');
  4835. lDict.AddName('Subtype', 'Link');
  4836. { Invert link on click - PDF 1.3 spec pg.410. It is the default value, but
  4837. some PDF viewers don't apply that if not explicity specified. }
  4838. lDict.AddName('H', 'I');
  4839. { Border array consists of 3 or 4 values. The first three elements describe
  4840. the horizontal corner radius, the vertical corner radius and the border
  4841. width. A 0 border width means no border is drawn. The optional 4th element
  4842. is an array defining a dash pattern. For example: /Border [16 16 2 [2 1]] }
  4843. ar := CreateArray;
  4844. lDict.AddElement('Border', ar);
  4845. if an.FBorder then
  4846. s := '1'
  4847. else
  4848. s := '0';
  4849. ar.AddFreeFormArrayValues('0 0 ' + s);
  4850. ar := CreateArray;
  4851. lDict.AddElement('Rect', ar);
  4852. s := ar.FloatStr(an.FLeft);
  4853. s := s + ' ' + ar.FloatStr(an.FBottom);
  4854. s := s + ' ' + ar.FloatStr(an.FLeft + an.FWidth);
  4855. s := s + ' ' + ar.FloatStr(an.FBottom + an.FHeight);
  4856. ar.AddFreeFormArrayValues(s);
  4857. ADict := CreateDictionary;
  4858. lDict.AddElement('A', ADict);
  4859. ADict.AddName('Type', 'Action');
  4860. ADict.AddName('S', 'URI');
  4861. ADict.AddString('URI', an.FURI);
  4862. result := GlobalXRefCount-1;
  4863. end;
  4864. function TPDFDocument.CreateCIDToGIDMap(const AFontNum: integer): integer;
  4865. var
  4866. lXRef: TPDFXRef;
  4867. begin
  4868. lXRef := CreateGlobalXRef;
  4869. result := GlobalXRefCount-1;
  4870. lXRef.FStream := CreateStream(True);
  4871. lXRef.FStream.AddItem(TCIDToGIDMap.Create(self, AFontNum));
  4872. end;
  4873. function TPDFDocument.CreateContentsEntry(const APageNum: integer): integer;
  4874. var
  4875. Contents: TPDFXRef;
  4876. i: integer;
  4877. begin
  4878. Contents:=CreateGlobalXRef;
  4879. Contents.FStream:=CreateStream(False);
  4880. Result:=GlobalXRefCount-1;
  4881. { TODO: This is terrible code. See if we can make a better plan getting hold
  4882. of the reference to the Page dictionary. }
  4883. i := 2 + Pages[APageNum].Annots.Count; // + GetTotalAnnotsCount;
  4884. GlobalXrefs[GlobalXRefCount-i].Dict.AddReference('Contents',Result);
  4885. end;
  4886. procedure TPDFDocument.CreatePageStream(APage : TPDFPage; PageNum: integer);
  4887. var
  4888. i: integer;
  4889. PageStream : TPDFStream;
  4890. begin
  4891. PageStream:=GlobalXRefs[PageNum].FStream;
  4892. for i:=0 to APage.ObjectCount-1 do
  4893. begin
  4894. PageStream.AddItem(APage.Objects[i]);
  4895. end;
  4896. end;
  4897. function TPDFDocument.CreateGlobalXRef: TPDFXRef;
  4898. begin
  4899. Result:=Self.CreateXRef;
  4900. AddGlobalXRef(Result);
  4901. end;
  4902. function TPDFDocument.AddGlobalXRef(AXRef: TPDFXRef): Integer;
  4903. begin
  4904. Result:=FGlobalXRefs.Add(AXRef);
  4905. end;
  4906. function TPDFDocument.GlobalXRefByName(const AName: String): TPDFXRef;
  4907. begin
  4908. Result:=FindGlobalXRef(AName);
  4909. if Result=Nil then
  4910. Raise EPDF.CreateFmt(rsErrNoGlobalDict,[AName]);
  4911. end;
  4912. function TPDFDocument.ImageStreamOptions: TPDFImageStreamOptions;
  4913. begin
  4914. Result:=[];
  4915. if (poCompressImages in Options) then
  4916. Include(Result,isoCompressed);
  4917. if (poUseImageTransparency in Options) then
  4918. Include(Result,isoTransparent);
  4919. end;
  4920. function TPDFDocument.CreateLineStyles: TPDFLineStyleDefs;
  4921. begin
  4922. Result:=TPDFLineStyleDefs.Create(TPDFLineStyleDef);
  4923. end;
  4924. function TPDFDocument.CreateSectionList: TPDFSectionList;
  4925. begin
  4926. Result:=TPDFSectionList.Create(TPDFSection)
  4927. end;
  4928. function TPDFDocument.CreateFontDefs: TPDFFontDefs;
  4929. begin
  4930. Result := TPDFFontDefs.Create(TPDFFont);
  4931. end;
  4932. function TPDFDocument.CreatePDFInfos: TPDFInfos;
  4933. begin
  4934. Result:=TPDFInfos.Create;
  4935. end;
  4936. function TPDFDocument.CreatePDFImages: TPDFImages;
  4937. begin
  4938. Result:=TPDFImages.Create(Self,TPDFImageItem);
  4939. end;
  4940. function TPDFDocument.CreatePDFPages: TPDFPages;
  4941. begin
  4942. Result:=TPDFPages.Create(Self);
  4943. end;
  4944. constructor TPDFDocument.Create(AOwner : TComponent);
  4945. begin
  4946. inherited Create(AOwner);
  4947. FFontFiles:=TStringList.Create;
  4948. FLineStyleDefs:=CreateLineStyles;
  4949. FSections:=CreateSectionList;
  4950. FFonts:=CreateFontDefs;
  4951. FInfos:=CreatePDFInfos;
  4952. FImages:=CreatePDFImages;
  4953. FPages:=CreatePDFPages;
  4954. FPreferences:=True;
  4955. FPageLayout:=lSingle;
  4956. FDefaultPaperType:=ptA4;
  4957. FDefaultOrientation:=ppoPortrait;
  4958. FZoomValue:='100';
  4959. FOptions := [poCompressFonts, poCompressImages];
  4960. FUnitOfMeasure:=uomMillimeters;
  4961. FLineCapStyle := plcsRoundCap;
  4962. end;
  4963. procedure TPDFDocument.StartDocument;
  4964. begin
  4965. Reset;
  4966. CreateRefTable;
  4967. CreateTrailer;
  4968. FCatalogue:=CreateCatalogEntry;
  4969. CreateInfoEntry(poUTF16Info in Options);
  4970. if poMetadataEntry in Options then
  4971. CreateMetadataEntry;
  4972. if not (poNoTrailerID in Options) then
  4973. CreateTrailerID;
  4974. CreatePreferencesEntry;
  4975. if (FontDirectory = '') then
  4976. FontDirectory:=ExtractFilePath(ParamStr(0));
  4977. end;
  4978. procedure TPDFDocument.Reset;
  4979. begin
  4980. FLineStyleDefs.Clear;
  4981. FFonts.Clear;
  4982. FImages.Clear;
  4983. FFontFiles.Clear;
  4984. FreeAndNil(FPages);
  4985. FPages:=CreatePDFPages;
  4986. FreeAndNil(FSections);
  4987. FSections:=CreateSectionList;
  4988. end;
  4989. destructor TPDFDocument.Destroy;
  4990. begin
  4991. FreeAndNil(FLineStyleDefs);
  4992. FreeAndNil(FInfos);
  4993. FreeAndNil(FFonts);
  4994. FreeAndNil(FImages);
  4995. FreeAndNil(FFontFiles);
  4996. FreeAndNil(FPages);
  4997. FreeAndNil(FSections);
  4998. Trailer.Free;
  4999. FGlobalXRefs.Free;
  5000. inherited;
  5001. end;
  5002. function TPDFDocument.CreateSectionPageOutLine(const S: TPDFSection;
  5003. const PageOutLine, PageIndex, NewPage, ParentOutline, NextOutline,
  5004. PrevOutLine: Integer): Integer; // Return pages ID
  5005. Var
  5006. ADict: TPDFDictionary;
  5007. Arr : TPDFArray;
  5008. begin
  5009. ADict:=GlobalXRefs[ParentOutline].Dict;
  5010. (ADict.ValueByName('Count') as TPDFInteger).Inc;
  5011. // add page reference to outline destination
  5012. ADict:=GlobalXRefs[PageOutLine].Dict;
  5013. Arr:=(ADict.ValueByName('Dest') as TPDFArray);
  5014. Arr.AddItem(CreateReference(NewPage));
  5015. Arr.AddItem(CreateName('Fit'));
  5016. Result:=PrevOutline;
  5017. if PageIndex=0 then
  5018. begin
  5019. GlobalXRefs[ParentOutline].Dict.AddReference('First',GLobalXRefCount-1);
  5020. Result:=GLobalXRefCount-1;
  5021. // add page reference to parent outline destination
  5022. ADict:=GlobalXRefs[ParentOutline].Dict;
  5023. Arr:=(ADict.ValueByName('Dest') as TPDFArray);
  5024. Arr.AddItem(CreateReference(NewPage));
  5025. Arr.AddItem(CreateName('Fit'));
  5026. end
  5027. else
  5028. begin
  5029. GlobalXRefs[NextOutline].Dict.AddReference('Next',GLobalXRefCount-1);
  5030. GlobalXRefs[PageOutLine].Dict.AddReference('Prev',PrevOutline);
  5031. if (PageIndex<S.PageCount) then
  5032. Result:=GLobalXRefCount-1;
  5033. end;
  5034. if PageIndex=S.PageCount-1 then
  5035. GlobalXRefs[ParentOutline].Dict.AddReference('Last',GLobalXRefCount-1);
  5036. end;
  5037. function TPDFDocument.CreateSectionOutLine(const SectionIndex, OutLineRoot,
  5038. ParentOutLine, NextSect, PrevSect: Integer): Integer; // Previous section
  5039. Var
  5040. ADict: TPDFDictionary;
  5041. begin
  5042. Result:=PrevSect;
  5043. ADict:=GlobalXRefs[OutlineRoot].Dict;
  5044. (ADict.ValueByName('Count') as TPDFInteger).Inc;
  5045. if (SectionIndex=0) then
  5046. begin
  5047. GlobalXRefs[OutlineRoot].Dict.AddReference('First',GLobalXRefCount-1);
  5048. Result:=GLobalXRefCount-1;
  5049. end
  5050. else
  5051. begin
  5052. GlobalXRefs[NextSect].Dict.AddReference('Next',GLobalXRefCount-1);
  5053. GlobalXRefs[ParentOutline].Dict.AddReference('Prev', PrevSect);
  5054. if (SectionIndex<Sections.Count-1) then
  5055. Result:=GLobalXRefCount-1;
  5056. end;
  5057. if SectionIndex=Sections.Count-1 then
  5058. GlobalXRefs[OutlineRoot].Dict.AddReference('Last',GLobalXRefCount-1);
  5059. end;
  5060. function TPDFDocument.CreateSectionsOutLine: Integer; // Parent page ID
  5061. var
  5062. pc,j: integer;
  5063. ParentOutline,TreeRoot,OutlineRoot : Integer;
  5064. K,PageNum: integer;
  5065. PageOutline, NextOutline, NextSect, NewPage, PrevOutline, PrevSect: integer;
  5066. ADict: TPDFDictionary;
  5067. Arr : TPDFArray;
  5068. S : TPDFSection;
  5069. begin
  5070. Result:=0;
  5071. TreeRoot:=0;
  5072. if (Sections.Count>1) then
  5073. begin
  5074. If (poOutline in Options) then
  5075. begin
  5076. OutlineRoot:=CreateOutlines;
  5077. // add outline reference to catalog dictionary
  5078. GlobalXRefs[Catalogue].Dict.AddReference('Outlines',GLobalXRefCount-1);
  5079. // add useoutline element to catalog dictionary
  5080. GlobalXRefs[Catalogue].Dict.AddName('PageMode','UseOutlines');
  5081. end;
  5082. TreeRoot:=CreatePagesEntry(Result);
  5083. end
  5084. else
  5085. begin
  5086. Result:=CreatePagesEntry(Result);
  5087. TreeRoot:=Result;
  5088. end;
  5089. NextSect:=0;
  5090. PrevSect:=0;
  5091. PrevOutLine:=0;
  5092. NextOutLine:=0;
  5093. for J:=0 to Sections.Count-1 do
  5094. begin
  5095. S:=Sections[J];
  5096. if (poOutline in options) then
  5097. begin
  5098. ParentOutline:=CreateOutlineEntry(OutlineRoot,j+1,-1,S.Title);
  5099. PrevSect:=CreateSectionOutline(J,OutlineRoot,ParentOutLine,NextSect,PrevSect);
  5100. NextSect:=ParentOutline;
  5101. Result:=CreatePagesEntry(TreeRoot);
  5102. end;
  5103. for k:=0 to S.PageCount-1 do
  5104. begin
  5105. with S do
  5106. NewPage:=CreatePageEntry(Result,K);
  5107. // add zoom factor to catalog dictionary
  5108. if (j=0) and (k=0) then
  5109. begin
  5110. ADict:=GlobalXRefByName('Catalog').Dict;
  5111. Arr:=ADict.ValueByName('OpenAction') as TPDFArray;
  5112. Arr.AddItem(CreateReference(GLobalXRefCount-1));
  5113. Arr.AddItem(CreateName('XYZ null null '+TPDFObject.FloatStr(StrToInt(FZoomValue) / 100), False));
  5114. end;
  5115. PageNum:=CreateContentsEntry(k); // pagenum = object number in the pdf file
  5116. CreatePageStream(S.Pages[k],PageNum);
  5117. if (Sections.Count>1) and (poOutline in Options) then
  5118. begin
  5119. PageOutLine:=CreateOutlineEntry(ParentOutline,j+1,k+1,S.Title);
  5120. CreateSectionPageOutLine(S,PageOutLine,K,NewPage,ParentOutLine,NextOutLine,PrevOutLine);
  5121. NextOutline:=PageOutLine;
  5122. end;
  5123. end;
  5124. end;
  5125. // update count in root parent pages dictionary
  5126. ADict:=GlobalXRefs[TreeRoot].Dict;
  5127. Pc:=0;
  5128. For J:=0 to Sections.Count-1 do
  5129. Inc(Pc,Sections[J].PageCount);
  5130. (ADict.ValueByName('Count') as TPDFInteger).Value:=PC;
  5131. end;
  5132. procedure TPDFDocument.CreateFontEntries;
  5133. var
  5134. i: integer;
  5135. NumFont: integer;
  5136. FontName: string;
  5137. begin
  5138. // select the font type
  5139. NumFont:=0;
  5140. for i:=0 to Fonts.Count-1 do
  5141. begin
  5142. FontName := Fonts[i].Name;
  5143. if IsStandardPDFFont(FontName) then
  5144. CreateStdFont(FontName, NumFont)
  5145. else if LoadFont(Fonts[i]) then
  5146. begin
  5147. if poSubsetFont in Options then
  5148. Fonts[i].GenerateSubsetFont;
  5149. CreateTtfFont(NumFont);
  5150. end
  5151. else
  5152. CreateTp1Font(NumFont); // not implemented yet
  5153. Inc(NumFont);
  5154. end;
  5155. end;
  5156. procedure TPDFDocument.CreateImageEntries;
  5157. Var
  5158. I : Integer;
  5159. IDict : TPDFDictionary;
  5160. begin
  5161. for i:=0 to Images.Count-1 do
  5162. begin
  5163. CreateImageEntry(Images[i].Width,Images[i].Height,i,IDict);
  5164. if Images[i].HasMask then
  5165. CreateImageMaskEntry(Images[i].Width,Images[i].Height,i,IDict);
  5166. end;
  5167. end;
  5168. procedure TPDFDocument.CreateAnnotEntries(const APageNum: integer; const APageDict: TPDFDictionary);
  5169. var
  5170. i: integer;
  5171. refnum: integer;
  5172. ar: TPDFArray;
  5173. begin
  5174. if GetTotalAnnotsCount = 0 then
  5175. Exit;
  5176. ar := CreateArray;
  5177. APageDict.AddElement('Annots', ar);
  5178. for i := 0 to Pages[APageNum].Annots.Count-1 do
  5179. begin
  5180. refnum := CreateAnnotEntry(APageNum, i);
  5181. ar.AddItem(CreateReference(refnum));
  5182. end;
  5183. end;
  5184. procedure TPDFDocument.SaveToStream(const AStream: TStream);
  5185. var
  5186. i, XRefPos: integer;
  5187. begin
  5188. CreateSectionsOutLine;
  5189. CreateFontEntries;
  5190. CreateImageEntries;
  5191. (Trailer.ValueByName('Size') as TPDFInteger).Value:=GlobalXRefCount;
  5192. AStream.Position:=0;
  5193. TPDFObject.WriteString(PDF_VERSION+CRLF, AStream);
  5194. TPDFObject.WriteString(PDF_BINARY_BLOB+CRLF, AStream); // write some binary data as recommended in PDF Spec section 3.4.1 (File Header)
  5195. // write numbered indirect objects
  5196. for i:=1 to GlobalXRefCount-1 do
  5197. begin
  5198. XRefPos:=AStream.Position;
  5199. WriteObject(i, AStream);
  5200. GlobalXRefs[i].Offset:=XRefPos;
  5201. end;
  5202. XRefPos:=AStream.Position;
  5203. // write xref table
  5204. TPDFObject.WriteString('xref'+CRLF+'0 '+IntToStr(GlobalXRefCount)+CRLF, AStream);
  5205. with GlobalXRefs[0] do
  5206. TPDFObject.WriteString(FormatPDFInt(Offset, 10)+' '+FormatPDFInt(PDF_MAX_GEN_NUM, 5)+' f'+CRLF, AStream);
  5207. WriteXRefTable(AStream);
  5208. // write trailer
  5209. TPDFObject.WriteString('trailer'+CRLF, AStream);
  5210. Trailer.Write(AStream);
  5211. // write offset of last xref table
  5212. TPDFObject.WriteString(CRLF+'startxref'+CRLF+IntToStr(XRefPos)+CRLF, AStream);
  5213. TPDFObject.WriteString(PDF_FILE_END, AStream);
  5214. end;
  5215. procedure TPDFDocument.SaveToFile(const AFileName: String);
  5216. Var
  5217. F : TFileStream;
  5218. begin
  5219. F:=TFileStream.Create(AFileName,fmCreate);
  5220. try
  5221. SaveToStream(F);
  5222. finally
  5223. F.Free;
  5224. end;
  5225. end;
  5226. function TPDFDocument.IsStandardPDFFont(AFontName: string): boolean;
  5227. begin
  5228. { Acrobat Reader expects us to be case sensitive. Other PDF viewers are case-insensitive. }
  5229. if (AFontName='Courier') or (AFontName='Courier-Bold') or (AFontName='Courier-Oblique') or (AFontName='Courier-BoldOblique')
  5230. or (AFontName='Helvetica') or (AFontName='Helvetica-Bold') or (AFontName='Helvetica-Oblique') or (AFontName='Helvetica-BoldOblique')
  5231. or (AFontName='Times-Roman') or (AFontName='Times-Bold') or (AFontName='Times-Italic') or (AFontName='Times-BoldItalic')
  5232. or (AFontName='Symbol')
  5233. or (AFontName='ZapfDingbats') then
  5234. Result := True
  5235. else
  5236. Result := False;
  5237. end;
  5238. function TPDFDocument.CreateEmbeddedFont(const APage: TPDFPage; AFontIndex, AFontSize: Integer): TPDFEmbeddedFont;
  5239. begin
  5240. Result:=TPDFEmbeddedFont.Create(Self, APage, AFontIndex, IntToStr(AFontSize))
  5241. end;
  5242. function TPDFDocument.CreateText(X, Y: TPDFFloat; AText: AnsiString; const AFont: TPDFEmbeddedFont;
  5243. const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean): TPDFText;
  5244. begin
  5245. Result:=TPDFText.Create(Self, X, Y, AText, AFont, ADegrees, AUnderline, AStrikeThrough);
  5246. end;
  5247. function TPDFDocument.CreateText(X, Y: TPDFFloat; AText: UTF8String; const AFont: TPDFEmbeddedFont;
  5248. const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean): TPDFUTF8Text;
  5249. begin
  5250. Result := TPDFUTF8Text.Create(Self, X, Y, AText, AFont, ADegrees, AUnderline, AStrikeThrough);
  5251. end;
  5252. function TPDFDocument.CreateText(X, Y: TPDFFloat; AText: UnicodeString; const AFont: TPDFEmbeddedFont;
  5253. const ADegrees: single; const AUnderline: boolean; const AStrikethrough: boolean): TPDFUTF16Text;
  5254. begin
  5255. Result := TPDFUTF16Text.Create(Self, X, Y, AText, AFont, ADegrees, AUnderline, AStrikeThrough);
  5256. end;
  5257. function TPDFDocument.CreateRectangle(const X,Y,W,H, ALineWidth: TPDFFloat; const AFill, AStroke: Boolean): TPDFRectangle;
  5258. begin
  5259. Result:=TPDFRectangle.Create(Self,X,Y,W,H,ALineWidth,AFill, AStroke);
  5260. end;
  5261. function TPDFDocument.CreateRoundedRectangle(const X, Y, W, H, ARadius, ALineWidth: TPDFFloat;
  5262. const AFill, AStroke: Boolean): TPDFRoundedRectangle;
  5263. begin
  5264. Result := TPDFRoundedRectangle.Create(Self, X, Y, W, H, ARadius, ALineWidth, AFill, AStroke);
  5265. end;
  5266. function TPDFDocument.CreateColor(AColor: TARGBColor; AStroke: Boolean): TPDFColor;
  5267. begin
  5268. Result:=TPDFColor.Create(Self,AStroke,AColor);
  5269. end;
  5270. function TPDFDocument.CreateBoolean(AValue: Boolean): TPDFBoolean;
  5271. begin
  5272. Result:=TPDFBoolean.Create(Self,AValue);
  5273. end;
  5274. function TPDFDocument.CreateInteger(AValue: Integer): TPDFInteger;
  5275. begin
  5276. Result:=TPDFInteger.Create(Self,AValue);
  5277. end;
  5278. function TPDFDocument.CreateReference(AValue: Integer): TPDFReference;
  5279. begin
  5280. Result:=TPDFReference.Create(Self,AValue);
  5281. end;
  5282. function TPDFDocument.CreateString(const AValue: String): TPDFString;
  5283. begin
  5284. Result:=TPDFString.Create(Self,AValue);
  5285. end;
  5286. function TPDFDocument.CreateUTF16String(const AValue: UnicodeString; const AFontIndex: integer): TPDFUTF16String;
  5287. begin
  5288. Result:=TPDFUTF16String.Create(Self,AValue,aFontIndex);
  5289. end;
  5290. function TPDFDocument.CreateUTF8String(const AValue: UTF8String; const AFontIndex: integer): TPDFUTF8String;
  5291. begin
  5292. Result := TPDFUTF8String.Create(self, AValue, AFontIndex);
  5293. end;
  5294. function TPDFDocument.CreateLineStyle(APenStyle: TPDFPenStyle; const ALineWidth: TPDFFloat): TPDFLineStyle;
  5295. begin
  5296. Result := TPDFLineStyle.Create(Self, APenStyle, 0, ALineWidth);
  5297. end;
  5298. function TPDFDocument.CreateName(AValue: String; const AMustEscape: boolean = True): TPDFName;
  5299. begin
  5300. Result:=TPDFName.Create(Self,AValue,AMustEscape);
  5301. end;
  5302. function TPDFDocument.CreateStream(OwnsObjects : Boolean = True): TPDFStream;
  5303. begin
  5304. Result:=TPDFStream.Create(Self,OwnsObjects);
  5305. end;
  5306. function TPDFDocument.CreateDictionary: TPDFDictionary;
  5307. begin
  5308. Result:=TPDFDictionary.Create(Self);
  5309. end;
  5310. function TPDFDocument.CreateXRef: TPDFXRef;
  5311. begin
  5312. Result:=TPDFXRef.Create(Self);
  5313. end;
  5314. function TPDFDocument.CreateArray: TPDFArray;
  5315. begin
  5316. Result:=TPDFArray.Create(Self);
  5317. end;
  5318. function TPDFDocument.CreateImage(const ALeft, ABottom, AWidth,
  5319. AHeight: TPDFFloat; ANumber: integer): TPDFImage;
  5320. begin
  5321. Result:=TPDFImage.Create(Self,ALeft,ABottom,AWidth,AHeight,ANumber);
  5322. end;
  5323. function TPDFDocument.AddFont(AName: String): Integer;
  5324. var
  5325. F: TPDFFont;
  5326. i: integer;
  5327. begin
  5328. { reuse existing font definition if it exists }
  5329. Result:=Fonts.FindFont(AName);
  5330. if Result>=0 then exit;
  5331. F := Fonts.AddFontDef;
  5332. F.Name := AName;
  5333. F.IsStdFont := True;
  5334. Result := Fonts.Count-1;
  5335. end;
  5336. function TPDFDocument.AddFont(AFontFile: String; AName: String): Integer;
  5337. var
  5338. F: TPDFFont;
  5339. i: integer;
  5340. lFName: string;
  5341. begin
  5342. { reuse existing font definition if it exists }
  5343. Result:=Fonts.FindFont(AName);
  5344. if Result>=0 then exit;
  5345. F := Fonts.AddFontDef;
  5346. if ExtractFilePath(AFontFile) <> '' then
  5347. // assume AFontFile is the full path to the TTF file
  5348. lFName := AFontFile
  5349. else
  5350. // assume it's just the TTF filename
  5351. lFName := IncludeTrailingPathDelimiter(FontDirectory)+AFontFile;
  5352. F.FontFile := lFName;
  5353. F.Name := AName;
  5354. F.IsStdFont := False;
  5355. Result := Fonts.Count-1;
  5356. end;
  5357. function TPDFDocument.AddLineStyleDef(ALineWidth: TPDFFloat; AColor: TARGBColor;
  5358. APenStyle: TPDFPenStyle): Integer;
  5359. Var
  5360. F : TPDFLineStyleDef;
  5361. begin
  5362. F:=FLineStyleDefs.AddLineStyleDef;
  5363. F.LineWidth:=ALineWidth;
  5364. F.Color:=AColor;
  5365. F.PenStyle:=APenStyle;
  5366. Result:=FLineStyleDefs.Count-1;
  5367. end;
  5368. initialization
  5369. PDFFormatSettings:= DefaultFormatSettings;
  5370. PDFFormatSettings.DecimalSeparator := '.';
  5371. PDFFormatSettings.ThousandSeparator := ',';
  5372. PDFFormatSettings.DateSeparator := '/';
  5373. PDFFormatSettings.TimeSeparator := ':';
  5374. end.