JPEG画像ファイルを読み込み、90度単位で回転させ、別JPEG画像ファイルとして保存したいと思っています。
GDI+(GDIPAPI, GDIPOBJ)を使うことで比較的容易に実現できるらしいと聞いたのですが、具体的にどうすればいいのか、どなたかご教授願えませんでしょうか。
過去記事でサンプルコードの掲載サイトが紹介されていましたが、現在はなくなってしまっているようで、参照できませんでした。
https://www.petitmonte.com/bbs/answers?question_id=2793
とりあえず delphi jpeg rotate lossless をキーワードに検索してみてはいかがでしょう。
通りすがり様ありがとうございます。
検索してみたところ、
Delphiについてはアプリの紹介サイトくらいしか見つかりませんでした。
他には、
http://www.ijg.org/files/
で jpegTranなるC言語らしきソースコードがありましたが、
難解すぎて私にはとても手を出せそうにありませんでした。
msdnのサイト
https://msdn.microsoft.com/en-us/library/windows/desktop/ms533845(v=vs.85).aspx
に、英語でよく分かりませんが多分目的に合致するだろうサンプルコードがありました。
GDI+を使ったシンプルなコードのようなので、おそらくこれをDelphiに翻訳するのが近道
なのだろうと思いますが、C言語系は触ったことがないので頭を抱えています。
helper functionて何でしょうか?
ところどころに「->」の記述が見られますが(image->GetWidth() 等)、Delphiではどんな記述になるのでしょうか?
ど素人丸出しで恥ずかしい限りですが、ご教示願えますでしょうか。
StackOverFlowのコピペ。
Delphi10.2.1 で確認
https://stackoverflow.com/questions/10633400/rotate-bitmap-by-real-angle
uses
GDIPAPI, GDIPOBJ, GDIPUTIL;
procedure TForm1.Button1Click(Sender: TObject);
var
encoderClsid: TGUID;
encoderParameters: TEncoderParameters;
transformation: TEncoderValue;
Image: TGPImage;
path: string;
begin
Image := TGPImage.Create('input.jpg'); //適当に
GetEncoderClsid('image/jpeg', encoderClsid);
encoderParameters.Count := 1;
encoderParameters.Parameter[0].Guid := EncoderTransformation;
encoderParameters.Parameter[0].Type_:= EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues := 1;
transformation := EncoderValueTransformRotate270;
encoderParameters.Parameter[0].Value := @transformation;
path:= extractfilepatH(Application.ExeName);
Image.Save(path + 'imageOUT.jpg', encoderClsid, @encoderParameters);
Image.Free;
end;
msdnのサンプルコードをよくわからないなりに翻訳してみました。
uses GDIPAPI, GDIPOBJ, GDIPUTIL
procedure TForm1.buttonJpegRotate;
var
GdiplusStartupInput : TGdiplusStartupInput;
GdiplusStartupOutput: TGdiplusStartupOutput;
gdiplusToken : cardinal;
encoderClsid : TGUID;
encoderParameters : TEncoderParameters;
transformation : TEncoderValue;
stat : TStatus;
begin
// Initialize GDI+.
GdiplusStartup(gdiplusToken, @GdiplusStartupInput, @GdiplusStartupOutput);
//① Get a JPEG image from the disk.
//Image* image = new Image(L"test1.jpg");
// Get the CLSID of the JPEG encoder.
GetEncoderClsid('image/jpeg', &encoderClsid);
// Rotate the image.
encoderParameters.Count := 1;
encoderParameters.Parameter[0].Guid := EncoderTransformation;
encoderParameters.Parameter[0].Type_ := EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues := 1;
transformation := EncoderValueTransformRotate90;
encoderParameters.Parameter[0].Value := @transformation;
//② Save the image.
//stat = image->Save(L"ShapesR90.jpg", &encoderClsid, &encoderParameters);
GdiplusShutdown(gdiplusToken);
end;
①②で imageクラスを使っているようなのですが、
Delphiで同じことをするにはどのようにしたらよいのでしょうか。
ところで、当該サイトの英文を翻訳してみたところ、
「画像の幅と高さが両方とも16の倍数の場合、画像の回転と保存のプロセスによって情報が失われることはありません。」
とありました。
これは単に当該コードの制限事項なのか、あるいはJpegの特性でひょっとして
画像の幅と高さが共に16の倍数の場合は、BitMapからJpegへ変換しても劣化しないということなのか
ご存じの方はいらっしゃいますでしょうか。
↑を書いてる間に ウォレスさんが答えてくださっていました。
ありがとうございます!
JpegはDCTを用いて8X8ブロック毎に圧縮していますので画像の縦および横が8の倍数とき、ブロック内のエンコード値を軸回転することで、無劣化で回転できるはずです。
16の倍数なのはなぜでしょうか。。。恐らくGDIの実装上の制約ではないかと。
「BitMapからJpegへ変換しても劣化しない」というのはかなり難しいのではないかと。。。
論理的には必ず劣化しますが、DCT後の間引きをやめる、YUVではなくRGBで圧縮する、などのオプションを設定できれば、劣化は極めてすくなくなります。無劣化になるかどうかは数学者の出番ですね。。。
あれれリンク先が間違ってるよ
https://stackoverflow.com/questions/41619757/why-is-timage-rotating-my-image
おかしいな。。。ココです。
http://delphikingdom.ru/asp/answer.asp?IDAnswer=49892
ウォレス様ありがとうございます。
やっぱりそうですよね。。。
試しにループ実行してみたところ、
16の倍数(688×880 ピクセル)の画像では 1000回実行しても劣化せず、
非倍数(673×870 ピクセル)の画像では じわじわ劣化していきました。
これ以上はおそらく無理だろうと思われますので、
未解決ではありますが、クローズとさせていただきます。
ありがとうございました。
ツイート | ![]() |