153 lines
4.4 KiB
Perl
153 lines
4.4 KiB
Perl
|
#!/usr/bin/perl
|
||
|
#
|
||
|
|
||
|
package Apache::LiveJournal::PalImg;
|
||
|
|
||
|
use strict;
|
||
|
use Apache::Constants qw(:common REDIRECT HTTP_NOT_MODIFIED);
|
||
|
use PaletteModify;
|
||
|
|
||
|
# URLs of form /palimg/somedir/file.gif[extra]
|
||
|
# where extras can be:
|
||
|
# /p... - palette modify
|
||
|
|
||
|
sub handler
|
||
|
{
|
||
|
my $r = shift;
|
||
|
my $uri = $r->uri;
|
||
|
my ($base, $ext, $extra) = $uri =~ m!^/palimg/(.+)\.(\w+)(.*)$!;
|
||
|
$r->notes("codepath" => "img.palimg");
|
||
|
return 404 unless $base && $base !~ m!\.\.!;
|
||
|
|
||
|
my $disk_file = "$LJ::HOME/htdocs/palimg/$base.$ext";
|
||
|
return 404 unless -e $disk_file;
|
||
|
|
||
|
my @st = stat(_);
|
||
|
my $size = $st[7];
|
||
|
my $modtime = $st[9];
|
||
|
my $etag = "$modtime-$size";
|
||
|
|
||
|
my $mime = {
|
||
|
'gif' => 'image/gif',
|
||
|
'png' => 'image/png',
|
||
|
}->{$ext};
|
||
|
|
||
|
my $palspec;
|
||
|
if ($extra) {
|
||
|
if ($extra =~ m!^/p(.+)$!) {
|
||
|
$palspec = $1;
|
||
|
} else {
|
||
|
return 404;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return send_file($r, $disk_file, {
|
||
|
'mime' => $mime,
|
||
|
'etag' => $etag,
|
||
|
'palspec' => $palspec,
|
||
|
'size' => $size,
|
||
|
'modtime' => $modtime,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
sub parse_hex_color
|
||
|
{
|
||
|
my $color = shift;
|
||
|
return [ map { hex(substr($color, $_, 2)) } (0,2,4) ];
|
||
|
}
|
||
|
|
||
|
sub send_file
|
||
|
{
|
||
|
my ($r, $disk_file, $opts) = @_;
|
||
|
|
||
|
my $etag = $opts->{'etag'};
|
||
|
|
||
|
# palette altering
|
||
|
my %pal_colors;
|
||
|
if (my $pals = $opts->{'palspec'}) {
|
||
|
my $hx = "[0-9a-f]";
|
||
|
if ($pals =~ /^g($hx{2,2})($hx{6,6})($hx{2,2})($hx{6,6})$/) {
|
||
|
# gradient from index $1, color $2, to index $3, color $4
|
||
|
my $from = hex($1);
|
||
|
my $to = hex($3);
|
||
|
return 404 if $from == $to;
|
||
|
my $fcolor = parse_hex_color($2);
|
||
|
my $tcolor = parse_hex_color($4);
|
||
|
if ($to < $from) {
|
||
|
($from, $to, $fcolor, $tcolor) =
|
||
|
($to, $from, $tcolor, $fcolor);
|
||
|
}
|
||
|
$etag .= ":pg$pals";
|
||
|
for (my $i=$from; $i<=$to; $i++) {
|
||
|
$pal_colors{$i} = [ map {
|
||
|
int($fcolor->[$_] +
|
||
|
($tcolor->[$_] - $fcolor->[$_]) *
|
||
|
($i-$from) / ($to-$from))
|
||
|
} (0..2) ];
|
||
|
}
|
||
|
} elsif ($pals =~ /^t($hx{6,6})($hx{6,6})?$/) {
|
||
|
# tint everything towards color
|
||
|
my ($t, $td) = ($1, $2);
|
||
|
$pal_colors{'tint'} = parse_hex_color($t);
|
||
|
$pal_colors{'tint_dark'} = $td ? parse_hex_color($td) : [0,0,0];
|
||
|
} elsif (length($pals) > 42 || $pals =~ /[^0-9a-f]/) {
|
||
|
return 404;
|
||
|
} else {
|
||
|
my $len = length($pals);
|
||
|
return 404 if $len % 7; # must be multiple of 7 chars
|
||
|
for (my $i = 0; $i < $len/7; $i++) {
|
||
|
my $palindex = hex(substr($pals, $i*7, 1));
|
||
|
$pal_colors{$palindex} = [
|
||
|
hex(substr($pals, $i*7+1, 2)),
|
||
|
hex(substr($pals, $i*7+3, 2)),
|
||
|
hex(substr($pals, $i*7+5, 2)),
|
||
|
substr($pals, $i*7+1, 6),
|
||
|
];
|
||
|
}
|
||
|
$etag .= ":p$_($pal_colors{$_}->[3])" for (sort keys %pal_colors);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$etag = '"' . $etag . '"';
|
||
|
my $ifnonematch = $r->header_in("If-None-Match");
|
||
|
return HTTP_NOT_MODIFIED if
|
||
|
defined $ifnonematch && $etag eq $ifnonematch;
|
||
|
|
||
|
# send the file
|
||
|
$r->content_type($opts->{'mime'});
|
||
|
$r->header_out("Content-length", $opts->{'size'});
|
||
|
$r->header_out("ETag", $etag);
|
||
|
if ($opts->{'modtime'}) {
|
||
|
$r->update_mtime($opts->{'modtime'});
|
||
|
$r->set_last_modified();
|
||
|
}
|
||
|
$r->send_http_header();
|
||
|
|
||
|
# HEAD request?
|
||
|
return OK if $r->method eq "HEAD";
|
||
|
|
||
|
my $fh = Apache::File->new($disk_file);
|
||
|
return 404 unless $fh;
|
||
|
binmode($fh);
|
||
|
|
||
|
my $palette;
|
||
|
if (%pal_colors) {
|
||
|
if ($opts->{'mime'} eq "image/gif") {
|
||
|
$palette = PaletteModify::new_gif_palette($fh, \%pal_colors);
|
||
|
} elsif ($opts->{'mime'} == "image/png") {
|
||
|
$palette = PaletteModify::new_png_palette($fh, \%pal_colors);
|
||
|
}
|
||
|
unless ($palette) {
|
||
|
return 404; # image isn't palette changeable?
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$r->print($palette) if $palette; # when palette modified.
|
||
|
$r->send_fd($fh); # sends remaining data (or all of it) quickly
|
||
|
$fh->close();
|
||
|
return OK;
|
||
|
}
|
||
|
|
||
|
1;
|
||
|
|