こんにちは
GhostScriptのgsdll32.dllを使って、pdfから画像を取り出したいと思って、次のリンクなどを参考にしています。
http://stackoverflow.com/questions/14764652/calling-external-dll-with-array-of-pchar-as-parameter-in-xe
uses gsapi;
procedure PDF2PNG(input : AnsiString; output: AnsiString);
var
ExitCode:integer;
instance: Pointer;
Arg: array of PAnsiChar;
begin
ExitCode := gsapi_new_instance(instance, nil);
if ExitCode < 0 then
raise Exception.Create('Impossible to open an instance of ghostscript. Error ExitCode: '+IntToStr(ExitCode));
try
SetLength(Arg, 11);
Arg[0] := PAnsiChar('ps2pdf');
Arg[1] := PAnsiChar('-dNOPAUSE');
Arg[2] := PAnsiChar('-dBATCH');
Arg[3] := PAnsiChar('-dSAFER');
Arg[4] := PAnsiChar('-sDEVICE=pngalpha');
Arg[5] := PAnsiChar('-r300');
Arg[6] := PAnsiChar('-dTextAlphaBits=4');
Arg[7] := PAnsiChar('-sOutputFile='+output+' Page-%02d.png');
Arg[8] := PAnsiChar('-c');
Arg[9] := PAnsiChar('.setpdfwrite');
Arg[10]:= PAnsiChar('-f'+ input);
ExitCode := gsapi_init_with_args(instance, Length(Arg), @Arg[0]);
if ExitCode < 0 then raise Exception.Create('ERROR: init_args: '+IntToStr(ExitCode));
gsapi_exit(instance);
finally
gsapi_delete_instance(instance);
end;
end;
procedure TForm1.Button4Click(Sender: TObject);
var
PdfPath:string;
begin
PdfPath:= 'C:\tmp\';
pdf2tif(PdfPath+'test.pdf',PdfPath+'test.png');
end;
「Impossible to open an instance of ghostscript. Error code: -100.」が出て出力できません。
どこが悪いのかどなたか、教えてください。
よろしくお願いします。
Ghostscript 9.20
https://ghostscript.com/download/
Win10とDelphi 10 Seattleを使っています。
gsapi_new_instanceはどのような定義ですか?
gsapi_new_instance(@instance,nil);
のような気がしますが。
通りすがりさん、早速ありがとうございます。
>gsapi_new_instanceはどのような定義ですか?
uses している gsapi.pas の
function gsapi_init_with_args(pinstance:Pgs_main_instance;argc:integer;argv:PPAnsiChar):integer; stdcall;
を呼んで、
implementation 下は、
function gsapi_init_with_args; stdcall; external gsdll32 name 'gsapi_init_with_args';
となっています。
gsapi.pasは、
最初に貼った、http://stackoverflow.com/questions/14764652/calling-external-dll-with-array-of-pchar-as-parameter-in-xe
の中ほどの
Update: here is a corrected version of the gsapi.pas unit that should work in both Delphi versions:
以下のものです。
「delphi gsapi gsdll32.dll」等で検索すると似たような、サンプルがいくつもあり、コピペして見ていますが、
同じようなエラーになります。コピペばかりで根本が分かっていないものですから・・・
お世話になります。
>gsapi_new_instance(@instance,nil);
>のような気がしますが。
"@"を入れてみましたら、
「Impossible to open an instance of ghostscript. Error code: -100.」が
「ERROR: init_args: -100.」に変わりました。
うまくいったようですね。つまりコピペではなくきちんとコードを理解して記述すれば動くようになるということです。
あなたが読む気のないコードをこちらも読む気はないので当てずっぽうですが、コンパイルエラーが出ないのに
正しく動かない理由は、DLLで『ポインタのポインタ』を要求しているのに、あなたのコードは単なるポインタを
渡しているから、のような気がします。コンパイラは単なるポインタの受け渡しをすればよいと理解してそのような
バイナリを出力しますが、実際に動作させるとDLLは渡されたアドレスから逆参照を2回行って、不正な内容が
存在しているのでエラーを返している、ということではないかと。
>コンパイルエラーが出ないのに正しく動かない理由は、
>DLLで『ポインタのポインタ』を要求しているのに、あなたのコードは単なるポインタを渡しているから、
>不正な内容が存在しているのでエラーを返している、ということではないかと。
>うまくいったようですね。
せっかく、遅い時間にもかかわらず助言をいただいたのに、理解できずにすいません。
DLLに送った内容が不正という事でしょうか?
もう少しもがいてみます。
リンク先の中段辺りのgsapi.pasを使ってるという事ですが、そのgsapi.pasは、「Update: here is a corrected version of the gsapi.pas unit that should work in both Delphi versions: 」のgsapi.pasのリンク先の物を使ってませんか?
そのリンク先のじゃなく、SOの回答の中に書いてあるgsapi.pasをコピーしたら、そこにあるコードでそのまま動くんじゃないですかね?
回答の中に書いてあるgsapi.pasと回答からリンク張ってある先のgsapi.pasは同じじゃないですよ
auさん、ご指摘ありがとうございます。
>回答の中に書いてあるgsapi.pasと回答からリンク張ってある先のgsapi.pasは同じじゃないですよ
おっしゃる通りでした。
他の形式はこれから試してみますが、以下、bmpで試したところ問題なくPDFがbmpに変換されました。
//procedure pdf2bmp(input : String; output: String);
procedure pdf2bmp(input : AnsiString; output: AnsiString);
var
code:integer;
instance: Pointer;
argv: array of PAnsiChar;
// argv:PPAnsiChar;
begin
code := gsapi_new_instance(instance, nil);
if code < 0 then
raise Exception.Create('Impossible to open an instance of ghostscript. Error code: '+IntToStr(code));
try
SetLength(argv, 8);
argv[0] := PAnsiChar('gsdll32TEST');
argv[1] := PAnsiChar('-dSAFER');
argv[2] := PAnsiChar('-dBATCH');
argv[3] := PAnsiChar('-dNOPAUSE');
argv[4] := PAnsiChar('-sDEVICE=bmp16m');
argv[5] := PAnsiChar('-r400');
// argv[6] := PAnsiChar('-sOutputFile=test.bmp'); //-->Stringでok
argv[6] := PAnsiChar('-sOutputFile='+output); //-->AnsiStringならok
// argv[7] := PAnsiChar('test.pdf'); //-->Stringでok
argv[7] := PAnsiChar(input); //-->AnsiStringならok
code := gsapi_init_with_args(instance, Length(argv), @argv[0]);
if code < 0 then
raise Exception.Create('ERROR: init_args: '+IntToStr(code));
try
// ...
finally
gsapi_exit(instance);
end;
finally
gsapi_delete_instance(instance);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
//PdfPath:String;
PdfPath:AnsiString;
begin
PdfPath:= 'C:\tmp\';
pdf2bmp(PdfPath+'test.pdf',PdfPath+'test.bmp');
end;
意味が分かってないのに、あちこちからコピペして試しているうちに、なおさら訳が分からなくなっていました。
ポインタの概念はわかりませんが、DLLを初めて利用しとても有難いものだと思いました。
おかげさまで利用のためのヒントをいただいた気がします。
通りすがりさん、au さん、本当にありがとうございました。
Tiffやpng等、Ghostscriptをバッチファイルで使うのと同じように変換できました。
ありがとうございました。
ツイート | ![]() |