Delphi+ImageMagick


mzAt  2009-04-19 10:30:26  No: 34074

こんにちは。
いつも拝見させていただいております。
件名につきまして、皆様のお知恵をお貸しいただければと思います。

epsファイルをbmpに変換しデータベース(FireBird)からテキストデータを
表示させて、イメージ+データベーステキストを記載した帳票をエクセルへ
出力するプログラムを書こうとしております。

また、このプログラムはサーバーのタスクによりバッチ処理に手行い
時間毎にエクセルファイルを作成していく仕組みにして行くつもりです。

只今、勉強もふくめて調査中でしてDelphiからImageMagick  dllを利用してまずはepsファイルをフォームに張り付けたScrollbox+Timageに表示する
プログラムを書こうと決めた矢先Delphi wrapper for ImageMagick library
を見つけたので早速ダウンロードして実行してみましたが
ImageMagick library not loadedとエラーが出るばかりで
表示ができません。ImageMagickもインストールし環境変数の設定も
行いましたが(PathにLibフォルダのパスを追加)それでもエラーが発生します。なぜなのでしょうか?dllの参照方法に問題があるのでしょうか?

皆様のお力をお貸しください。
よろしくお願いいたします。


mzAt  2009-04-19 10:37:12  No: 34075

自己レスです。
Ghostscriptもインストールすみです。Pathも設定しております。
ImageMagickのconvertコマンドを使えば、変換可能ですができれば変換は
bat処理ではなく、delphi内部で行いたいと考えています。

よろしくお願いいたします。


TS  2009-04-21 07:51:36  No: 34076

まずImageMagickを知りませんでした。
http://www.imagemagick.org/script/index.php

delphiで操作できそうですが。
http://www.simdesign.nl/components/imagemagick.html

ImageMagickAPI.pasの
function InitImageMagick(const path: string): Boolean;
内の
FMagickHandle := LoadLibrary(magick_dll_name);
でFMagickHandleに0が入ります。
上記のmagick_dll_name は 'CORE_RL_magick_.dll'
これをバスの通っているはずのC:\Windows\system32とかに置いても
結果は同じでした。

これが使えれば面白いかも。

誰か教えて下さい。


TS  2009-04-22 04:08:08  No: 34077

CORE_RL_magick_.dll がVisual C++で作成されており
Visual C++ ライブラリのランタイム コンポーネントを
インストールする必要があるみたいです。

http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=9b2da534-3e03-4391-8a4d-074b9f2bc1bf

これを入れると確かに
FMagickHandle := LoadLibrary(magick_dll_name);
でFMagickHandleに数字が入り認識したみたいです。

しかし何が悪いのかテストプログラムのフアイル名を選択
した時点でフリーズします。

ネットで検索して
chdir('C:\Program Files\ImageMagick-6.5.1-Q16');
すれば良いみたいな書き込みがあったのですが。
これをやっても駄目でした。


TS  2009-04-22 04:30:17  No: 34078

mzAt さんの症状とは違うみたいです。 

>ImageMagick library not loadedとエラーが出るばかりで

これは  chdir('C:\Program Files\ImageMagick-6.5.1-Q16');  を
FMagickHandle := LoadLibrary(magick_dll_name);の前に
追加する事によってエラーが出なくなりませんか。


TS  2009-04-22 17:15:32  No: 34079

完全に独り言になってますが。

ImageMagickはCのソースがあり
MagickCore.h  に

#if !defined(MaxTextExtent)
#  define MaxTextExtent  4096
#endif
#define MagickSignature  0xabacadabUL

ImageMagickAPI unit内の定義は
const
  MaxTextExtent =2053;           // DO NOT CHANGE! This is defined
                                 // in CORE_RL_magick_.dll
  MagickSignature = $ABACADAB;   // DO NOT CHANGE!

MaxTextExtentは合って無いのは分かりますが、
私はC言語は分からないのですが0xabacadabULは$ABACADABでいいのでしょうか

ちなみにMaxTextExtent =4096;
としても症状変わらずです。


TS  2009-04-22 23:44:43  No: 34080

0xabacadabUL  のULの意味は分かりました。

ImageMagickはバージョンが古い物用にしか対応していない様です。
ラザロ用の物がDelphiでもそのまま使えました。


mzAt  2009-04-23 00:46:06  No: 34081

こんいちは。レスポンスがなくすみません。
TS様こんにちは。mzAtと申します。
C:\Windows\system32に該当するdllを置いてTS様と同様な操作を
行っていましたがImageMagick library not loadedの症状は相変わらずで
最新版のImageMagickをインストールすると
エラーが変化しました。
$ABACADABの読み込みエラーとでます。
また、TS様にご指摘いただいた内容で同様な操作をすると
引用・・・chdir('C:\Program Files\ImageMagick-6.5.1-Q16');
$ABACADABの読み込みエラーとでます。
>ImageMagickはバージョンが古い物用にしか対応していない様です。
ラザロ用の物がDelphiでもそのまま使えました。
というのは、2007では使えないという解釈でしょうか?

すみません。ImageMagickを使うことで、imagekitを使うことなく
TIFファイルの編集ソフトも容易に出来るのではないかと考えています。
最初にレスを立ち上げた内容ももちろん実現したいですが

お教えください。
お願いいたします。


TS  2009-04-23 01:41:50  No: 34082

http://wiki.lazarus.freepascal.org/PascalMagick/ja

>というのは、2007では使えないという解釈でしょうか?
一応冗談ですが、Excel2007では使えません。

デモはそのままでは使いませんでしたが、ほとんどそのままで
使用できます。

私も使用方法とかは分かりません、知りたいので、
結果を教えて下さい。


TS  2009-04-23 03:20:39  No: 34083

残念ながらC言語の解説ですが。

MagickWand日本語解説「魔法使いKの杖」
http://magickwand.blog43.fc2.com/blog-category-0.html


TS  2009-04-23 05:39:39  No: 34084

ImageMagickの取り扱える画像の種類は半端ではありませし
Delphiから好きに加工できると言うのは面白いですね。

デモの部分を書き換えてみました。

画像を250,250ピクセルにして
画像を反転して
画像の中の150,150の大きさに50,50の所から初めて切り抜き
をすると言う事をしましたが画像処理のほとんどはこんな
感じで出来るのでしょうね。
Tiffで試しましたが時間が掛かる事を除けばプログラムとしては
簡単ですね。   

   while (MagickNextImage(wand) <> MagickFalse) do
     begin
       MagickResizeImage(wand, 250, 250, LanczosFilter, 1.0);
       MagickFlipImage(wand);
       MagickCropImage(wand,150,150,50,50);
     end;

unit magick_wand;
データ構造の核の部分
type
  MagickWand = record
    id: Cardinal;
    name: array[1..MaxTextExtent] of Char;
    exception: ExceptionInfo;
    image_info: PImageInfo;
    quantize_info: PQuantizeInfo;
    images: PImage;
    active, pend, debug: MagickBooleanType;
    signature: Cardinal;
  end;

  PMagickWand = ^MagickWand;

複数の画像を処理できる様になっている為
私には頭の痛い構造になっています。
誰か上記のデモ部分にTBitMapの型に変更する部分の
書き方を教えていただけませんか。

>只今、勉強もふくめて調査中でしてDelphiからImageMagick  dllを利用して>>まずはepsファイルをフォームに張り付けたScrollbox+Timageに表示する

上記の理由でmzAt  さんの希望するところまでは行っていません。
書き出したものを読み込めば出来たと言えば出来たのですが。


TS  2009-04-24 04:52:46  No: 34085

MagickGetImageBlobの関数でデータを取り込む様ですが
PascalMagickはこれを定義していません(コメントアウトしてある)

書き込みが無いようなのでDelphi(バージョンは関係ありません)
でImageMagickを使って画像変換する目的を達したので、

私の発言はこれにて終了します。


mzAt  2009-04-24 08:56:02  No: 34086

こんばんは。
最初にTS様いろいろなアドバイスありがとうございます。
仕事が忙しくて、書き込みが出ていません。地変失礼しました。
自分なりにいろいろとためしてみてはいます。
MagickWand日本語解説「魔法使いKの杖」等も参照いたしましたが、
Microsoft Visual C++ 2008 Redistributable Packageをインストールすると
とりあえず、dllをロードすることには成功します。

こののち、画像を取り込もうとすると
アドレスADACADADでADACADADに対する読み込み違反・・・というエラーが
出るようになります。
現在は、ここまでしか調査できていません。

また、http://tech.groups.yahoo.com/group/delphimagick/message/59から
ImageMagick library not loaded  といった内容の質問が作者に届いていたようで作者が解決策を英語で記載していますが同様の処理を行っても
アドレスADACADADでADACADADに対する読み込み違反・・・というエラーは回避できていません。
解決には至っておりませんが、私は引き続き調査を行っていきます。


Mr.XRAY  2009-04-24 16:36:29  No: 34087

mzAtさん,こんにちは.Mr.XRAYです.

今,一連のこのスレッド読ませて頂きました.
このImageMagickですが,サイトを昨年9月に移動した際,レンタルサーバにあることを知り
使い出しました.それまで,縮小画像が汚いのが綺麗に表示されるようになりました.

そこで,Webアプリ開発の時に,テスト用に開発のWindowsマシンに導入してみようかと
考えていましたが,TSさんのレスを読む限りちょっと面倒なようです.

タイトルを読んで,この機会に私もテスト的に導入しようと思ったのですが,
mzAtさんが成功したら,それを参考にしようと考えています.

是非,うまくいくことを願っています.
また,いい報告をお待ちしています.
解決策ではなく,ゴミレスでゴメンさい.


TS  2009-04-24 17:39:24  No: 34088

Mr.XRAYさん書き込みありがとうございます。

mzAtさんが誤解している様ですので改めて書きます。

ImageMagickは前にも書きましたが、古いバージョンの
ものです、これはあきらめて下さい、ほとんど修正は無理です。

http://wiki.lazarus.freepascal.org/PascalMagick/ja
PascalMagickを使用して下さい。
後半の私の記事はこれを使用した物です、
PascalMagickはラザロ(Lazarus現在の最新のバージョンは
日本語入力ばっちりの無料のパスカルコンパイラ)様の物
ですが修正なしでDelphi(バージョンは問いません)
で使用出来ます。

解凍すると出来る、magickとwandにパスを通す。

これにコンソール用のテストコードがありますが
ボタンと最初の命令を関数にしただけの修正でテストし
なんの問題もありません、png形式をjpg,tiffの形式の
画像で試しましたがtiff形式は変換に時間が掛かりましたが
実行に問題はありません、

前に書いた画像変形以外にもおそらく全ての機能が
使用できるはずです。

wandフォルダー内のmagick_image.incに関数が定義されているのですが
これのMagickGetImageBlobの関数が定義されていません。

この関数でデータを取り込む様ですが
function MagickGetImageBlob(wand: PMagickWand; length: Psize_t): PByte; cdecl; external WandExport;
これをPsize_tがどこに定義されているのか探すのですが、見つからず
ここで一応止めています。

リニックス様にテストプログラムが書かれていますので、
PascalMagicもリニックスで動作しない所は書かれていないのかも
知れません。


TS  2009-04-24 17:54:17  No: 34089

リニックス様 ->リニックス用

てすとプログラムはpng形式ファイルを読み込み画像を
指定の大きさに変換後jpg形式ファイルに変換してセーブ
すると言う物です。


Mr.XRAY  2009-04-25 01:32:10  No: 34090

TSさん,更に情報ありがとうございます.

http://wiki.lazarus.freepascal.org/PascalMagick/ja

PascalMagickですね.了解しました.

>リニックス用にテストプログラムが書かれていますので、

レンタルサーバのはPerlMagickという名前です.
多分,これをWindowsで使用可能にしたのがImageMagickらしいでので,そうなのでしょう

>MagickGetImageBlob

これを必要とするかどうかが,今のところネックということですね.
頭に入れておきます.


TS  2009-04-25 17:15:48  No: 34091

Psize_t は  PCardinalで良いんですかね、特別に定義してある
物とばかり思って探していたらえらく時間を取りました。
少しC言語やってみないといけないですね。

下記の3つのmagick_image.incに付け加えてみました。
最初にMagickSetFormat(wand,Pchar('JPEG'));の様に画像スタイルを設定

PB:=MagickGetImageBlob(wand,PC);

でPC(PCardinal)に画像の大きさが
PB(PByte)に画像の先頭のポインターのアドレスが入るみたいです。

引き続き調査中です。
この情報で後はこうしたら出来るよ、ここは違うよと出来たら教えて下さい。

function MagickGetImageBlob(wand: PMagickWand; length: PCardinal): PByte; cdecl; external WandExport;

function MagickGetImagesBlob(wand: PMagickWand; length: PCardinal): PByte; cdecl; external WandExport;

function MagickSetFormat(wand: PMagickWand; format:Pchar): MagickBooleanType; cdecl; external WandExport;


mzAt  2009-04-25 21:46:39  No: 34092

TS様
Mr.XRAY様  こんにちは。mzAtです。
お返事が遅くなり、すみません。

早速ですがPascalImageにてTS様の方法で試してみました。
TS様が言われるとおり、変換はとてもスムースです。
とりわけ、EPSをJPGに変換という要件はOKになりました。
ありがとうございます。
ただし、現在はImagemagickのリファレンス
http://www.impressjapan.jp/books/2647
にある各コマンド
変換はconvert 表示はdisplayとありますように
imagemagickのコマンド群を使うときにdll内の関数のいずれかを
使用するのか調査しています。
step1で目指すのは、変換と表示ですが
たくさんのお知恵を貸していただきありがとうございます。
私は、継続的に調べてまいりますが、書き込みのレスポンスが
遅くなることは、ご容赦ください。
本当に感謝しております。


TS  2009-04-25 23:29:32  No: 34093

>imagemagickのコマンド群を使うときにdll内の関数のいずれかを
>使用するのか調査しています。

PascalMagicを使用するなら調査の必要は無いと思いますが
magick_image.inc内等で定義されているもの以外は使用できません。

MagickWand日本語解説「魔法使いKの杖」
http://magickwand.blog43.fc2.com/blog-category-0.html

がそのdll内の関数の使用方法の解説です。
  MagickFlipImage(wand);
  MagickCropImage(wand,150,150,50,50);
これもここの解説を使ったものです。

>にある各コマンド
>変換はconvert 表示はdisplayとありますように
あくまでも推測ですがこれはそれこそimagemagickのコマンドの命令
ではないでしょうか。


TS  2009-04-26 01:05:22  No: 34094

回転・反転・傾斜
http://magickwand.blog43.fc2.com/blog-category-39.html
拡大・縮小・切抜き
http://magickwand.blog43.fc2.com/blog-category-38.html

procedure test01;
var
  status: MagickBooleanType;
  wand: PMagickWand;
  st:string;
  PC:PCardinal;
  PB:PByte;
  PByteA:PByteArray;
  F:TFileStream;
  Jpeg :TJpegImage;
  PJpeg:^TJpegImage;
begin
  { Read an image. }

  MagickWandGenesis;

  wand := NewMagickWand;

  try
    //status := MagickReadImage(wand, 'image.png');

    status := MagickReadImage(wand, 'test01.tif');
    //status := MagickReadImage(wand, 'test02.jpg');

    if (status = MagickFalse) then ThrowWandException(wand);
    { Turn the images into a thumbnail sequence. }

    MagickResetIterator(wand);

    while (MagickNextImage(wand) <> MagickFalse) do
     begin
       MagickResizeImage(wand, 250, 250, LanczosFilter, 1.0);
       MagickFlipImage(wand);
       MagickCropImage(wand,100,100,50,50);
       MagickSetFormat(wand,Pchar('JPEG'));
       //BITMAPでは失敗する何と指定すればいいのか不明?
       New(PC);
       New(PB);
       PB:=MagickGetImageBlob(wand,PC);
       PByteA:=Pointer(PB);
       F:=TfileStream.Create('test4.jpg',fmCreate);
       F.Write(PByteA^,Cardinal(PC^));
       F.Free;
       Form1.BitBtn1.Caption:= Format( '%6d',[Cardinal(PC^)]);
       //H210425 ここまでは上手く行く
       //test4.jpgとimage.jpgは同じ物が作られる
       //下記の処理でフリーズする、ポインターの扱い方が分からない
       (*
       Jpeg:=TJpegImage.Create;
       PJpeg:=Pointer(PB);
       Jpeg.Assign(TJpegImage(PJpeg^));
       Form1.Image1.Picture.Assign(Jpeg);
       Jpeg.Free;
       *)
     end;
    { Write the image as MIFF and destroy it. }

    status := MagickWriteImages(wand, 'image.jpg', MagickTrue);
    if (status = MagickFalse) then ThrowWandException(wand);

  finally
    wand := DestroyMagickWand(wand);

    MagickWandTerminus;

  end;
end;


TS  2009-04-26 04:46:19  No: 34095

var  M:TMemoryStream;

失敗した所に下記を追加で表示出来ました。
目的達成、やれやれようやく出来ました。

       M:=TMemoryStream.Create;
       M.Clear;
       M.Write(PByteA^,Cardinal(PC^));
       M.Position:=0;
       BitMap:=TBitMap.Create;
       BitMap.LoadFromStream(M);
       Form1.Image1.Picture.Graphic := Bitmap;
       M.Free;
       BitMap.Free;

mzAtさん、Mr.XRAYさん  出来れば試して見て下さい。


Mr.XRAY  2009-04-26 04:56:28  No: 34096

TSさんお疲れ様です.
貴重なテスト,ありがとうございます.
人柱になってしまいましたね.

もう少しサイトの整備ができたらと考えていたのですが,
いい機会ですので,近日中に兆戦してみるつもりです.

mzAtさんの方はうまくいっているのでしょうか?


TS  2009-04-26 04:58:25  No: 34097

修正
MagickSetFormat(wand,Pchar('BMP'));
画像の種類は拡張子指定で良いみたいですね。


TS  2009-04-26 05:06:32  No: 34098

Mr.XRAYさんの途中のレスが無かったら最後までやって
なかったでしょうね、ありがとうございました。

表示のしたかはMemoryStreamを使いましたが
ポインターの指定でやれる方法があるのでしょうか
もっと良い方法があれば教えて下さい。


TS  2009-04-26 08:31:16  No: 34099

MagickWand日本語解説「魔法使いKの杖」
http://magickwand.blog43.fc2.com/blog-category-0.html

がそのdll内の関数の使用方法の解説です。

と前に書きましたが、この中に画像の中に描画する機能が
あるみたいでしたので、これもテストして見ました。
下記の様な感じで出来る事を確認しました。
抜粋のみです。

「魔法使いKの杖」の解説に無い関数もありますが、
magick_image.incに付け加えれば使用できる様です。

http://magickwand.blog43.fc2.com/blog-category-49.html

var
  DrawW:PDrawingWand;
begin
  DrawW:= NewDrawingWand;
  //線を引いてみる
  DrawLine(DrawW,10,10,200,200);

  MagickDrawImage(wand,DrawW);
  
  DrawW := DestroyDrawingWand(DrawW);
end;


mzAt  2009-04-26 20:11:51  No: 34100

みなさまこんにちは。mzAtです。
TS様関数についてテストありがとうございます。
PascalMagick内の関数までテストしていただき申し訳ない次第です。
>あくまでも推測ですがこれはそれこそimagemagickのコマンドの命令
>ではないでしょうか
コマンドラインからとプログラムとしようするでは違うのですね。
ただ、イメージに落書きができるようになった今では
もはやいまさらですが、ここへきてTIFの編集ソフトを作成する夢も広がってきました。

今、ちょっと試していたのは、
eps→jpg→バイナリデータをADO  ChunkメソッドでSQLのimage型に保存
これをファイヤーバードに置き換えてエクセルにてアタッチ、バイナリデータを画像に変換ごエクセルに描写・・・
というテストを行っておりました。
関数につては、ご指摘いただいた「魔法使いKの杖」の解説にある関数以上の
利用がなかったからです。

また、関数のつけくわけもできるということで
目からうろこでした。本当にありがとうごあいます。

Imagekitを使わなくてもTIFviewerを作成できる大きなヒントを得ましたので
こちらもすすめていこうとおもいます。Win2000以降TIFveiwerはその表示方法や編集方法がOSがマイナーアップするたびに粗悪になっていっている気がしていますし(そういった中で編集用のソフトを作ってほしいとの声も
周りからちらほら出ています故)

まずは、eps表示+データベースから画像を引き出すをまとめます。
また、お返事が遅くなり、失礼しました。

けして、ページを見ていないわけではないのです。


mzAt  2009-04-26 20:43:24  No: 34101

再度、書き込みです。
>失敗した所に下記を追加で表示出来ました。
>目的達成、やれやれようやく出来ました。

>       M:=TMemoryStream.Create;
>       M.Clear;
>       M.Write(PByteA^,Cardinal(PC^));
>       M.Position:=0;
>       BitMap:=TBitMap.Create;
>       BitMap.LoadFromStream(M);
>       Form1.Image1.Picture.Graphic := Bitmap;
>       M.Free;
>       BitMap.Free;

にて表示することができました。
ありがとうございます。

私からみなさまにご提供できることがなく
申し訳ないです。


Mr.XRAY  2009-04-26 21:02:12  No: 34102

Mr.XRAYです.やってみました.

1. http://www.imagemagick.org/script/binary-releases.php#windows から
    ImageMagick-6.5.1-6-Q16-windows-dll.exeをダウンロードしてインストール
    必要なDLLがProgram Filesにインストールされ,環境変数PATHに追加される
    
2.  Microsoft Visual C++ 2008 再頒布可能パッケージ (x86)  
    http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=9b2da534-3e03-4391-8a4d-074b9f2bc1bf
    をダウンロードしてインストール
    
3.  http://sourceforge.net/project/showfiles.php?group_id=92177&package_id=174103&release_id=431432
    からPascalMagick-0.4.zipをダウンロードして解凍
    
4.  このdemo1フォルダ内のwanddemo.dprを削除
     wanddemo.lprの拡張子をdprに変更し,Delphi7のIDEで開きコンパイル
     
5.  出来たEXEを実行
    フォルダ内のimage.pngのサイズ縮小されたimage.jpgが作成された
    
以上です.次に

5.  作成したEXEのあるフォルダごと,他のPCにコピーして実行
6.  CORE_RL_wand_.dllを要求してきたので,フォルダにコピーしたが次のエラー
7.  Microsoft Visual C++ 2008 再頒布可能パッケージ をインストールしたらOK

と,ここまでなのですが.
DLLはパスが通っていればいいようですが,ランタイムパッケージが必要なんですね.
う〜ん.ちょっと考えてしまいます.


あの…  2009-04-27 09:12:23  No: 34103

>  M:=TMemoryStream.Create;
>  M.Clear;
>  M.Write(PByteA^,Cardinal(PC^));
>  M.Position:=0;
>  BitMap:=TBitMap.Create;
>  BitMap.LoadFromStream(M);
>  Form1.Image1.Picture.Graphic := Bitmap;
>  M.Free;
>  BitMap.Free;
これは、もうチョット簡単なコードになるかな?

type
  _TStream = class(TCustomMemoryStream);

var
  ms: TMemoryStream;
  PB: PByte;
  C: Cardinal;
  .....
begin
  .....
  PB := MagickGetImageBlob(wand, @C);
  ms := TMemoryStream.Create;
  _TStream(ms).SetPointer(PB, C);
  Image1.Picture.BITMAP.LoadFromStream(ms);
  ms.Free;
end;

JPGの場合、

  Jpeg:=TJpegImage.Create;
  ms := TMemoryStream.Create;
  _TStream(ms).SetPointer(PB, C);
  Jpeg.LoadFromStream(ms);
  Image1.Picture.Assign(Jpeg);
  ms.Free;
  Jpeg.Free;


TS  2009-04-27 17:07:05  No: 34104

あの…さん  
ありがとうございます。

このゆう書き方を知りたかったのです。
無駄な事をやっている認識はあったのですが。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加