PDFからサムネイル画像を生成する

Acrobatアプリケーション間通信APIを使用したアプリケーションの開発

Acrobat APIは、Acrobatアプリケーション間通信(IAC)オブジェクトを使用する2つの異なるレイヤーを持っていると考えてください:

  • Acrobatアプリケーション(AV)レイヤー。AVレイヤーでは、ドキュメントの表示方法を制御できます。たとえば、ドキュメントオブジェクトの表示はAcrobatに関連付けられたレイヤーに存在します。
  • ポータブルドキュメント(PD)レイヤー。PDレイヤーは、ページなどのドキュメント内の情報にアクセスするためのものです。PDレイヤーからは、ページの削除、移動、置換、注釈属性の変更など、PDFドキュメントの基本的な操作を行うことができます。また、PDFページを印刷したり、テキストを選択したり、操作されたテキストにアクセスしたり、サムネイルを作成または削除したりすることもできます。

私たちの目的はPDFページをサムネイル画像に変換することなので、IACにより重点を置いています。IAC APIには、PDDoc、PDPage、PDAnnotなどのオブジェクトが含まれており、ユーザーがポータブルドキュメント(PD)レイヤーを扱うことを可能にします。以下のコードサンプルは、フォルダーをスキャンし、PDFページをサムネイル画像に変換します。Acrobat SDKを使用することで、PDFメタデータを読み取り、ドキュメント内のページ数を取得することもできます。

Acrobatアプローチ

各ドキュメントのサムネイル画像を生成するために、Adobe Acrobat 7.0 SDKとMicrosoft .NET 2.0 Frameworkを使用しました。

Acrobat SDKは、Adobe Acrobatのフルバージョンと組み合わせることで、PDF情報を操作およびアクセスするために使用できるCOMオブジェクトのライブラリを公開します(残念ながら無料のAdobe ReaderはCOMインターフェースを公開していません)。これらのCOMオブジェクトをCOM Interop経由で使用して、PDFドキュメントを読み込み、最初のページを取得し、そのページをクリップボードにレンダリングします。その後、.NET Frameworkを使用して、これをビットマップにコピーし、画像をスケーリングして結合し、結果をGIFまたはPNGファイルとして保存します。

Adobe Acrobatがインストールされると、regedit.exeを使用してHKEY_CLASSES_ROOTの下にあるAcroExch.PDDocというエントリを探します。

AcroExch.PDDocエントリを示すレジストリ

todo:image_alt_text

// For complete examples and data files, visit https://github.com/aspose-pdf/Aspose.PDF-for-.NET
private static void GenerateThumbnailImagesFromPDF()
{
    // Acrobat objects
    Acrobat.CAcroPDDoc pdfDoc;
    Acrobat.CAcroPDPage pdfPage;
    Acrobat.CAcroRect pdfRect;
    Acrobat.CAcroPoint pdfPoint;

    AppSettingsReader appSettings = new AppSettingsReader();
    string pdfInputPath = appSettings.GetValue("pdfInputPath", typeof(string)).ToString();
    string pngOutputPath = appSettings.GetValue("pngOutputPath", typeof(string)).ToString();
    string templatePortraitFile = Application.StartupPath + @"\pdftemplate_portrait.gif";
    string templateLandscapeFile = Application.StartupPath + @"\pdftemplate_landscape.gif";

    // Get list of files to process from the input path
    string[] files = Directory.GetFiles(pdfInputPath, "*.pdf");

    for (int n = 0; n < files.Length; n++)
    {
        string inputFile = files[n];
        string outputFile = Path.Combine(pngOutputPath, Path.GetFileNameWithoutExtension(inputFile) + ".png");

        // Create PDF document
        pdfDoc = (Acrobat.CAcroPDDoc)Microsoft.VisualBasic.Interaction.CreateObject("AcroExch.PDDoc", "");

        if (pdfDoc.Open(inputFile) == 0)
        {
            throw new FileNotFoundException($"Unable to open PDF file: {inputFile}");
        }

        int pageCount = pdfDoc.GetNumPages();
        pdfPage = (Acrobat.CAcroPDPage)pdfDoc.AcquirePage(0);
        pdfPoint = (Acrobat.CAcroPoint)pdfPage.GetSize();

        pdfRect = (Acrobat.CAcroRect)Microsoft.VisualBasic.Interaction.CreateObject("AcroExch.Rect", "");
        pdfRect.Left = 0;
        pdfRect.right = pdfPoint.x;
        pdfRect.Top = 0;
        pdfRect.bottom = pdfPoint.y;

        pdfPage.CopyToClipboard(pdfRect, 0, 0, 100);
        IDataObject clipboardData = Clipboard.GetDataObject();

        if (clipboardData.GetDataPresent(DataFormats.Bitmap))
        {
            Bitmap pdfBitmap = (Bitmap)clipboardData.GetData(DataFormats.Bitmap);

            int thumbnailWidth = 45;
            int thumbnailHeight = 59;
            string templateFile = pdfPoint.x < pdfPoint.y ? templatePortraitFile : templateLandscapeFile;

            if (pdfPoint.x > pdfPoint.y)
            {
                // Swap width and height for landscape orientation
                (thumbnailWidth, thumbnailHeight) = (thumbnailHeight, thumbnailWidth);
            }

            Bitmap templateBitmap = new Bitmap(templateFile);
            Image pdfImage = pdfBitmap.GetThumbnailImage(thumbnailWidth, thumbnailHeight, null, IntPtr.Zero);

            Bitmap thumbnailBitmap = new Bitmap(thumbnailWidth + 7, thumbnailHeight + 7, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            templateBitmap.MakeTransparent();

            using (Graphics thumbnailGraphics = Graphics.FromImage(thumbnailBitmap))
            {
                thumbnailGraphics.DrawImage(pdfImage, 2, 2, thumbnailWidth, thumbnailHeight);
                thumbnailGraphics.DrawImage(templateBitmap, 0, 0);
                thumbnailBitmap.Save(outputFile, System.Drawing.Imaging.ImageFormat.Png);
            }

            Console.WriteLine("Generated thumbnail: {0}", outputFile);

            pdfDoc.Close();
            Marshal.ReleaseComObject(pdfPage);
            Marshal.ReleaseComObject(pdfRect);
            Marshal.ReleaseComObject(pdfDoc);
        }
    }
}

Aspose.PDF for .NETアプローチ

Aspose.PDF for .NETは、PDFドキュメントを扱うための広範なサポートを提供します。また、PDFドキュメントのページをさまざまな画像形式に変換する機能もサポートしています。上記の機能は、Aspose.PDF for .NETを使用することで簡単に実現できます。

Aspose.PDFには明確な利点があります:

  • PDFファイルを扱うためにAdobe Acrobatをシステムにインストールする必要がありません。
  • Aspose.PDF for .NETの使用は、Acrobat Automationと比較してシンプルで理解しやすいです。

PDFページをJPEGに変換する必要がある場合、Aspose.PDF.Devices名前空間には、PDFページをJPEG画像にレンダリングするためのJpegDeviceというクラスがあります。以下のコードスニペットを見てください。

// For complete examples and data files, visit https://github.com/aspose-pdf/Aspose.PDF-for-.NET
private static void GenerateThumbnailImagesFromPDF()
{
    // The path to the documents directory
    var dataDir = RunExamples.GetDataDir_AsposePdf_Images();

    // Retrieve names of all the PDF files in a particular directory
    string[] fileEntries = Directory.GetFiles(dataDir, "*.pdf");

    // Iterate through all the files entries in array
    for (int counter = 0; counter < fileEntries.Length; counter++)
    {
        // Open PDF document
        using (var document = new Aspose.Pdf.Document(fileEntries[counter]))
        {
            for (int pageCount = 1; pageCount <= document.Pages.Count; pageCount++)
            {
                using (FileStream imageStream = new FileStream(dataDir + @"\Thumbanils" + counter.ToString() + "_" + pageCount + ".jpg", FileMode.Create))
                {
                    var resolution = new Aspose.Pdf.Devices.Resolution(300);
                    var jpegDevice = new Aspose.Pdf.Devices.JpegDevice(45, 59, resolution, 100);
                    // Convert a particular page and save the image to stream
                    jpegDevice.Process(document.Pages[pageCount], imageStream);
                }
            }
        }
    }
}