Techninis straipsnis

Dvigubo pasukimo ir pritaikyto mastelio klaidos PDFium Delphi kalboje

FPDF_RenderPageBitmap rotate argumentas pridedamas prie puslapio /Rotate, todėl tą pačią rotaciją perdavus dar kartą puslapis pasukamas du kartus

Problema pasirodo tik pasuktuose puslapiuose: miniatiūra gali būti šonu, apversta arba suspausta be jokios klaidos

Kodėl PDFium pasuka puslapį du kartus

FPDF_RenderPageBitmap rotate PDFiumPas API pateikia kaip ro0, ro90, ro180 ir ro270 TPdf.RenderPage, RenderTile bei RenderPageThumbnail metoduose

TPdf.PageRotation nuskaito /Rotate, tačiau perduoti ją į RenderPage Rotation argumentą reiškia pridėti, o ne pakeisti pasukimą

// Wrong: PageRotation already reflects /Rotate, and PDFium applies
// it automatically on every render -- passing it again as Rotation
// doubles the angle
Bitmap := Pdf.RenderPage(0, 0, TargetW, TargetH, Pdf.PageRotation, []);

// Right: leave Rotation at its ro0 default and let PDFium apply the
// page's own /Rotate exactly once
Bitmap := Pdf.RenderPage(0, 0, TargetW, TargetH, ro0, []);

Kam iš tikrųjų skirtas Rotation parametras

TPdfView.PageRotation saugo dokumento rotaciją, o TPdfView.Rotation yra laikina peržiūros rotacija, kuri failo nekeičia

// View-only: rotates what the user sees, changes nothing in the file
procedure TViewerForm.RotateViewClick(Sender: TObject);
begin
  case PdfView.Rotation of
    ro0:   PdfView.Rotation := ro90;
    ro90:  PdfView.Rotation := ro180;
    ro180: PdfView.Rotation := ro270;
    ro270: PdfView.Rotation := ro0;
  end;
end;

// Persistent: rewrites the page's own /Rotate entry in the document
procedure TViewerForm.RotatePageClick(Sender: TObject);
begin
  case PdfView.PageRotation of
    ro0:   PdfView.PageRotation := ro90;
    ro90:  PdfView.PageRotation := ro180;
    ro180: PdfView.PageRotation := ro270;
    ro270: PdfView.PageRotation := ro0;
  end;
end;

Kodėl pritaikyto mastelio dydis sugenda taip pat

Pritaikymo skaičiavimas turi sukeisti plotį ir aukštį, kai /Rotate yra 90 arba 270, nes FPDF_GetPageSizeByIndex grąžina nepasuktą dydį

Prieš skaičiuodami langelį patikrinkite rotaciją, sukeiskite matmenis, o tikram atvaizdavimui perduokite ro0

Taisyklingos miniatiūros neperrašant pritaikymo matematikos

TPdf.RenderPageThumbnail šią logiką jau turi ir grąžina bitmapą nekeisdamas dabartinio puslapio

// PageW, PageH are a page's own (unrotated) dimensions in points, for
// example from FPDF_GetPageSizeByIndex, which reports size before
// /Rotate is applied
function FitBox(PageW, PageH: Double; Rotation: TRotation;
  MaxW, MaxH: Integer; out FitW, FitH: Integer): Boolean;
var
  PgW, PgH, Swap: Integer;
begin
  PgW := Round(PageW);
  PgH := Round(PageH);
  if PgW < 1 then PgW := 1;
  if PgH < 1 then PgH := 1;

  if Rotation in [ro90, ro270] then
  begin
    Swap := PgW;
    PgW := PgH;
    PgH := Swap;
  end;

  Result := (MaxW > 0) and (MaxH > 0);
  if not Result then
    Exit;

  if PgW * MaxH > PgH * MaxW then
  begin
    FitW := MaxW;
    FitH := (MaxW * PgH) div PgW;
  end
  else
  begin
    FitH := MaxH;
    FitW := (MaxH * PgW) div PgH;
  end;
end;

FitBox naudinga miniatiūrų tinkleliams, spaudos peržiūrai ir dialogams, kuriems reikia tos pačios rotacijai jautrios matematikospodėliavimą ir sklandų mastelį PDFium Delphi peržiūros programoje

Kaip pastebėti dvigubą pasukimą anksčiau nei klientas

Dvigubą pasukimą patikrinkite naudodami bent vieną /Rotate 90 ir vieną /Rotate 270 puslapį, nes vien /Rotate 0 testas klaidos neatskleis

Puslapių atvaizdavimas į JPEG su PDFium Component palieka Rotation kaip ro0 ir leidžia PDFium pačiam taikyti /RotatePDF puslapių atvaizdavimą į JPEG su PDFium Component

Šie atvaizdavimo ir miniatiūrų dydžio metodai priklauso PDFium Component for Delphi ir C++BuilderPDFium Component