Hết thảy mấy chữ cái ký tự có mầm hình bám mác lộ diện nhô lên trong lòng PDF thảy mang nợ đeo kèm dóng dây 1 trỏ tham chiếu nối ngỏ ghim vô phông mảng đã giáng nét hoạ tạc nên chúng, xong rồi bộ Component PDFium lại đưa đường nải lối đặng bạn bám mòn lướt rà ngả phả mảng tham chiếu đấy lộn rẽ giật lùi về chạm cái khối đồ dạng phông (font object) hòng thò tay bứt đọc tuốt tút tụt ngọn nguồn những rành rẽ tin mà ẻm mang hẵng biết (knows). Bệ ngạch đơn vị vạch cự lách vào mâm ngỏ là mặt cái chữ cắm toạ chứ chẳng đai trọn trùm bản văn kiện: lách trượt vớt bứt gõ đánh cắm một chữ từ đai khất đánh trỏ toạ vạch toạ cự nấc đánh rẽ ngỏ mảng tại ở phần tảng lớp văn (character by its index) nới ngỏ mâm rồi tra hỏi cái đai vạch trổ mác (family name), nhãn ghim phả gốc cội (base name), cự đo lằn bề cộm đậm (weight), ngạch dóng ngả rẽ xiên chéo rạch lằn nghiêng (italic angle), cùng dải tin về mảng nải ngạch vạch chóp bản lộ tướng phả phông cắm mác đấy thực thà ngự có ẩn lọt đai bọc trong 1 phiến file hơm (embedded). Đặc mục phần thuộc lớp sau vớt chót đấy cộm rành nguyên một nải bộ thuộc cái chi hẵng là phần ngạch dóng đám dải truy xét lật tung moi cào ngỏ rà tới tấp đằng nải sâu dòi trong rải nải, ấy do phần phông bọc kẹp nhét chèn ẩn thì đi cùng ngỏ lết dắt tệp văn (travels with the document), mác đai không ẩn thì đai ghim gỡ mang ngỏ hứa nải bọc hứa xuông bảo cỗ máy chàng đọc sách lơ ngơ lại đai ngẫu trùng hẵng mang dóng lọt tải bệ kiểu cài mặt phông tương đương hệt như dzầy nọ (same typeface installed)
Bộ component dóng đai lộ giãi bày nải dóng đám thông dải bộ này rành rẽ ngỏ đai thông ngạch phả dóng xuyên cùng chính gã đai mặt mâm đồ ngạch mác TPdf và TPdfView nải đai dóng đai bệ mà nhà bạn quen rinh mượn bợ chép hòng nặn đúc hiển dựng với tạc rạch ngỏ vớt móc bứt dải tách tháo bưng nguyên đoạn mảng nải bộ văn vớt bứt text mảng. Tịnh trơn trượt không tồn chứa 1 gã hệ rẽ dóng đai uẩn rạch dóng chia tách đánh lẻ bóng phân đồ 1 bộ bảng dóng nhãn danh phông mảng phả mác (font table) nào sất cần cho bứt rẽ nẻo bới cào đâm thò ngỏ banh ra cả. Ngay chóc sau bệ hồi ngạch mà nguyên tảng vựa lóng lọng chứa cự văn bản mác chóp một mâm trang nải ngạch được ghim phả rập bộ tra nặn xé dọn mã cú tháo phanh banh dỡ phả (parsed), cả đám vạch dóng cự điệu bộ hệ mục tính uỷ rẽ dóng phông chữ ấy (font properties) nải dóng bọc sẽ nhô tòn ten lòng thòng rớt rụng ẹo bám đính giáng trượt thả treo vắt tuột ngỏ cắm vào uỷ bộ ngỏ ngạch nấc vạch toạ lằn dóng phân cự rẽ lọt phân vạch chữ kia rành (character index), bạn tuỳ cơ xọc rành đọc rạch gõ nấc đi vớt ngạch ngỏ moi từng mảng điểm nấc điểm hình mác chữ ngỏ (one glyph at a time). Toạ vạch sơ phác đồ đúc ngỏ trọn vừa vặn khuôn cấu vào mảng vạch mà PDF trữ ngụ lưu giấu vựa kho phả luồng chứa đai thông ghim tài từ mốc đai sơ nguyên sơ khai lóng uỷ rẽ dóng khởi mở vạch dóng nảy mâm đầu: một rạch phả dóng ngỏ bệ một nhành dóng lẻ trang (single page) cắm mác nhấp nháy bật ngỏ rẽ tắt bóc gỡ hoán đai đổi tráo xoay chiều phông uỷ ngỏ tá chục nấc lóng vạch chục rẽ ngỏ lần, mà dóng bộ vạch lời uỷ nải phả đáp mảng dóng báo bệ lời đai ngỏ thực nhất nhất mực thẳng rành chân ngay trọn thật thà giáng đánh gỡ mác trả đai giải rẽ cho gã ghim mác dóng 1 trỏ dóng lời gõ "phiến mặt văn tệp nọ ẵng nằm bám rúc ấp lót dưới đai lọng uỷ dóng thuộc lọng phông bộ hệ gì dzậy (what font is this document in)" là "đai nải tuỳ lọng coi bạn ngỏ ghim muốn trỏ mác giáng dóng gọi vạch ngỏ dóng rạch cái phả gã bệ chữ nào đó thôi (it depends which character you mean)."
Đọc phông chữ đằng sau một ký tự
Hoạt động hữu ích nhỏ nhất là lấy chỉ mục của một ký tự và xuất ra mọi thứ mà PDFium có thể cho bạn biết về phông chữ của nó. Mỗi thuộc tính phông chữ trên TPdf và TPdfView đều được lập chỉ mục theo vị trí ký tự, do đó chỉ mục xuyên suốt tất cả chúng. Trang đó cũng phải là trang hiện tại để chỉ mục phân giải đối với đúng văn bản, điều này quan trọng một khi bạn di chuyển qua trang một
procedure DescribeFontAt(Pdf: TPdf; CharIndex: Integer);
var
Report: TStringList;
PtSize: Single;
begin
Report := TStringList.Create;
try
PtSize := Pdf.FontSize[CharIndex];
Report.Add('Character : ' + Pdf.Character[CharIndex]);
Report.Add('Family : ' + Pdf.FontFamilyName[CharIndex]);
Report.Add('Base name : ' + Pdf.FontBaseName[CharIndex]);
Report.Add('Weight : ' + IntToStr(Pdf.FontWeight[CharIndex]));
Report.Add('Italic : ' + IntToStr(Pdf.FontItalicAngle[CharIndex]) + ' deg');
Report.Add('Size : ' + FormatFloat('0.0', PtSize) + ' pt');
Report.Add('Ascent : ' + FormatFloat('0.0', Pdf.FontAscent[CharIndex, PtSize]));
Report.Add('Descent : ' + FormatFloat('0.0', Pdf.FontDescent[CharIndex, PtSize]));
Report.Add('Embedded : ' + BoolToStr(Pdf.FontIsEmbedded[CharIndex], True));
ShowMessage(Report.Text);
finally
Report.Free;
end;
end;
Một vài chữ ký (signatures) làm ngạc nhiên những người đến từ các thư viện khác. FontAscent và FontDescent lấy hai đối số, chỉ mục ký tự và kích thước điểm, bởi vì PDFium báo cáo các số liệu đó bằng đơn vị không gian glyph mà chỉ trở thành pixel khi bạn chia tỷ lệ chúng theo kích thước văn bản được đặt. Truyền giá trị bạn đã đọc từ FontSize[CharIndex] và bạn nhận được ascent và descent cùng các điểm với phần còn lại của bố cục. Descent trả về số âm, vì nó đo dưới đường cơ sở. Tên họ và tên cơ sở là các chuỗi riêng biệt có chủ đích: tên cơ sở là mục /BaseFont thô từ PDF, thường mang tiền tố tập con như ABCDEF+, trong khi tên họ là tên đã được dọn dẹp mà trình kết xuất phân giải nó
Chuyển đổi một cú nhấp chuột thành một chỉ mục ký tự
Trong một trình xem, bạn hiếm khi biết trước chỉ mục. Người dùng nhấp vào một glyph và bạn phải chuyển đổi tọa độ pixel thành ký tự bên dưới nó. CharacterIndexAtPos làm chính xác điều đó, lấy vị trí chuột và dung sai rồi trả về chỉ mục của ký tự gần nhất hoặc giá trị âm khi cú nhấp chuột rơi vào khoảng trắng hoặc trang trống
procedure TFormMain.PdfViewMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
Index: Integer;
begin
if not PdfView.Active then
Exit;
// 4 px of slack in each direction so a near-miss still hits the glyph.
Index := PdfView.CharacterIndexAtPos(X, Y, 4.0, 4.0);
if Index < 0 then
Exit; // clicked between glyphs; leave the panel alone
PdfView.CurrentCharIndex := Index;
DescribeFontAt(PdfView.Pdf, Index);
end;
Dung sai rất đáng để tinh chỉnh. Quá chặt chẽ và người dùng cảm thấy như họ phải đáp xuống chính xác nét thẳng của một chữ cái; quá lỏng lẻo và một cú nhấp chuột ở lề sẽ bám vào một ký tự ở xa không liên quan gì đến ý định của họ. Ba đến năm pixel thiết bị là điểm khởi đầu hợp lý để xem trên màn hình. Chỉ mục được trả về nằm trong văn bản đã phân tích cú pháp của trang hiện tại, cùng một không gian chỉ mục mà mọi thuộc tính phông chữ mong đợi, vì vậy bạn có thể giao thẳng nó cho quy trình trên. Lưu trữ nó trong CurrentCharIndex là tùy chọn nhưng thuận tiện: khung nhìn giữ nó như là khái niệm về glyph được lấy tiêu điểm, rất tiện lợi nếu các phần khác của giao diện người dùng muốn đọc vùng chọn mà không cần phải lấy lại
Nhúng là thuộc tính quan trọng
Đối với hầu hết các công việc thực tế, câu hỏi duy nhất đáng trả lời là mỗi phông chữ có được nhúng hay không. Một tài liệu có tất cả các phông chữ bên trong nó sẽ hiển thị giống nhau trên RIP của phòng in, máy tính xách tay của đồng nghiệp và máy chủ hoàn toàn không có GUI. Một tài liệu dựa vào phông chữ Helvetica không được nhúng đang đánh cược rằng mọi máy đó đều được cài đặt một phông chữ khớp và khi ván cược thất bại, trình đọc sẽ thay thế bằng một thứ gì đó gần giống, số liệu sẽ thay đổi và một biểu mẫu được bố trí cẩn thận sẽ thay đổi luồng nội dung vừa đủ để bị hỏng. Duyệt qua văn bản trang và phân nhóm các phông chữ theo trạng thái nhúng sẽ cho bạn câu trả lời đó một cách dễ dàng
procedure ReportNonEmbeddedFonts(Pdf: TPdf);
var
Embedded, External: TStringList;
I: Integer;
Name: string;
begin
Embedded := TStringList.Create;
External := TStringList.Create;
try
Embedded.Sorted := True;
Embedded.Duplicates := dupIgnore;
External.Sorted := True;
External.Duplicates := dupIgnore;
for I := 0 to Pdf.CharacterCount - 1 do
begin
Name := Pdf.FontBaseName[I];
if Name = '' then
Continue; // generated spaces and the like have no font
if Pdf.FontIsEmbedded[I] then
Embedded.Add(Name)
else
External.Add(Name);
end;
if External.Count > 0 then
ShowMessage(IntToStr(External.Count) +
' non-embedded font(s):' + sLineBreak + External.Text)
else
ShowMessage('All ' + IntToStr(Embedded.Count) +
' font(s) on this page are embedded.');
finally
Embedded.Free;
External.Free;
end;
end;
Có hai chi tiết giúp điều này được chính xác. Đầu tiên, CharacterCount là cho mỗi trang, vì vậy kiểm tra toàn bộ tài liệu có nghĩa là đặt Pdf.PageNumber cho từng trang một và chạy lại vòng lặp, hợp nhất các kết quả. Thứ hai, lớp văn bản chứa các ký tự được tạo ra chẳng hạn như khoảng trắng mà người đọc suy ra giữa các từ và chúng không có đối tượng phông chữ phía sau; kiểm tra tên cơ sở rỗng sẽ bỏ qua chúng thay vì ghi nhận một bóng ma. Tên cơ sở là khóa đúng để loại bỏ trùng lặp ở đây vì tiền tố tập con mà nó mang phân biệt hai tập con khác nhau của cùng một họ, đây thường là điều bạn muốn biết
Rút phông chữ được nhúng ra
Khi một phông chữ được nhúng, bạn có thể đọc trực tiếp các byte của nó. FontData trả về chương trình phông chữ thô, cùng một dữ liệu TrueType hoặc CFF mà PDF mang, đủ để ghi một tệp phông chữ độc lập hoặc để lấy dấu vân tay phông chữ với một thư viện đã biết. Nó trả về một mảng trống khi phông chữ không được nhúng, do đó việc kiểm tra nhúng và kiểm tra độ dài cùng nhau bảo vệ việc ghi
procedure SaveEmbeddedFont(Pdf: TPdf; CharIndex: Integer;
const OutputFile: string);
var
Data: TBytes;
Stream: TFileStream;
begin
if not Pdf.FontIsEmbedded[CharIndex] then
begin
ShowMessage('That glyph''s font is not embedded; nothing to extract.');
Exit;
end;
Data := Pdf.FontData[CharIndex];
if Length(Data) = 0 then
Exit;
Stream := TFileStream.Create(OutputFile, fmCreate);
try
Stream.WriteBuffer(Data[0], Length(Data));
finally
Stream.Free;
end;
ShowMessage('Wrote ' + IntToStr(Length(Data)) + ' bytes.');
end;
Các byte là tập con được nhúng, không phải là phông chữ bán lẻ gốc, do đó những gì bạn nhận lại thường chỉ bao gồm các glyph mà tài liệu thực sự đã sử dụng. Điều này hoàn toàn đúng đối với pháp y và xác minh nhưng không phù hợp để sử dụng lại; một tập con của Times New Roman chứa ba mươi glyph không phải là phông chữ bạn có thể cài đặt và nhập bằng bàn phím. Hãy coi việc trích xuất như một cách để kiểm tra những gì đã được gửi đi, chứ không phải như một công cụ phục hồi phông chữ. Nếu bạn cần tên cơ sở khớp để gắn nhãn đầu ra, hãy đọc FontBaseName[CharIndex] cùng với dữ liệu và loại bỏ thẻ tập con ở đầu nếu bạn muốn có họ phông chữ không
Hiểu số độ đậm (weight number)
FontWeight trả về lớp độ đậm bằng số, cùng thang đo từ 100 đến 900 mà CSS sử dụng, trong đó 400 là bình thường và 700 là in đậm. PDFium báo cáo bất cứ điều gì phông chữ khai báo, không phải lúc nào cũng là hàng trăm tròn; một phông chữ có thể công bố 350 hoặc 650, và việc coi bất kỳ thứ gì ở mức 600 trở lên là "đủ đậm để quan tâm" sẽ tốt hơn so với việc kiểm tra chính xác 700. Góc nghiêng là một tín hiệu đồng hành: một giá trị khác không, thường là số âm, có nghĩa là thiết kế xiên hoặc in nghiêng thực sự, và số không có nghĩa là thẳng đứng. Cùng với nhau, chúng cho phép bạn phân biệt đoạn chạy in nghiêng đậm với đoạn bình thường mà không cần kết xuất bất cứ thứ gì, đây là loại kiểm tra mà một lần chạy trước hoặc kiểm tra khả năng truy cập muốn thực hiện hàng loạt
Không có thao tác đọc nào yêu cầu bitmap được hiển thị. Chúng đến từ lớp văn bản đã được phân tích cú pháp, vì vậy một tài liệu đang mở ở đúng trang là tất cả những gì bạn cần thiết lập, điều này giúp việc kiểm tra phông chữ trở nên rẻ khi chạy trên toàn bộ kho lưu trữ. Nếu bạn kết hợp điều này với trích xuất văn bản, các chỉ mục ký tự tương tự xếp hàng với văn bản bạn lấy ra, do đó phông chữ của một glyph và giá trị Unicode của nó là hai lần đọc đối với một chỉ mục. Bài viết đồng hành về trích xuất văn bản từ tệp PDF bằng PDFium Component đề cập sâu hơn đến khía cạnh đó của lớp văn bản
Các thuộc tính phông chữ được hiển thị ở đây là một phần của PDFium Delphi VCL Component