그 지원 티켓에 대한 짧은 답은 예, 한계와 함께입니다. HotPDF 2.730.0은 Win64에서 Free Pascal 3.2.2와 Lazarus 4.6으로 빌드되며, 코어 생성, 로드, 저장 경로는 작동합니다. 뒤따르지 않는 것은 정적으로 링크된 네이티브 코덱 오브젝트나 델파이 익명 메서드에 기대는 모든 것입니다
질문은 보통 같은 방식으로 도착합니다. 크로스 플랫폼 도구를 위해 Lazarus로 표준화한 팀, 또는 Free Pascal 코드베이스를 물려받은 팀이 델파이용으로 이미 라이선스한 같은 PDF 구성 요소를 원합니다. 성숙한 델파이 라이브러리의 이식은 구문 문제가 아닌 경우가 드뭅니다. 흥미로운 부분은 이식이 드러내는 것으로, 라이브러리가 어디서 조용히 하나의 툴체인에 결합되어 있었는가입니다. 이 사례에서 결합은 아주 구체적인 두 곳에 앉아 있습니다. 번들 코덱의 오브젝트 파일 ABI와 버전 심볼 뒤에 숨은 컴파일러 기능입니다
HPDFDoc이 컴파일되기 전 Free Pascal 3.2.2가 필요로 하는 것
HotPDF는 Free Pascal 아래에서 델파이 모드에서만, 그리고 Lazarus LCL 유닛 디렉터리가 검색 경로에 있을 때만 컴파일됩니다. 둘 다 협상 대상이 아닙니다. HotPDF.inc는 {$IFDEF FPC} 블록 안에서 {$MODE DELPHI}와 {$H+}로 컴파일러를 전환하고, FPC_FULLVERSION이 30202 미만이면 {$FATAL}로 더 오래된 것을 거부합니다. 그래서 3.0.x 설치는 깨진 유닛을 낳는 대신 시끄럽게 실패합니다. Lazarus 런타임 패키지 HotPDFLaz.lpk가 나머지를 인코딩합니다. 필수 패키지로서의 LCL과 사용자 지정 옵션으로서의 -Mdelphi입니다
콘솔 출력만 원하는 사람에게 LCL 요구는 의외이지만 구조적입니다. HPDFFPCCompat은 Free Pascal에 동등물이 없는 델파이 VCL 타입을 공급합니다. TMetafile과 TMetafileCanvas를 LCL 비트맵과 캔버스 클래스로 매핑하고 TRichEdit를 TMemo로 별명 붙이며, HPDFDoc은 TPNGObject를 Graphics.TPortableNetworkGraphic으로 별명 붙입니다. 그것들을 기능 동등이 아니라 컴파일 타임 심으로 다루십시오. 비트맵이 뒤를 받치는 메타파일 클래스는 유닛을 컴파일 상태로 유지할 뿐, 메타파일 경로가 델파이에서처럼 행동하게 만들지 않습니다. 비 GUI 스모크 테스트조차 Interfaces를 끌어들이고, 빌드 스크립트는 lcl\units\x86_64-win64와 lazutils 출력 디렉터리에 -Fu를 넘깁니다
D2009+가 버전 게이트를 겸할 수 없는 이유
Free Pascal 빌드를 현대 컴파일러로 취급하고 가장 새로운 델파이 기능 심볼을 정의하는 것이 유혹적입니다. HotPDF는 그러지 않고, 이유는 분명히 말할 가치가 있습니다. D2009+는 유니코드 문자열만 뜻하지 않습니다. 공개 API가 익명 메서드로 표현되는 유닛에도 게이트를 칩니다. Free Pascal 3.2.2는 델파이 익명 메서드도 그런 API도 지원하지 않으므로, 심볼을 빌리면 컴파일될 수 없는 코드가 끌려옵니다. 그래서 HPDFDoc의 uses 절은 별개의 조건부 꼬리 둘을 실으며, 둘 사이의 겹침은 사고가 아니라 의도입니다
uses
// ...
HPDFJavaScript,
HPDFFormCalcGraph
{$IFDEF FPC}
, HPDFFPCCodecStubs,
HPDFCMS,
HPDFWinCertSigner
{$ENDIF}
{$IFDEF D2009+}
, HPDFXFARuntime,
HPDFCMS,
HPDFWinCertSigner,
HPDFSignVerify,
HPDFSignatureBatch
{$ENDIF};
네이티브 코덱은 왜 링커에서 멈추는가
하나의 특정 툴체인이 내보낸 Win64 COFF 오브젝트이고, Win64의 두 Free Pascal 링커 어느 쪽도 그것을 소비하지 않기 때문입니다. 내부 링커도, 외부 GNU ld 경로도 아닙니다. 이것은 오브젝트 파일 ABI 문제지 Pascal 문제가 아니며, 조건부 소스 몇 줄로 고쳐지지 않습니다. 라이브러리는 이용 가능한 유일한 정직한 경로를 택합니다. 정적 코덱 오브젝트를 끌어오는 모든 {$L} 지시문이 {$IFNDEF FPC}로 싸여 Free Pascal 빌드는 그저 생략하고, HPDFFPCCodecStubs가 누락된 외부 심볼마다 반환하는 대신 예외를 던지는 스텁을 공급합니다
// HPDFFPCCodecStubs.pas
function HPDFFPCNativeCodecUnavailable: PtrUInt;
begin
raise ENotSupportedException.Create(
'This native codec is not available in the Free Pascal build');
end;
function HPDFFPCStub_deflate: PtrUInt; cdecl;
public name 'deflate';
begin
Result := HPDFFPCNativeCodecUnavailable;
end;
그 스텁 테이블은 길고, 읽으면 오늘날 어느 기능이 델파이 전용인지 정확히 알 수 있습니다. zlib-ng와 zopfli deflate 진입점, libjpeg 압축과 압축 해제, OpenJPEG JPEG 2000 코덱, libtiff와 압축별 초기화기, JBIG2 인코딩과 디코딩, Little-CMS 색 변환 진입점, 그리고 AES 원시 기능입니다. 목록보다 스텁 뒤의 설계 선택이 중요합니다. 링크 시점의 누락 심볼은 여러분이 한 번도 만지지 않은 유닛에서 정의되지 않은 참조의 벽을 줍니다. ENotSupportedException을 던지는 스텁은 돌아가는 빌드, 이유를 이름짓는 메시지, 호출 지점을 가리키는 스택 트레이스를 줍니다. 또한 Free Pascal 빌드가 델파이 빌드가 올바른 바이트를 낳는 곳에서 조용히 잘못된 바이트를 낳는 일은 결코 없음을 뜻합니다. 2차 효과도 기록하십시오. 격리된 프로세스에서 신뢰할 수 없는 이미지 코덱 실행은 델파이 빌드에서만 생기는 결정입니다. Free Pascal 빌드에는 애초에 샌드박스에 넣을 in-process 네이티브 디코더가 없기 때문입니다
압축: 첫 번째로 바꿀 줄은 cmNone이다
다른 것을 이식하기 전에 Compression을 cmNone으로 놓으십시오. THPDFCompressionMethod는 정확히 두 값을 제공합니다. cmNone과 cmFlateDecode입니다. 둘째는 Free Pascal 빌드에서 스텁인 deflate 진입점으로 곧장 흘러듭니다. 압축 끈 상태로 먼저 코어 객체 모델을 검증한 뒤 무엇이 더 필요한지 결정하십시오. 배송되는 스모크 테스트가 쓰는 순서입니다. 한 페이지짜리 비압축 문서를 만들고, 다시 적재하고, 페이지 수가 1로 돌아왔는지 단언합니다. 비압축 출력은 더 크고, 여전히 완전히 유효한 PDF입니다
program HotPDFLazarusSmoke;
{$mode delphi}
{$H+}
uses
Interfaces, SysUtils, HPDFDoc;
var
Pdf, Reloaded: THotPDF;
OutputFile: string;
PageCount: Integer;
begin
OutputFile := IncludeTrailingPathDelimiter(GetTempDir) +
'HotPDF-FPC-Smoke.pdf';
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := OutputFile;
Pdf.Compression := cmNone; // cmFlateDecode는 스텁 심볼에 닿는다
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 12);
Pdf.CurrentPage.TextOut(72, 72, 0, 'HotPDF Free Pascal smoke test');
Pdf.EndDoc;
finally
Pdf.Free;
end;
Reloaded := THotPDF.Create(nil);
try
PageCount := Reloaded.LoadFromFile(OutputFile);
if PageCount <> 1 then
raise Exception.CreateFmt('Expected one page, got %d', [PageCount]);
finally
Reloaded.Free;
end;
end.
병렬 페이지 렌더링에는 무슨 일이 벌어지는가
여전히 컴파일되고, 여전히 올바른 비트맵을 반환하며, 병렬이기는 그만둡니다. THotPDF.RenderLoadedPagesParallel과 THotPDF.RenderLoadedPagesParallelOrdered는 인라인 procedure 클로저를 실은 TThread.CreateAnonymousThread 위에 세워져 있는데, Free Pascal 3.2.2는 그것을 표현할 수 없습니다. 그래서 Free Pascal 분기는 결정론적 직렬 폴백을 돌립니다. 페이지 인덱스를 순서대로 걷고, 각각에 RenderLoadedPageToBitmap을 부르고, 성공을 셉니다. API 모양, 반환 값, 출력 배열은 변하지 않으며, 단일 코드베이스가 양쪽으로 빌드되는 이유가 그것입니다
var
Bitmaps: THPDFBitmapArray;
Info: THPDFParallelRenderPipelineInfo;
Rendered: Integer;
begin
Rendered := Pdf.RenderLoadedPagesParallel([0, 1, 2, 3], 150, 4,
Bitmaps, Info);
// Delphi: Info.WorkerCount는 메모리 예산이 허용한 값이다
// Free Pascal: Info.WorkerCount는 언제나 1, 페이지는 인덱스 순서
if Info.WorkerCount = 1 then
LogSerialFallback(Rendered, Info.RequestedWorkerCount);
폴백은 조용하지 않은데, 설계할 때 중심에 둘 부분입니다. THPDFParallelRenderPipelineInfo를 정직하게 채웁니다. 요청에서 온 PageCount, 요구한 것을 되울리는 RequestedWorkerCount, 1로 놓인 WorkerCount, 실제 돌아온 것과 맞는 완료 및 전달 카운트. Info를 검사해 진행 바나 메모리 예산을 잡던 코드는 계속 돌며 가정이 아니라 진실을 읽습니다. 처리량 계획이 병렬 렌더 파이프라인과 그 백프레셔 모델에 의존한다면 그 계획은 델파이 계획입니다. Free Pascal에서는 페이지를 비트맵으로 렌더링하는 단일 스레드 비용에 페이지 수를 곱해 예산을 잡으십시오
실제로 출시할 빌드는 어느 쪽인가
선호가 아니라 기능으로 고르십시오. 워크플로가 문서 조립, 텍스트와 벡터 그리기, 폼 채우기, 로드와 저장이라면 Win64의 Free Pascal 빌드가 그것을 덮고, 무언가를 켜기 전에 압축 끈 상태로 검증해야 합니다. JPEG이나 JPEG 2000, TIFF, JBIG2 이미지, ICC 색 변환, 압축 출력, 다중 코어에 의존하는 처리량이 관련되면 지금은 델파이나 C++Builder에 머무십시오. 경계는 오브젝트 파일 ABI와 누락된 언어 기능이 긋는데, 둘 다 지원 매트릭스에 묻히는 대신 소스에서 보이고, 잘못된 결과가 아니라 이름 붙은 오류로 실패합니다
Free Pascal과 Lazarus 패키지는 델파이와 C++Builder 유닛과 같은 배포본에 실려 옵니다. 라이선스 하나가 둘을 덮고, 도입을 결정하기 전에 여러분의 문서로 Lazarus 경로를 시험해 볼 수 있습니다. HotPDF Delphi PDF Component 제품 페이지가 현재 컴파일러 지원 매트릭스와 전체 API 참조를 실어 나릅니다