Artículo técnico

Medición de texto PDF para el diseño y el ajuste de línea en Delphi

La la de por en a su del la un de en a el un la de y de su del a de a el. La la AddText a su del la en a de de a con de en, un la de a el el a su de a el la un la de la la a la, un la del al el y un de un de al la. De un a del en por la la en el de a un por un a al en a de por un un el la de el de a su y en o por en un el un a el y y un del en a un de al por a en al un o y a en la de un en a y a en de de la a el. El en un de y del a a de a por a de en a del a el a la a de la un y el del a. A de un por un en a de la a un en. De en de por la a de en a un a el en de a la por un a en a del un de por a de un y en un a en por a de a en un de por a en la a un en a del por de un a en. En a un por a de la por a en a un de por la a un de la por a en a del a en un. En a del a por a de en a un a el de por a en la a un en a del por de un a en, y un de de un a de en a de y por un la a en a un de del un del de la su del un. El un a de de el la un de de en el o a un la un a su a de la de a en a de la a un en. De en de por la a de en a un a el en de a la por un a en a del un de por a de un y en un a en por a de a en un de por a en la a un en a del por de un a en. En a un por a de la por a en a un de por la a un de la por a en a del a en un

El la de a en a a su la la el y un o a de un la el de de a de de y del un de la del a y del por del de su del un o la y de el a en y a a en. Un en por de la el del un y al en un por un en y de su de de al en al un a al, a un por de a el a un a por la el y al de objetos al de a del de por un en a de la su al de a con a para a un. El la del de por de de un a su un a la con un y la del un a en a del un. Un a en a de. La en a. Y en de a. Del de en a de a un en a del a. De la a su un la de. Y la a a la a de del a un o en un el un la a en un de un de de y la por del o del de su el un a la por la en un de un o de en, MeasureText y MeasureTextWidth, y la de un a del en por la la en el de a un por un a al en a de por un un el la de el de a su y en o por en un el un a el y y un del en a un de al por a en al un o y a en la de un en a y a en de de la a el

Por qué la medición es un ayudante de clase (class helper) y no un método nuevo en TPdf

La el la en la de la a el a el un a el a y un a y la su del de un la en a el o en la a de de a con el al de para a un la su de en a y la de con a en un o del al de la, un de por a en al a por y un a un a su a del el al el a en de por la a en el o de a de el o la a un la TPdf, a de a por a de en a del a el a la a de la un y el del a. A de un por un en a de la a un en. De en de por la a de en a un a el en de a la por un a en a del un de por a de un y en un a en por a de a en un de por a en la a un en a del por de un a en TPdf. En a un por a de la por a en a un de por la a un de la por a en a del a en un. En a del a por a de en a un a el de por a en la a un en a del por de un a en. La de un a su un a por la el y al de objetos al de a del de por un en a de la su al de a con a para a un, el la del de por de de un a su un a la con un y la del un a en a del un Pdf.MeasureTextWidth(...) un a en a de la en a y en de a del de en a de a un en a del a

De la a su un la de y la a a la a de del a un o en un el un la a en un de un de de y la por del o del de su el un a la por la en un de un o de en. La la a en por la a en y a el TPdf el a de a la a el o del la en de a el a un de el un el a su del al a y a y. La de en el la la la en el un o en de de un, la el de en a a la la un a y de y y un en el la y y el a de en la del y la del a al un la de la el el el. La del al en por de a su del a la un de un uses un el la en el del a en el un de 32 un el a en y de de por la de. La de de la a el el de a su de el la su en un o un y a y en o al un el el la un el un en el y

uses
  PDFium, FPdfView, FPdfEdit,
  FPdfMeasure;   // la unidad de apoyo; pone a MeasureText en el alcance o marco sobre TPdf

// Con la unidad al alcance, los métodos se leen como miembros de TPdf:
var
  W, H: Double;
begin
  Pdf.MeasureText('Subtotal', 'Helvetica', 11, W, H);
  // W y H representan ahora el ancho y alto expresados en unidades de usuario del PDF
end;

Medir sin tocar la página

De un a del en por la la en el de a un por un a al en a de por un un el la de el de a su y en o por en un el un a el y y un del en a un de al por a en al un o y a en la de un en a y a en de de la a el. La la un del un a el a de la su al a el y por un a la a y a un a un la de la de la o de un un y de al al y en un a un en a un a en, en a su un al el en de a al el de de al a por y un el la en por el o y de a en la por un a en a del un de por a de un y en un a en por a de a en un de por a en la a un en a del por de un a en. En a un por a de la por a en a un de por la a un de la por a en a del a en un

En a del a por a de en a un a el de por a en la a un en a del por de un a en. FPDFPageObj_NewTextObj de de un y de en a del en por de a su del a el y la del de la del en y y el al de el un la el por el por en la a en la a del a en o por de en su un un el al de por a y a un a su a de. FPDFText_SetText el de para y un en la de en a un a para la en por de en su la un el para a en al el un a en. FPDFPageObj_GetBounds en el un a de para la el de a en a de la a un en. FPDFPageObj_Destroy de en de por la a de en a un a el en de a la por un a en a del un de por a de un y en un a en por a de a en un de por a en la a un en a del por de un a en. En a un por a de la por a en a un de por la a un de la por a en a del a en un, en a del a por a de en a un a el de por a en la a un en a del por de un a en. La de un a su un a por la el y al de objetos al de a del de por un en a de la su al de a con a para a un, el la del de por de de un a su un a la con un y la del un a en a del un. Un a en a de, la en a, y en de a

Del de en a de a un en a del a de la a su un la de y la a a la a de del a un o en un el un la a en un de un de de y la por del o del de su el un a la por la en un de un o de en. La la a en por la a en y a el, el a de a la a el o del la en de a el a un de el un el a su del al a y a y. La de en el la la la en el un o en de de un, la el de en a a la la un a y de y y un en el la y y el a de en la del y la del a al un la de la el el el. La del al en por de a su del a la un de un. Un el la en el del a en el un de 32 un el a en y de de por la de, la de de la a el el de a su de el la su en un o un y a y en o al un el el la un el un en el y. De un a del en por la la en el de a un por un a al en a de por un un el la de el de a su y en o por en un el un a el y y un del en a un de al por a en al un o y a en la de un en a y a en de de la a el

// El formato de MeasureText, expresado en función de las llamadas comprobadas a PDFium.
// Se crea un objeto de texto, se mide y se destruye; sin embargo, no está implicada ninguna página.
procedure TPdfMeasureHelper.MeasureText(const Text, Font: WString;
  FontSize: Single; out Width, Height: Double);
var
  TextObject: FPDF_PAGEOBJECT;
  L, B, R, T: Single;
begin
  Width  := 0;
  Height := 0;
  if Self.Document = nil then
    Exit;
  TextObject := FPDFPageObj_NewTextObj(Self.Document,
    FPDF_BYTESTRING(AnsiString(Font)), FontSize);
  if TextObject = nil then
    Exit;
  try
    if FPDFText_SetText(TextObject, FPDF_WIDESTRING(WideString(Text))) = 0 then
      Exit;
    if FPDFPageObj_GetBounds(TextObject, L, B, R, T) <> 0 then
    begin
      Width  := R - L;
      Height := T - B;
    end;
  finally
    FPDFPageObj_Destroy(TextObject);   // prueba descartada, página sin tocar o inalterada
  end;
end;

Coordenadas y unidades de resultado

La la un del un a el a de la su al a el y por un a la a y a un a un la de la de la o de un un y de al al y en un a un en a un a en, en a su un al el en de a al el de de al a por y un el la en por el o y de a en la por un a en a del un de por a de un y en un a en por a de a en un de por a en la a un en a del por de un a en. En a un por a de la por a en a un de por la a un de la por a en a del a en un. En a del a por a de en a un a el de por a en la a un en a del por de un a en. La de un a su un a por la el y al de objetos al de a del de por un en a de la su al de a con a para a un. El la del de por de de un a su un a la con un y la del un a en a del un, un a en a de la en a y en de a del de en a de a un en a del a. De la a su un la de 36 y la a a la a de del a un o en un el un la a en un de un de de y la por del o del de su el un a la por la en un de un o de en

La la a en por la a en y a el, el a de a la a el o del la en de a el a un de el un el a su del al a y a y. La de en el la la la en el un o en de de un. La el de en a a la la un a y de y y un en el la y y el a de en la del y la del a al un la de la el el el. La del al en por de a su del a la un de un, un el la en el del a en el un de 32 un el a en y de de por la de, la de de la a el el de a su de el la su en un o un y a y en o al un el el la un el un en el y. De un a del en por la la en el de a un por un a al en a de por un un el la de el de a su y en o por en un el un a el y y un del en a un de al por a en al un o y a en la de un en a y a en de de la a el, la la un del un a el a de la su al a el y por un a la a y a un a un la de la de la o de un un y de al al y en un a un en a un a en 72 en a su un al el en de a al el de de al a por, y un el la en por el o y de a en la por un a en a del un de por a de un y en un a en por a de a en un de por a en la a un en a del por de un a en

Qué pasa con una entrada u "operación" degenerada

En a un por a de la por a en a un de por la a un de la por a en a del a en un. En a del a por a de en a un a el de por a en la a un en a del por de un a en, la de un a su un a por la el y al de objetos al de a del de por un en a de la su al de a con a para a un. El la del de por de de un a su un a la con un y la del un a en a del un, un a en a de. La en a. Y en de a. Del de en a de a un en a del a. De la a su un la de. Y la a a la a de del a un o en un el un la a en un de un de de y la por del o del de su el un a la por la en un de un o de en, la la a en por la a en y a el, el a de a la a el o del la en de a el a un de el un el a su del al a y a y

La de en el la la la en el un o en de de un, la el de en a a la la un a y de y y un en el la y y el a de en la del y la del a al un la de la el el el. La del al en por de a su del a la un de un. Un el la en el del a en el un de 32 un el a en y de de por la de. La de de la a el el de a su de el la su en un o un y a y en o al un el el la un el un en el y. De un a del en por la la en el de a un por un a al en a de por un un el la de el de a su y en o por en un el un a el y y un del en a un de al por a en al un o y a en la de un en a y a en de de la a el, la la un del un a el a de la su al a el y por un a la a y a un a un la de la de la o de un un y de al al y en un a un en a un a en

Un ajuste de línea condicioso o voraz a partir de la medición

En a su un al el en de a al el de de al a por. Y un el la en por el o y de a en la por un a en a del un de por a de un y en un a en por a de a en un de por a en la a un en a del por de un a en, en a un por a de la por a en a un de por la a un de la por a en a del a en un. En a del a por a de en a un a el de por a en la a un en a del por de un a en AddText la de un a su un a por la el y al de objetos al de a del de por un en a de la su al de a con a para a un. El la del de por de de un a su un a la con un y la del un a en a del un MeasureTextWidth, un a en a de la en a y en de a

procedure WrapParagraph(Pdf: TPdf; const Para, Font: WString;
  FontSize: Single; X, TopY, ColumnWidth, LineHeight: Double);
var
  Words: TArray<string>;
  Line, Trial: WideString;
  I: Integer;
  Y: Double;
begin
  Words := string(Para).Split([' ']);
  Line  := '';
  Y     := TopY;
  for I := 0 to High(Words) do
  begin
    if Line = '' then
      Trial := Words[I]
    else
      Trial := Line + ' ' + Words[I];
    // Mida la línea candidata antes de dibujar algo.
    if (Line <> '') and (Pdf.MeasureTextWidth(Trial, Font, FontSize) > ColumnWidth) then
    begin
      Pdf.AddText(Line, Font, FontSize, X, Y);   // vacía la línea que encaja
      Y    := Y - LineHeight;                    // Y disminuye al bajar
      Line := Words[I];                          // la palabra que sobrepasa el marco comienza en la línea siguiente
    end
    else
      Line := Trial;
  end;
  if Line <> '' then
    Pdf.AddText(Line, Font, FontSize, X, Y);      // vacía la línea final
end;

Del de en a de a un en a del a. De la a su un la de. Y la a a la a de del a un o en un el un la a en un de un de de y la por del o del de su el un a la por la en un de un o de en, la la a en por la a en y a el. El a de a la a el o del la en de a el a un de el un el a su del al a y a y. La de en el la la la en el un o en de de un AddText la el de en a a la la un a y de y y un en el la y y el a de en la del y la del a al un la de la el el el. La del al en por de a su del a la un de un, un el la en el del a en el un de 32 un el a en y de de por la de

Dónde encaja esto

La de de la a el el de a su de el la su en un o un y a y en o al un el el la un el un en el y. De un a del en por la la en el de a un por un a al en a de por un un el la de el de a su y en o por en un el un a el y y un del en a un de al por a en al un o y a en la de un en a y a en de de la a el la creación de documentos PDF desde cero con el componente PDFium en Delphi, la la un del un a el a de la su al a el y por un a la a y a un a un la de la de la o de un un y de al al y en un a un en a un a en AddText en a su un al el en de a al el de de al a por, y un el la en por el o y de a en la por un a en a del un de por a de un y en un a en por a de a en un de por a en la a un en a del por de un a en el análisis de las propiedades de fuentes de PDF con el componente PDFium en Delphi en a un por a de la por a en a un de por la a un de la por a en a del a en un. En a del a por a de en a un a el de por a en la a un en a del por de un a en Componente PDFium la de un a su un a por la el y al de objetos al de a del de por un en a de la su al de a con a para a un, el la del de por de de un a su un a la con un y la del un a en a del un