O HotPDF desenha gráficos vetoriais construindo um caminho na página atual e, em seguida, solicitando que seja pintado. Não existe nenhum passo de mapa de bits (bitmap) intermédio. Uma linha que desenhe com MoveTo e LineTo acaba como operadores de caminho de PDF no fluxo de conteúdo, pelo que permanece um verdadeiro vetor: nítido num zoom de 50%, nítido a 1600%, e por uma fração do tamanho que uma versão rasterizada custaria. Para diagramas, réguas de tabela, eixos de gráficos e decorações de formulários, é exatamente isso que pretende, e a API subjacente é suficientemente pequena para ser aprendida de uma só vez
Toda a superfície de desenho reside em THotPDF.CurrentPage. Entre BeginDoc e EndDoc define a cor e a largura da linha nesse objeto de página, traça a geometria e chama um operador de pintura para a confirmar. Os quatro primitivos que irá utilizar mais vezes são MoveTo e LineTo para caminhos arbitrários, Rectangle para caixas, Circle para discos, e os dois operadores de pintura Stroke e Fill
O sistema de coordenadas situa-se no canto inferior esquerdo
Esta é a única coisa que faz tropeçar toda a gente que chega da VCL. O TCanvas com o qual pinta os controlos coloca a origem no canto superior esquerdo com o Y a crescer para baixo. O PDF faz o oposto. O HotPDF mede a partir do canto inferior esquerdo da página em pontos (1/72 de polegada), com o Y a aumentar à medida que se sobe. Um ponto em Y := 720 fica perto do topo de uma página US Letter, que tem 792 pontos de altura, e Y := 50 fica perto da base. Se o seu primeiro desenho sair invertido verticalmente, a razão é esta: o código transferido de gráficos de ecrã pressupõe a direção errada e sai pelo rebordo inferior
A mesma convenção rege TextOut, de modo que texto e formas partilham um mesmo modelo mental depois de o interiorizar. Planeie a sua estrutura e disposição decidindo onde assenta a base de cada elemento, e não o topo, o resto surge com facilidade a partir daí
Caminhos: MoveTo, LineTo, Stroke
Um caminho traçado corresponde a uma caneta levantada, colocada e arrastada. MoveTo levanta a caneta e define o ponto de partida sem desenhar nada. Cada LineTo prolonga o caminho atual para um novo ponto. Nada aparece na página até que chame Stroke, o qual desenha o caminho acumulado utilizando a cor de traço e a largura de linha atuais e, em seguida, limpa o caminho para que o próximo MoveTo comece do zero
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'DrawPaths.pdf';
Pdf.BeginDoc;
// Line width is in points and applies until you change it.
Pdf.CurrentPage.SetLineWidth(1.5);
Pdf.CurrentPage.SetRGBStrokeColor(clBlack);
// A horizontal rule near the top of the page (Y measured from bottom).
Pdf.CurrentPage.MoveTo(72, 720);
Pdf.CurrentPage.LineTo(523, 720);
Pdf.CurrentPage.Stroke; // commit the path; nothing drew before this
// A thicker connected polyline: three segments in one path.
Pdf.CurrentPage.SetLineWidth(3);
Pdf.CurrentPage.SetRGBStrokeColor(RGB(30, 90, 200));
Pdf.CurrentPage.MoveTo(72, 640);
Pdf.CurrentPage.LineTo(172, 690);
Pdf.CurrentPage.LineTo(272, 620);
Pdf.CurrentPage.LineTo(372, 680);
Pdf.CurrentPage.Stroke;
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Há dois pormenores que poupam tempo real de depuração. A largura da linha é um estado, e não um argumento: SetLineWidth define-a uma vez e cada Stroke subsequente utiliza esse valor até que o altere novamente, razão pela qual a polilinha acima é mais grossa do que a régua. E o caminho é reposto após cada Stroke, pelo que um Stroke esquecido significa que a geometria que planeou com tanto cuidado nunca chegará a ser apresentada. Se uma forma estiver a faltar na saída, a chamada de pintura é o primeiro local a verificar
As coordenadas são pontos, e os pontos são fracionários. MoveTo e LineTo aceitam valores Single, pelo que uma linha muito fina a 0.5 pontos ou uma posição a 72.25 é válida e significativa, e não arredondada para a unidade inteira mais próxima. Essa precisão é importante em duas direções opostas. Uma largura de linha inferior a cerca de 0.5 pode renderizar-se como a linha mais fina possível dependente do dispositivo, que desaparece no ecrã e reaparece quando impressa, pelo que uma regra visível requer uma largura definida propositadamente em vez da predefinição. No outro extremo, o encaixe de réguas de tabela e linhas de grelha em coordenadas de pontos inteiros impede que uma grelha densa pareça ligeiramente irregular nos locais em que as linhas adjacentes arredondam de forma diferente. Decida o espaçamento da grelha em pontos logo à partida e o resto da estrutura herdá-lo-á
Formas preenchidas e cor
As primitivas fechadas podem ser preenchidas em vez de delineadas. Rectangle recebe uma posição e um tamanho, Circle recebe um centro e um raio, e qualquer um deles é confirmado com Fill, que pinta o interior na cor de preenchimento atual, ou com Stroke para ter apenas o contorno. A cor de preenchimento e a cor de traço são partes distintas de estado, definidas com SetRGBFillColor e SetRGBStrokeColor, ambas as quais aceitam um único TColor. Isto significa que pode reutilizar as constantes de cor do Delphi e o auxiliar RGB diretamente
// Rectangle(X, Y, Width, Height): X and Y are the lower-left corner.
Pdf.CurrentPage.SetRGBFillColor(RGB(220, 60, 60));
Pdf.CurrentPage.Rectangle(72, 500, 160, 90);
Pdf.CurrentPage.Fill;
// Circle(X, Y, Radius): X and Y are the center.
Pdf.CurrentPage.SetRGBFillColor(clNavy);
Pdf.CurrentPage.Circle(420, 545, 45);
Pdf.CurrentPage.Fill;
// Outline only: set a stroke color and a width, then Stroke.
Pdf.CurrentPage.SetLineWidth(2);
Pdf.CurrentPage.SetRGBStrokeColor(clBlack);
Pdf.CurrentPage.Rectangle(72, 400, 160, 60);
Pdf.CurrentPage.Stroke;
Preste atenção à forma do argumento em Rectangle. Trata-se da posição acrescida do tamanho, X, Y, Width, Height, e não de dois cantos opostos. O TCanvas.Rectangle conhecido dos programadores Delphi requer (Left, Top, Right, Bottom), pelo que a memória muscular vai entregar ao HotPDF um segundo canto onde este espera uma largura e uma altura, e a caixa vai sair com o tamanho errado. O par (X, Y) corresponde ao canto inferior esquerdo, de forma consistente com a origem da página. Para um círculo, (X, Y) corresponde ao centro e o terceiro argumento é o raio em pontos
Uma escolha de cor em que o exemplo original errou
Uma versão mais antiga deste exemplo preenchia as cores com Random($FFFFFF) em todas as formas. Parece muito animado, e é o instinto errado para documentos gerados. Um PDF que constrói a partir de código é geralmente algo que também vai querer testar, e as cores de preenchimento aleatórias tornam o resultado impossível de comparar entre execuções: um diff byte a byte contra um ficheiro sabidamente bom irá falhar sempre, sem qualquer razão real. Escolha cores explícitas. Quando pretende variedade numa série de formas, determine-a a partir dos seus dados ou de uma matriz de paleta fixa, para que a mesma entrada produza sempre o mesmo ficheiro. O determinismo vale mais do que a inovação quando o artefacto se movimenta através de um pipeline de lançamento
Juntar as primitivas: uma caixa de destaque
Cada primitiva é simples por si só; a recompensa surge quando um punhado delas compõe algo de que um relatório efetivamente necessita. Um destaque (callout), a caixa com notas que aponta para uma figura e a explica, utiliza tudo o que foi focado até agora: um retângulo preenchido com um contorno, uma linha de ponteiro traçada, um ponto para fixar o ponteiro e texto colocado no interior da caixa utilizando as mesmas coordenadas (canto inferior esquerdo) que as formas empregam. FillAndStroke ganha o seu lugar aqui, pintando o interior e o contorno de um caminho numa única confirmação em vez de construir o retângulo duas vezes
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'Callout.pdf';
Pdf.BeginDoc;
// 1. The box: pale fill plus a visible border, one path, one commit.
// Rectangle is lower-left corner plus size, Y measured from the bottom
Pdf.CurrentPage.SetRGBFillColor(RGB(255, 244, 214)); // pale amber panel
Pdf.CurrentPage.SetRGBStrokeColor(RGB(180, 130, 40)); // darker rim
Pdf.CurrentPage.SetLineWidth(1);
Pdf.CurrentPage.Rectangle(90, 600, 240, 70);
Pdf.CurrentPage.FillAndStroke;
// 2. The pointer: one stroked segment from the box edge down
// toward the thing being annotated
Pdf.CurrentPage.SetLineWidth(1.5);
Pdf.CurrentPage.MoveTo(90, 615); // left edge of the box
Pdf.CurrentPage.LineTo(66, 546);
Pdf.CurrentPage.Stroke;
// 3. A filled dot anchors the pointer at its target
Pdf.CurrentPage.SetRGBFillColor(RGB(180, 130, 40));
Pdf.CurrentPage.Circle(64, 542, 3);
Pdf.CurrentPage.Fill;
// 4. The label, positioned relative to the box's lower-left corner.
// Text and shapes share one coordinate system, so the offsets
// are plain arithmetic against (90, 600)
Pdf.CurrentPage.SetFont('Arial', [fsBold], 10);
Pdf.CurrentPage.TextOut(102, 645, 0, 'Check this total');
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(102, 628, 0, 'The rounding rule changed in the');
Pdf.CurrentPage.TextOut(102, 616, 0, 'June release; verify against v2.1');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Note como é reduzida a gestão de estados de que a composição necessita. A cor de preenchimento, a cor do traço e a largura da linha são definidas de forma individual logo antes da forma que as utiliza, de modo que cada bloco de desenho é lido como uma unidade autossuficiente e pode ser reordenado ou extraído para um auxiliar sem que venha a arrastar atrás de si estados ocultos. Envolva isto num procedimento que aceita o ponto de fixação e as cadeias, e obtém uma anotação de diagrama reutilizável pelo custo de quarenta linhas
Onde o desenho vetorial compensa e onde não
Recorra a estas chamadas de caminhos e formas sempre que a geometria for gerada: linhas de grelha de gráficos e barras, as linhas regradas de uma tabela de faturas, caixas de destaque num diagrama, um logótipo expresso sob a forma de alguns caminhos. Tudo isto permite o redimensionamento sem desfocar e sem acrescentar quase nada ao tamanho do ficheiro, porque um retângulo representa alguns números em vez de milhares de píxeis. O reverso da medalha também deve ser considerado. Se aquilo que na realidade tem for uma fotografia ou uma captura de ecrã, desenhe-a antes como imagem com AddImage e ShowImage; o rastreio de um mapa de bits com chamadas de vetor não traz qualquer vantagem. Os segmentos a direito, os retângulos e os círculos apresentados comportam a grande maioria dos verdadeiros trabalhos de relatórios, e os três aprimoramentos sobre os quais os programadores depois perguntam, nomeadamente curvas, padrões de traço e transparência, assentam no mesmo objeto de página
Curvas, traços e transparência resumidos
As curvas de forma livre alargam o mesmo mecanismo de caminho que já se encontra na sua posse. CurveToC(X1, Y1, X2, Y2, X3, Y3) adiciona um segmento cúbico de Bezier do ponto atual para (X3, Y3), curvando-se para os dois pontos de controlo, e as variantes de formato abreviado CurveToV e CurveToY abrangem os casos em que um ponto de controlo coincide com uma extremidade. Um caminho pode misturar os segmentos LineTo e CurveToC com toda a liberdade, e tudo isto precedido por um único Stroke ou a que a consolidação Fill vincule a esse pressuposto. Sendo, de resto, também desta forma que são compostos os cantos de linhas suaves com gráficos curvilíneos num esquema para formas com vertentes redondas ou arredondadas
Os traços tracejados constituem um estado, à semelhança do que sucede com a largura da linha. SetDash([3, 3], 0) altera todos os traços subsequentes para o padrão ligado em três pontos e desligado em três pontos, a matriz que soletra os comprimentos de percurso ativados/desativados (on/off) em pontos e o desfasamento da parte de arranque face ao início para que a cadência entre ciclos no segundo parâmetro proceda; NoDash devolve a caneta à condição de linha a cheio ininterrupta. Defina-o, aplique nos traços das linhas de grelha que necessita e, face as premissas em perspetiva recoloque aos mesmos para as formas em contínuo de linha não partida porque noutras de qualquer forma sem esta o modelo passível face aos elementos a que perante eles lhe sigam ficam de base pela regra nos tracejados e à sua silenciada condição inerente e de aparente inocuidade contaminados
A transparência atravessa um estado de nomeação perante vertentes e aspetos ao plano de configuração gráfico muito acima da versão pelo apelo numa componente base à cor no seu argumento. Esse pressuposto a tal decorre da condição segundo a qual os esquemas para a lógica no PDF assumem num quadro sobre as propriedades nos de atributos do sistema do diretório e pelo que nos do referencial de estado da alfa se lhe reportam às gráficas e que as constituem. Confirme-se essa vertente por um registo com correspondência nas formatações sobre um com referências de inserção ao longo da folha com um `RegisterExtGState`. Numa transferência face aos parâmetros num 1 perante do traço num limite oposto à do zero pela dimensão na sua espessura, numa versão com alfa a preenchimentos bem como para as configurações base na segunda de um percurso sob registos do traço alfa e que devolve na fixação no retorno à sua base para onde a designação lhe for remetida com os propósitos por via a um formato nos desenvolvimentos por `CurrentPage.SetGraphicsState`. Daqui para uma face nas escalas em relação face às quais a partir desta perspetiva perante as passagens nas de tintas e aos correspondentes e preenchimentos com passagens de níveis sob o estado que com de opacidades se pautou nesse enquadramento num plano superior das escalas nas atribuições relativas do que do passo às de antes no esquema se assumia e em perante. Reveste de formalismos do de cariz pesados por contraponto em vertentes numa simples dimensão sobre bases para definir de modo singelo uma da cor. Para valer em todas perante ao lado os pressupostos justificados nas condições que em escalas no patamar aos desempenhos das perspetivas a exigência na qual por vez inicial prefigure com de necessidades e com garantias na não inibição e supressões gráficas à barra face à relevância nas atribuições pela de sublinhar perante aos seus com destaque um enquadramento nos carateres face ao encobrimento não se verificar numa de sobreposições nos pressupostos pelas partes em destaque (ao qual de sublinhado)
E um costume nas margens com validade subjacente na das condições que a valência lhe confere, cinge o propósito no do facto em avaliações pela componente face as de análises em verificação. Com nas suas das lógicas a de geometrias com aprovações em geradas pelo do se da avaliação num na conformação face de sua e com à da margem com os desajustes para a falência nas de um com base a clientes, por, num a das vias de a para o não sob regra em o aos esquemas na da a perante o em fontes por no substituição à de ou em na do texto de na em o misture que, num a do tamanho a no assumida no página da de que a e num e não do que se a de mantenha. Numa a um do terminada no na a de a ficheiro de o em a do alguns a num por e a de para da do ampliação de da a na a a lógicas às e confirmar a a da no do e arestas à o em permaneçam a da as lógicas e a de num para verifique as da a do a o e do a o de a num à todas do a caia na as nas formas dentro o na a de margem à de o em a lógicas da à num da do pretendida nas a lógicas de. Uma da num para em um de esquema da a no a de cores do com a no o em lógicas o num a no a a o num das lógicas à no de que de num a de para lógicas do a a automática do a a em à de a um num da e num da no em a uma na à lógicas da do PDF nas à referência de a no do a para de a lógicas de a à da verificação do e num da num em de o a lógicas
As chamadas MoveTo, LineTo, Stroke, Fill e as de cores aqui apresentadas fazem parte do Componente HotPDF para Delphi e C++Builder