web-dev-qa-db-ja.com

Image.Save()はjpegファイルにどの品質レベルを使用しますか?

Jpgファイルを読み込んで向きを変えて品質100で保存したとき、本当に驚きました。サイズは元のサイズのほぼ4倍でした。さらに調査するために、品質を明示的に設定せずに開いて保存したところ、ファイルサイズはまったく同じでした。これは何も変更されていないので、まったく同じビットをファイルに書き込むだけであると考えました。この仮定をテストするために、画像を斜めに横切って太い線を描き、品質を設定せずに再度保存しました(今回は、「ダーティ」になるため、ファイルが跳ね上がると予想していました)が、約10 KB減少しました。

この時点では、圧縮品質を指定せずにImage.Save()を呼び出すだけで何が起こっているのか、本当に理解できません。品質が100に設定されている(基本的には圧縮されていない)場合、品質がまだ設定されていないときにファイルサイズが元のサイズに(画像が変更された後)非常に近いのはなぜですか。

Image.Save()のドキュメントを読みましたが、舞台裏で何が起こっているかについての詳細が欠けています。私はどのように考えてもグーグル検索しましたが、表示されている内容を説明する追加情報を見つけることができません。私は31時間ずっと働いていたので、明らかな何かが欠けているかもしれません; 0)

これは、画像をデータベースに保存するためのいくつかのライブラリメソッドを実装しているときに発生しました。 「SaveImage」メソッドをオーバーロードして明示的に品質を設定できるようにし、テスト中に、上で説明した奇妙な(私にとって)結果に遭遇しました。あなたが落とすことができるどんな光でもありがたいです。

ここに私が経験していることを説明するいくつかのコードがあります:

string filename = @"C:\temp\image testing\hh.jpg";
string destPath = @"C:\temp\image testing\";

using(Image image = Image.FromFile(filename))
{
    ImageCodecInfo codecInfo = ImageUtils.GetEncoderInfo(ImageFormat.Jpeg);

    //  Set the quality
    EncoderParameters parameters = new EncoderParameters(1);

    // Quality: 10
    parameters.Param[0] = new EncoderParameter(
        System.Drawing.Imaging.Encoder.Quality, 10L);
    image.Save(destPath + "10.jpg", codecInfo, parameters);

    // Quality: 75
    parameters.Param[0] = new EncoderParameter(
        System.Drawing.Imaging.Encoder.Quality, 75L);
    image.Save(destPath + "75.jpg", codecInfo, parameters);

    // Quality: 100
    parameters.Param[0] = new EncoderParameter(
        System.Drawing.Imaging.Encoder.Quality, 100L);
    image.Save(destPath + "100.jpg", codecInfo, parameters);

    //  default
    image.Save(destPath + "default.jpg", ImageFormat.Jpeg);

    //  Big line across image
    using (Graphics g = Graphics.FromImage(image))
    {
        using(Pen pen = new Pen(Color.Red, 50F))
        {
            g.DrawLine(pen, 0, 0, image.Width, image.Height);
        }
    }

    image.Save(destPath + "big red line.jpg", ImageFormat.Jpeg);
}

public static ImageCodecInfo GetEncoderInfo(ImageFormat format)
{
    return ImageCodecInfo.GetImageEncoders().ToList().Find(delegate(ImageCodecInfo codec)
    {
        return codec.FormatID == format.Guid;
    });
}
33
scubasteve

リフレクターを使用すると、Image.Save()はGDI +関数 GdipSaveImageToFile に要約され、encoderParams NULLになります。したがって、問題は、JPEGエンコーダーがnull encoderParamsを取得したときに何を行うかだと思います。ここでは75%が提案されていますが、確かな参照は見つかりません。

[〜#〜] edit [〜#〜]上記のプログラムを実行して品質値1..100とそれらをデフォルトの品質で保存されたjpgと比較する(たとえば、fc.exe/Bを使用)

19
Ohad Schneider

IIRC、75%ですが、どこで読んだか思い出せません。

5
leppie

Image.Saveメソッドについてはあまり詳しくありませんが、太い線を追加すると、jpg画像のサイズが論理的に縮小されることはわかります。これは、jpgの保存(およびエンコード)方法が原因です。

黒い太い線は非常にシンプルで小さなエンコーディングを作成します(私が正しく覚えている場合、これはほとんどが離散コサイン変換の後で発生します)。したがって、変更された画像は少ないデータ(バイト)を使用して保存できます。

jpgエンコードステップ

サイズの変更(追加された行なし)について、どの画像を再度開いて保存したかわかりません

さらに調査するために、品質を明示的に設定せずに開いて保存しましたが、ファイルサイズはまったく同じでした

古い(元の通常サイズ)画像を開いて再保存した場合、デフォルトの圧縮と元の画像の圧縮は同じになる可能性があります。新しい(4X大きい)画像を開いて再保存した場合、saveメソッドのデフォルトの圧縮は(ロード時のように)画像から派生している可能性があります。

繰り返しますが、私はsaveメソッドがわからないので、アイデアを投げ出しているだけです(たぶん、それらがあなたをリードしてくれるでしょう)。

0
Neowizard

画像を<100%の品質レベルでJPEGファイルとして保存すると、保存された画像にアーティファクトが導入されます。これは、圧縮プロセスの副作用です。これが、画像を100%で再保存すると、実際にファイルのサイズが元のサイズを超えて増加する理由です-皮肉なことに、ビットマップにはより多くの情報があります。

このため、後でファイルを編集する場合は、常に非可逆形式(PNGなど)での保存を試みる必要があります。そうしないと、複数の非可逆変換によって出力の品質に影響が出ます。

0
Dave R.