Technisch artikel

HotPDF TextOut in Delphi: Grootte, Stijl, Rotatie en Afstand

Elke zichtbare string in een HotPDF document komt tot stand via één aanroep: TextOut(X, Y, hoek, Tekst). Het Hello World voorbeeld gebruikt het op zijn eenvoudigst, met een eenmalig ingesteld lettertype en vier argumenten die op logische standaardwaarden zijn gelaten. Voorbij die eerste pagina dragen diezelfde vier argumenten het volledige gewicht van de lay-out. Het derde argument roteert de run. Het lettertype dat er net voor is ingesteld bepaalt de grootte en stijl. En het X, Y paar, gemeten vanaf de paginahoek in punten, is het enige dat tussen een net rapport staat en tekst die overlapt, afsnijdt of een regel lager wegdrijft op de printer van iemand anders. Dit is waar TextOut zijn geld opbrengt, en waar de standaardwaarden niet meer volstaan

De signatuur is de moeite waard om in gedachten te prenten voordat u iets anders doet: X en Y zijn Single in punten, hoek is een Extended in graden, en Tekst is een WideString, dus Unicode gaat erdoorheen zonder een aparte aanroep. Een tweede overload neemt een PWORD plus een lengte voor wanneer u al glyphcodes vasthoudt, maar voor gewone strings is de WideString-vorm degene waar u naar grijpt

Grootte en stijl komen van SetFont, niet van TextOut

TextOut heeft geen parameter voor grootte. De grootte, het gewicht, de schuinte, alles leeft in de SetFont aanroep die aan de run voorafgaat, en het blijft van kracht totdat de volgende SetFont het vervangt. Dat is het enige feit dat de meeste verwarring op de eerste dag verklaart: een regel wordt vetgedrukt omdat iets drie aanroepen eerder [fsBold] instelde en niets het heeft gewist

Pdf.CurrentPage.SetFont('Times New Roman', [], 24);
Pdf.CurrentPage.TextOut(72, 740, 0, 'Quarterly Report');        // 24pt regular

Pdf.CurrentPage.SetFont('Times New Roman', [fsBold], 12);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Revenue');                 // 12pt bold

Pdf.CurrentPage.SetFont('Times New Roman', [fsItalic], 11);
Pdf.CurrentPage.TextOut(72, 694, 0, 'figures in thousands');    // 11pt italic

Pdf.CurrentPage.SetFont('Courier New', [fsBold, fsItalic], 10);
Pdf.CurrentPage.TextOut(72, 676, 0, '  +18.4% YoY');            // styles combine

Het tweede argument is een TFontStyles verzameling, dus [fsBold, fsItalic] is vet cursief en [] is normaal. De grootte is in punten, dezelfde eenheid als de coördinaten, wat het redeneren over verticale spatiëring eenvoudig maakt: een 12-punts regel heeft ruwweg 14 tot 16 punten verticale stap nodig om te ademen, dus Y met 14 laten zakken per regel is een redelijke start-regelafstand. Er is geen automatische regelopschuiving. U berekent elke basislijn zelf, wat vervelend is voor een alinea maar exact voor een formulier, waar elk veld op een vaste coördinaat staat

Twee praktische opmerkingen over de naam van het lettertype. Het wordt herleid aan de hand van de lettertypen die op de build-machine zijn geïnstalleerd, en wat het besturingssysteem ook teruggeeft, wordt ingesloten. Een naam die op uw bureaublad wordt herleid, hoeft dus niet gegarandeerd hetzelfde lettertype te zijn als een naam die op een buildserver wordt herleid. En het lettertype moet de scripts in de string dekken. Een reeks Cyrillische of CJK-tekst onder een lettertype dat alleen Latijns is, wordt zonder foutmelding weergegeven als ontbrekende-glyph-vakjes, wat de reden is dat de Hello World-pagina naar een breed Unicode-lettertype grijpt wanneer het talen combineert

HotPDF TextOut pagina met Arial, Times New Roman en Courier New gerenderd in normale, vette en cursieve stijlen over meerdere tekensets

Het hoekargument roteert rond het anker

Het derde argument is het argument dat de meeste code voor altijd op nul laat staan. Geef een waarde ongelijk aan nul door en de run roteert tegen de klok in rond zijn eigen (X, Y) anker, de linkerbenedenhoek van de tekst, met dat aantal graden. Het anker zelf beweegt niet, dus dezelfde coördinaat die een horizontaal label plaatste, plaatst zijn geroteerde tweelingbroer; alleen de richting waarin de glyphs marcheren verandert

Pdf.CurrentPage.SetFont('Arial', [fsBold], 11);

// A vertical axis label down the left margin: 90 degrees reads bottom-to-top.
Pdf.CurrentPage.TextOut(40, 300, 90, 'Units sold');

// A diagonal DRAFT watermark across the page body.
Pdf.CurrentPage.SetFont('Arial', [fsBold], 60);
Pdf.CurrentPage.TextOut(150, 250, 45, 'DRAFT');

// Column headers tilted 60 degrees so long labels fit a narrow table.
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(120, 600, 60, 'Q1 actual');
Pdf.CurrentPage.TextOut(160, 600, 60, 'Q2 actual');

Negentig graden is het veelvoorkomende geval, een label dat langs de zijkant van een grafiek loopt of een rugtitel. Vijfenveertig graden behandelt gekantelde kolomkoppen, de truc waarmee een breed label boven een smalle kolom kan staan zonder over te lopen in zijn buren. Rotatie verandert niet hoe het anker wordt geïnterpreteerd, wat mensen op het verkeerde been zet: een 90-graden run begint nog steeds op (X, Y) en groeit van daaruit naar boven, dus om een geroteerd label te centreren past u het anker aan, niet de hoek. Wanneer meerdere geroteerde runs een basislijn delen, geef ze dan dezelfde Y en stap X, precies zoals u Y zou stappen voor gestapelde horizontale lijnen

Coördinaten plaatsen zonder te gissen

Coördinaten zijn het onderdeel dat een beoordeling overleeft of deze stilletjes faalt. HotPDF meet vanaf de linkerbenedenhoek van de pagina, Y neemt naar boven toe, in punten op 72 per inch. Een US Letter-pagina is 612 bij 792 punten; A4 is 595 bij 842. Een bovenmarge van één inch op Letter plaatst daarom uw eerste basislijn in de buurt van Y = 792 min 72 min de lettergrootte, niet bij een klein getal in de buurt van de bovenkant. Iedereen die van schermcoördinaten komt, waarbij Y vanaf nul naar beneden groeit, schrijft de eerste regel buiten de onderrand en vraagt zich tien minuten lang af waar deze gebleven is

Behandel lay-out als rekenkunde ten opzichte van benoemde ankers in plaats van een kolom met magische getallen. Een linkermarge, een lopende basislijn die u per regel verlaagt, en een vaste regelafstand veranderen een blok labels in een korte lus in plaats van een muur van letterlijke waarden:

const
  LeftMargin = 72;        // 1 inch in
  TopBaseline = 720;       // first line, ~1 inch down on Letter
  Leading = 16;            // vertical step between lines
var
  Y: Single;
  Line: string;
begin
  Pdf.CurrentPage.SetFont('Arial', [], 11);
  Y := TopBaseline;
  for Line in ReportLines do
  begin
    Pdf.CurrentPage.TextOut(LeftMargin, Y, 0, Line);
    Y := Y - Leading;
    if Y < 72 then            // bottom margin reached
    begin
      Pdf.AddPage;
      Pdf.CurrentPage.SetFont('Arial', [], 11);  // font resets on a new page
      Y := TopBaseline;
    end;
  end;
end;

De bewaking tegen pagina-einden is de regel die iedereen als eerste vergeet en die in de praktijk het hardst toeslaat. Er zit geen flow-layout onder TextOut. Verlaag voorbij de ondermarge en de tekst blijft in de goot tekenen, van de pagina af, in het niets, zonder waarschuwing. Dus u houdt Y zelf in de gaten, roept AddPage aan wanneer deze de drempel overschrijdt, en stelt de basislijn opnieuw in. De SetFont na AddPage is geen optionele opvulling: het huidige lettertype overleeft een pagina-einde niet, en de eerste run op de nieuwe pagina wordt in het standaardlettertype van de viewer weergegeven als u deze overslaat

Teken- en woordafstand voor pasvorm en uitlijning

Soms is een string correct, maar is de breedte verkeerd: een koptekst die een vaste regel moet overspannen, een code die met luchtigere cijfers moet lezen, een kolom waarvan de waarden verschoven moeten worden om uit te lijnen. PDF heeft hiervoor twee tekststatus-operatoren, tekenafstand (Tc, extra ruimte toegevoegd na elke glyph) en woordafstand (Tw, extra ruimte toegevoegd bij elk spatiekarakter), en beide worden uitgedrukt in ongeschaalde tekstruimte-eenheden, effectief punten bij de huidige lettergrootte. Ze zijn status, geen argumenten voor TextOut, dus u stelt ze in, tekent en stelt ze weer terug

// Letter-space a short heading so it stretches across a rule.
Pdf.CurrentPage.SetCharacterSpacing(4);
Pdf.CurrentPage.SetFont('Arial', [fsBold], 14);
Pdf.CurrentPage.TextOut(72, 740, 0, 'S U M M A R Y');
Pdf.CurrentPage.SetCharacterSpacing(0);   // reset before normal body text

// Open up the gaps between words on a single wide line.
Pdf.CurrentPage.SetWordSpacing(6);
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Name        Department        Extension');
Pdf.CurrentPage.SetWordSpacing(0);

Woordafstand werkt alleen op de spatie (code 32), wat een consequentie heeft die goed is om te weten: het doet niets binnen een CJK-run die geen ASCII-spaties heeft, en het werkt vreemd in combinatie met tekst die als glyph-indexen gecodeerd is in plaats van als bytes. Voor Latijnse tabeluitvoer is het de goedkope manier om ruimtes te verbreden zonder de string opnieuw te typen. Tekenafstand is de betere tool voor een koptekst die een doelbreedte moet bereiken, omdat het de aanpassing gelijkmatig over elke glyph verspreidt in plaats van het te bundelen bij de spaties

Het terugzetten is de hele discipline. Spatiëring maakt, net als het lettertype, deel uit van de tekenstatus van de pagina, en de status blijft bestaan totdat u deze wijzigt. Als u de letterafstand van een kop vergroot en vergeet deze op nul te zetten, neemt elke alinea eronder de uitrekking over, wat leest als een subtiele, moeilijk te plaatsen onjuistheid die een vluchtige proeflezing overleeft en faalt bij een zorgvuldige. De betrouwbare gewoonte is om een spatiëringswaarde in te stellen, de run te tekenen die het nodig heeft, en het op de volgende regel terug op nul te zetten, zodat latere code niet hoeft te weten wat een eerdere sectie deed

HotPDF TextOut pagina die horizontale tekstschaling, tekenafstand, woordafstand en vul versus lijnweergavemodi vergelijkt

De uitvoer controleren waar deze daadwerkelijk faalt

Tekstopmaak faalt op de tweede machine, niet op de eerste, dus de controles die ertoe doen vinden plaats weg van uw bureau. Open het gegenereerde bestand op een systeem waarop uw ontwikkelaars-lettertype-set niet is geïnstalleerd en bevestig dat de ingesloten lettertypes nog steeds worden weergegeven, inclusief Latijns met accenten, eventuele niet-Latijnse scripts en leestekens, in één keer in plaats van de makkelijke tekens steekproefsgewijs te controleren. Selecteer en kopieer een paar regels om te bevestigen dat de tekst echte tekst is en geen contouren, wat ertoe doet op het moment dat zoeken of extractie van toepassing is. Voer representatieve gegevens in de lay-out, het langste Duitse label en het breedste getal, niet een nette tijdelijke aanduiding, want de run die buiten een veld loopt, is altijd degene die u niet met de hand hebt getypt. En als de pagina op een voorbedrukt formulier moet landen, print of raster dan één monster en leg het tegen het origineel; een afwijking in de basislijn van een kwart millimeter is onzichtbaar op het scherm en overduidelijk op papier

Als u nog geen enkele pagina heeft geschreven, begin dan met het HotPDF Hello World voorbeeld, dat het document, het lettertype en het linksonder-coördinatensysteem instelt waar alles hierboven van afhangt. De TextOut, SetFont en spatiërings-aanroepen die hier worden getoond maken deel uit van de HotPDF Component voor Delphi en C++Builder