Top > Programming Language > Perl [全て閉じる]
2010年9月13日

ActivePerl 5.10でImageMagickが正常に動作しない不具合の対処

September 13,2010 1:23 AM
Tag:[, ]
Permalink

Windows+ActivePerl 5.10でImageMagickをインストールしたときにImageMagickが正常に動作しない不具合の対処方法をまとめました。

このエントリーは、「Movable Type 5で「サーバーに Image::Magickか、Image::Magickの動作に必要な他のモジュールがインストールされていません。」となる事象について」から、さらに追跡調査したものです。

実験環境は次の通りです。

  • Windows XP Professional Service Pack 3(2台)
  • ActivePerl 5.10.1 Build 1006
  • ImageMagick 6.5.5-5 Q8/ImageMagick 6.5.6-10 Q8/ImageMagick 6.5.9-1 Q8(5.10.1 Build 1006に対応する最初のバージョン・途中のバージョン・最後のバージョンで実験)
  • Movable Type 5.02

PerlMagickは、前回はppmコマンドでインストールしましたが、今回はImageMagickに同梱されているものをそのまま使用しました。

ImageMagickの過去バージョンは以下のリンクからダウンロードできます。

Main Site » Mirror » image_magick

1.問題点

ImageMagickをインストールしているにもかかわらず、次のようにダッシュボードに「Image::Magickが設定されていません。」というメッセージが表示されます。

メッセージが表示

この状態でアイテムをアップロードしてもサムネイルが作成されず、真っ黒な表示になります。

真っ黒な表示

サムネイルが作成されていれば、5項のキャプチャ画像のように表示されます。

2.問題の解析

詳細は割愛しますが、サムネイルが作成されない原因は、前エントリーでも記した通り、プログラム内の「require Image::Magick」というところでエラーになっているためです。

今回は、エラーの詳細を知るために、次のサンプルプログラムをコマンドプロンプトから実行しました。「1.png」はサンプルプログラムと同じフォルダに配置している、任意の画像ファイルです。

#!/usr/bin/perl
 
eval { require Image::Magick };
if (my $err = $@) {
   die $err;
}
 
my $file = '1.png';
(my $ext = $file) =~ s/.*\.//;
my %arg = (magick => lc($ext));
my $magick = Image::Magick->new(%arg);
$magick->Read($file);
my ($width, $height) = $magick->Get('width', 'height');
print $width."x".$height;

NGを確認するのであれば、最初の5行だけあればいいです。

#!/usr/bin/perl
 
eval { require Image::Magick };
if (my $err = $@) {
   die $err;
}

ImageMagick 6.5.7-9 Q8のインストール直後にサンプルプログラムを実行すると、次のように「CORE_RL_magick.dllが見つからなかったため、このアプリケーションを開始できませんでした。アプリケーションをインストールし直すとこの問題は解決される場合があります。」というエラーが表示されました。

エラー1

実行後、コマンドプロンプトには次のように「指定されたモジュールが見つかりません。」というエラーが表示されました。

Can't load 'C:/usr/site/lib/auto/Image/Magick/Magick.dll' for module Image::Magick: load_file:指定されたモジュールが見つかりません。 at C:/usr/lib/DynaLoader.pm line 201.
 at test.pl line 3
Compilation failed in require at test.pl line 3.
&Image::Magick::constant not defined. The required ImageMagick libraries are not installed or not installed properly.
END failed--call queue aborted at test.pl line 5.

エラー2

別のPCで、ImageMagick 6.5.7-9 Q8インストール直後にサンプルプログラムを実行すると、こちらは「再帰が深すぎます。スタックがオーバーフローしました。」というエラーが表示されました。

Can't load 'C:/usr/site/lib/auto/Image/Magick/Magick.dll' for module Image::Magick: load_file:再帰が深すぎます。スタックがオーバーフローしました。 at C:/usr/lib/DynaLoader.pm line 201.
 at test2.pl line 3
Compilation failed in require at test2.pl line 3.
&Image::Magick::constant not defined. The required ImageMagick libraries are not installed or not installed properly.
END failed--call queue aborted at test2.pl line 5.

エラー3

なお、サンプルプログラムではなく、コマンドプロンプトからImageMagickの動作を確認する方法は以下です。すべて正常に動作すれば、imdisplayコマンド実行後にImageMagickのロゴが表示されます。ただし、Perlのrequire文は実行しないので、これが正常に実行されても、Perlを使っているツールの不具合が解消されているとは限らないようです。

ImageMagick - Install from Binary Distribution

C:¥>convert logo: logo.gif
C:¥>identify logo.gif
C:¥>imdisplay logo.gif

4.原因

「CORE_RL_magick.dll」はImageMagickのインストールフォルダ直下にあるライブラリなのですが、このライブラリが正常に参照できていないのが真の原因と推測されます。コマンドプロンプトに表示されたメッセージは、「CORE_RL_magick.dll」がみつからないことによる、二次的なエラーと思われます。

「CORE_RL_magick.dll」を正しく参照できるようにするには、環境変数が設定されていればよいと思います。ImageMagickのインストール直後は、環境変数「Path」にImageMagickのインストールフォルダが設定されていますが、インストール直後はPathが効いておらず、「CORE_RL_magick.dll」が参照できないようです。

なお、ImageMagickのインストールとアンインストールを何回か繰り返して試したところ、「CORE_RL_magick.dllが見つからなかったため~」というダイアログは表示されず、コマンドプロンプト上のエラーメッセージのみが表示されるケースもありました。

5.対処1

ImageMagick 6.5.6-10 Q8/ImageMagick 6.5.9-1 Q8については、WIndowsを再起動することで、コマンドプロンプトから利用可能になり、Movable Typeでもサムネイルが表示されました。ImageMagick 6.5.5-5 Q8では再起動してもNGのままでした。

サムネイル表示

また、ImageMagickのインストールとアンインストールを何回か繰り返して試したところ、再起動せずにコマンドプロンプトからは動作OKとなり、Movable Typeでは再起動しないとサムネイルが表示されないというケースがありました。

6.対処2

ImageMagick 6.5.6-10 Q8については、再起動を行う前に、「Movable Type 5で「サーバーに Image::Magickか、Image::Magickの動作に必要な他のモジュールがインストールされていません。」となる事象について」に記したとおり、環境変数MAGICK_HOMEを追加することで、次のようにコマンドプロンプトから動作可能になるケースがありました。

コマンドプロンプトから動作可能

7.対処3

今回は実施していませんが、ネット上ではppmコマンドでPerlMagickをインストールすることで解決しているという情報があります。

8.まとめ

ActivePerl 5.10.1 build 1006であればImageMagick 6.5.9-1との組み合わせが良好と思われます。

現在の最新バージョンであるActivePerl 5.10.1 build 1007は試していませんが、ImageMagickが正常に動作しない場合、次の順番で対処を行ってみてください。

  1. ImageMagickのバージョンは、ImageMagickに同梱されているPerlMagickのバージョンをActivePerlのバージョンに合わせ、かつ新しいものを選択(参考:ImageMagick と Image::Magick(PerlMagick) のバージョン対応
  2. ImageMagickインストール後にPC再起動
  3. MAGICK_HOMEの設定+PC再起動
  4. ImageMagickでPerlMagickを同時にインストールせずに、ppmでインストール+PC再起動

今回の実施環境では、解決できない事象には遭遇しませんでしたが、ActivePerlやImageMagickのバージョンによっては解決しない場合があるかもしれません。

最後に、今回の実施結果を簡単にまとめておきます。

インストール直後再起動MAGICK_HOME設定MAGICK_HOME設定後の再起動
6.5.5NGNGNGNG
6.5.6
(1回目)
NG-MS-DOS OK/MT NGMT OK
※再起動のみでOKとなった可能性あり
6.5.6
(2回目)
MS-DOS OK/MT NGMT OK--
6.5.9OK---
Comments [0] | Trackbacks [0]
2010年7月 5日

XML::Simpleを使ったXMLデータへのアクセス方法

July 5,2010 2:55 AM
Tag:[, ]
Permalink

XML::Simpleで取得したデータへのアクセス方法です。

XML::Simpleを使ったXML要素へのアクセス方法をネットで調べたところ、取得したデータをData::Dumperで出力している例がほとんどで、情報収集に苦労したので、各XML要素への具体的なアクセス方法を掲載しておきます。

といってすべてのケースが網羅できている訳ではありません。予めご了承ください。

1.サンプルXML

サンプルXMLです。これはExcelから出力するXML形式のスプレッドシートを想定しています。文字エンコーディングはUTF-8です。

<?xml version="1.0" encoding="UTF-8"?>
<Workbook>
 <Worksheet>
  <Table>
   <Row>
    <Cell><Data Type="String">番号</Data></Cell>
    <Cell><Data Type="String">種別</Data></Cell>
    <Cell><Data Type="String">ページ</Data></Cell>
   </Row>
   <Row>
    <Cell><Data Type="String">1-1</Data></Cell>
    <Cell><Data Type="String">A</Data></Cell>
    <Cell><Data Type="String">10ページ</Data></Cell>
   </Row>
   <Row>
    <Cell><Data Type="String">1-2</Data></Cell>
    <Cell><Data Type="String">B</Data></Cell>
    <Cell><Data Type="String">20ページ</Data></Cell>
   </Row>
   <Row>
    <Cell><Data Type="String">1-3</Data></Cell>
    <Cell><Data Type="String">C</Data></Cell>
    <Cell><Data Type="String">30ページ</Data></Cell>
   </Row>
  </Table>
 </Worksheet>
 <Worksheet>
  <Table>
   <Row>
    <Cell><Data Type="String">番号</Data></Cell>
    <Cell><Data Type="String">種別</Data></Cell>
    <Cell><Data Type="String">ページ</Data></Cell>
   </Row>
   <Row>
    <Cell><Data Type="String">2-1</Data></Cell>
    <Cell><Data Type="String">D</Data></Cell>
    <Cell><Data Type="String">10ページ</Data></Cell>
   </Row>
   <Row>
    <Cell><Data Type="String">2-2</Data></Cell>
    <Cell><Data Type="String">E</Data></Cell>
    <Cell><Data Type="String">20ページ</Data></Cell>
   </Row>
   <Row>
    <Cell><Data Type="String">2-3</Data></Cell>
    <Cell><Data Type="String">F</Data></Cell>
    <Cell><Data Type="String">30ページ</Data></Cell>
   </Row>
  </Table>
 </Worksheet>
 <Worksheet>
  <Table>
   <Row>
    <Cell><Data Type="String">番号</Data></Cell>
    <Cell><Data Type="String">種別</Data></Cell>
    <Cell><Data Type="String">ページ</Data></Cell>
   </Row>
   <Row>
    <Cell><Data Type="String">3-1</Data></Cell>
    <Cell><Data Type="String">G</Data></Cell>
    <Cell><Data Type="String">10ページ</Data></Cell>
   </Row>
   <Row>
    <Cell><Data Type="String">3-2</Data></Cell>
    <Cell><Data Type="String">H</Data></Cell>
    <Cell><Data Type="String">20ページ</Data></Cell>
   </Row>
   <Row>
    <Cell><Data Type="String">3-3</Data></Cell>
    <Cell><Data Type="String">I</Data></Cell>
    <Cell><Data Type="String">30ページ</Data></Cell>
   </Row>
  </Table>
 </Worksheet>
</Workbook>

2.Data::Dumperでの出力

1項のXMLデータのData::Dumperで出力を掲載します。3項以降で示すコードとの比較に利用してください。

$VAR1 = {
          'Table' => {
                     'Row' => [
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "\x{756a}\x{53f7}"
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "\x{7a2e}\x{5225}"
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              },
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => '1-1'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => 'A'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "10\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              },
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => '1-2'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => 'B'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "20\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              },
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => '1-3'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => 'C'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "30\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              }
                            ]
                   }
        };
$VAR2 = {
          'Table' => {
                     'Row' => [
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "\x{756a}\x{53f7}"
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "\x{7a2e}\x{5225}"
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              },
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => '2-1'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => 'D'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "10\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              },
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => '2-2'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => 'E'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "20\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              },
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => '2-3'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => 'F'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "30\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              }
                            ]
                   }
        };
$VAR3 = {
          'Table' => {
                     'Row' => [
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "\x{756a}\x{53f7}"
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "\x{7a2e}\x{5225}"
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              },
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => '3-1'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => 'G'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "10\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              },
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => '3-2'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => 'H'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "20\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              },
                              {
                                'Cell' => [
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => '3-3'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => 'I'
                                                    }
                                          },
                                          {
                                            'Data' => {
                                                      'Type' => 'String',
                                                      'content' => "30\x{30da}\x{30fc}\x{30b8}"
                                                    }
                                          }
                                        ]
                              }
                            ]
                   }
        };

3.サンプル

1項のXMLデータ(text.xml)を出力するサンプルコードです。説明のために、最下層のデータに一気にアクセスせず、順番に取得するようにしています。XMLファイルの取得方法など、より適切なコードがあればアドバイスお待ちしています。

#!/usr/bin/perl
 
use strict;
use utf8;
binmode STDOUT => ":utf8";
use XML::Simple;
 
open(FILE, "./test.xml");
undef $/;
my $xml = new XML::Simple();
my $xmldata = $xml->XMLin(<FILE>);
close(FILE);
 
my @worksheets = @{$xmldata->{Worksheet}};
for my $worksheet (@worksheets) {
    my @rows = @{%{$worksheet}->{Table}->{Row}};
    for my $row (@rows) {
        my @cells = @{%{$row}->{Cell}};
        for my $cell (@cells) {
            print %{$cell}->{Data}->{content};
        }
   }
}

以下、コードの簡単な解説です。

4.Worksheetの取得方法

Worksheetにハッシュでアクセスし、配列にします。

my @worksheets = @{$xmldata->{Worksheet}};

5.Rowの取得方法

4項で取得した@worksheetsをfor文でまわします。$worksheetをハッシュにして、取得したRowを配列にします。

for my $worksheet (@worksheets) {
    my @rows = @{%{$worksheet}->{Table}->{Row}};
    …中略…
}

6.Cellの取得方法

5項で取得した@rowsをfor文でまわします。$rowをハッシュにして、取得したCellを配列にします。

for my $row (@rows) {
    my @cells = @{%{$row}->{Cell}};
    …中略…
}

7.Dataの出力方法

6項で取得した@cellsをfor文でまわします。$cellをハッシュにして、最後に{content}を与えます。

for my $cell (@cells) {
    print %{$cell}->{Data}->{content};
}

8.参考サイト

参考サイトは以下です。ありがとうございました。

Perl 開発者のための XML: 第 1 回 XML と Perl -- 魔法の組み合わせ
Comments [0] | Trackbacks [0]
2010年6月18日

XML::Simpleで取得したデータが引き起こす文字化けの対処方法

June 18,2010 1:55 AM
Tag:[]
Permalink

XML::Simpleを使ったPerlスクリプトの文字化けではまってしまったので、その備忘録です。

1.発生事象

Perlスクリプトで次のXMLファイルを読み込みます。ファイルの文字コードはUTF-8です。

<?xml version="1.0" encoding="utf-8"?>
<list>
<name>ほげ</name>
</list>

Perlスクリプト(CGI)のサンプルは次の通りです。ファイルの文字コードはUTF-8です。

#!/usr/bin/perl
 
use strict;
 
use CGI;
use XML::Simple;
 
my $q = new CGI;
print $q->header(-charset=>'utf-8');
print $q->start_html;
 
my $xml = XMLin('foo.xml');
my $name = $xml->{name};
 
print <<EOF;
<form method="post" action="hoge.cgi">
名前:<input type="text" id="hoge" name="hoge" value="$name" />
<input type="submit" name="submit" value="送信" />
</form>
EOF
 
print $q->end_html;

このCGIをブラウザで表示すると、次のように、スクリプトに記述した全角文字の文字化けが発生します。

文字化けが発生

XMLファイルから取得する文字が、次のように全角文字でなければ文字化けは発生しません。

<?xml version="1.0" encoding="utf-8"?>
<list>
<name>hoge</name>
</list>

文字化けが発生しない

2.原因

XMLinで日本語を含む文字列を取得する場合、XML宣言のencoding属性に指定した文字コードの内部文字列に変換されます。よって外部に出力する場合、バイト文字列に変換(エンコード)する必要があるようです。

Data::Dumperで$nameを出力すると、「ほげ」は次のようになっていました。

$VAR1 = "\x{307b}\x{3052}";

試しに、次のようなサンプルであれば、

my $name = 'ほげ';

Data::Dumperで$nameを出力すると、

$VAR1 = 'ほげ';

となりました。

推測ですが、文字化けが発生したのは、内部文字列とバイト文字列が混在していたため、Perl自体がバイト文字列である「名前」「送信」をさらにエンコードを行い、文字化けが発生したものと思われます(解釈が間違っていたらご指摘ください)。

3.対処

スクリプトの$nameをUTF-8にエンコードすることで解決しました。

#!/usr/bin/perl
 
use strict;
 
use CGI;
use XML::Simple;
use Encode;
 
my $q = new CGI;
print $q->header(-charset=>'utf-8');
print $q->start_html;
 
my $xml = XMLin('foo.xml');
my $name = encode('UTF-8', $xml->{name});
 
print <<EOF;
<form method="post" action="hoge.cgi">
名前:<input type="text" id="hoge" name="hoge" value="$name" />
<input type="submit" name="submit" value="送信" />
</form>
EOF
 
print $q->end_html;

文字化けが発生しない

4.その他

出力時だけでなく、スクリプトに記述した全角文字と比較をする際も、予めエンコードしておく必要があります。

my $name = encode('UTF-8', $xml->{name});
if ($name eq 'ほげ') { ... }

以上です。色々調べてこれが最適解と思ったのですが、より適切な解決方法がありましたらコメントください。

2010.6.18 追記
下記の記事で、utf8プラグマの情報頂きました。ありがとうございました。

日曜プログラマのそゞろ事 - XML::Simpleで文字化けしない方法

5.参考サイト

参考サイトは下記です。ありがとうございました。

サンプルコードによるPerl入門 - XML::Simple - シンプルなXMLパーサ / Perlモジュール徹底解説
Comments [1] | Trackbacks [1]
Now loading...
Introduction
List of "Perl"
Recent Entries
Recent Comments
Recent Trackbacks
QRcode

現在停止中です
携帯電話からこのQRcodeを撮影することで携帯用URLを取得することができます

URI for cellular phones
ギターに入った猫
Styles
Font Size
Default
For defective color vision
Gray Scale
RGB Color
Search this site
loading ...
Categories
Monthly Archives
BlogPeople
Syndicate this site
FeedBurner(RSS1.0/RSS2.0/Atom)
Counter
これまでのアクセス
Powered by
Movable Type 5.12