generated from jric11/baseProject
Initial commit
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* autoload.php
|
||||
*
|
||||
* Autoloader for Tecnick.com libraries
|
||||
*
|
||||
* @since 2015-03-04
|
||||
* @category Library
|
||||
* @package Pdf
|
||||
* @author Nicola Asuni <info@tecnick.com>
|
||||
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||||
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||||
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||||
*
|
||||
* This file is part of tc-lib-pdf software library.
|
||||
*/
|
||||
\spl_autoload_register(
|
||||
function ($class) {
|
||||
$prefix = 'Com\\Tecnick\\';
|
||||
$len = \strlen($prefix);
|
||||
if (\strncmp($prefix, $class, $len) !== 0) {
|
||||
return;
|
||||
}
|
||||
$relative_class = \substr($class, $len);
|
||||
$file = \dirname(__DIR__).'/'.\str_replace('\\', '/', $relative_class).'.php';
|
||||
if (\file_exists($file)) {
|
||||
require $file;
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Renderability scoring for the real-page corpus.
|
||||
*
|
||||
* Usage:
|
||||
* php resources/css/renderability_score.php
|
||||
* --corpus=test/fixtures/html/real_pages/corpus.json
|
||||
* --json=target/report/renderability-score.json
|
||||
* --markdown=target/report/renderability-score.md
|
||||
* --acceptable-threshold=80
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/** @return array<string, string> */
|
||||
function rs_parse_args(array $argv): array
|
||||
{
|
||||
$out = [];
|
||||
foreach ($argv as $idx => $arg) {
|
||||
if ($idx === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!\str_starts_with((string) $arg, '--')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pair = \explode('=', (string) \substr((string) $arg, 2), 2);
|
||||
$key = (string) ($pair[0] ?? '');
|
||||
$val = (string) ($pair[1] ?? '1');
|
||||
if ($key !== '') {
|
||||
$out[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{version:int,failure_tags:array<int,string>,severity_levels:array<int,string>,pages:array<int,array<string,mixed>>}
|
||||
*/
|
||||
function rs_load_corpus(string $path): array
|
||||
{
|
||||
$raw = \file_get_contents($path);
|
||||
if ($raw === false) {
|
||||
throw new RuntimeException('Unable to read corpus file: ' . $path);
|
||||
}
|
||||
|
||||
/** @var array<string, mixed>|null $decoded */
|
||||
$decoded = \json_decode($raw, true);
|
||||
if (!\is_array($decoded)) {
|
||||
throw new RuntimeException('Invalid corpus JSON file: ' . $path);
|
||||
}
|
||||
|
||||
return [
|
||||
'version' => (int) ($decoded['version'] ?? 0),
|
||||
'failure_tags' => \array_values(\array_map('strval', (array) ($decoded['failure_tags'] ?? []))),
|
||||
'severity_levels' => \array_values(\array_map('strval', (array) ($decoded['severity_levels'] ?? []))),
|
||||
'pages' => \array_values((array) ($decoded['pages'] ?? [])),
|
||||
];
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
function rs_score_page(array $page, int $acceptableThreshold): array
|
||||
{
|
||||
$severityPenalty = [
|
||||
'critical' => 45,
|
||||
'high' => 25,
|
||||
'medium' => 12,
|
||||
'low' => 5,
|
||||
];
|
||||
|
||||
$flowRiskTags = ['overflow', 'overlap'];
|
||||
$structureRiskTags = ['dropped-style', 'selector-miss'];
|
||||
|
||||
$penalty = 0;
|
||||
$highSeverityFailures = 0;
|
||||
$textFlowPreserved = true;
|
||||
$structurePreserved = true;
|
||||
$majorBlockPlacementPreserved = true;
|
||||
|
||||
$failures = (array) ($page['failures'] ?? []);
|
||||
foreach ($failures as $failure) {
|
||||
if (!\is_array($failure)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$severity = (string) ($failure['severity'] ?? 'low');
|
||||
$tag = (string) ($failure['tag'] ?? '');
|
||||
|
||||
$penalty += $severityPenalty[$severity] ?? 0;
|
||||
|
||||
if (\in_array($severity, ['high', 'critical'], true)) {
|
||||
$highSeverityFailures++;
|
||||
}
|
||||
|
||||
if ($severity === 'critical') {
|
||||
$majorBlockPlacementPreserved = false;
|
||||
}
|
||||
|
||||
if (\in_array($tag, $flowRiskTags, true) && \in_array($severity, ['high', 'critical'], true)) {
|
||||
$textFlowPreserved = false;
|
||||
}
|
||||
|
||||
if (\in_array($tag, $structureRiskTags, true) && \in_array($severity, ['high', 'critical'], true)) {
|
||||
$structurePreserved = false;
|
||||
}
|
||||
|
||||
if (($tag === 'overlap') && \in_array($severity, ['medium', 'high', 'critical'], true)) {
|
||||
$majorBlockPlacementPreserved = false;
|
||||
}
|
||||
}
|
||||
|
||||
$score = \max(0, 100 - $penalty);
|
||||
$acceptable = ($score >= $acceptableThreshold) && $textFlowPreserved;
|
||||
|
||||
return [
|
||||
'id' => (string) ($page['id'] ?? ''),
|
||||
'archetype' => (string) ($page['archetype'] ?? ''),
|
||||
'fixture' => (string) ($page['fixture'] ?? ''),
|
||||
'score' => $score,
|
||||
'acceptable' => $acceptable,
|
||||
'text_flow_preserved' => $textFlowPreserved,
|
||||
'structure_preserved' => $structurePreserved,
|
||||
'major_block_placement_preserved' => $majorBlockPlacementPreserved,
|
||||
'high_severity_failures' => $highSeverityFailures,
|
||||
'known_failures' => \count($failures),
|
||||
];
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
function rs_build_report(array $corpus, int $acceptableThreshold): array
|
||||
{
|
||||
$pages = [];
|
||||
$totalScore = 0.0;
|
||||
$acceptableCount = 0;
|
||||
$flowCount = 0;
|
||||
$highSeverityFailures = 0;
|
||||
|
||||
foreach ($corpus['pages'] as $page) {
|
||||
if (!\is_array($page)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$row = rs_score_page($page, $acceptableThreshold);
|
||||
$pages[] = $row;
|
||||
$totalScore += (float) $row['score'];
|
||||
|
||||
if ((bool) $row['acceptable']) {
|
||||
$acceptableCount++;
|
||||
}
|
||||
if ((bool) $row['text_flow_preserved']) {
|
||||
$flowCount++;
|
||||
}
|
||||
$highSeverityFailures += (int) $row['high_severity_failures'];
|
||||
}
|
||||
|
||||
$count = \count($pages);
|
||||
$overallScore = ($count > 0) ? \round($totalScore / $count, 2) : 0.0;
|
||||
$passRate = ($count > 0) ? \round(($acceptableCount * 100) / $count, 2) : 0.0;
|
||||
$textFlowRate = ($count > 0) ? \round(($flowCount * 100) / $count, 2) : 0.0;
|
||||
|
||||
return [
|
||||
'generated_at' => \gmdate('c'),
|
||||
'corpus_version' => (int) ($corpus['version'] ?? 0),
|
||||
'page_count' => $count,
|
||||
'acceptable_threshold' => $acceptableThreshold,
|
||||
'overall_score' => $overallScore,
|
||||
'pass_rate' => $passRate,
|
||||
'text_flow_rate' => $textFlowRate,
|
||||
'high_severity_failures' => $highSeverityFailures,
|
||||
'pages' => $pages,
|
||||
];
|
||||
}
|
||||
|
||||
function rs_to_markdown(array $report): string
|
||||
{
|
||||
$lines = [];
|
||||
$lines[] = '## CSS Renderability Score';
|
||||
$lines[] = '';
|
||||
$lines[] = '| Metric | Value |';
|
||||
$lines[] = '|---|---:|';
|
||||
$lines[] = '| Corpus version | ' . (string) ($report['corpus_version'] ?? 0) . ' |';
|
||||
$lines[] = '| Page count | ' . (string) ($report['page_count'] ?? 0) . ' |';
|
||||
$lines[] = '| Overall score | ' . (string) ($report['overall_score'] ?? 0) . ' |';
|
||||
$lines[] = '| Pass rate | ' . (string) ($report['pass_rate'] ?? 0) . '% |';
|
||||
$lines[] = '| Text flow preserved | ' . (string) ($report['text_flow_rate'] ?? 0) . '% |';
|
||||
$lines[] = '| High severity failures | ' . (string) ($report['high_severity_failures'] ?? 0) . ' |';
|
||||
$lines[] = '';
|
||||
$lines[] = '| Page | Score | Acceptable | Text Flow | High-Severity Failures |';
|
||||
$lines[] = '|---|---:|:---:|:---:|---:|';
|
||||
|
||||
foreach ((array) ($report['pages'] ?? []) as $row) {
|
||||
if (!\is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lines[] = '| ' . (string) ($row['id'] ?? '')
|
||||
. ' | ' . (string) ($row['score'] ?? 0)
|
||||
. ' | ' . (((bool) ($row['acceptable'] ?? false)) ? 'yes' : 'no')
|
||||
. ' | ' . (((bool) ($row['text_flow_preserved'] ?? false)) ? 'yes' : 'no')
|
||||
. ' | ' . (string) ($row['high_severity_failures'] ?? 0) . ' |';
|
||||
}
|
||||
|
||||
$lines[] = '';
|
||||
|
||||
return \implode(PHP_EOL, $lines) . PHP_EOL;
|
||||
}
|
||||
|
||||
$args = rs_parse_args($argv);
|
||||
$corpusPath = $args['corpus'] ?? 'test/fixtures/html/real_pages/corpus.json';
|
||||
$jsonPath = $args['json'] ?? 'target/report/renderability-score.json';
|
||||
$markdownPath = $args['markdown'] ?? 'target/report/renderability-score.md';
|
||||
$acceptableThreshold = (int) ($args['acceptable-threshold'] ?? '80');
|
||||
|
||||
$corpus = rs_load_corpus($corpusPath);
|
||||
$report = rs_build_report($corpus, $acceptableThreshold);
|
||||
$markdown = rs_to_markdown($report);
|
||||
|
||||
$jsonDir = \dirname($jsonPath);
|
||||
if (($jsonDir !== '.') && !\is_dir($jsonDir)) {
|
||||
\mkdir($jsonDir, 0777, true);
|
||||
}
|
||||
$mdDir = \dirname($markdownPath);
|
||||
if (($mdDir !== '.') && !\is_dir($mdDir)) {
|
||||
\mkdir($mdDir, 0777, true);
|
||||
}
|
||||
|
||||
\file_put_contents($jsonPath, \json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL);
|
||||
\file_put_contents($markdownPath, $markdown);
|
||||
|
||||
echo 'Renderability score report written to: ' . $jsonPath . PHP_EOL;
|
||||
echo 'Renderability markdown summary written to: ' . $markdownPath . PHP_EOL;
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Renderability trend updater.
|
||||
*
|
||||
* Usage:
|
||||
* php resources/css/renderability_trend.php
|
||||
* --score=target/report/renderability-score.json
|
||||
* --history=target/report/renderability-trend.json
|
||||
* --markdown=target/report/renderability-trend.md
|
||||
* --sha=<git-sha>
|
||||
* --ref=<branch-or-tag>
|
||||
* --run-id=<ci-run-id>
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/** @return array<string, string> */
|
||||
function rt_parse_args(array $argv): array
|
||||
{
|
||||
$out = [];
|
||||
foreach ($argv as $idx => $arg) {
|
||||
if ($idx === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!\str_starts_with((string) $arg, '--')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pair = \explode('=', (string) \substr((string) $arg, 2), 2);
|
||||
$key = (string) ($pair[0] ?? '');
|
||||
$val = (string) ($pair[1] ?? '1');
|
||||
if ($key !== '') {
|
||||
$out[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
function rt_load_json_file(string $path): array
|
||||
{
|
||||
$raw = \file_get_contents($path);
|
||||
if ($raw === false) {
|
||||
throw new RuntimeException('Unable to read JSON file: ' . $path);
|
||||
}
|
||||
|
||||
/** @var array<string, mixed>|null $decoded */
|
||||
$decoded = \json_decode($raw, true);
|
||||
if (!\is_array($decoded)) {
|
||||
throw new RuntimeException('Invalid JSON in file: ' . $path);
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
function rt_load_history(string $path): array
|
||||
{
|
||||
if (!\is_file($path)) {
|
||||
return ['history' => []];
|
||||
}
|
||||
|
||||
$decoded = rt_load_json_file($path);
|
||||
$history = \array_values((array) ($decoded['history'] ?? []));
|
||||
|
||||
return ['history' => $history];
|
||||
}
|
||||
|
||||
function rt_direction(float $current, ?float $previous): string
|
||||
{
|
||||
if ($previous === null) {
|
||||
return 'new';
|
||||
}
|
||||
|
||||
if ($current > $previous) {
|
||||
return 'up';
|
||||
}
|
||||
|
||||
if ($current < $previous) {
|
||||
return 'down';
|
||||
}
|
||||
|
||||
return 'flat';
|
||||
}
|
||||
|
||||
function rt_to_markdown(array $trend, array $latest): string
|
||||
{
|
||||
$rows = \array_slice((array) ($trend['history'] ?? []), -5);
|
||||
|
||||
$lines = [];
|
||||
$lines[] = '## CSS Renderability Trend';
|
||||
$lines[] = '';
|
||||
$lines[] = '| Metric | Value |';
|
||||
$lines[] = '|---|---:|';
|
||||
$lines[] = '| Current overall score | ' . (string) ($latest['overall_score'] ?? 0) . ' |';
|
||||
$lines[] = '| Direction | ' . (string) ($latest['direction'] ?? 'new') . ' |';
|
||||
$lines[] = '| Current pass rate | ' . (string) ($latest['pass_rate'] ?? 0) . '% |';
|
||||
$lines[] = '| Current text flow rate | ' . (string) ($latest['text_flow_rate'] ?? 0) . '% |';
|
||||
$lines[] = '| Current high severity failures | ' . (string) ($latest['high_severity_failures'] ?? 0) . ' |';
|
||||
$lines[] = '';
|
||||
$lines[] = '| Timestamp | Ref | Score | Pass Rate | Text Flow | High Severity |';
|
||||
$lines[] = '|---|---|---:|---:|---:|---:|';
|
||||
|
||||
foreach ($rows as $row) {
|
||||
if (!\is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lines[] = '| ' . (string) ($row['timestamp'] ?? '')
|
||||
. ' | ' . (string) ($row['ref'] ?? '')
|
||||
. ' | ' . (string) ($row['overall_score'] ?? 0)
|
||||
. ' | ' . (string) ($row['pass_rate'] ?? 0) . '%'
|
||||
. ' | ' . (string) ($row['text_flow_rate'] ?? 0) . '%'
|
||||
. ' | ' . (string) ($row['high_severity_failures'] ?? 0) . ' |';
|
||||
}
|
||||
|
||||
$lines[] = '';
|
||||
|
||||
return \implode(PHP_EOL, $lines) . PHP_EOL;
|
||||
}
|
||||
|
||||
$args = rt_parse_args($argv);
|
||||
$scorePath = $args['score'] ?? 'target/report/renderability-score.json';
|
||||
$historyPath = $args['history'] ?? 'target/report/renderability-trend.json';
|
||||
$markdownPath = $args['markdown'] ?? 'target/report/renderability-trend.md';
|
||||
$sha = $args['sha'] ?? '';
|
||||
$ref = $args['ref'] ?? '';
|
||||
$runId = $args['run-id'] ?? '';
|
||||
$maxEntries = (int) ($args['max-entries'] ?? '120');
|
||||
|
||||
$score = rt_load_json_file($scorePath);
|
||||
$trend = rt_load_history($historyPath);
|
||||
|
||||
$history = (array) ($trend['history'] ?? []);
|
||||
$previous = null;
|
||||
if ($history !== []) {
|
||||
$last = \end($history);
|
||||
if (\is_array($last) && \array_key_exists('overall_score', $last)) {
|
||||
$previous = (float) $last['overall_score'];
|
||||
}
|
||||
}
|
||||
|
||||
$currentOverall = (float) ($score['overall_score'] ?? 0);
|
||||
$entry = [
|
||||
'timestamp' => \gmdate('c'),
|
||||
'run_id' => $runId,
|
||||
'ref' => $ref,
|
||||
'sha' => $sha,
|
||||
'overall_score' => $currentOverall,
|
||||
'pass_rate' => (float) ($score['pass_rate'] ?? 0),
|
||||
'text_flow_rate' => (float) ($score['text_flow_rate'] ?? 0),
|
||||
'high_severity_failures' => (int) ($score['high_severity_failures'] ?? 0),
|
||||
'direction' => rt_direction($currentOverall, $previous),
|
||||
];
|
||||
|
||||
$history[] = $entry;
|
||||
if (($maxEntries > 0) && (\count($history) > $maxEntries)) {
|
||||
$history = \array_slice($history, -$maxEntries);
|
||||
}
|
||||
|
||||
$trend = ['history' => \array_values($history)];
|
||||
$markdown = rt_to_markdown($trend, $entry);
|
||||
|
||||
$historyDir = \dirname($historyPath);
|
||||
if (($historyDir !== '.') && !\is_dir($historyDir)) {
|
||||
\mkdir($historyDir, 0777, true);
|
||||
}
|
||||
$mdDir = \dirname($markdownPath);
|
||||
if (($mdDir !== '.') && !\is_dir($mdDir)) {
|
||||
\mkdir($mdDir, 0777, true);
|
||||
}
|
||||
|
||||
\file_put_contents($historyPath, \json_encode($trend, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL);
|
||||
\file_put_contents($markdownPath, $markdown);
|
||||
|
||||
echo 'Renderability trend history written to: ' . $historyPath . PHP_EOL;
|
||||
echo 'Renderability trend markdown written to: ' . $markdownPath . PHP_EOL;
|
||||
@@ -0,0 +1,7 @@
|
||||
~#PKGNAME#~ (~#VERSION#~-~#RELEASE#~) UNRELEASED; urgency=low
|
||||
|
||||
* Please check the
|
||||
https://github.com/~#VENDOR#~/~#PROJECT#~
|
||||
commit history
|
||||
|
||||
-- Nicola Asuni <info@tecnick.com> ~#DATE#~
|
||||
@@ -0,0 +1,44 @@
|
||||
Source: ~#PKGNAME#~
|
||||
Maintainer: Nicola Asuni <info@tecnick.com>
|
||||
Section: php
|
||||
Priority: optional
|
||||
Build-Depends: debhelper-compat (= 13)
|
||||
Standards-Version: 4.7.2
|
||||
Rules-Requires-Root: no
|
||||
Homepage: https://github.com/~#VENDOR#~/~#PROJECT#~
|
||||
Vcs-Git: https://github.com/~#VENDOR#~/~#PROJECT#~.git
|
||||
Vcs-Browser: https://github.com/~#VENDOR#~/~#PROJECT#~
|
||||
|
||||
Package: ~#PKGNAME#~
|
||||
Provides: php-~#PROJECT#~
|
||||
Architecture: all
|
||||
Depends: php (>= 8.2.0), php-ctype, php-json, php-mbstring, php-xml,
|
||||
php-tecnickcom-tc-lib-barcode (<< 3.0.0),
|
||||
php-tecnickcom-tc-lib-barcode (>= 2.13.2),
|
||||
php-tecnickcom-tc-lib-color (<< 3.0.0),
|
||||
php-tecnickcom-tc-lib-color (>= 2.13.3),
|
||||
php-tecnickcom-tc-lib-file (<< 3.0.0),
|
||||
php-tecnickcom-tc-lib-file (>= 3.7.3),
|
||||
php-tecnickcom-tc-lib-pdf-encrypt (<< 3.0.0),
|
||||
php-tecnickcom-tc-lib-pdf-encrypt (>= 2.9.3),
|
||||
php-tecnickcom-tc-lib-pdf-font (<< 3.0.0),
|
||||
php-tecnickcom-tc-lib-pdf-font (>= 3.13.2),
|
||||
php-tecnickcom-tc-lib-pdf-graph (<< 3.0.0),
|
||||
php-tecnickcom-tc-lib-pdf-graph (>= 2.15.2),
|
||||
php-tecnickcom-tc-lib-pdf-image (<< 3.0.0),
|
||||
php-tecnickcom-tc-lib-pdf-image (>= 3.12.2),
|
||||
php-tecnickcom-tc-lib-pdf-page (<< 5.0.0),
|
||||
php-tecnickcom-tc-lib-pdf-page (>= 4.14.2),
|
||||
php-tecnickcom-tc-lib-pdf-sign (<< 2.0.0),
|
||||
php-tecnickcom-tc-lib-pdf-sign (>= 1.1.3),
|
||||
php-tecnickcom-tc-lib-unicode (<< 3.0.0),
|
||||
php-tecnickcom-tc-lib-unicode (>= 3.0.2),
|
||||
php-tecnickcom-tc-lib-unicode-data (<< 3.0.0),
|
||||
php-tecnickcom-tc-lib-unicode-data (>= 3.0.2),
|
||||
php-tecnickcom-tc-lib-pdf-parser (<< 4.0.0),
|
||||
php-tecnickcom-tc-lib-pdf-parser (>= 3.14.2),
|
||||
${misc:Depends}
|
||||
Recommends: php-curl, php-intl
|
||||
Description: PHP library for PDF document generation
|
||||
This package provides tc-lib-pdf, a modular PHP library to compose PDF
|
||||
documents with text, graphics, tables, metadata, and signatures.
|
||||
@@ -0,0 +1,20 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: ~#PROJECT#~
|
||||
Source: https://github.com/~#VENDOR#~/~#PROJECT#~
|
||||
|
||||
Files: *
|
||||
Copyright: Copyright 2001-2026 Nicola Asuni <info@tecnick.com>
|
||||
License: LGPL-3
|
||||
|
||||
License: LGPL-3
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/> or
|
||||
/usr/share/common-licenses/LGPL-3
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/make -f
|
||||
%:
|
||||
dh $@
|
||||
@@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
||||
@@ -0,0 +1,5 @@
|
||||
Bug-Database: https://github.com/~#VENDOR#~/~#PROJECT#~/issues
|
||||
Bug-Submit: https://github.com/~#VENDOR#~/~#PROJECT#~/issues/new
|
||||
Changelog: https://github.com/~#VENDOR#~/~#PROJECT#~/releases
|
||||
Repository: https://github.com/~#VENDOR#~/~#PROJECT#~.git
|
||||
Repository-Browse: https://github.com/~#VENDOR#~/~#PROJECT#~
|
||||
@@ -0,0 +1,4 @@
|
||||
version=4
|
||||
opts=filenamemangle=s/.+\/v?(\d[\d\.]+)\.tar\.gz/php-tecnickcom-tc-lib-pdf_$1.orig.tar.gz/ \
|
||||
https://github.com/~#VENDOR#~/~#PROJECT#~/tags \
|
||||
.*/archive/refs/tags/v?(\d[\d\.]*)\.tar\.gz
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Creator: CorelDRAW -->
|
||||
|
||||
<svg
|
||||
xml:space="preserve"
|
||||
width="193.58325mm"
|
||||
height="42.165092mm"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
|
||||
viewBox="0 0 193.58325 42.165092"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
|
||||
id="metadata28"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata>
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
type="text/css"
|
||||
id="style6">
|
||||
|
||||
.fil0 {fill:#FFCC00}
|
||||
.fil1 {fill:#003882}
|
||||
|
||||
</style>
|
||||
|
||||
<metadata
|
||||
id="CorelCorpID_0Corel-Layer" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</defs>
|
||||
<rect
|
||||
style="fill:#f9f9f9"
|
||||
x="0"
|
||||
height="42.164902"
|
||||
width="78.583298"
|
||||
y="0"
|
||||
class="fil0"
|
||||
id="_131743536" /><polygon
|
||||
id="_133179360"
|
||||
class="fil1"
|
||||
points="47.9167,11.4997 47.9167,30.6655 72.8333,30.6655 72.8333,36.4152 42.1667,36.4152 42.1667,5.75 72.8333,5.75 72.8333,11.4997 "
|
||||
style="fill:#800000"
|
||||
transform="translate(0,1.18344e-5)" /><polygon
|
||||
id="_133867968"
|
||||
class="fil1"
|
||||
points="18.2083,11.4997 5.75,11.4997 5.75,5.75 18.2083,5.75 23.9583,5.75 36.4167,5.75 36.4167,11.4997 23.9583,11.4997 23.9583,36.4152 18.2083,36.4152 "
|
||||
style="fill:#800000"
|
||||
transform="translate(0,1.18344e-5)" /><rect
|
||||
style="fill:#800000;fill-opacity:1;stroke-width:0.87149"
|
||||
height="42.1646"
|
||||
width="114.99956"
|
||||
y="0.00049330539"
|
||||
x="78.583702"
|
||||
class="fil1"
|
||||
id="_133329728" /><path
|
||||
id="_133133936"
|
||||
style="fill:#f9f9f9"
|
||||
class="fil0"
|
||||
d="m 157.16726,6.0126118 v 0.08888 5.6606372 6.708117 5.74952 12.457638 h 5.75003 V 24.219769 h 24.91631 v -5.74952 H 162.91729 V 11.762132 H 187.8336 V 6.0126118 h -24.91631 z" />
|
||||
<path
|
||||
id="path1"
|
||||
class="fil0"
|
||||
d="m 84.3333,6.0126118 h 5.75 19.1666 5.75 v 5.7497002 6.708 5.7497 h -5.75 -19.1666 v 12.4577 h -5.75 v -12.4577 -5.7497 -6.708 z m 24.9166,5.7497002 H 90.0833 v 6.708 h 19.1666 z"
|
||||
style="fill:#f9f9f9" /><path
|
||||
id="path2"
|
||||
style="fill:#f9f9f9;fill-opacity:1"
|
||||
class="fil1"
|
||||
d="m 120.75066,6.0126118 v 5.7500372 18.691882 6.223393 l 9.73687,-4.033345 4.14342,-1.716175 11.03653,-4.571297 2.30374,-0.954464 3.44578,-1.427303 V 17.752464 11.762649 6.0126118 Z m 5.75004,5.7500372 h 19.16678 v 8.371065 l -17.38033,7.199044 -1.78645,0.740007 z" /></svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,47 @@
|
||||
# External Preflight Matrix
|
||||
|
||||
This folder contains a minimal scaffold to generate one sample PDF for each supported mode and run external validators.
|
||||
|
||||
## Included scripts
|
||||
|
||||
- `generate_mode_samples.php` generates sample PDFs for:
|
||||
- `pdfx`, `pdfx1a`, `pdfx3`, `pdfx4`, `pdfx5`
|
||||
- `pdfua`, `pdfua1`, `pdfua2`
|
||||
- `run_preflight_matrix.sh` runs:
|
||||
- `qpdf --check` when `qpdf` is available
|
||||
- `verapdf --format text --flavour ua1|ua2` for PDF/UA samples when `verapdf` is available
|
||||
- a custom PDF/X validator command when `PDFX_VALIDATOR_CMD` is set
|
||||
|
||||
## Usage
|
||||
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
make preflight
|
||||
```
|
||||
|
||||
Optional PDF/X validator hook:
|
||||
|
||||
```bash
|
||||
PDFX_VALIDATOR_CMD='my-pdfx-validator --mode "$MODE" "$FILE"' make preflight
|
||||
```
|
||||
|
||||
The script runs the command through `bash -lc` with these environment variables set per file:
|
||||
|
||||
- `MODE`: the current conformance mode, for example `pdfx4`
|
||||
- `FILE`: the generated sample PDF path
|
||||
- `REPORT`: the report file path under `target/preflight/report/`
|
||||
|
||||
Optional custom output directory:
|
||||
|
||||
```bash
|
||||
bash resources/preflight/run_preflight_matrix.sh /tmp/tc-lib-pdf-preflight
|
||||
```
|
||||
|
||||
Reports are written under `target/preflight/report/` (or the custom output path).
|
||||
|
||||
## Notes
|
||||
|
||||
- This is a tooling scaffold for repeatable external validation runs.
|
||||
- veraPDF is used here as an explicit PDF/UA validator, not as a PDF/X validator.
|
||||
- Final compliance claims still require profile-specific preflight policies and manual review using your selected validation authority.
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* Generate one minimal PDF sample per supported PDF/X and PDF/UA mode.
|
||||
*
|
||||
* Usage:
|
||||
* php resources/preflight/generate_mode_samples.php [output-directory]
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
define('K_PATH_FONTS', (string) \realpath(__DIR__ . '/../../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
|
||||
|
||||
$outDir = $argv[1] ?? (__DIR__ . '/../../target/preflight');
|
||||
if (!\is_dir($outDir) && !\mkdir($outDir, 0775, true) && !\is_dir($outDir)) {
|
||||
\fwrite(STDERR, "Unable to create output directory: {$outDir}\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$modes = [
|
||||
'pdfx',
|
||||
'pdfx1a',
|
||||
'pdfx3',
|
||||
'pdfx4',
|
||||
'pdfx5',
|
||||
'pdfua',
|
||||
'pdfua1',
|
||||
'pdfua2',
|
||||
];
|
||||
|
||||
foreach ($modes as $mode) {
|
||||
$pdf = new \Com\Tecnick\Pdf\Tcpdf('mm', true, false, true, $mode);
|
||||
$font = $pdf->font->insert($pdf->pon, 'helvetica', '', 12);
|
||||
$page = $pdf->addPage();
|
||||
$pdf->page->addContent($font['out']);
|
||||
|
||||
$title = \strtoupper($mode);
|
||||
$pdf->addHTMLCell('<h1>Conformance sample</h1><p>Mode: ' . $title . '</p>', 15, 20, 180);
|
||||
|
||||
$rawPdf = $pdf->getOutPDFString();
|
||||
$outFile = $outDir . '/mode-' . $mode . '.pdf';
|
||||
if (\file_put_contents($outFile, $rawPdf) === false) {
|
||||
\fwrite(STDERR, "Unable to write sample file: {$outFile}\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
\fwrite(STDOUT, $mode . "\t" . $outFile . "\n");
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
OUT_DIR="${1:-${ROOT_DIR}/target/preflight}"
|
||||
REPORT_DIR="${OUT_DIR}/report"
|
||||
GENERATOR="${ROOT_DIR}/resources/preflight/generate_mode_samples.php"
|
||||
|
||||
PDFX_MODES=(pdfx pdfx1a pdfx3 pdfx4 pdfx5)
|
||||
PDFUA_MODES=(pdfua pdfua1 pdfua2)
|
||||
ALL_MODES=("${PDFX_MODES[@]}" "${PDFUA_MODES[@]}")
|
||||
|
||||
VERAPDF_BIN="${VERAPDF_BIN:-$(command -v verapdf || true)}"
|
||||
QPDF_BIN="${QPDF_BIN:-$(command -v qpdf || true)}"
|
||||
PDFX_VALIDATOR_CMD="${PDFX_VALIDATOR_CMD:-}"
|
||||
|
||||
pdfua_flavour() {
|
||||
case "$1" in
|
||||
pdfua|pdfua1)
|
||||
printf 'ua1'
|
||||
;;
|
||||
pdfua2)
|
||||
printf 'ua2'
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
mkdir -p "${OUT_DIR}" "${REPORT_DIR}"
|
||||
|
||||
echo "[preflight] generating conformance samples in ${OUT_DIR}"
|
||||
php "${GENERATOR}" "${OUT_DIR}" >/dev/null
|
||||
|
||||
failures=0
|
||||
checks=0
|
||||
|
||||
if [[ -n "${QPDF_BIN}" ]]; then
|
||||
echo "[preflight] running qpdf structural checks"
|
||||
for mode in "${ALL_MODES[@]}"; do
|
||||
file="${OUT_DIR}/mode-${mode}.pdf"
|
||||
report="${REPORT_DIR}/qpdf-${mode}.txt"
|
||||
if "${QPDF_BIN}" --check "${file}" >"${report}" 2>&1; then
|
||||
echo "[ok] qpdf ${mode}"
|
||||
checks=$((checks + 1))
|
||||
else
|
||||
echo "[fail] qpdf ${mode} (see ${report})"
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "[skip] qpdf not found; install qpdf to enable structural validation"
|
||||
fi
|
||||
|
||||
if [[ -n "${PDFX_VALIDATOR_CMD}" ]]; then
|
||||
echo "[preflight] running configured PDF/X validator"
|
||||
for mode in "${PDFX_MODES[@]}"; do
|
||||
file="${OUT_DIR}/mode-${mode}.pdf"
|
||||
report="${REPORT_DIR}/pdfx-validator-${mode}.txt"
|
||||
if MODE="${mode}" FILE="${file}" REPORT="${report}" bash -lc "${PDFX_VALIDATOR_CMD}" >"${report}" 2>&1; then
|
||||
echo "[ok] pdfx-validator ${mode}"
|
||||
checks=$((checks + 1))
|
||||
else
|
||||
echo "[fail] pdfx-validator ${mode} (see ${report})"
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "[skip] no PDF/X profile validator configured; set PDFX_VALIDATOR_CMD to enable PDF/X authority checks"
|
||||
fi
|
||||
|
||||
if [[ -n "${VERAPDF_BIN}" ]]; then
|
||||
echo "[preflight] running veraPDF PDF/UA profile checks"
|
||||
for mode in "${PDFUA_MODES[@]}"; do
|
||||
file="${OUT_DIR}/mode-${mode}.pdf"
|
||||
report="${REPORT_DIR}/verapdf-${mode}.txt"
|
||||
flavour="$(pdfua_flavour "${mode}")"
|
||||
if "${VERAPDF_BIN}" --format text --flavour "${flavour}" "${file}" >"${report}" 2>&1; then
|
||||
echo "[ok] veraPDF ${mode} (${flavour})"
|
||||
checks=$((checks + 1))
|
||||
else
|
||||
echo "[fail] veraPDF ${mode} (${flavour}) (see ${report})"
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "[skip] veraPDF not found; install verapdf to enable explicit PDF/UA profile validation"
|
||||
fi
|
||||
|
||||
echo "[preflight] completed checks=${checks} failures=${failures}"
|
||||
if [[ ${failures} -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,77 @@
|
||||
# SPEC file
|
||||
|
||||
%global c_vendor %{_vendor}
|
||||
%global gh_owner %{_owner}
|
||||
%global gh_project %{_project}
|
||||
|
||||
Name: %{_package}
|
||||
Version: %{_version}
|
||||
Release: %{_release}%{?dist}
|
||||
Summary: PHP library to generate PDF documents
|
||||
|
||||
License: LGPLv3+
|
||||
URL: https://github.com/%{gh_owner}/%{gh_project}
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: php(language) >= 8.2.0
|
||||
Requires: php-ctype
|
||||
Requires: php-date
|
||||
Requires: php-filter
|
||||
Requires: php-hash
|
||||
Requires: php-json
|
||||
Requires: php-mbstring
|
||||
Requires: php-openssl
|
||||
Requires: php-pcre
|
||||
Requires: php-xml
|
||||
Requires: php-zlib
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-barcode) < 3.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-barcode) >= 2.13.2
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-color) < 3.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-color) >= 2.13.3
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-image) < 3.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-image) >= 3.12.2
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-font) < 3.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-font) >= 3.13.2
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-file) < 3.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-file) >= 3.7.3
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-encrypt) < 3.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-encrypt) >= 2.9.3
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-sign) < 2.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-sign) >= 1.1.3
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-unicode-data) < 3.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-unicode-data) >= 3.0.2
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-unicode) < 3.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-unicode) >= 3.0.2
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-page) < 5.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-page) >= 4.14.2
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-graph) < 3.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-graph) >= 2.15.2
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-parser) < 4.0.0
|
||||
Requires: php-composer(%{c_vendor}/tc-lib-pdf-parser) >= 3.14.2
|
||||
|
||||
Recommends: php-curl
|
||||
Recommends: php-intl
|
||||
|
||||
Provides: php-composer(%{c_vendor}/%{gh_project}) = %{version}
|
||||
Provides: php-%{gh_project} = %{version}
|
||||
|
||||
%description
|
||||
PHP library to generate PDF documents
|
||||
|
||||
%build
|
||||
#(cd %{_current_directory} && make build)
|
||||
|
||||
%install
|
||||
rm -rf "%{buildroot}"
|
||||
(cd "%{_current_directory}" && make install DESTDIR="%{buildroot}")
|
||||
|
||||
%files
|
||||
%attr(-,root,root) %{_libpath}
|
||||
%attr(-,root,root) %{_docpath}
|
||||
%docdir %{_docpath}
|
||||
%config(noreplace) %{_configpath}*
|
||||
|
||||
%changelog
|
||||
* Tue Apr 21 2026 Nicola Asuni <info@tecnick.com> 8.7.0-1
|
||||
- Update RPM packaging metadata and release mapping.
|
||||
Reference in New Issue
Block a user