: # This grossness allows perl to be anywhere in PATH. Perl would # interpret #!/bin/sh, so we must hope we get a Bourne shell. eval 'exec perl -w -S $0 ${1+"$@"}' if 0; # acjpeg 0.2.0 (2002-Jan-23-Wed) # Adam M. Costello # http://www.cs.berkeley.edu/~amc/ # acjpeg [ ... ] # # A wrapper around cjpeg that uses an alternative method to adjust the # quality: geometric interpolation between six reference tables. The # quality is a real number in the range 0 to 1, and the following six # values use the reference tables: # 0.0: tables filled with the value 2047 # 0.2: base tables used by libjpeg (same as cjpeg -q 50) # 0.4: "normal" tables used by the Canon Powershot S40 # 0.6: "fine" tables used by the Canon Powershot S40 # 0.8: "superfine" tables used by the Canon Powershot S40 # 1.0: tables filled with the value 1 # are passed through to cjpeg. The options -optimize and # -progressive (which can be abbreviated -opt and -pro) are recommended. # Both improve compression slightly without affecting quality (but # progressive encoding is a non-baseline JPEG feature). # The default behavior of subsampling the chrominance channels (by a # factor of 2 both horizontally and vertically) is retained, because # both human eyes and typical cameras/scanners capture the chrominance # information with less resolution. For scaled-down images, however, # there may exist chrominance information at the same resolution as # the luminance information, and it might be desirable to preserve # it (see the -sample argument of cjpeg). But if this is done, the # chrominance quantization table produced by this script might no longer # be appropriate. # acjpeg tables # # Merely prints the tables to stdout. use strict; my $quality = shift; my $tmpfile; if ($quality eq 'tables') { $quality = shift; } else { $tmpfile = "/tmp/acjpeg-$$"; open TMP, "> $tmpfile" or die "cannot open $tmpfile"; select TMP; } my @refq = ( [ # tables for quality 0.0: [ # luminance table: [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], ], [ # chrominance table: [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], [ qw( 2047 2047 2047 2047 2047 2047 2047 2047 ) ], ], ], [ # tables for quality 0.2 (libjpeg base tables): [ # luminance table: [ qw( 16 11 10 16 24 40 51 61 ) ], [ qw( 12 12 14 19 26 58 60 55 ) ], [ qw( 14 13 16 24 40 57 69 56 ) ], [ qw( 14 17 22 29 51 87 80 62 ) ], [ qw( 18 22 37 56 68 109 103 77 ) ], [ qw( 24 35 55 64 81 104 113 92 ) ], [ qw( 49 64 78 87 103 121 120 101 ) ], [ qw( 72 92 95 98 112 100 103 99 ) ], ], [ # chrominance table: [ qw( 17 18 24 47 99 99 99 99 ) ], [ qw( 18 21 26 66 99 99 99 99 ) ], [ qw( 24 26 56 99 99 99 99 99 ) ], [ qw( 47 66 99 99 99 99 99 99 ) ], [ qw( 99 99 99 99 99 99 99 99 ) ], [ qw( 99 99 99 99 99 99 99 99 ) ], [ qw( 99 99 99 99 99 99 99 99 ) ], [ qw( 99 99 99 99 99 99 99 99 ) ], ], ], [ # tables for quality 0.4 (Canon "normal" tables): [ # luminance table: [ qw( 9 6 5 9 13 22 29 35 ) ], [ qw( 6 6 8 11 15 33 34 30 ) ], [ qw( 8 7 9 13 22 33 39 31 ) ], [ qw( 8 9 12 16 28 49 45 34 ) ], [ qw( 10 12 21 32 39 61 58 42 ) ], [ qw( 13 19 31 36 45 58 63 51 ) ], [ qw( 28 36 44 49 58 68 66 55 ) ], [ qw( 41 52 54 55 62 56 57 54 ) ], ], [ # chrominance table: [ qw( 9 9 12 20 15 26 79 79 ) ], [ qw( 9 10 12 10 26 26 79 79 ) ], [ qw( 12 12 10 10 26 79 79 79 ) ], [ qw( 20 10 10 26 79 79 79 79 ) ], [ qw( 15 26 26 79 79 79 79 79 ) ], [ qw( 26 26 79 79 79 79 79 79 ) ], [ qw( 79 79 79 79 79 79 79 79 ) ], [ qw( 79 79 79 79 79 79 79 79 ) ], ], ], [ # tables for quality 0.6 (Canon "fine" tables): [ # luminance table: [ qw( 1 1 1 2 3 6 8 10 ) ], [ qw( 1 1 2 3 4 8 9 8 ) ], [ qw( 2 2 2 3 6 8 10 8 ) ], [ qw( 2 2 3 4 7 12 11 9 ) ], [ qw( 3 3 8 11 10 16 15 11 ) ], [ qw( 3 5 8 10 12 15 16 13 ) ], [ qw( 7 10 11 12 15 17 17 14 ) ], [ qw( 14 13 13 15 15 14 14 14 ) ], ], [ # chrominance table: [ qw( 4 4 5 9 15 26 26 26 ) ], [ qw( 4 4 5 10 19 26 26 26 ) ], [ qw( 5 5 8 9 26 26 26 26 ) ], [ qw( 9 10 9 13 26 26 26 26 ) ], [ qw( 15 19 26 26 26 26 26 26 ) ], [ qw( 26 26 26 26 26 26 26 26 ) ], [ qw( 26 26 26 26 26 26 26 26 ) ], [ qw( 26 26 26 26 26 26 26 26 ) ], ], ], [ # tables for quality 0.8 (Canon "superfine" tables): [ # luminance table: [ qw( 1 1 1 1 1 2 3 3 ) ], [ qw( 1 1 1 1 1 3 3 3 ) ], [ qw( 1 1 1 1 2 3 3 3 ) ], [ qw( 1 1 1 1 2 4 4 3 ) ], [ qw( 1 1 3 4 4 6 6 4 ) ], [ qw( 1 2 3 3 4 5 6 5 ) ], [ qw( 2 3 4 4 5 6 6 5 ) ], [ qw( 5 5 5 5 5 5 5 5 ) ], ], [ # chrominance table: [ qw( 1 1 2 4 6 11 11 11 ) ], [ qw( 1 1 2 4 8 11 11 11 ) ], [ qw( 2 2 3 4 11 11 11 11 ) ], [ qw( 4 4 4 5 11 11 11 11 ) ], [ qw( 6 8 11 11 11 11 11 11 ) ], [ qw( 11 11 11 11 11 11 11 11 ) ], [ qw( 11 11 11 11 11 11 11 11 ) ], [ qw( 11 11 11 11 11 11 11 11 ) ], ], ], [ # tables for quality 1.0: [ # luminance table: [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], ], [ # chrominance table: [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], [ qw( 1 1 1 1 1 1 1 1 ) ], ], ], ); sub pow($$) { my ($a, $b) = @_; return exp($b * log($a)); } my ($lotable, $hitable, $exp, $flavor, $row, $col, $loq, $hiq); die 'quality must be in [0,1]' if $quality < 0 || $quality > 1; $lotable = int($quality / 0.2); if ($lotable == 5) { $lotable = 4 } $hitable = $lotable + 1; $exp = ($hitable - $quality * 5); for ($flavor = 0; $flavor <= 1; ++$flavor) { printf "# %sinance:\n", $flavor ? 'chrom' : 'lum'; for ($row = 0; $row < 8; ++$row) { for ($col = 0; $col < 8; ++$col) { # The higher quality table has the smaller q values: $loq = $refq[$hitable][$flavor][$row][$col]; $hiq = $refq[$lotable][$flavor][$row][$col]; printf " %3.0f", $loq * pow($hiq / $loq, $exp) + (sqrt(($row * $row + $col * $col) / 98.0) * 2 - 1) / 6; # We use the position to slightly bias the rounding so that when # large portions of the table are constant in both the lower and # higher tables, the values don't all change at exactly the same # quality threshold. } print "\n"; } } if (defined $tmpfile) { close TMP; select STDOUT; system 'cjpeg', '-qtables', $tmpfile, @ARGV; unlink $tmpfile; }