콘텐츠로 이동
getnextpdf.com

CJK 및 아랍어 PDF에서 복사-붙여넣기 정확도 확보하기

중국어, 일본어, 한국어(CJK), 아랍어 텍스트를 복사해 붙여넣어도 원래의 논리적 문자로 유지되는 Portable Document Format (PDF) 파일을 만듭니다. 엔진은 /ToUnicode CMap을 통해 모든 글리프를 유니코드로 매핑하고, 그 결과를 Normalization Form Compatibility Composition (NFKC)으로 정규화하며, 글자 모양 처리가 적용되거나 글자 간격이 적용된 런을 /ActualText를 담은 /Span으로 감쌉니다. 글꼴을 등록하고 콘텐츠를 작성하면 정확한 추출이 유지됩니다. 검증에는 PyMuPDF가 아니라 pdftotext/Poppler를 사용하십시오. veraPDF는 추출이 아니라 PDF/Universal Accessibility 2 (PDF/UA-2)를 검증합니다.

Terminal window
composer require nextpdf/core

Noto Sans CJK와 같은 CJK 글꼴, 그리고 문자 맵에 아랍어 표현 형식-B(Arabic Presentation Forms-B) 블록이 포함된 아랍어 지원 글꼴(예: Noto Naskh Arabic)을 등록하십시오. 임베드할 수 있는 라이선스를 보유한 글꼴만 임베드하십시오.

콘텐츠 스트림의 글리프 코드는 유니코드가 아닙니다. /ToUnicode CMap은 각 코드를 유니코드로 다시 매핑하여 리더가 텍스트를 추출할 수 있게 합니다(ISO 32000-2 §9.10). 엔진은 Unicode UAX #15에 정의된 대로 해당 값을 Normalization Form Compatibility Composition (NFKC)으로 정규화합니다. CJK 호환성 표의 문자와 아랍어 표현 형식은 각각의 기본 문자로 매핑되므로, 검색과 복사는 호환성 코드 포인트가 아니라 정규 텍스트를 반환합니다.

두 가지 경우에는 /ToUnicode만으로는 부족합니다. 글자 간격이 적용된 라틴 문자와 글자 모양 처리가 적용된 오른쪽에서 왼쪽으로 쓰는 아랍어입니다. 엔진은 이들을 간격이 벌어지거나 재정렬된 글리프로 그리므로, 글리프 순서만으로는 논리적 문자열을 복원할 수 없습니다. 엔진은 각 런을 /Span 마크된 콘텐츠 시퀀스로 감싸고, 여기에 감싸인 콘텐츠를 정확히 대체하는 /ActualText를 담습니다(ISO 32000-2 §14.9). /ActualText를 존중하는 추출기는 논리적 문자열을 반환합니다.

심볼위치역할
FontRegistry::register(string $fontFile, string $alias = ''): FontInfoNextPDF\Typography\FontRegistryCJK 및 아랍어 글꼴 페이스를 등록합니다.
DocumentFactory::create(): DocumentNextPDF\Core\DocumentFactory사용자 레지스트리를 읽는 문서를 빌드합니다.
Document::writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutput다국어 콘텐츠를 렌더링합니다.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
$fonts = new FontRegistry();
$fonts->register(__DIR__ . '/NotoSansCJK-Regular.ttf', alias: 'CJK');
$fonts->register(__DIR__ . '/NotoNaskhArabic-Regular.ttf', alias: 'Arabic');
$doc = (new DocumentFactory($fonts, new ImageRegistry(maxCacheBytes: 0)))->create();
$doc->addPage();
$doc->writeHtml(
'<p style="font-family: \'CJK\';">PDF 2.0 引擎 — 量子</p>'
. '<p style="direction: rtl; font-family: \'Arabic\';">فاتورة</p>'
);
$doc->save(__DIR__ . '/multilingual.pdf');
Terminal window
pdftotext multilingual.pdf - | head
# Extracts the logical text: "PDF 2.0 引擎 — 量子" and the logical Arabic "فاتورة",
# not compatibility code points or reversed presentation forms.

이 자체 완결형 예제는 문서에 태그를 지정하고, 글자 간격이 적용된 제목을 추가한 뒤, 하니스 경로에 출력합니다.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
$fonts = new FontRegistry();
$fonts->register(__DIR__ . '/NotoSansCJK-Regular.ttf', alias: 'CJK');
$fonts->register(__DIR__ . '/NotoNaskhArabic-Regular.ttf', alias: 'Arabic');
$doc = (new DocumentFactory($fonts, new ImageRegistry(maxCacheBytes: 0)))->create();
$doc->setTitle('Multilingual extraction');
$doc->enableTaggedPdf('en');
$doc->addPage();
$html = <<<'HTML'
<h1 style="font-family: 'CJK'; letter-spacing: 3px;">CODE WORD</h1>
<p style="font-family: 'CJK';">中文 · 日本語 · 한국어 · 量子 (compatibility ideograph)</p>
<p style="direction: rtl; font-family: 'Arabic';">المبلغ الإجمالي 380.00</p>
HTML;
$doc->writeHtml($html);
$out = getenv('NEXTPDF_OUT');
$doc->save($out !== false ? $out : __DIR__ . '/multilingual-copy-paste-extraction.pdf');
echo "Wrote the multilingual PDF\n";

생성된 출력에 pdftotext를 실행하십시오. 글자 간격이 적용된 제목은 추가 공백 없이 CODE WORD로 추출되고, CJK 줄은 기본 문자로 추출되며, 아랍어 줄은 논리적 문자열로 추출됩니다.

  • 추출 검증에는 PyMuPDF가 아니라 pdftotext를 사용하십시오. PyMuPDF의 원시 텍스트 모드는 인라인 /ActualText를 무시하고 시각적 글리프를 반환하므로, 정확성을 실제보다 낮게 보고할 수 있습니다. Poppler(pdftotext)는 /ActualText를 존중합니다. veraPDF는 추출이 아니라 PDF/UA-2를 검증합니다.
  • 추출에는 /ToUnicode가 필요합니다. 작성기가 /ToUnicode CMap을 출력하도록 글꼴을 등록하고 임베드하십시오. 임베드되지 않은 비표준 글꼴은 유니코드 매핑을 보장할 수 없습니다.
  • /ActualText는 글자 모양 처리가 적용되거나 글자 간격이 적용된 런을 다룹니다. 일반 텍스트처럼 글자 모양 처리가 없고 글자 간격도 적용되지 않은 경우, /ToUnicode만으로 정확하게 추출됩니다. /Span 래퍼는 간격이 벌어지거나 재정렬된 런을 보존합니다.
  • 태그된 HTML 표는 PDF/UA-2 검사를 통과합니다. 추출은 정확하며, 태그된 HTML <table>은 이제 veraPDF --flavour ua2를 실패 없이 통과합니다. 접근성을 참조하십시오.

/ToUnicode CMap과 /Span 래퍼를 빌드하는 비용은 글리프 수에 따라 선형으로 확장됩니다. 이 레시피의 예산은 wall_ms: 1500, peak_mb: 96입니다.

출력 크기를 제한하려면 사용자가 제공한 다국어 문자열의 길이를 검증하십시오. /ToUnicode 빌더는 서로게이트 절반과 코드스페이스를 벗어난 코드를 거부하므로, 잘못된 형식의 맵으로 인해 손상된 추출 리소스가 생성되지 않습니다. 엔진은 어떤 스크립트도 실행하지 않으며 로컬 글꼴을 처리할 때 원격 리소스를 가져오지 않습니다.

진술사양조항
/ToUnicode CMap은 추출을 위해 문자 코드를 유니코드로 매핑합니다.ISO 32000-2§9.10
/ActualText는 감싸인 콘텐츠를 정확히 대체합니다.ISO 32000-2§14.9
NFKC는 호환성 분해 후 정규 합성입니다.Unicode UAX #15§1.2

해당 없음.