午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

PDFをjpegに変換するアプリ、jpeg品質指定と予測ファイルサイズの取得

一昨日の

gogowaten.hatenablog.com

続き

 

f:id:gogowaten:20200102111719p:plain

 

  • jpegの画質を指定できるようにした、最低10から最高の100
  • 表示するページを指定できるようにした
  • 保存されるjpegファイルサイズの予測を表示
  • 表示する画像は指定した画質相当のものにした
  • クリックで元のBitmap画像とjpeg画像を比較できるようにした

ダウンロード

PDFtoJPEG_1.1.zip

 

f:id:gogowaten:20200102112428p:plain

jpeg品質(画質)やページの変更は、更新ボタンを押すまで適用されない

予測ファイルサイズは今表示している1ページ分だけのもの

 

 

jpegの画質を指定できるようにした、最低10から最高の100

表示する画像は指定した画質相当のものにした

f:id:gogowaten:20200102114045p:plain

jpeg品質10

がさがさになるけど予測ファイルサイズは97KBと、かなり小さくなる

 

クリックで元のBitmap画像とjpeg画像を比較できるようにした

f:id:gogowaten:20200102114529p:plain

左クリック中

左クリックを押したり離したりで、どれくらい画質が劣化するのか見比べられる

 

表示するページを指定できるようにした

f:id:gogowaten:20200102115344p:plain

2ページめ

表示したいページ数に合わせてから、更新ボタンで表示される


保存されるjpegファイルサイズの予測を表示

f:id:gogowaten:20200102115918p:plain

2ページめを品質10のときの予測ファイルサイズは103KB、保存ボタンでjpeg作成

 

f:id:gogowaten:20200102120117p:plain

101KBってあるけどウィンドウズは1Kを1024で計算するからかな

103876/1024=101.44

だいたいあっている

表示してみると

f:id:gogowaten:20200102120033j:plain

こんなかんじ

 


jpeg画像の予測ファイルサイズの取得は

gogowaten.hatenablog.com

このときに使った方法の

Streamに一時保存してから読み込む方法

  1. //Streamに一時保存方式、BmpBitmapのエンコーダーデコーダーを使う
  2. private BitmapSource GetClipboardBitmapEncDec()
  3. {
  4. BitmapSource source = Clipboard.GetImage();
  5. if (source == null)
  6. {
  7. return null;
  8. }
  9. var encoder = new BmpBitmapEncoder();
  10. encoder.Frames.Add(BitmapFrame.Create(source));
  11. using (var stream = new System.IO.MemoryStream())
  12. {
  13. encoder.Save(stream);
  14. stream.Seek(0, System.IO.SeekOrigin.Begin);
  15. var decoder = new BmpBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
  16. source = decoder.Frames[0];
  17. }
  18. return source;
  19. }

これを使って表示すると

 BitmapのEncoderとDecoderを使う方法から

 

//プレビュー用のjpeg画像作成は
//BitmapSourceをEncoderでstreamにSaveして、それをDecoderで取得?する
private BitmapSource MakeJpegPreviewImage(BitmapSource source, int quality)
{
    if (source == null) { return null; }
    
    var encoder = new JpegBitmapEncoder();
    JpegBitmapDecoder decoder;
    encoder.QualityLevel = quality;
    encoder.Frames.Add(BitmapFrame.Create(source));
    using (var stream = new MemoryStream())
    {
        //jpeg画像をSaveしてから取り出す
        encoder.Save(stream);
        stream.Seek(0, SeekOrigin.Begin);
        decoder = new JpegBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
        //このときのstreamのlengthがjpeg画像のサイズになるみたいなので取得、表示
        var fileSize = stream.Length / 1000;
        if (fileSize > 1000)
        {
            tbFileSize.Text = $"{(stream.Length / 1000 / 1000.0).ToString(".0")} MB";
        }
        else
        {
            tbFileSize.Text = $"{stream.Length / 1000} KB";
        }
    }
    return decoder.Frames[0];
}

EncoderでstreamにSaveしたときのstreamの長さ(length)が、そのままファイルサイズになるみたいだったので、これを表示するようにしただけ、1000KBを超えたらMBで表示するようにした

streamって長さがあるのね、長さってことは連なっている感じなんかなあ

 

 

保存部分の修正

前回は

private async Task SaveSub2(PdfDocument pdfDocument, double dpi, string directory, string fileName, int pageIndex, int quality, int keta)
{
    using (PdfPage page = pdfDocument.GetPage((uint)pageIndex))
    {
        //指定されたdpiを元に画像サイズ指定、四捨五入              
        var options = new PdfPageRenderOptions();
        options.DestinationHeight = (uint)Math.Round(page.Size.Height * (dpi / 96.0), MidpointRounding.AwayFromZero);
        using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream())
        {
            await page.RenderToStreamAsync(stream, options);
            BitmapImage image = new BitmapImage();
            image.BeginInit();
            image.CacheOption = BitmapCacheOption.OnLoad;
            image.StreamSource = stream.AsStream();
            image.EndInit();
            JpegBitmapEncoder encoder = new JpegBitmapEncoder();
            encoder.QualityLevel = quality;
            encoder.Frames.Add(BitmapFrame.Create(image));
            pageIndex++;
            string renban = pageIndex.ToString("d" + keta);
            using (var fileStream = new FileStream(
                System.IO.Path.Combine(directory, fileName) + "_" + renban + ".jpg", FileMode.Create, FileAccess.Write))
            {
                encoder.Save(fileStream);
            }
        }
    }
}

この太字のところが意味なかった

Encoderに渡すBitmapFrameを作成するのに、streamから作成したBitmapImageを使っていたけど、streamから直接BitmapFrameを作成するようにした

前回:stream→BitmapImage→BitmapFrame

 

今回:stream→BitmapFrame

/// <summary>
/// jpeg画像で保存
/// </summary>
/// <param name="pdfDocument">読み込んだPDF、Windows.Data.Pdf.PdfDocument</param>
/// <param name="dpi">PDFファイルを読み込む時のDPI</param>
/// <param name="directory">保存フォルダ</param>
/// <param name="fileName">保存名</param>
/// <param name="pageIndex">保存するPDFのページ</param>
/// <param name="quality">jpegの品質min0、max100</param>
/// <param name="keta">保存名につける連番0埋めの桁数</param>
/// <returns></returns>
private async Task SaveSub2(PdfDocument pdfDocument, double dpi, string directory, string fileName, int pageIndex, int quality, int keta)
{
    using (PdfPage page = pdfDocument.GetPage((uint)pageIndex))
    {
        //指定されたdpiを元に画像サイズ指定、四捨五入              
        var options = new PdfPageRenderOptions();
        options.DestinationHeight = (uint)Math.Round(page.Size.Height * (dpi / 96.0), MidpointRounding.AwayFromZero);

        using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream())
        {
            await page.RenderToStreamAsync(stream, options);//画像に変換したのはstreamへ

            JpegBitmapEncoder encoder = new JpegBitmapEncoder();
            encoder.QualityLevel = quality;

            //streamから直接BitmapFrameを作成することができた                   
            encoder.Frames.Add(BitmapFrame.Create(stream.AsStream()));
            //連番ファイル名を作成して保存
            pageIndex++;
            string renban = pageIndex.ToString("d" + keta);
            using (var fileStream = new FileStream(
                System.IO.Path.Combine(directory, fileName) + "_" + renban + ".jpg", FileMode.Create, FileAccess.Write))
            {
                encoder.Save(fileStream);
            }
        }
    }

}

短くなった

 

今回のでいろいろ使い勝手が良くなって、あとはマルチスレッドに対応できればなあ

 

 関連記事

続きは翌日

gogowaten.hatenablog.com