일본어 소설을 페이지에 펼쳐보면 가장 먼저 눈에 띄는 것은 텍스트가 가로줄을 가로지르는 것이 아니라 단을 따라 아래로 흐르며, 단은 페이지의 오른쪽 가장자리에서 왼쪽으로 진행된다는 점입니다. 세로 읽기에 익숙한 독자들은 가로 텍스트가 왠지 낯설고 차갑게 느껴진다고 합니다. 엔지니어링 측면에서의 문제는 거의 모든 디지털 텍스트 시스템과 마찬가지로 PDF가 왼쪽에서 오른쪽으로 진행하는 수평 기준선(baseline)을 중심으로 구축되었으며, 콘텐츠 스트림(content stream)에는 "이 단락을 아래로 작성하라"는 개념이 없다는 것입니다. 따라서 Delphi 애플리케이션이 대만, 일본 또는 한국 독자를 위해 인증서, 시, 간판 또는 전통적 형식의 법률 문서를 작성해야 하는 경우, 레이아웃을 직접 한 글자씩 아래로, 한 단씩 왼쪽으로 수동 조립해야 합니다
HotPDF는 문자별 관리를 대신 수행하는 스위치를 제공합니다. 설정한 글꼴에는 IsVertical 플래그가 포함되어 있으며, 이 기능을 켜면 한 번의 TextOut 호출로 전체 문자열을 기준선(baseline)을 따라 출력하는 대신 수직 열에 쌓아줍니다. 열의 배치, 우측에서 좌측으로 진행하는 순서, 그리고 보이지 않지만 매우 중요한 글리프 대체(glyph substitution)에 대한 내용은 이 페이지의 나머지 부분에서 다루겠습니다

스위치는 SetFont에 위치합니다
세로 레이아웃은 페이지나 문서의 속성이 아닙니다. 사용자가 텍스트를 그리는 글꼴의 속성이며, SetFont의 다섯 번째 인수를 통해 해당 기능을 켭니다
// SetFont(FontName, FontStyle, Size, FontCharset, IsVertical)
// The 5th argument flips the current font into vertical mode.
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, DEFAULT_CHARSET, False); // horizontal
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, DEFAULT_CHARSET, True); // vertical
플래그가 글꼴에 포함되어 있으므로, 마지막 인수를 다르게 하여 SetFont를 다시 호출하기만 하면 가로 쓰기와 세로 쓰기를 간단히 전환할 수 있습니다. 한 페이지 내에서 상단에는 가로 제목을, 그 아래에는 세로 본문을 배치할 수 있으며 HotPDF는 페이지 단위가 아닌 글꼴 개체 단위로 두 모드를 구분하여 유지합니다. 이것이 사용자가 어떠한 특별한 모드 처리 없이도 혼합 레이아웃을 구성할 수 있는 이유입니다. 세로 SetFont를 사용한 후의 모든 TextOut은 텍스트를 아래로 쌓아 올리고, 가로 SetFont를 사용한 후의 모든 TextOut은 텍스트를 기준선(baseline)을 따라 출력하며, 가장 최근에 호출된 SetFont 설정이 우선적으로 적용됩니다
네 번째 인수는 Windows 문자 집합으로, 가로 호출 시 취하는 인수와 동일합니다. DEFAULT_CHARSET를 전달하면 시스템이 문자열별로 글리프를 확인할 수 있는데, 세로 문서에서는 종종 여러 문자가 섞이므로 이 기능이 중요합니다. 글꼴과 관련된 그 외 모든 사항은 여전히 적용됩니다. 글꼴은 빌드 컴퓨터에 설치되어 있어야 하며, Arial Unicode MS 글꼴이 없는 리더에서도 동일한 CJK 글리프가 렌더링되도록 하려면 항상 FontEmbedding := True로 설정해야 합니다
한 번의 TextOut 호출은 하나의 열입니다
세로 글꼴이 활성화된 상태에서는 TextOut을 호출해도 지정된 지점부터 문자열이 가로로 퍼지지 않습니다. 첫 번째 문자를 맨 위에 심고 나머지 문자를 똑바로 아래로 나아가며 출력하는데, 각 글리프마다 글꼴의 줄 높이(line height)만큼 전진합니다. 전달한 X값은 열의 위치를 고정하고, 전달한 Y값은 열 상단의 시작 지점을 고정합니다. 따라서 실제 단락을 배치하려면 CJK 텍스트의 열이 우측에서 좌측으로 읽히기 때문에 열당 하나의 TextOut을 발행하고 호출 사이의 X값을 좌측으로 이동해야 합니다
var
Pdf: THotPDF;
const
ColTop = 760; // y of the first glyph in every column (points)
ColGap = 28; // horizontal distance between columns
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'VerticalText.pdf';
Pdf.FontEmbedding := True; // embed the CJK face for portable rendering
Pdf.BeginDoc;
Pdf.CurrentPage.Size := psA4;
// A horizontal heading first, in the ordinary writing mode.
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 16, DEFAULT_CHARSET, False);
Pdf.CurrentPage.TextOut(60, 800, 0, 'Tang poem, vertical layout');
// Switch the font into vertical mode; every TextOut below now stacks.
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 18, DEFAULT_CHARSET, True);
// Columns advance right to left, so X decreases with each call.
Pdf.CurrentPage.TextOut(520, ColTop, 0, '床前明月光');
Pdf.CurrentPage.TextOut(520 - ColGap, ColTop, 0, '疑是地上霜');
Pdf.CurrentPage.TextOut(520 - ColGap * 2, ColTop, 0, '舉頭望明月');
Pdf.CurrentPage.TextOut(520 - ColGap * 3, ColTop, 0, '低頭思故鄉');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
시는 원래 읽혀야 할 방식대로 읽힙니다. 즉 가장 오른쪽 단을 먼저 위에서 아래로 읽은 다음, 눈이 왼쪽의 다음 단으로 이동합니다. 문자열 자체에는 이러한 순서를 설정(encode)하는 기능이 전혀 들어있지 않습니다. 이러한 순서 설정은 호출할 때마다 줄어드는 X 좌표값을 통해 적용됩니다. 방향을 거꾸로 설정하면 시가 반대로 출력되며, 이는 가로 레이아웃을 세로 레이아웃으로 변경(porting)할 때 발생하는 가장 흔한 실수 중 하나입니다
좌표: 페이지 아래로, 오른쪽에서 왼쪽으로
서로 반대 방향으로 당기는 두 개의 축이 작용하므로 정확하게 이해할 필요가 있습니다. HotPDF는 페이지의 왼쪽 하단 모서리부터 Y값이 위로 증가하는 방식을 사용하여 포인트 단위로 측정합니다. 따라서 수직 단은 Y값이 높은 곳(페이지의 맨 위 근처)에서 시작하며 HotPDF가 각 문자에 대해 한 줄 높이만큼 Y값을 빼면서 차례로 문자를 내리며 출력합니다. 사용자는 각 단마다 시작 Y값을 한 번만 설정하면 되고 아래로 내리는 작업은 컴포넌트가 처리합니다
가로 축은 사용자가 직접 조작해야 하는 축입니다. 각 열(column)은 고유한 X값을 가지며, 읽는 순서가 우측에서 좌측이므로 이어지는 열들은 점점 더 작은 X값으로 이동합니다. 가장 오른쪽 단의 X값을 선택한 다음, ColGap이 있는 예제에서와 같이 호출이 이어질 때마다 고정된 단 간격을 빼는 것이 합리적입니다. 간격은 자유롭게 선택할 수 있지만, 너무 좁으면 인접한 열과 겹치고 너무 넓으면 글이 흩어져 보입니다. 12에서 18포인트의 본문 텍스트의 경우 글꼴 크기보다 약간 큰 간격이 편안하게 읽힙니다
모양이 변경되어야 하는 글리프
일부 문자들은 단순히 가로 형태를 회전시킨 것으로는 부족하여 텍스트가 세로로 바뀔 때 반드시 다른 문자로 대체되어야 합니다. HotPDF가 여러분을 대신해 처리하는 한 가지 문자는 커피(コーヒー)와 같은 가타카나 단어에 나타나는 장모음 바인 일본어 장음 부호 ー(U+30FC)입니다. 가로로 그리면 기준선(baseline) 위의 짧은 대시(dash) 형태가 됩니다. 만약 똑같은 글리프를 열(column)로 쌓게 된다면 단을 평평하게 가로지르게 될 텐데 이는 잘못된 형태입니다. 세로 일본어에서 이 표시는 텍스트 사이를 연결하는 세로줄 모양(vertical stroke)이 됩니다. HotPDF는 수직 경로에서 U+30FC를 감지하고 수직 막대(U+007C)로 렌더링하므로 사용자가 아무런 작업을 하지 않아도 장모음 부호가 올바른 방향을 가리키도록 설정합니다
이러한 단일 대체만으로도 대부분의 초보적인 구현에서 발생하는 문제들을 해결할 수 있지만, 일반적인 문제가 더 깊이 존재하는 부분을 알아두는 것도 가치가 있습니다. 완벽한 세로 타이포그래피는 또한 라틴 문자 및 서양식 구두점을 90도로 회전시키고, 작은 가나(kana) 문자를 이동시키며 괄호 및 쉼표 등을 세로 형태에 맞게 재배치합니다. 그리고 이에 대한 완전한 구현은 고정된 규칙이 아닌 글꼴의 OpenType 세로 기능(vertical features)에 존재합니다. HotPDF는 글꼴에 이러한 기능이 포함되어 있을 때 이를 활용할 수 있습니다. 세로 대체 기능(vert 및 vrt2 GSUB 기능)과 세로 커닝(vkrn 및 vpal GPOS 조회사전)은 옵트인(opt-in) 방식으로 활성화된 글꼴에 실제로 해당 기능이 정의되어 있을 때만 수직 경로를 따라 적용됩니다. Arial Unicode MS처럼 넓은 적용 범위를 가진 단일 서체의 혼합 CJK 텍스트의 경우, 내장된 U+30FC 처리와 일정한 줄 높이 간격만으로도 정확하고 읽기 쉬운 단(column)을 생성할 수 있습니다. OpenType 기능은 미세한 세로 설정을 위해 디자인된 글꼴을 사용하면서, 기본 가나 문자의 위치와 글리프(inter-glyph) 간격을 원하는 경우에 특히 중요해집니다
한 페이지에 문자 및 방향 혼합하기
실제 문서는 순수하게 한 가지로만 작성되는 경우가 드뭅니다. 일본어로 세로 쓰기가 적용된 페이지에 가로로 된 영어 캡션이 있거나 페이지 하단에 페이지 번호가 있거나 일본어 옆에 한국어 단락이 세로로 배치되어 있을 수도 있습니다. 세로 플래그(vertical flag)는 글꼴 수준의 스위치이므로 전체 페이지 상태를 따로 관리할 필요 없이 SetFont를 교대로 호출하여 이들을 구성할 수 있습니다. 가로 글꼴을 설정하여 런닝 헤더(running header)와 폴리오(folio)를 쓰고, 세로 글꼴을 설정하여 단을 배치하며 바닥글을 위해 가로 글꼴을 다시 설정합니다. 각 영역은 가장 최근의 SetFont 모드를 선택하므로 방향을 변경할 때마다 해당 설정만 호출해주면 됩니다
문자가 혼합될 때 고려해야 할 한 가지 세부 사항: 한·중·일 표의 문자(ideograph)는 정사각형에 가깝고 일정한 간격으로 쌓아지지만, 수직 열(column)에 임베디드된 라틴 텍스트 출력(run)은 이렇게 일정한 간격을 갖지 못합니다. 기본적으로 세로로 된 텍스트 안에 몇 개의 라틴 단어가 필요한 경우 이들을 단을 따라 내려가도록 회전시킬지 아니면 짧은 가로 삽입형으로 똑바로 세워 배치할지 신중하게 결정하고 표의 문자(ideograph)를 의미하는 세로 간격을 따르지 않고 자체 TextOut으로 해당 문자열 조각의 위치를 조정하세요. 이러한 혼합 출력을 자체적인 배치 문제로 취급하면 단의 리듬(rhythm)을 원래대로 유지할 수 있습니다
샘플에서 제품 제작 환경으로
구성 요소들은 작고 예측 가능하게 결합됩니다. SetFont에서 수직 플래그(vertical flag)를 켜고, 고정된 최상단 Y값에서 열(column)당 TextOut을 하나씩 발행한 다음 호출 간에 X값을 줄여 단이 오른쪽에서 왼쪽으로 읽히도록 설정합니다. 글꼴을 임베디드하여 CJK 글리프가 독자의 장비에서도 유지되도록 하고 컴포넌트가 U+30FC 장모음 마크와 (글꼴이 지원하는 경우) OpenType 세로 기능(vertical features)을 처리할 수 있도록 합니다. 이 시점에서 레이아웃을 실제 제작 환경에 적용하는 과정은 대개 산술적인 계산과 관련이 있습니다. 측정된 텍스트 블록의 너비에서 열의 X 위치를 도출하고, 긴 단락을 페이지 높이에 맞는 여러 열로 나누며, 가로형 머리글(headers)과 폴리오(folios)를 위한 공간을 확보하는 등의 작업이 이에 해당합니다
가로 TextOut 규칙 및 유니코드 글꼴 등록을 포함하여 이를 기반으로 하는 광범위한 텍스트 및 글꼴 표면에 대해서는 다국어 Hello World 예제 및 TextOut 샘플을 참조하십시오. 여기에 나와있는 SetFont 수직 스위치 및 TextOut 호출은 Delphi 및 C++Builder용 HotPDF 컴포넌트의 일부입니다