M.C.P.C.

―むり・くり―プラスコミュニケーション(更新終了)


| トップページ |

2009年12月23日 18:25

PSP用天気予報画像を自動組版して作るPerlスクリプト

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

PSPのブラウザ全画面表示(480x272px)で見られる、天気予報画像を生成するPerlスクリプトです。作例ではフォントにIPAゴシックを指定していますが、用途によって適切なフォントを指定してみてください。

実行例:

HTMLソースは

<img src="http://labo.dtpwiki.jp/psptenki/weather.cgi?city=150010&day=today" />

が表示、

<img src="http://labo.dtpwiki.jp/psptenki/weather.cgi?city=150010&day=tomorrow" />

が表示されます。

バックエンドでlivedoor Weather Hacksを使っています。
お天気Webサービス仕様 - Weather Hacks - livedoor 天気情報 [weather.livedoor.com]

開発中のPSP実機での表示例はこちら。
M.C.P.C.: PSPでデジタルサイネージ風に天気予報表示させてみた

ソース:

Filename: weather.cgi

#!/usr/bin/perl
 
# filename: weather.cgi
# livedoor Weather Hacksを使い、指定された地域、指定日の
# 天気予報を取得し、PSPのディスプレイサイズ(480x272pixel)
# 内で組版し、JPEG画像として出力します。
# 使用例: <img src="weather.cgi?city=50&day=today" /> 
 
use strict;
use warnings;
use CGI;
use DateTime::Format::HTTP;
use Encode;
use Image::Magick;
use PDFJ 'SJIS';
use utf8;
use WebService::Livedoor::Weather;
 
# PDFJからエクスポートされるText()をCP932に固定する
sub Text_fixup {
  no warnings 'redefine';
  *main::Text = sub {
    return PDFJ::Text
           ->new(encode('cp932', shift ), @_);
  };
}
Text_fixup();
 
 
# メインルーチン
my $q = CGI->new();
( my $day  = $q->param('day' ) || 'today' ) =~ s/[^\w]//g;
( my $city = $q->param('city') || 150010  ) =~ s/[^\d]//g;
my $w = WebService::Livedoor::Weather->new()
        ->get( $city, $day );
$w->{city} = $city;
 
#use CGI::Carp qw(fatalsToBrowser);use YAML::Syck;die Dump($w);
show_image($w);
 
exit;
 
 
# Weather Hacksの結果からPDFJで組版し、JPEGで表示
sub show_image {
  my $w= shift;
  
  ( my $description = $w->{description} ) =~ s/<br.*//;
  my $forecastdate = DateTime::Format::HTTP
                       ->parse_datetime($w->{forecastdate})
                       ->ymd('/');
  my $pdfversion  = 1.6;
  my $paperwidth  = 480; # PSP display width
  my $paperheight = 272; # PSP display height
  
  # make PDFJ object
  my $d = PDFJ::Doc->new($pdfversion, $paperwidth, $paperheight);
  
  # make font object
  my $p_font = $d->new_font('IPAfont00301/ipag.ttf', '90ms-RKSJ-H');
  
  # make page object 
  my $p_page = $d->new_page;
  
  # make paragraph/text object
  my $para_title
    = Paragraph( 
        Text( "$w->{title}($forecastdate)",
              TStyle( font => $p_font, fontsize => 24)
        ),
        PStyle( size => 456, align => 'b', linefeed => 35, )
      );
  my $para_telop
    = Paragraph(
        Text( $w->{telop},
              TStyle( font => $p_font, fontsize => 36, )
        ),
        PStyle( size => 456, align => 'm', linefeed => 60, )
      );
  my $para_description
    = Paragraph(
        Text( $description,
              TStyle( font => $p_font, fontsize => 24, )
        ),
        PStyle( size => 456, align => 'w', linefeed => 32, )
      );
  my $para_copyright
    = Paragraph(
        Text( $w->{version},
              TStyle( font => $p_font, fontsize => 12, )
        ),
        PStyle( size => 456, align => 'e', linefeed => 15, )
      );
  
  # make block object
  my $p_block = Block(
                  'V',
                  $para_title,
                  $para_telop,
                  $para_description,
                  BStyle(align => 'b')
                );
  my $x = 12;
  my $y = $paperheight - 8;
  $p_block->show($p_page, $x, $y);
  my $p_block2 = Block(
                  'V',
                  $para_copyright,
                  BStyle(align => 'b')
                );
  $x = 12;
  $y = 15;
  $p_block2->show($p_page, $x, $y);
  
  # write PDF
  #write_jpg($d);      # Image::Magick バージョン
  write_jpg2($d, $w); # Google Docs バージョン
  
  return;
}
 
# オンメモリでPDF->JPEG処理、標準出力へ(ImageMagick使用)
sub write_jpg {
  my $d = shift;
  my $pdf;
  # PDFJで組版したPDFを$pdfに代入
  {
    open my $fh, '>', \$pdf or die $!;
    $d->print($fh);
    close $fh;
  }
  # $pdfのPDFデータをImageMagickでJPEGに変換
  my $img = Image::Magick->new( magick => 'pdf' );
  $img->BlobToImage($pdf);
  print $q->header( -type => 'image/jpeg' );
  binmode STDOUT;
  #$img->Set( quality => 75 );
  $img->Write('jpg:-');
  undef $img;
  
  return;
}
 
# PDFを公開領域に書きだして、Google Docで
# PDF->画像変換処理へリダイレクト
sub write_jpg2 {
  my $d  = shift;
  my $w  = shift;
  my $dt = DateTime::Format::HTTP
           ->parse_datetime( $w->{publictime} );
  ( my $day  = $w->{forecastday} ) =~ s/[^\w]//g;
  ( my $city = $w->{city       } ) =~ s/[^\d]//g;
  my $ymdhms  = $dt->ymd('') . $dt->hms('');
  
  # PDF書きだし用ファイル名・パス準備
  my $pdffile = "${city}_${day}_$ymdhms.pdf";
  my $pdfdir  = '/var/www/html/psptenki/pdf';
    # PDFを書きだす公開ディレクトリ(作っておくこと)
  my $pdfdir_url = 'http://example.com/psptenki/pdf';
    # PDFを書きだす公開ディレクトリのURL
  my $file = "$pdfdir/$pdffile"; 
  my $url  = "$pdfdir_url/$pdffile";
  
  # PDFを公開ディレクトリに書き出し
  $d->print($file);
  chmod 0666, $file;
  
  # Google Docsにリダイレクト
  print $q->redirect( "http://docs.google.com/viewer?"
               ."a=bi&pagenumber=1&w=480&url=$url" );  
  return;
}
 
 
__END__

PSPで直接指定した場合、勝手にmarginつくので、HTMLに組み込んで読むようにしたほうがいいと思います。

また、PSPの画面を自動更新してほしいっていう場合には、HTMLに組み込み、こんな風にしてみたらどうでしょう。

filename: 50.html

<html>
  <head>
    <meta http-equiv="refresh"
      content="3600; url=50.html" />
    <style>
      * {
        margin: 0px;
        padding: 0px;
      }
      img {
        width: 480px;
      }
    </style>
  </head>
  <body>
    <img src="weather.cgi?city=50&day=today" />
  </body>
</html>

これの設置場所のURLをPSPのWebブラウザで読み込む。これで我が家ではPSPで常に最新の天気状況が表示されいます。多い日も安心です。雪が。

あと、画像とMETA REFRESHという古式ゆかりな技術を使っているだけあって、HT-03AのブラウザでもW-ZERO3[es]のブラウザでもみられます。ニンテンドーDSブラウザは微妙。少なくとも初代DSブラウザはだめだったなあ。

~~~

さて、今回のスクリプトですが、PDFJという組版エンジンでPSPの画面サイズ(480x272px)で組版して、できたPDFをImageMagick、またはGoogle DocsのViewerでJPEG変換する、というものです。印刷屋さんで言うとIDMLとかInDesign Serverとか使わなくてもできちゃうのがかっこいいところだと思います。

この程度のものになにも組版エンジン使わなくてもいいんじゃないかーて思った方もいるかもしれませんが、せっかく印刷屋さんにいるんだから一応ジャスティファイぐらいかけたいなーというのと、好きなフォント使いたいなーというので、PDFJを使ってみました。PDFJは、設置するにあたり制限が非常に少ないのも魅力。Apache FOPとか設置するだけで難儀だぞ。

なんだったら、液晶AQUOSの画面サイズ(1366x768ぐらい?)のやつも作れるわけですが、うちハイビジョンテレビないんです。困ったね。

(2014-07-23修正)

取得する都市の番号の書式が変わっていたので変更。当初は「50」で指定していたところを、「150010」にしました。

投稿 大野 義貴 [Perl] | |

トラックバック(0)

トラックバックURL: http://blog.dtpwiki.jp/MTOS/mt-tb.cgi/3076

コメントする