Increase image quality to reduce noise at edges of letters
[bookreader.git] / GnuBookIA / datanode / GnuBookImages.php
1 <?php
2
3 /*
4 Copyright(c)2008 Internet Archive. Software license AGPL version 3.
5
6 This file is part of GnuBook.
7
8     GnuBook is free software: you can redistribute it and/or modify
9     it under the terms of the GNU Affero General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12
13     GnuBook is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU Affero General Public License for more details.
17
18     You should have received a copy of the GNU Affero General Public License
19     along with GnuBook.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 $MIMES = array('jpg' => 'image/jpeg',
23                'png' => 'image/png');
24
25 $zipPath  = $_REQUEST['zip'];
26 $file     = $_REQUEST['file'];
27
28 // Unfortunately kakadu requires us to know a priori if the
29 // output file should be .ppm or .pgm.  By decompressing to
30 // .bmp kakadu will write a file we can consistently turn into
31 // .pnm.  Really kakadu should support .pnm as the file output
32 // extension and automatically write ppm or pgm format as
33 // appropriate.
34 $decompressToBmp = true;
35 if ($decompressToBmp) {
36   $stdoutLink = '/tmp/stdout.bmp';
37 } else {
38   $stdoutLink = '/tmp/stdout.ppm';
39 }
40
41 if (isset($_REQUEST['ext'])) {
42   $ext = $_REQUEST['ext'];
43 } else {
44   // Default to jpg
45   $ext = 'jpg';
46 }
47
48 $fileExt = strtolower(pathinfo($file, PATHINFO_EXTENSION));
49
50 // Image conversion options
51 $pngOptions = '';
52 $jpegOptions = '-quality 75';
53
54 // The pbmreduce reduction factor produces an image with dimension 1/n
55 // The kakadu reduction factor produceds an image with dimension 1/(2^n)
56
57 if (isset($_REQUEST['height'])) {
58     $ratio = floatval($_REQUEST['origHeight']) / floatval($_REQUEST['height']);
59     if ($ratio <= 2) {
60         $scale = 2;
61         $powReduce = 1;    
62     } else if ($ratio <= 4) {
63         $scale = 4;
64         $powReduce = 2;
65     } else {
66         //$powReduce = 3; //too blurry!
67         $scale = 2;
68         $powReduce = 1;
69     }
70
71 } else {
72     $scale = $_REQUEST['scale'];
73     if (1 >= $scale) {
74         $scale = 1;
75         $powReduce = 0;
76     } else if (2 == $scale) {
77         $powReduce = 1;
78     } else if (4 == $scale) {
79         $powReduce = 2;
80     } else if (8 == $scale) {
81         $powReduce = 3;
82     } else if (16 == $scale) {
83         $powReduce = 4;
84     } else if (32 == $scale) {
85         $powReduce = 5;
86     } else {
87         // $$$ Leaving this in as default though I'm not sure why it is...
88         $scale = 8;
89         $powReduce = 3;
90     }
91 }
92
93 if (!file_exists($stdoutLink)) 
94 {  
95   system('ln -s /dev/stdout ' . $stdoutLink);  
96 }
97
98
99 putenv('LD_LIBRARY_PATH=/petabox/sw/lib/kakadu');
100
101 $unzipCmd  = 'unzip -p ' . 
102         escapeshellarg($zipPath) .
103         ' ' . escapeshellarg($file);
104         
105 if ('jp2' == $fileExt) {
106     $decompressCmd = 
107         " | /petabox/sw/bin/kdu_expand -no_seek -quiet -reduce $powReduce -i /dev/stdin -o " . $stdoutLink;
108     if ($decompressToBmp) {
109         $decompressCmd .= ' | bmptopnm ';
110     }
111 } else if ('tif' == $fileExt) {
112     // We need to create a temporary file for tifftopnm since it cannot
113     // work on a pipe (the file must be seekable).
114     // We use the GnuBookTiff prefix to give a hint in case things don't
115     // get cleaned up.
116     $tempFile = tempnam("/tmp", "GnuBookTiff");
117     
118     if (1 != $scale) {
119         if (onPowerNode()) {
120             $pbmReduce = ' | pnmscale -reduce ' . $scale;
121         } else {
122             $pbmReduce = ' | pnmscale -nomix -reduce ' . $scale;
123         }
124     } else {
125         $pbmReduce = '';
126     }
127     
128     $decompressCmd = 
129         ' > ' . $tempFile . ' ; tifftopnm ' . $tempFile . ' 2>/dev/null' . $pbmReduce;
130
131 } else {
132     GBfatal('Unknown source file extension: ' . $fileExt);
133 }
134        
135 // Non-integer scaling is currently disabled on the cluster
136 // if (isset($_REQUEST['height'])) {
137 //     $cmd .= " | pnmscale -height {$_REQUEST['height']} ";
138 // }
139
140 if ('jpg' == $ext) {
141     $compressCmd = ' | pnmtojpeg ' . $jpegOptions;
142 } else if ('png' == $ext) {
143     $compressCmd = ' | pnmtopng ' . $pngOptions;
144 }
145
146 $cmd = $unzipCmd . $decompressCmd . $compressCmd;
147
148 //print $cmd;
149
150 header('Content-type: ' . $MIMES[$ext]);
151 header('Cache-Control: max-age=15552000');
152
153 passthru ($cmd);
154
155 if (isset($tempFile)) {
156   unlink($tempFile);
157 }
158
159 function GBFatal($string) {
160     echo "alert('$string')\n";
161     die(-1);
162 }
163
164 // Returns true if using a power node
165 function onPowerNode() {
166     exec("lspci | fgrep -c Realtek", $output, $return);
167     if ("0" != $output[0]) {
168         return true;
169     } else {
170         exec("egrep -q AMD /proc/cpuinfo", $output, $return);
171         if ($return == 0) {
172             return true;
173         }
174     }
175     return false;
176 }
177
178
179 ?>
180