1 # An object that looks a bit like an Image::Magick object, but has a lot fewer
2 # methods, and can use qscale behind-the-scenes instead if possible.
4 package Sesse::pr0n::QscaleProxy;
19 Apache2::ServerUtil->server->log_error("Could not load the qscale module ($@); continuing with ImageMagick only.");
27 $ref->{'magick'} = Image::Magick->new;
37 if (exists($self->{'qscale'})) {
38 qscale::qscale_destroy($self->{'qscale'});
39 delete $self->{'qscale'};
46 if (exists($self->{'magick'})) {
47 return $self->{'magick'}->Clone();
50 my $clone = Sesse::pr0n::QscaleProxy->new;
51 $clone->{'qscale'} = qscale::qscale_clone($self->{'qscale'});
56 my ($self, $arg) = @_;
58 if (exists($self->{'magick'})) {
59 return $self->{'magick'}->Get($arg);
63 return $self->{'qscale'}->{'height'};
64 } elsif ($arg eq 'columns') {
65 return $self->{'qscale'}->{'width'};
67 die "Unknown attribute '$arg'";
72 my ($self, @args) = @_;
74 if (exists($self->{'magick'})) {
75 return $self->{'magick'}->Read(@args);
77 if (exists($self->{'qscale'})) {
78 qscale::qscale_destroy($self->{'qscale'});
79 delete $self->{'qscale'};
83 if (scalar @args == 1) {
84 @args = ( filename => $args[0] );
89 if (exists($args{'filename'})) {
90 $qscale = qscale::qscale_load_jpeg($args{'filename'});
91 } elsif (exists($args{'file'})) {
92 $qscale = qscale::qscale_load_jpeg_from_stdio($args{'file'});
94 die "Missing a file or file name to load JPEG from";
97 if (qscale::qscale_is_invalid($qscale)) {
98 return "400 Image loading failed";
100 $self->{'qscale'} = $qscale;
104 # Note: sampling-factor is not an ImageMagick parameter; it's qscale specific.
106 my ($self, %args) = @_;
108 if (exists($self->{'magick'})) {
109 return $self->{'magick'}->Resize(%args);
112 if (!(exists($args{'width'}) &&
113 exists($args{'height'}) &&
114 exists($args{'filter'}) &&
115 exists($args{'sampling-factor'}))) {
116 die "Need arguments width, height, filter and sampling-factor.";
121 if (defined($args{'sampling-factor'}) && $args{'sampling-factor'} =~ /^(\d)x(\d)$/) {
132 if ($args{'filter'} eq 'Lanczos') {
133 $filter = $qscale::LANCZOS;
134 } elsif ($args{'filter'} eq 'Mitchell') {
135 $filter = $qscale::MITCHELL;
137 die "Unknown filter " . $args{'filter'};
140 my $nqscale = qscale::qscale_scale($self->{'qscale'}, $args{'width'}, $args{'height'}, $samp_h0, $samp_v0, $samp_h1, $samp_v1, $samp_h2, $samp_v2, $filter);
141 qscale::qscale_destroy($self->{'qscale'});
142 $self->{'qscale'} = $nqscale;
150 if (exists($self->{'magick'})) {
151 $self->{'magick'}->Strip();
156 my ($self, %args) = @_;
158 if (exists($self->{'magick'})) {
159 return $self->{'magick'}->write(%args);
162 # For some reason we seem to get conditions of some sort when using
163 # qscale for this, but not when using ImageMagick. Thus, we put the
164 # atomic-write code here and not elsewhere in pr0n.
165 my $filename = $args{'filename'};
166 my $quality = $args{'quality'};
169 if (!defined($args{'interlace'})) {
170 $jpeg_mode = $qscale::SEQUENTIAL;
171 } elsif ($args{'interlace'} eq 'Plane') {
172 $jpeg_mode = $qscale::PROGRESSIVE;
174 die "Unknown interlacing mode " . $args{'interlace'};
177 my $tmpname = $filename . "-tmp-$$-" . int(rand(100000));
179 my $ret = qscale::qscale_save_jpeg($self->{'qscale'}, $tmpname, $quality, $jpeg_mode);
181 if (rename($tmpname, $filename)) {
184 return "400 Image renaming to from $tmpname to $filename failed: $!";
187 return "400 Image saving to $tmpname failed";