クリップボードからコピーした画像データを拡張子pngで保存してそれを読み込むと
「無効なヘッダが含まれています 破損してるか・・・」
と出てきて読めません
画像編集ソフトから出力するpngファイルは読めて自分で保存したpngが読めないようです。
しかし保存したpngファイルは画像編集ソフトで読めます。
色々 試行錯誤してみると
TPngImageへAssignして保存すると大丈夫みたいなのですが
TImageから保存すると ビットマップ形式のpngファイルになっているのでしょうか?
Windows10 + DelphiXE5
uses PNGImage,Clipbrd;
これは NG
Image1.Picture.Bitmap.Assign(Clipboard);
Image1.Picture.SaveToFile('a.png');
Image1.Picture.LoadFromFile('a.png');
これは OK
Image1.Picture.Bitmap.Assign(Clipboard);
Image1.Picture.SaveToFile('b.bmp');
Image1.Picture.LoadFromFile('b.bmp');
これなら OK
var
p : TPngImage;
begin
Image1.Picture.Bitmap.Assign(Clipboard);
p := TPngImage.Create;
p.Assign(Image1.Picture.Bitmap);
p.SaveToFile('c.png');
Image1.Picture.LoadFromFile('c.png');
最近 Delphi を始めた方ですね 😁
// TBitmap に Assign するので TPicture に格納されるのは TBitmap 形式
Image1.Picture.Bitmap.Assign(Clipboard);
// TPicture には TBitmpa 形式の画像がある
// 拡張子を変えただけではその拡張子に相当する形式にはならない
Image1.Picture.SaveToFile('a.png');
// TPicture.LoadFromFile は拡張子で形式を判定する
// しかし,実際に読み込んだのは TBitmap のファイルなので処理できない
// したがってエラー
Image1.Picture.LoadFromFile('a.png');
PNG 画像をクリップボードにコピーすると,
CF_BITMAP, CF_DIB, CF_DIBV5 形式のビットマップもクリップボードに格納されます.
自分でクリップボードへのコピー形式を設定すれば,PNG だけをコピーできます.
> PNG 画像をクリップボードにコピーすると,
> CF_BITMAP, CF_DIB, CF_DIBV5 形式のビットマップもクリップボードに格納されます.
画像を扱うアプリの中には (特に昔のアプリ)
クリップボードから PNG 形式の画像を取得できないのがあります.
そんなアプリでも,この仕様によって,ビットマップ画像としては取得できます.
レスありがとうございます。
>最近 Delphi を始めた方ですね
あ、いえ もう20年以上前からのユーザーです・・・
あの頃 PNGはおろか GifとかJpegも扱えなかったので
おそらくこの分野だけ初心者の知識しか無いかもしれません。
TBitmapを独自拡張して高速描画とかはもう使われなくなってんですねぇ
確認したところ「CF_BITMAP」形式で送られてきていました。
PNGで送られて来ていないうえに
それを不適切な拡張子で保存したのでエラーになるのは当然ですね。
勉強になりました。
CF_BITMAP形式でしか取得出来ないものもあるので
ビットマップとしてTImageに受け取った後
TPngImageにAssignして PNG形式で保存する形式で進めたいと思います。
ありがとうございました。
今回の現象は,多分,冷静に考えると分かった内容だと思います.
でも一度疑問に思うと
「えっ ? 何故」
とはまってしまうんですよね.
私もよくあります.
ところでご存じだとは思いますが,
ついでに,他の方の参考になるかも知れないので・・・
ファイルの先頭にマジックナンバー と呼ばれる識別値があるファイルがあります
この値を利用して画像ファイルの形式を判定できることがあります.
以下はビットマップと PNG 画像ファイルの例です.
この他にも MIME タイプという値で判定する方法もあります.
//=============================================================================
// 画像ファイルが BMP 形式かを調べる
// BMP の場合は先頭のの 2 バイトが BM という文字
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LStream : TMemoryStream;
LBiffer : array [0.19] of AnsiChar;
begin
LStream := TMemoryStream.Create;
try
LStream.LoadFromFile('503.bmp');
FillChar(LBiffer, SizeOf(LBiffer), #0);
LStream.Position := 0;
LStream.Read(LBiffer[0], 2);
if SameText('BM', LBiffer) then begin
ShowMessage(LBiffer);
end;
finally
FreeAndNil(LStream);
end;
end;
//=============================================================================
// 画像ファイルが PNG 形式かを調べる
// PNG の場合は 2 バイト目から PNG という文字になっている
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LStream : TMemoryStream;
LBiffer : array [0..19] of AnsiChar;
begin
Memo1.Lines.Clear;
LStream := TMemoryStream.Create;
try
LStream.LoadFromFile('503.png');
FillChar(LBiffer, SizeOf(LBiffer), #0);
LStream.Position := 1;
LStream.Read(LBiffer[0], 3);
if SameText('PNG', LBiffer) then begin
ShowMessage(LBiffer);
end;
finally
FreeAndNil(LStream);
end;
end;
大変参考になります。
今回ファイルの判断方法として
CreateOleObject('Shell.Application');にて
GetDetailsOf(n,m);
を使用していたのですが
その中のファイルの種類を取得すると PNGが返って来ていたのも原因でした。
こういう所でつまづくと
気になって開発が止まってしまいますね
> CreateOleObject('Shell.Application');
おっ,使っていますね.これ便利です.
ツイート | ![]() |