Business Central中Base64 Convert生成的Base64与在线转换器不一致
我尝试将报表转换为Base64编码,通过API发送给其他应用。测试时,在线PDF转Base64转换器生成的编码能让接收应用正常获取文档,但用Business Central的AL程序转换时,API调用报错“PDF Validation failed”。对比两者输出发现结果不同,以下是我的转换代码:
local procedure BssiReport() var ReportOutstream: OutStream; ReportInstream: InStream; TempBlob: Codeunit "Temp Blob"; res: Text; Txt: Text; Base64Convert: Codeunit "Base64 Convert"; begin TempBlob.CreateOutStream(ReportOutstream); Report.SaveAs(Report::BssiPLMLeaseSummary, '<?xml version="1.0" standalone="yes"?><ReportParameters name="test" id="50505555"><Options><Field name="test" /><Field name="testdate">2022-07-20</Field></Options><DataItems><DataItem name="test2">VERSION(1) SORTING(Field1) WHERE(Field1=1(A100))</DataItem><DataItem name="test3">VERSION(1) SORTING(Field1,Field2)</DataItem><DataItem name="test4">VERSION(1) SORTING(Field1,Field5,Field2)</DataItem><DataItem name="test5">VERSION(1) SORTING(Field1,Field3,Field4,Field5,Field6)</DataItem><DataItem name="test6">VERSION(1) SORTING(Field2,Field48,Field3,Field4,Field5,Field1)</DataItem><DataItem name="test7">VERSION(1) SORTING(Field2,Field48,Field3,Field4,Field5,Field1)</DataItem><DataItem name="test8">VERSION(1) SORTING(Field2)</DataItem></DataItems></ReportParameters>', ReportFormat::Pdf, ReportOutstream); TempBlob.CreateInStream(ReportInstream); WHILE NOT (ReportInstream.EOS) DO BEGIN ReportInstream.READTEXT(Txt); res += Txt; END; jsonObj.Add('documentBase64', Base64Convert.ToBase64(res)); //... end;
在线转换器生成的输出开头:
"JVBERi0xLjcNCiWhs8XXDQoxIDAgb2JqDQo8PC9QYWdlcyAyIDAgUiAvVHlwZS9DYXRhbG9nPj4NCmVuZG9iag0KMiAwIG9iag0KPDwvQ291bnQgMS9LaWRzWyA0IDAgUiBdL1R5cGUvUGFnZXM+Pg0KZW5kb2JqDQozIDAgb2JqDQo8PC9DcmVhdGlvbkRhdGUoRDoyMDIyMDcwNDExMTYxOCkvQ3JlYXRvcihQREZpdW0pL1Byb2R1Y2VyKFBERml1bSk+Pg0KZW5kb2JqDQo0IDAgb2JqDQo8PC9Db250ZW50cyA1IDAgUiAvTWVkaWFCb3..."
Business Central生成的输出开头:
"JVBERi0xLjcl77+977+977+977+977+977+977+9MSAwIG9ialsvUERGL1RleHQvSW1hZ2VCL0ltYWdlQy9JbWFnZUldZW5kb2JqMiAwIG9iajw8L1R5cGUvUGFnZS9QYXJlbnQgNiAwIFIvTWVkaWFCb3hbMCAwIDc5MiA2MTJdL0NvbnRlbnRzIDUgMCBSL1Jlc291cmNlczw8L1Byb2NTZXQgMSAwIFIvWE9iamVjdDw8Pj4vRm9udDw8L0YzIDMgMCBSL0Y0IDQgMCBSPj4+Pj4+ZW5kb2JqMyAwIG9iajw8L1R5cGUvRm9udC9TdWJ0eXBlL1R..."
为什么两者输出不一致?
核心问题
你用READTEXT读取PDF二进制流的方式错误。PDF是二进制文件,并非文本文件,用文本读取逻辑会破坏原始字节数据:
READTEXT会将二进制字节按默认编码(通常为UTF-8)解析成文本,无法识别的字节会被替换成�(对应Base64中的77+9),直接损坏了PDF的原始结构。- 在线转换器是直接读取二进制字节再转Base64,因此能保留完整正确的PDF数据。
修复代码
直接对二进制流进行Base64转换,跳过文本转换的中间步骤:
local procedure BssiReport() var ReportOutstream: OutStream; ReportInstream: InStream; TempBlob: Codeunit "Temp Blob"; Base64Convert: Codeunit "Base64 Convert"; Base64Result: Text; begin TempBlob.CreateOutStream(ReportOutstream); // 保存报表到Blob(原代码这部分逻辑正常) Report.SaveAs(Report::BssiPLMLeaseSummary, '<?xml version="1.0" standalone="yes"?><ReportParameters name="test" id="50505555"><Options><Field name="test" /><Field name="testdate">2022-07-20</Field></Options><DataItems><DataItem name="test2">VERSION(1) SORTING(Field1) WHERE(Field1=1(A100))</DataItem><DataItem name="test3">VERSION(1) SORTING(Field1,Field2)</DataItem><DataItem name="test4">VERSION(1) SORTING(Field1,Field5,Field2)</DataItem><DataItem name="test5">VERSION(1) SORTING(Field1,Field3,Field4,Field5,Field6)</DataItem><DataItem name="test6">VERSION(1) SORTING(Field2,Field48,Field3,Field4,Field5,Field1)</DataItem><DataItem name="test7">VERSION(1) SORTING(Field2,Field48,Field3,Field4,Field5,Field1)</DataItem><DataItem name="test8">VERSION(1) SORTING(Field2)</DataItem></DataItems></ReportParameters>', ReportFormat::Pdf, ReportOutstream); // 直接从二进制流转换Base64,避免文本解析 TempBlob.CreateInStream(ReportInstream); Base64Convert.ToBase64(ReportInstream, Base64Result); jsonObj.Add('documentBase64', Base64Result); //... end;
关键说明
Base64 Convert代码单元提供了直接接收InStream的ToBase64方法,专门用于处理二进制数据,能完美保留原始PDF的字节结构。- 禁止用文本操作处理二进制文件,任何文本编码转换都会破坏非文本文件的原始数据。
内容的提问来源于stack exchange,提问作者bssienes

