35

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

この時点で、圧縮品質を指定せずに 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;
    });
}
4

4 に答える 4

21

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

編集上記のプログラムを 1..100 の品質値で実行し、デフォルトの品質で保存された jpg と比較することで、おそらく自分で見つけることができます (たとえば、fc.exe /B を使用)。

于 2010-10-18T12:28:57.570 に答える
6

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

于 2010-10-18T08:17:16.750 に答える
0

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

太い黒い線は、非常に単純で小さいエンコーディングになります (私の記憶が正しければ、これは主に離散コサイン変換の後で関連します)。したがって、変更された画像は、より少ないデータ (バイト) を使用して保存できます。

jpg エンコード手順

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

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

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

繰り返しますが、保存方法がわからないので、アイデアを投げかけているだけです (おそらく、それらが手がかりになるでしょう)。

于 2010-10-18T09:19:07.923 に答える
0

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

これは、後でファイルを編集する予定がある場合は、常に損失のない形式 (PNG など) で保存しようとする必要がある理由でもあります。そうしないと、複数の損失のある変換によって出力の品質に影響を与えることになります。

于 2010-10-18T13:33:38.850 に答える