root/websites/showa_photo_generator/s.cgi @ 38876

Revision 280, 5.3 kB (checked in by fujiwara, 6 years ago)

websites/showa_photo_generator: added license.

  • Property svn:executable set to *
Line 
1#!/usr/bin/perl
2# -*- coding:utf-8 -*-
3#
4# Author: FUJIWARA Shunichiro <fujiwara.shunichiro at gmail.com>
5# License: Same as Perl
6#
7
8use strict;
9use Imager;
10use Imager::Fill;
11use Imager::Font;
12use URI::Fetch;
13use Cache::Memcached;
14use CGI::Carp qw / fatalsToBrowser /;
15use CGI;
16use Digest::SHA qw/ sha1_hex /;
17use List::Util qw/ min max /;
18use Data::Dumper;
19
20my $q = CGI->new;
21
22my $cache = Cache::Memcached->new({
23    servers => ['127.0.0.1:11211'],
24});
25
26my $uri;
27if ( $q->param('uri') ) {
28    $uri = $q->param('uri');
29}
30else {
31    $uri = $q->path_info;
32    $uri =~ s{^/}{};
33    $uri =~ s{(^https?:/)([^/])}{$1/$2};
34}
35
36my $data;
37if ( $uri ) {
38    $data = data_from_uri($uri, $q);
39    $data = convert( $data, $cache, $q );
40    if ($cache) {
41        $cache->set( cache_key( $uri, $q ) => $data => 3600 );
42    }
43    output($data);
44}
45elsif ( $q->param('file') ) {
46    $data = data_from_upload( $q->param('file') );
47    my $file = store_file( convert( $data, undef, $q ) );
48    redirect($file);
49}
50elsif ( $q->param('files') ) {
51    $data = data_from_upload_multi( $q->param('files') );
52    my $file = store_file( convert( $data, undef, $q ) );
53    output_text( URI->new_abs( $file, $q->url )->as_string );
54}
55else {
56    error("no data");
57}
58exit;
59
60sub store_file {
61    my $data = shift;
62    my $file = sprintf "files/%s.jpg", sha1_hex( rand() . $ENV{REMOTE_ADDR} );
63    open my $out, '>', $file or die $!;
64    print $out $data;
65    close $out;
66    return $file;
67}
68
69sub data_from_upload {
70    my $fh = shift;
71    local $/ = undef;
72    $data = <$fh>;
73}
74
75sub data_from_upload_multi {
76    my $n = shift;
77    local $/ = undef;
78
79    for my $i ( 1 .. $n ) {
80        my $info = $q->uploadInfo( $q->param("file_$i") );
81        if ( $info->{'Content-Type'} =~ /^image\// ) {
82            my $fh = $q->upload("file_$i");
83            return <$fh>;
84        }
85    }
86    return;
87}
88
89sub cache_key {
90    my ( $uri, $q ) = @_;
91
92    return sprintf(
93        "result:%s:%s:%s:%s",
94        $uri,
95        $q->param('date'),
96        $q->param('noborder'),
97        $q->param('glossy'),
98    );
99}
100
101sub data_from_uri {
102    my ( $uri, $q ) = @_;
103    if ( my $data = $cache->get( cache_key( $uri, $q ) ) ) {
104        output($data);
105        exit;
106    }
107    else {
108    }
109    my $res = URI::Fetch->fetch( $uri, Cache => $cache )
110        or error( URI::Fetch->errstr );
111    return $res->content;
112}
113
114sub convert {
115    my ( $data, $cache, $q ) = @_;
116
117    my $img = Imager->new;
118    $img->read( data => $data )
119        or error( $img->errstr );
120
121    $img->filter( type => "contrast", intensity => 0.7 );
122    $img->filter( type => "conv", coef => [ 0, 1, 0.2 ] );
123    $img = solid_border( $img, "#bbbbbb" ) unless $q->param('noborder');
124
125    my $fill = Imager::Fill->new( solid => random_color('302515'), combine => 'add' );
126    $img->box( fill => $fill );
127    $fill = Imager::Fill->new( solid => '#111111', combine => 'add' );
128    $img->box( fill => $fill );
129    $img = add_date( $img, $q->param('date') )
130        if $q->param('date');
131
132    my $amount = $q->param('glossy') ? 3 : 10;
133    $img->filter(
134        type    => 'noise',
135        amount  => $amount,
136        subtype => 1,
137    );
138
139    $img->write( data => \$data, type => 'jpeg' );
140
141    return $data;
142}
143
144sub redirect {
145    my $path = shift;
146    print "Location: $path\n\n";
147}
148
149sub error {
150    my $msg = shift;
151    print "status: 500\n";
152    print "Content-Type: text/html\n\n";
153    die $msg;
154}
155
156sub output {
157    print "Content-Type: image/jpeg\n";
158    print "Content-Length: ", length($_[0]), "\n";
159    print "\n";
160    print $_[0];
161}
162
163sub output_text {
164    my $file = shift;
165    print "Content-Type: text/plain; charset=utf-8\n";
166    print "\n";
167    print "昭和の写真ジェネレータ\n";
168    print "変換されました\n$file\n";
169}
170
171# solid_border is based on Imager/samples/border.pl
172# http://search.cpan.org/~tonyc/Imager/samples/border.pl
173sub solid_border {
174  my ( $source, $color ) = @_;
175
176  my $w = $source->getwidth();
177  my $h = $source->getheight();
178  my $border = int ( max( $w * 0.015, $h * 0.015, 5 ) );
179  my $out = Imager->new(
180      xsize    => $source->getwidth()  + 2 * $border,
181      ysize    => $source->getheight() + 2 * $border,
182      bits     => $source->bits,
183      channels => $source->getchannels,
184  );
185
186  $out->box( filled => 1, color => $color )
187    or die "Invalid color '$color':", $out->errstr, "\n";
188
189  $out->paste(
190      left => $border,
191      top  => $border,
192      img  => $source,
193  );
194
195  return $out;
196}
197
198sub random_color {
199    my $code = shift;
200    my @color = map { hex $_ } ( $code =~ m{(..)}g );
201
202    for my $c ( @color ) {
203        $c *= ( 1 + ( rand() > 0.5 ? +1 : -1 ) * rand(0.15) );
204        $c = min( $c, 255 );
205        $c = max( $c, 0   );
206    }
207    $code = sprintf('#%02x%02x%02x', @color);
208    return $code;
209}
210
211sub add_date {
212    my $img  = shift;
213    my $date = shift;
214    $date =~ s/[^ \d\-\.]//g;
215
216    my $color  = Imager::Color->new('#ffaa33');
217    my $ttfont = Imager::Font->new(
218        file  => '7barPBd.TTF', # http://www.trojanbear.net/omake.htm#sevenbarb
219    );
220    my $size = int( ($img->getwidth + $img->getheight) * 0.02 );
221    $img->align_string(
222        font   => $ttfont,
223        text   => $date,
224        x      => int( $img->getwidth  - $size * 1.5 ),
225        y      => int( $img->getheight - $size * 1.5 ),
226        halign => 'right',
227        valign => 'bottom',
228        size   => $size,
229        color  => $color,
230        aa     => 1,
231    );
232    return $img;
233}
Note: See TracBrowser for help on using the browser.