第18回 ルビ位置を設定する

ルビ位置がすべて左端だと読みにくいので、今回は少しはまともな位置に表示されるように調整します。

本来であれば文字列の横幅を使用フォントを利用して計算、そこから表示位置を逆算するべきなのですが、PDF内で使われている文字の幅取得など考えるだけで疲れそうなので割愛し、適当に設定することにしました。

■PDFTextWriter.cs
		/// <summary>
		/// "小説家になろう"の縦書きPDF変換処理
		/// </summary>
		public bool ConvertPDFFile(string strFile, PDFTextReader srcPDF)
		{
			Close();

			int nObjIndex = 1;

			using (FileStream fs = new FileStream(strFile, FileMode.Create, FileAccess.Write))
			using (PDFRawWriter bw = new PDFRawWriter(fs))
			{
				//ヘッダー出力
				bw.WriteLine("%PDF-1.7");

				//フォント出力
				int nResourceIndex;
				{
					nResourceIndex = nObjIndex;



					//フォント埋め込み
					{
						List<KeyValuePair<string, int>> listFonts = new List<KeyValuePair<string, int>>();

						{
							string strFontObjName = "F0";
							listFonts.Add(new KeyValuePair<string, int>(strFontObjName, nObjIndex));
							WriteFont_EmbeddedUnicode(bw, ref nObjIndex, strFontObjName, @"msgothic.otf");//, "MS-Gothic", "MS Gothic");
						}

						//フォント一覧のみのリソース
						nResourceIndex = nObjIndex;
						_listnXref.Add(bw.BaseStream.Position);
						{
							bw.WriteLine("" + nObjIndex + " 0 obj");
							bw.WriteLine("<</Font");
							bw.WriteLine("<<");
							foreach (KeyValuePair<string, int> pair in listFonts)
							{
								bw.WriteLine("/" + pair.Key + " " + pair.Value + " 0 R");
							}
							bw.WriteLine(">>");
							bw.WriteLine(">>");
							bw.WriteLine("endobj");
						}
						nObjIndex++;
					}
				}

				//カタログ出力
				int nRoot = nObjIndex;
				{
					WriteCatalog(bw, ref nObjIndex, nObjIndex + 1);
				}

				//ページ出力
				{
					List<int> listPage = new List<int>();

					//全ページのインデックスを出力
					int nPagesReferenceIndex = nObjIndex;
					{
						for (int i = 0; i < srcPDF.Pages.Count; i++)
						{
							listPage.Add(nObjIndex + 1 + i * 2);	//iページ目のインデックスを渡す
						}

						WritePages(bw, ref nObjIndex, listPage);
					}


					//サイズは適当に決定
					int nWidth = 455;
					int nHeight = 615;

					//ページ出力
					for (int i = 0; i < srcPDF.Pages.Count; i++)
					{
						PDFPage page = srcPDF.Pages[i];

						WritePageContentsIndex(bw, ref nObjIndex, nPagesReferenceIndex, nResourceIndex, nObjIndex + 1, nWidth, nHeight);

						//ページテキスト出力
						{
							List<PDFText> listTexts = new List<PDFText>();

							//テキストの準備
							{
								float y = nHeight - 5;
								foreach (object item in page.Items)
								{
									if (item.GetType() != typeof(PDFText))
										continue;

									PDFText text = (PDFText)item;

									//ページ番号は左下に表示
									if ((int)(text.fY) == 56)		//"小説家になろう"PDFのページ番号y座標は56.7?
									{
										listTexts.Add(new PDFText("F0", text.fPoint, 5, 5, text.strText));
										continue;
									}

									//表紙(i == 0)と最終ページ以外はオリジナルの行間隔で表示
									if (i > 0 && i < srcPDF.Pages.Count - 1)
										y = (int)(text.fX * nHeight / 842.0);
									else
										y -= 17;		//表紙(i == 0)と最終ページは固定行間隔で表示


									float x = 10;

									//"小説家になろう"PDFのルビは文字サイズ7.0f?
									if ((int)text.fPoint == 7)
									{
										x = (float)(nWidth - text.fY * nWidth / 595.0) - 50;
										x *= 1.2f;			//フォントの幅を計算してどの位置に表示するか産出するのが面倒だから、MSゴシックと小説家になろうPDFの横幅差を1.2と決め打ち
										y += 3;
									}

									listTexts.Add(new PDFText("F0", text.fPoint, x, y, text.strText));
								}
							}


							//コンテンツの書き出し
							using (MemoryStream ms = new MemoryStream())
							using (BinaryWriter bwms = new BinaryWriter(ms))
							{
								//文字データをPDF出力用に準備
								PrepareTextContents(ms, listTexts);

								//Kindleはコンテンツ内容によって勝手にズーム表示しちゃうから、
								//すべてのページに枠線を描くことで勝手にズームしないようにする
								//座標固定で枠線を描く
								PrepareLineContents(ms, 2, 2, 2, nHeight - 2);
								PrepareLineContents(ms, 2, 2, nWidth - 2, 2);
								PrepareLineContents(ms, nWidth - 2, 2, nWidth - 2, nHeight - 2);
								PrepareLineContents(ms, 2, nHeight - 2, nWidth - 2, nHeight - 2);

								ms.Flush();

								byte[] data = ms.ToArray();

								//ページコンテンツの出力
								WriteFlateData(bw, ref nObjIndex, data);
							}
						}
					}
				}

				//クロスリファレンス/トレーラー出力
				WriteXrefTrailer(bw, nRoot);
			}

			return true;
		}

プロジェクトファイルをダウンロード


カテゴリー「PDFを処理する(C#)」 のエントリー