本示例演示了 HotPDF 组件在 Delphi 中的强大文本输出功能。该演示展示了各种字体处理、字符集支持、文本格式化选项以及高级渲染技术,这些功能使 HotPDF 成为专业 PDF 生成的理想选择。
图1:HotPDF 组件演示不同字体系列(Arial、Times New Roman、Courier New)和多种字符集(阿拉伯语、东欧、俄语、土耳其语、OEM)的字符输出效果
图2:展示文本缩放、字符间距调整、单词间距修改以及不同文本渲染模式(填充、描边、填充+描边、不可见)的高级文本格式化功能
ShowCharset
仅用于演示通过字符代码显示字符集中的字符。对于常规文本显示,您只需直接使用 TextOut
来显示所需的字符串。
program TextOut; {$APPTYPE CONSOLE} uses SysUtils, Graphics, HotPDF_Core; var HotPDF: THotPDF; OutlineRoot, CurrnetOutline: THotPDFOutlineItem; { ==================================================================== ShowFontGroup - 演示特定字体系列的所有样式变化 ==================================================================== 目的: 显示给定字体系列的四种样式变化:普通、粗体、斜体和粗斜体。 每种样式都以相同的示例文本呈现,以便进行视觉比较。 参数: @param FontName: String - 要演示的字体系列名称(例如 'Arial'、'Times New Roman') @param X: Integer - 字体组显示的 X 坐标位置 布局: - 字体名称标题位于顶部 - 四种样式垂直排列,间距为 20 像素 - 每种样式都使用相同的示例文本 "AaBbYyZz" 进行一致比较 } procedure ShowFontGroup(FontName: String; X: Integer); begin // 显示字体系列名称作为标题 HotPDF.CurrentPage.SetFont('Arial', [fsBold], 12); HotPDF.CurrentPage.TextOut(X, 70, 0, WideString(FontName)); // 演示普通样式 HotPDF.CurrentPage.SetFont(FontName, [], 16); HotPDF.CurrentPage.TextOut(X, 90, 0, WideString('AaBbYyZz')); // 演示粗体样式 HotPDF.CurrentPage.SetFont(FontName, [fsBold], 16); HotPDF.CurrentPage.TextOut(X, 110, 0, WideString('AaBbYyZz')); // 演示斜体样式 HotPDF.CurrentPage.SetFont(FontName, [fsItalic], 16); HotPDF.CurrentPage.TextOut(X, 130, 0, WideString('AaBbYyZz')); // 演示粗斜体样式 HotPDF.CurrentPage.SetFont(FontName, [fsBold, fsItalic], 16); HotPDF.CurrentPage.TextOut(X, 150, 0, WideString('AaBbYyZz')); end; { ==================================================================== ShowCharset - 演示特定字符集的字符显示 ==================================================================== 目的: 显示给定字符集中指定范围内的字符。字符以网格格式排列, 便于查看和比较。处理字符渲染错误并提供回退显示。 参数: @param FontCharset: TFontCharset - 要使用的 Windows 字符集 @param First: Integer - 要显示的第一个字符代码 @param Last: Integer - 要显示的最后一个字符代码 @param Y1: Integer - 字符集标题的 Y 坐标 @param Y2: Integer - 字符网格的起始 Y 坐标 布局: - 字符以 30 个字符为一行的网格排列 - 最多显示 3 行(总共 90 个字符) - 字符间距为 16 像素,便于阅读 - 使用异常处理来处理无效字符代码 } procedure ShowCharset(FontCharset: TFontCharset; First, Last: Integer; Y1, Y2: Integer); var i, CharCode, Row, CharInRow, XPos, YPos: Integer; begin // 显示字符集标题 HotPDF.CurrentPage.SetFont('Arial', [fsBold], 12); case FontCharset of ARABIC_CHARSET: HotPDF.CurrentPage.TextOut(50, Y1, 0, WideString('ARABIC_CHARSET')); EASTEUROPE_CHARSET: HotPDF.CurrentPage.TextOut(50, Y1, 0, WideString('EASTEUROPE_CHARSET')); OEM_CHARSET: HotPDF.CurrentPage.TextOut(50, Y1, 0, WideString('OEM_CHARSET')); RUSSIAN_CHARSET: HotPDF.CurrentPage.TextOut(50, Y1, 0, WideString('RUSSIAN_CHARSET')); TURKISH_CHARSET: HotPDF.CurrentPage.TextOut(50, Y1, 0, WideString('TURKISH_CHARSET')); end; // 设置字符显示的字体 HotPDF.CurrentPage.SetFont('Arial', [], 12); HotPDF.CurrentPage.SetFontCharset(FontCharset); // 显示字符网格(最多 90 个字符,3 行 x 30 列) for i := 0 to Min(89, Last - First) do begin // 计算网格位置 if i < 30 then begin // 第一行:字符 0-29 Row := 1; CharInRow := i; XPos := 50 + CharInRow * 16; YPos := Y2; end else if i < 60 then begin // 第二行:字符 30-59,在第一行下方 20 像素 Row := 2; CharInRow := i - 30; XPos := 50 + CharInRow * 16; YPos := Y2 + 20; end else begin // 第三行:剩余字符,与标题对齐 (x=50) Row := 3; CharInRow := i - 60; XPos := 50 + CharInRow * 16; YPos := Y2 + 40; // 第一行下方 40 像素 end; // 计算字符代码 CharCode := First + i; try // 对所有字符使用 WideString 转换 HotPDF.CurrentPage.TextOut(XPos, YPos, 0, WideString(WideChar(CharCode))); except // 如果发生任何错误,显示回退字符 HotPDF.CurrentPage.TextOut(XPos, YPos, 0, WideString('?')); end; end; end; { ==================================================================== ShowTable - 绘制演示表格结构 ==================================================================== 目的: 创建一个简单的表格结构来演示文本格式化效果。 用于文本缩放、字符间距和单词间距部分。 参数: @param X: Integer - 左边缘 X 坐标 @param Y: Integer - 顶边缘 Y 坐标 结构: 创建一个 300x100 像素的表格,分为: - 上单元格:300x50 像素 - 下单元格:300x50 像素 - 垂直分隔线:距离左边缘 130 像素 所有线条都用描边操作绘制以确保可见性 } procedure ShowTable(X, Y: Integer); begin // 绘制上表格单元格(300x50 矩形) HotPDF.CurrentPage.Rectangle(X, Y, 300, 50); HotPDF.CurrentPage.Stroke; // 绘制下表格单元格(300x50 矩形,向下偏移 50 像素) HotPDF.CurrentPage.Rectangle(X, Y + 50, 300, 50); HotPDF.CurrentPage.Stroke; // 绘制穿过两个单元格的垂直分隔线 HotPDF.CurrentPage.MoveTo(X + 130, Y); // 从上单元格顶部开始 HotPDF.CurrentPage.LineTo(X + 130, Y + 100); // 绘制到下单元格底部 HotPDF.CurrentPage.Stroke; end; { ==================================================================== 主程序执行 ==================================================================== 这是演示所有 HotPDF 文本输出功能的主程序体。程序按部分结构化, 每个部分演示文本处理的特定方面: 1. 字体组 - 显示不同的字体系列和样式 2. 字符集 - 演示字符编码处理 3. 文本缩放 - 显示水平文本缩放效果 4. 字符间距 - 演示字符间距调整 5. 单词间距 - 显示单词间距修改 6. 渲染模式 - 显示不同的文本渲染效果 每个部分都包含适当的标题、导航大纲和实际示例, 在适用的情况下提供前后对比。 } begin // 初始化 HotPDF 组件 HotPDF := THotPDF.Create(nil); try // 配置 PDF 文档属性以优化文本显示 HotPDF.AutoLaunch := true; // 创建后自动打开 PDF HotPDF.FontEmbedding := true; // 启用字体嵌入以确保跨系统的一致字符显示 HotPDF.StandardFontEmulation := false; // 禁用字体仿真以防止字符映射问题 HotPDF.FileName := 'TextOut.pdf'; // 设置输出文件名 HotPDF.PageLayout := plOneColumn; // 配置查看器显示单列 // 开始 PDF 文档创建 HotPDF.BeginDoc(true); // 创建启用压缩的 PDF OutlineRoot := HotPDF.OutlineRoot; // 初始化文档大纲导航 // ==================================================================== // 第 1 部分:字体组演示 // ==================================================================== // 本部分演示不同字体系列如何与各种样式组合 //(普通、粗体、斜体、粗斜体)一起显示 // 创建增强格式的部分标题 HotPDF.CurrentPage.SetFont('Arial', [fsBold, fsUnderline], 20); HotPDF.CurrentPage.TextOut(195, 30, 0, WideString('显示字体')); // 为此部分添加导航大纲条目 OutlineRoot.AddChild('显示字体', 195, 30); // 链接到坐标 // 显示三种跨系统常用的主要字体系列 ShowFontGroup('Arial', 50); // X=50 处的无衬线字体 ShowFontGroup('Times New Roman', 180); // X=180 处的衬线字体 ShowFontGroup('Courier New', 350); // X=350 处的等宽字体 // ==================================================================== // 第 2 部分:字符集演示 // ==================================================================== // 本部分演示不同 Windows 字符编码的正确处理 // 创建部分标题 HotPDF.CurrentPage.SetFont('Arial', [fsBold, fsUnderline], 20); HotPDF.CurrentPage.TextOut(200, 170, 0, WideString('字符集')); // 为字符集创建可展开结构的大纲组 // OutlineRoot.AddChild:在 PDF 导航树中创建新的书签/大纲条目 // 参数:('标题', X坐标, Y坐标) // - '字符集':在 PDF 大纲/书签面板中显示的文本 // - 250:X坐标(水平位置),点击时将导航到此处 // - 170:Y坐标(垂直位置),点击时将导航到此处 CurrnetOutline := OutlineRoot.AddChild('字符集', 250, 170); CurrnetOutline.Opened := true; // 默认展开此大纲部分 CurrnetOutline.AddChild('ARABIC_CHARSET', 50, 225); // 阿拉伯字符集:Unicode 范围 U+0600-U+0659(90 个字符) // 范围:1536-1625(阿拉伯块,包括字母、标点、数字和变音符号) // 以 3 行每行 30 个字符的形式显示 90 个阿拉伯字符 // 用于:阿拉伯语、波斯语、乌尔都语、普什图语、库尔德语和其他从右到左的文字 // procedure ShowCharset(FontCharset: TFontCharset; First, Last: Integer; Y1, Y2: Integer); // First 是第一个字符的代码,按顺序输出到 Last 字符 // Y1 是标题 Y 坐标,Y2 是起始字符 Y 坐标 ShowCharset(ARABIC_CHARSET, 1536, 1625, 225, 250); CurrnetOutline.AddChild('EASTEUROPE_CHARSET', 50, 325); // 东欧字符集:Unicode 范围 U+00A0-U+00F9(90 个字符) // 范围:160-249(带重音字符和符号的 Latin-1 补充) // 以 3 行每行 30 个字符的形式显示 90 个扩展拉丁字符 // 用于:法语、德语、西班牙语、葡萄牙语、意大利语、荷兰语、北欧语言 // ShowCharset 仅用于演示通过字符代码显示字符集中的字符 // 对于常规文本显示,您只需直接使用 TextOut 来显示所需的字符串 ShowCharset(EASTEUROPE_CHARSET, 160, 249, 325, 350); CurrnetOutline.AddChild('OEM_CHARSET', 50, 425); // OEM 字符集:ASCII 范围 32-121(90 个字符) // 范围:32-121(可打印的 ASCII,包括空格、符号、数字和字母) // 以 3 行每行 30 个字符的形式显示 90 个 ASCII 字符 // 用于:DOS 应用程序、控制台输出、传统系统 ShowCharset(OEM_CHARSET, 32, 121, 425, 450); CurrnetOutline.AddChild('RUSSIAN_CHARSET', 50, 525); // 俄语字符集:Unicode 范围 U+0400-U+0459(90 个字符) // 范围:1024-1113(西里尔块,包括俄语、乌克兰语、保加利亚语字母) // 以 3 行每行 30 个字符的形式显示 90 个西里尔字符 // 用于:俄语、保加利亚语、塞尔维亚语(西里尔)、马其顿语、乌克兰语、白俄罗斯语 ShowCharset(RUSSIAN_CHARSET, 1024, 1113, 525, 550); CurrnetOutline.AddChild('TURKISH_CHARSET', 50, 625); // 土耳其字符集:Unicode 范围 U+00A1-U+00FF(95 个字符) // 范围:161-255(可打印的 Latin-1 补充,避免控制字符 128-160) // 以 3 行每行 30 个字符的形式显示 90 个字符(95 个可用字符中的前 90 个) // 包括土耳其特殊字符:Ç(199), ç(231), Ğ(208), ğ(240), İ(221), ı(253), Ö(214), ö(246), Ş(222), ş(254), Ü(220), ü(252) // 用于:土耳其语及其独特字符和欧洲符号 ShowCharset(TURKISH_CHARSET, 161, 255, 625, 650); // ==================================================================== // 第 3 部分:文本缩放演示 // ==================================================================== // 本部分显示水平文本缩放如何影响文本外观 // 缩放修改字符的宽度,同时保持高度 // 为高级文本格式化演示开始新页面 HotPDF.AddPage; HotPDF.CurrentPage.SetFont('Arial', [fsBold, fsUnderline], 20); OutlineRoot.AddChild('水平文本缩放', 180, 40); // 添加到主大纲导航 HotPDF.CurrentPage.TextOut(180, 40, 0, WideString('水平文本缩放')); // 创建比较表格结构 ShowTable(130, 80); // 为比较添加描述性标签 HotPDF.CurrentPage.SetFont('Times New Roman', [], 12); HotPDF.CurrentPage.TextOut(160, 100, 0, WideString('默认 100')); // 正常缩放标签 HotPDF.CurrentPage.TextOut(165, 145, 0, WideString('设置为 50')); // 压缩缩放标签 // 演示正常文本缩放(100% - 默认) HotPDF.CurrentPage.SetFont('Times New Roman', [], 24); HotPDF.CurrentPage.TextOut(280, 95, 0, WideString('单词')); // 演示压缩文本缩放(50% 宽度) HotPDF.CurrentPage.SetHorizontalScaling(50); // 将文本压缩到 50% 宽度 HotPDF.CurrentPage.TextOut(285, 140, 0, WideString('单词')); HotPDF.CurrentPage.SetHorizontalScaling(100); // 重置为正常缩放 // ==================================================================== // 第 4 部分:字符间距演示 // ==================================================================== // 本部分演示字符间距如何影响文本可读性 // 字符间距在各个字符之间添加统一的空间 HotPDF.CurrentPage.SetFont('Arial', [fsBold, fsUnderline], 20); OutlineRoot.AddChild('字符间距', 200, 220); HotPDF.CurrentPage.TextOut(200, 220, 0, WideString('字符间距')); // 创建比较表格 ShowTable(130, 260); // 添加描述性标签 HotPDF.CurrentPage.SetFont('Times New Roman', [], 12); HotPDF.CurrentPage.TextOut(162, 280, 0, WideString('默认 0')); // 正常间距标签 HotPDF.CurrentPage.TextOut(162, 330, 0, WideString('设置间距 5')); // 扩展间距标签 // 演示正常字符间距(0 - 默认) HotPDF.CurrentPage.SetFont('Times New Roman', [], 24); HotPDF.CurrentPage.TextOut(278, 275, 0, WideString('字符')); // 演示扩展字符间距(字符之间 +5 单位) HotPDF.CurrentPage.SetCharacterSpacing(5); // 在每个字符之间添加 5 个单位 HotPDF.CurrentPage.TextOut(278, 320, 0, WideString('字符')); HotPDF.CurrentPage.SetCharacterSpacing(0); // 重置为正常间距 // ==================================================================== // 第 5 部分:单词间距演示 // ==================================================================== // 本部分演示单词间距如何影响文本布局 // 单词间距专门在单词之间(在空格字符处)添加空间 HotPDF.CurrentPage.SetFont('Arial', [fsBold, fsUnderline], 20); OutlineRoot.AddChild('单词间距', 200, 380); HotPDF.CurrentPage.TextOut(200, 380, 0, WideString('单词间距')); // 创建比较表格 ShowTable(130, 420); // 添加描述性标签 HotPDF.CurrentPage.SetFont('Times New Roman', [], 12); HotPDF.CurrentPage.TextOut(162, 440, 0, WideString('默认 0')); // 正常单词间距标签 HotPDF.CurrentPage.TextOut(162, 490, 0, WideString('设置间距 10')); // 扩展单词间距标签 // 演示正常单词间距(0 - 默认) HotPDF.CurrentPage.SetFont('Times New Roman', [], 24); HotPDF.CurrentPage.TextOut(280, 430, 0, WideString('单词 间距')); // 演示扩展单词间距(单词之间 +10 单位) HotPDF.CurrentPage.SetWordSpacing(10); // 在单词之间添加 10 个单位 HotPDF.CurrentPage.TextOut(280, 480, 0, WideString('单词 间距')); HotPDF.CurrentPage.SetWordSpacing(0); // 重置为正常间距 // ==================================================================== // 第 6 部分:文本渲染模式演示 // ==================================================================== // 本部分演示 PDF 中可用的不同文本渲染效果 // 文本可以填充、描边、两者兼有或不可见(用于高级效果) HotPDF.CurrentPage.SetFont('Arial', [fsBold, fsUnderline], 20); OutlineRoot.AddChild('渲染模式', 200, 550); HotPDF.CurrentPage.TextOut(200, 550, 0, WideString('渲染模式')); // 为渲染模式比较创建复杂的表格结构 // 主表格轮廓(500x150 像素) HotPDF.CurrentPage.Rectangle(50, 600, 500, 150); HotPDF.CurrentPage.Stroke; // 创建 4 个等宽列的垂直分隔线 HotPDF.CurrentPage.MoveTo(175, 600); // 第一个分隔线 HotPDF.CurrentPage.LineTo(175, 750); HotPDF.CurrentPage.Stroke; HotPDF.CurrentPage.MoveTo(300, 600); // 第二个分隔线 HotPDF.CurrentPage.LineTo(300, 750); HotPDF.CurrentPage.Stroke; HotPDF.CurrentPage.MoveTo(425, 600); // 第三个分隔线 HotPDF.CurrentPage.LineTo(425, 750); HotPDF.CurrentPage.Stroke; // 分隔标题和内容的水平分隔线 HotPDF.CurrentPage.MoveTo(50, 665); HotPDF.CurrentPage.LineTo(550, 665); HotPDF.CurrentPage.Stroke; // 添加描述每种渲染模式的列标题 HotPDF.CurrentPage.SetFont('Arial', [], 12); HotPDF.CurrentPage.TextOut(100, 620, 0, WideString('填充')); // 填充模式 - 实心彩色文本 HotPDF.CurrentPage.TextOut(215, 620, 0, WideString('描边')); // 描边模式 - 轮廓文本 HotPDF.CurrentPage.TextOut(320, 620, 0, WideString('填充描边')); // 组合模式 - 带轮廓的填充 HotPDF.CurrentPage.TextOut(465, 620, 0, WideString('不可见')); // 不可见模式 - 用于特殊效果 // 配置颜色以进行戏剧性的渲染效果演示 HotPDF.CurrentPage.SetFont('Arial', [fsBold], 72); // 大字体以确保清晰可见 HotPDF.CurrentPage.SetRGBStrokeColor(clRed); // 红色轮廓颜色 HotPDF.CurrentPage.SetRGBFillColor(clYellow); // 黄色填充颜色 // 演示填充渲染模式 - 实心彩色文本 HotPDF.CurrentPage.SetTextRenderingMode(trFill); HotPDF.CurrentPage.TextOut(90, 670, 0, WideString('P')); // 演示描边渲染模式 - 仅轮廓文本 HotPDF.CurrentPage.SetTextRenderingMode(trStroke); HotPDF.CurrentPage.TextOut(215, 670, 0, WideString('D')); // 演示填充+描边渲染模式 - 带彩色轮廓的填充文本 HotPDF.CurrentPage.SetTextRenderingMode(trFillThenStroke); HotPDF.CurrentPage.TextOut(340, 670, 0, WideString('F')); // 演示不可见渲染模式 - 文本存在但不可见 //(用于图像上的可搜索文本或高级布局技术) HotPDF.CurrentPage.SetTextRenderingMode(trInvisible); HotPDF.CurrentPage.TextOut(475, 670, 0, WideString('X')); // 为任何后续文本重置为默认渲染模式 HotPDF.CurrentPage.SetTextRenderingMode(trFillThenStroke); // 完成并保存 PDF 文档 HotPDF.EndDoc; finally // 确保 HotPDF 组件的正确清理 HotPDF.Free; end; end.
HotPDF Delphi组件:在PDF文档中创建垂直文本布局 本综合指南演示了HotPDF组件如何让开发者轻松在PDF文档中生成Unicode垂直文本。 理解垂直排版(縦書き/세로쓰기/竖排) 垂直排版,也称为垂直书写,中文称为縱書,日文称为tategaki(縦書き),是一种起源于2000多年前古代中国的传统文本布局方法。这种书写系统从上到下、从右到左流动,创造出具有深厚文化意义的独特视觉外观。 历史和文化背景 垂直书写系统在东亚文学和文献中发挥了重要作用: 中国:传统中文文本、古典诗歌和书法主要使用垂直布局。现代简体中文主要使用横向书写,但垂直文本在艺术和仪式场合仍然常见。 日本:日语保持垂直(縦書き/tategaki)和水平(横書き/yokogaki)两种书写系统。垂直文本仍广泛用于小说、漫画、报纸和传统文档。 韩国:历史上使用垂直书写(세로쓰기),但现代韩语(한글)主要使用水平布局。垂直文本出现在传统场合和艺术应用中。 越南:传统越南文本在使用汉字(Chữ Hán)书写时使用垂直布局,但随着拉丁字母的采用,这种做法已基本消失。 垂直文本的现代应用 尽管全球趋向于水平书写,垂直文本布局在几个方面仍然相关: 出版:台湾、日本和香港的传统小说、诗集和文学作品…
HotPDF Delphi 컴포넌트: PDF 문서에서 세로쓰기 텍스트 레이아웃 생성 이 포괄적인 가이드는 HotPDF 컴포넌트를 사용하여…
HotPDF Delphiコンポーネント:PDFドキュメントでの縦書きテキストレイアウトの作成 この包括的なガイドでは、HotPDFコンポーネントを使用して、開発者がPDFドキュメントでUnicode縦書きテキストを簡単に生成する方法を実演します。 縦書き組版の理解(縦書き/세로쓰기/竖排) 縦書き組版は、日本語では縦書きまたはたてがきとも呼ばれ、2000年以上前の古代中国で生まれた伝統的なテキストレイアウト方法です。この書字体系は上から下、右から左に流れ、深い文化的意義を持つ独特の視覚的外観を作り出します。 歴史的・文化的背景 縦書きシステムは東アジアの文学と文書において重要な役割を果たしてきました: 中国:伝統的な中国語テキスト、古典詩、書道では主に縦書きレイアウトが使用されていました。現代の簡体字中国語は主に横書きを使用していますが、縦書きテキストは芸術的・儀式的な文脈で一般的です。 日本:日本語は縦書き(縦書き/たてがき)と横書き(横書き/よこがき)の両方の書字体系を維持しています。縦書きテキストは小説、漫画、新聞、伝統的な文書で広く使用されています。 韓国:歴史的には縦書き(세로쓰기)を使用していましたが、現代韓国語(한글)は主に横書きレイアウトを使用しています。縦書きテキストは伝統的な文脈や芸術的応用で見られます。 ベトナム:伝統的なベトナム語テキストは漢字(Chữ Hán)で書かれた際に縦書きレイアウトを使用していましたが、この慣行はラテン文字の採用とともにほぼ消失しました。 縦書きテキストの現代的応用 横書きへの世界的な傾向にもかかわらず、縦書きテキストレイアウトはいくつかの文脈で関連性を保っています: 出版:台湾、日本、香港の伝統的な小説、詩集、文学作品…
Отладка проблем порядка страниц PDF: Реальный кейс-стади компонента HotPDF Опубликовано losLab | Разработка PDF |…
PDF 페이지 순서 문제 디버깅: HotPDF 컴포넌트 실제 사례 연구 발행자: losLab | PDF 개발…
PDFページ順序問題のデバッグ:HotPDFコンポーネント実例研究 発行者:losLab | PDF開発 | Delphi PDFコンポーネント PDF操作は特にページ順序を扱う際に複雑になることがあります。最近、私たちはPDF文書構造とページインデックスに関する重要な洞察を明らかにした魅力的なデバッグセッションに遭遇しました。このケーススタディは、一見単純な「オフバイワン」エラーがPDF仕様の深い調査に発展し、文書構造に関する根本的な誤解を明らかにした過程を示しています。 PDFページ順序の概念 - 物理的オブジェクト順序と論理的ページ順序の関係 問題 私たちはHotPDF DelphiコンポーネントのCopyPageと呼ばれるPDFページコピーユーティリティに取り組んでいました。このプログラムはデフォルトで最初のページをコピーするはずでしたが、代わりに常に2番目のページをコピーしていました。一見すると、これは単純なインデックスバグのように見えました -…