Bỏ qua để đến nội dung

Graphics: nguyên hàm path + shading + transform

Module Graphics chuyển ý định vẽ thành các toán tử đồ họa Portable Document Format (PDF). Module này bao quát path, kiểu nét, không gian màu, phép biến đổi, shading, pattern, halftone và việc nạp hình ảnh.

Terminal window
composer require nextpdf/core:^3

Graphics là lớp vẽ vector và raster. Nó tạo ra các chuỗi toán tử để module ContentStream và Writer tuần tự hóa thành một PDF. Theo International Organization for Standardization (ISO) 32000-2 §8, một content stream mã hóa nội dung trang thành một chuỗi toán tử đồ họa có thứ tự. Module này phát ra các toán tử đó; nó không ghi tệp.

DrawingEngine là application programming interface (API) chính. Đây là một builder kiểu fluent và có trạng thái. Mỗi setter trả về self, ghi lại một thay đổi graphics-state hoặc một toán tử path-painting, rồi nối thêm vào bộ đệm nội bộ mà bạn đọc bằng getStream(). Engine mô hình hóa trực tiếp graphics state của PDF: độ rộng nét, kiểu nét, màu nét và màu tô, alpha và chế độ trộn, giới hạn miter, soft mask, clipping, overprint, flatness, smoothness, rendering intent, black generation và under-color removal đều ánh xạ tới một toán tử đã được tài liệu hóa. Các setter màu chấp nhận một value object Color hoặc một ColorSpace tường minh, nên không gian device và không gian dựa trên International Commission on Illumination (CIE) dùng cùng một dạng lệnh gọi.

Có ba nhóm thành phần vận hành cùng engine. Trước hết là đầu vào hình ảnh. ImageLoader giải mã một tệp hoặc một blob trong bộ nhớ thành một ImageLoadResult. ImageRegistry khử trùng lặp và theo dõi các hình ảnh đã giải mã bằng một MemoryReport, giúp tài liệu lớn vẫn nằm trong ngân sách bộ nhớ. Với đầu vào vector, SvgParserEpsParser chuyển Scalable Vector Graphics (SVG) và Encapsulated PostScript (EPS) thành cùng một operator stream, đồng thời phơi bày getBoundingBox() để phục vụ bố cục. Nhóm thứ ba xử lý độ trung thực device-color: shading (ShadingManager, các nhóm Type2/Type3 và mesh), pattern (PatternFill), halftone (Type1/Type5/Type6/Type10/Type16), transfer function, và các không gian màu dựa trên International Color Consortium (ICC).

TransformEngine là thành phần đồng hành chuyên xử lý các phép biến đổi tọa độ. Nó bọc một phép biến đổi bằng startTransform()stopTransform(), hai lệnh này phát ra cặp save/restore qQ. Nó cung cấp các helper affine có tên: scale, translate, rotate, skew, mirrorHmirrorV. Mỗi helper chấp nhận một pivot tùy chọn. Ma trận biến đổi ánh xạ một không gian tọa độ nội bộ vào không gian tọa độ đích. Đây cũng là mô hình mà ISO 32000-2 áp dụng cho các shading domain — §8.7.4.

Quản lý màu tuân theo Architectural Decision Record (ADR)-012: các không gian màu ICCBased và dựa trên CIE phát ra các toán tử content-stream cs/CS tường minh thay vì dựa vào device-color fallback. Các profile ICC được bọc vào một stream ICCBased với số lượng thành phần đúng theo ISO 32000-2 §8.6.5.5.

LớpCác phương thức chínhVai trò
DrawingEnginegetStream(), reset(), setLineWidth(), setLineStyle(), setDrawColor(), setFillColor(), setAlpha(), setSoftMask(), clip(), setOverprint(), setRenderingIntent(), line(), rect(), circle(), ellipse(), polygon(), linearGradient()Builder có trạng thái cho toán tử path + graphics-state
TransformEnginestartTransform(), stopTransform(), scale(), translate(), rotate(), skew(), mirrorH(), mirrorV(), getStream()Phép biến đổi tọa độ affine
ImageLoaderload(string $filePath), loadFromString(string $data, string $mimeType)Giải mã hình ảnh thành ImageLoadResult
ImageRegistryload(), loadFromString(), getMetadata(), memoryUsage(), reset()Bộ nhớ đệm hình ảnh khử trùng lặp kèm báo cáo bộ nhớ
SvgParserparse(), parseFile()Chuyển SVG thành operator stream
EpsParserparse(), parseFile(), getBoundingBox()Chuyển EPS thành operator stream
ShadingManagerđăng ký shading + phát ra dictionaryShading axial, radial và mesh
Halftone (trừu tượng)halftoneType(), toDict(), hasStream(), getStream()Type 1/5/6/10/16 halftone screen

Chạy composer docs:generate-api-php -- --module=Graphics để tạo bảng PHPDoc đầy đủ.

Nguồn: examples/06-colors-and-drawing.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Graphics\Color;
use NextPDF\Graphics\DrawingEngine;
use NextPDF\Graphics\LineStyle;
$engine = new DrawingEngine();
$engine
->setLineWidth(1.5)
->setDrawColor(Color::rgb(0, 51, 102))
->setFillColor(Color::rgb(230, 240, 250))
->rect(20.0, 20.0, 160.0, 80.0)
->line(20.0, 110.0, 180.0, 110.0, new LineStyle(dash: [3.0, 2.0]));
$contentStreamBytes = $engine->getStream();

Ví dụ này kết nối một image registry có báo cáo bộ nhớ với một cặp transform bracket. Nó phản ánh cấu trúc được dùng trong examples/07-images.phpexamples/21-transforms.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Graphics\DrawingEngine;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Graphics\TransformEngine;
$registry = new ImageRegistry();
$image = $registry->load('/srv/assets/logo.png');
$report = $registry->memoryUsage();
if ($report->bytes > 32 * 1024 * 1024) {
// Decoded image cache exceeded the budget — reset before the next page.
$registry->reset();
}
$transform = new TransformEngine();
$transform
->startTransform()
->translate(40.0, 700.0)
->scale(0.5, 0.5)
->stopTransform();
$engine = new DrawingEngine();
$engine->reset();
$page = $transform->getStream() . $engine->getStream();
  • DrawingEngine có trạng thái. Gọi reset() giữa các trang độc lập để graphics state trước đó không rò rỉ sang stream kế tiếp.
  • TransformEngine cần một cặp startTransform()/stopTransform() khớp nhau. Một cặp bracket không cân bằng sẽ để lại một q lơ lửng và làm hỏng stack save/restore phía sau trong Writer.
  • setSoftMask(), setOverprint(), setBlackGeneration()setUnderColorRemoval() ghi các marker graphics-state mở rộng. Khi profile từ chối tính năng này, chúng không có tác dụng. Hãy kiểm tra profile guard trước khi bạn dựa vào kết quả hiển thị.
  • ImageRegistry khử trùng lặp theo nội dung. Hai đường dẫn có byte giống hệt nhau dùng chung một object. Đừng giả định mỗi lệnh gọi load() tạo ra một hình ảnh PDF.
  • EpsParser::getBoundingBox() trả về bounding box đã phân tích, không phải page box. Hãy tự áp dụng clipping nếu EPS tràn ra ngoài hình chữ nhật đích.
  • Black-point compensation mang tính khuyến nghị và dựa trên marker. Bản thân cơ chế này không biến đổi pixel.

Có hai thay đổi phá vỡ tương thích ở phía producer. Cả hai biến tình trạng hỏng âm thầm trước đây thành lỗi tường minh ngay tại điểm gọi.

Việc xác thực đầu vào giờ ném ngoại lệ (ghi chú di trú). Đầu vào vẽ được xác thực trước khi đi vào operator stream, và các giá trị không hợp lệ bị từ chối bằng InvalidArgumentException. Những bên gọi từng truyền NaN, Infinity, hoặc các giá trị ngoài phạm vi trước đây sẽ tạo ra toán tử hỏng một cách âm thầm; cùng một đầu vào đó giờ làm phát sinh ngoại lệ. Các ràng buộc được xác thực gồm:

  • Alpha của màu phải hữu hạn và nằm trong [0, 1].
  • Các toán hạng của current transformation matrix (CTM), kích thước template, tọa độ gradient-vertex và tọa độ mesh-patch phải hữu hạn — không có NaN hay Infinity.
  • Một edge flag của gradient-patch phải là một trong {0, 1, 2, 3}.
  • Các tham số function Type 2/3/4 và tham số halftone được kiểm tra giới hạn.
  • Tên colourant được escape.
  • Tên layer của một optional-content group (OCG) phải không rỗng.

Hãy rà soát các điểm gọi tính toán tọa độ hoặc alpha từ dữ liệu thượng nguồn trước khi nâng cấp: một giá trị từng đi qua được giờ là lỗi nghiêm trọng.

ICCBased /N mặc định fail-closed. Đầu ra Plain-PDF từ chối một không gian màu ICCBased có số lượng thành phần /N nằm ngoài {1, 3, 4}, đồng thời đối chiếu /N đã khai báo với profile được nhúng và không gian /Alternate. Điều này tuân theo quy tắc ISO 32000-2 §8.6.5.5 cho stream ICCBased, vốn mang /N cùng với một không gian /Alternate. Một profile ICC N-kênh, chẳng hạn một profile hexachrome với N = 6, chỉ được giữ lại khi một profile PDF/A hoặc PDF/X đang hoạt động, với tùy chọn được bật qua IccConformancePolicy::ProfileGated. Đây là một cổng cấu trúc trên số lượng thành phần, không phải tuyên bố về chứng nhận PDF/A hay PDF/X.

Việc phát toán tử tuyến tính theo số lệnh gọi vẽ: O(n) lần nối vào một bộ đệm, không có reflow. Chi phí giải mã hình ảnh đến từ codec và số pixel, không phải từ registry. Cơ chế khử trùng lặp bằng content-hash của registry là đòn bẩy chính cho các tài liệu lớn: tài nguyên được dùng lại chỉ tốn một lần giải mã và một object PDF. performance_budget cho khối lượng công việc tham chiếu của module này là 1500 ms wall và 64 MB đỉnh. Dùng ImageRegistry::memoryUsage() để quan sát mức chiếm dụng của hình ảnh đã giải mã và reset() để giải phóng bộ nhớ đó giữa các nhóm trang.

SvgParserEpsParser tiêu thụ đầu vào vector không đáng tin cậy. Hãy xem cả hai là trình phân tích dữ liệu thù địch. Hãy áp đặt giới hạn kích thước đầu vào trước khi gọi parse(). Khi nguồn do người dùng cung cấp, hãy chạy việc trích xuất trong một worker bị giới hạn. EPS là một biến thể của PostScript. Trình phân tích chuyển đổi một tập con bị giới hạn và không chạy một trình thông dịch tổng quát, nhưng bạn vẫn nên giới hạn kích thước đầu vào và thời gian phân tích. Các image loader giải mã codec bên thứ ba. Hãy giữ các extension hình ảnh của runtime luôn mới và giới hạn kích thước đã giải mã. Xem mô hình mối đe dọa của engine trong /modules/core/security/ để biết ranh giới tin cậy và hướng dẫn cô lập worker.

Module phát ra các cấu trúc graphics-operator PDF nhất quán với ISO 32000-2 §8, các color-space dictionary ICCBased theo §8.6.5.5, và các shading dictionary có Domain, Function, Matrix và BBox tuân theo §8.7.4. Đây là các sự kiện hiện thực: src/Graphics/ tạo ra các dạng operator và dictionary, còn tests/Unit/Graphics/ cùng các baseline tests/Golden/PdfWriter/PdfWriterShadingGoldenBaselineSmokeTestPdfWriterExtGStateGoldenSmokeTest kiểm thử chúng. Chúng không phải là tuyên bố về tuân thủ PDF 2.0 hay PDF/X đầu-cuối. Tuân thủ toàn tài liệu được xác thực riêng bằng oracle và các bộ golden suite được mô tả trong /modules/core/conformance/. Hành vi profile cho ICC OutputIntents được quyết định bởi ADR-011 và ADR-012, không phải bởi riêng module này.