jpegファイルにyimas.save()を使用していますか?
-
08-10-2019 - |
質問
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;
});
}
解決
リフレクターを使用して、それが判明しました Image.Save()
GDI+関数に要約します gdipsaveimagetofile, 、 とともに encoderParams
ヌル。ですから、質問はjpegエンコーダーがnullを取得したときに何をするかだと思います encoderParams
. 。ここでは75%が提案されていますが、強固な参照は見つかりません。
編集 おそらく、1..100の品質値でプログラムを上記で実行し、デフォルトの品質で保存されたJPGと比較することで、おそらく自分で見つけることができます(たとえば、FC.exe /bを使用)
他のヒント
IIRC、それは75%ですが、これを読んだ場所を思い出せません。
画像についてはあまり知りません。SAVEメソッドですが、脂肪ラインを追加するとJPG画像のサイズが論理的に縮小することがわかります。これは、JPGの保存方法(およびエンコード)によるものです。
厚い黒い線は非常にシンプルで小さくエンコードになります(正しく覚えている場合は、これは主に個別のコサイン変換の後に関連しています)ので、変更された画像はより少ないデータ(バイト)を使用して保存できます。
サイズの変化(ラインが追加されていない)に関して、どの画像が再開され、再利用したかはわかりません
さらに調査するために、私は品質を明示的に設定せずに開き、保存しました、そしてファイルサイズはまったく同じでした
古い(元の通常のサイズ)画像を開いて再利用した場合、デフォルトの圧縮と元の画像圧縮は同じです。新しい(4倍の大きい)画像を開いて再利用した場合、保存方法のデフォルトの圧縮は画像から派生している可能性があります(ロードされたとき)。
繰り返しますが、私は保存方法がわからないので、私はただアイデアを投げているだけです(たぶん、彼らはあなたにリードを与えるでしょう)。
<100%の品質レベルのJPEGファイルとして画像を保存すると、保存された画像にアーティファクトを導入します。これは、圧縮プロセスの副作用です。これが、100%で画像を再節約することで、実際にファイルのサイズが元のファイルを超えて増加している理由です。皮肉なことに、ビットマップにはより多くの情報があります。
これは、ファイルに編集を行う予定がある場合、常に失われていない形式(PNGなど)で保存しようとする必要がある理由でもあります。