1 //========================================================================
2 //
3 // SplashBitmap.cc
4 //
5 //========================================================================
6 
7 //========================================================================
8 //
9 // Modified under the Poppler project - http://poppler.freedesktop.org
10 //
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
13 //
14 // Copyright (C) 2006, 2009, 2010 Albert Astals Cid <aacid@kde.org>
15 // Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com>
16 // Copyright (C) 2009 Shen Liang <shenzhuxi@gmail.com>
17 // Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
18 // Copyright (C) 2010 Adrian Johnson <ajohnson@redneon.com>
19 // Copyright (C) 2010 Harry Roberts <harry.roberts@midnight-labs.org>
20 // Copyright (C) 2010 Christian Feuers�nger <cfeuersaenger@googlemail.com>
21 //
22 // To see a description of the changes please see the Changelog file that
23 // came with your tarball or type make ChangeLog if you are building from git
24 //
25 //========================================================================
26 
27 #include <config.h>
28 
29 #ifdef USE_GCC_PRAGMAS
30 #pragma implementation
31 #endif
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <limits.h>
36 #include "goo/gmem.h"
37 #include "SplashErrorCodes.h"
38 #include "SplashBitmap.h"
39 #include "poppler/Error.h"
40 #include "goo/JpegWriter.h"
41 #include "goo/PNGWriter.h"
42 #include "goo/ImgWriter.h"
43 
44 //------------------------------------------------------------------------
45 // SplashBitmap
46 //------------------------------------------------------------------------
47 
SplashBitmap(int widthA,int heightA,int rowPadA,SplashColorMode modeA,GBool alphaA,GBool topDown)48 SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
49 			   SplashColorMode modeA, GBool alphaA,
50 			   GBool topDown) {
51   width = widthA;
52   height = heightA;
53   mode = modeA;
54   rowPad = rowPadA;
55   switch (mode) {
56   case splashModeMono1:
57     if (width > 0) {
58       rowSize = (width + 7) >> 3;
59     } else {
60       rowSize = -1;
61     }
62     break;
63   case splashModeMono8:
64     if (width > 0) {
65       rowSize = width;
66     } else {
67       rowSize = -1;
68     }
69     break;
70   case splashModeRGB8:
71   case splashModeBGR8:
72     if (width > 0 && width <= INT_MAX / 3) {
73       rowSize = width * 3;
74     } else {
75       rowSize = -1;
76     }
77     break;
78   case splashModeXBGR8:
79     if (width > 0 && width <= INT_MAX / 4) {
80       rowSize = width * 4;
81     } else {
82       rowSize = -1;
83     }
84     break;
85 #if SPLASH_CMYK
86   case splashModeCMYK8:
87     if (width > 0 && width <= INT_MAX / 4) {
88       rowSize = width * 4;
89     } else {
90       rowSize = -1;
91     }
92     break;
93 #endif
94   }
95   if (rowSize > 0) {
96     rowSize += rowPad - 1;
97     rowSize -= rowSize % rowPad;
98   }
99   data = (SplashColorPtr)gmallocn(rowSize, height);
100   if (!topDown) {
101     data += (height - 1) * rowSize;
102     rowSize = -rowSize;
103   }
104   if (alphaA) {
105     alpha = (Guchar *)gmallocn(width, height);
106   } else {
107     alpha = NULL;
108   }
109 }
110 
111 
~SplashBitmap()112 SplashBitmap::~SplashBitmap() {
113   if (rowSize < 0) {
114     gfree(data + (height - 1) * rowSize);
115   } else {
116     gfree(data);
117   }
118   gfree(alpha);
119 }
120 
121 
writePNMFile(char * fileName)122 SplashError SplashBitmap::writePNMFile(char *fileName) {
123   FILE *f;
124   SplashError e;
125 
126   if (!(f = fopen(fileName, "wb"))) {
127     return splashErrOpenFile;
128   }
129 
130   e = this->writePNMFile(f);
131 
132   fclose(f);
133   return e;
134 }
135 
136 
writePNMFile(FILE * f)137 SplashError SplashBitmap::writePNMFile(FILE *f) {
138   SplashColorPtr row, p;
139   int x, y;
140 
141   switch (mode) {
142 
143   case splashModeMono1:
144     fprintf(f, "P4\n%d %d\n", width, height);
145     row = data;
146     for (y = 0; y < height; ++y) {
147       p = row;
148       for (x = 0; x < width; x += 8) {
149 	fputc(*p ^ 0xff, f);
150 	++p;
151       }
152       row += rowSize;
153     }
154     break;
155 
156   case splashModeMono8:
157     fprintf(f, "P5\n%d %d\n255\n", width, height);
158     row = data;
159     for (y = 0; y < height; ++y) {
160       p = row;
161       for (x = 0; x < width; ++x) {
162 	fputc(*p, f);
163 	++p;
164       }
165       row += rowSize;
166     }
167     break;
168 
169   case splashModeRGB8:
170     fprintf(f, "P6\n%d %d\n255\n", width, height);
171     row = data;
172     for (y = 0; y < height; ++y) {
173       p = row;
174       for (x = 0; x < width; ++x) {
175 	fputc(splashRGB8R(p), f);
176 	fputc(splashRGB8G(p), f);
177 	fputc(splashRGB8B(p), f);
178 	p += 3;
179       }
180       row += rowSize;
181     }
182     break;
183 
184   case splashModeXBGR8:
185     fprintf(f, "P6\n%d %d\n255\n", width, height);
186     row = data;
187     for (y = 0; y < height; ++y) {
188       p = row;
189       for (x = 0; x < width; ++x) {
190 	fputc(splashBGR8R(p), f);
191 	fputc(splashBGR8G(p), f);
192 	fputc(splashBGR8B(p), f);
193 	p += 4;
194       }
195       row += rowSize;
196     }
197     break;
198 
199 
200   case splashModeBGR8:
201     fprintf(f, "P6\n%d %d\n255\n", width, height);
202     row = data;
203     for (y = 0; y < height; ++y) {
204       p = row;
205       for (x = 0; x < width; ++x) {
206 	fputc(splashBGR8R(p), f);
207 	fputc(splashBGR8G(p), f);
208 	fputc(splashBGR8B(p), f);
209 	p += 3;
210       }
211       row += rowSize;
212     }
213     break;
214 
215 #if SPLASH_CMYK
216   case splashModeCMYK8:
217     // PNM doesn't support CMYK
218     error(-1, "unsupported SplashBitmap mode");
219     return splashErrGeneric;
220     break;
221 #endif
222   }
223   return splashOk;
224 }
225 
226 
getPixel(int x,int y,SplashColorPtr pixel)227 void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
228   SplashColorPtr p;
229 
230   if (y < 0 || y >= height || x < 0 || x >= width) {
231     return;
232   }
233   switch (mode) {
234   case splashModeMono1:
235     p = &data[y * rowSize + (x >> 3)];
236     pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
237     break;
238   case splashModeMono8:
239     p = &data[y * rowSize + x];
240     pixel[0] = p[0];
241     break;
242   case splashModeRGB8:
243     p = &data[y * rowSize + 3 * x];
244     pixel[0] = p[0];
245     pixel[1] = p[1];
246     pixel[2] = p[2];
247     break;
248   case splashModeXBGR8:
249     p = &data[y * rowSize + 4 * x];
250     pixel[0] = p[2];
251     pixel[1] = p[1];
252     pixel[2] = p[0];
253     pixel[3] = p[3];
254     break;
255   case splashModeBGR8:
256     p = &data[y * rowSize + 3 * x];
257     pixel[0] = p[2];
258     pixel[1] = p[1];
259     pixel[2] = p[0];
260     break;
261 #if SPLASH_CMYK
262   case splashModeCMYK8:
263     p = &data[y * rowSize + 4 * x];
264     pixel[0] = p[0];
265     pixel[1] = p[1];
266     pixel[2] = p[2];
267     pixel[3] = p[3];
268     break;
269 #endif
270   }
271 }
272 
getAlpha(int x,int y)273 Guchar SplashBitmap::getAlpha(int x, int y) {
274   return alpha[y * width + x];
275 }
276 
writeImgFile(SplashImageFileFormat format,char * fileName,int hDPI,int vDPI)277 SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI) {
278   FILE *f;
279   SplashError e;
280 
281   if (!(f = fopen(fileName, "wb"))) {
282     return splashErrOpenFile;
283   }
284 
285   e = writeImgFile(format, f, hDPI, vDPI);
286 
287   fclose(f);
288   return e;
289 }
290 
writeImgFile(SplashImageFileFormat format,FILE * f,int hDPI,int vDPI)291 SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI) {
292   ImgWriter *writer;
293 	SplashError e;
294 
295   switch (format) {
296     #ifdef ENABLE_LIBPNG
297     case splashFormatPng:
298 	  writer = new PNGWriter();
299       break;
300     #endif
301 
302     #ifdef ENABLE_LIBJPEG
303     case splashFormatJpeg:
304       writer = new JpegWriter();
305       break;
306     #endif
307 
308     default:
309       // Not the greatest error message, but users of this function should
310       // have already checked whether their desired format is compiled in.
311       error(-1, "Support for this image type not compiled in");
312       return splashErrGeneric;
313   }
314 
315 	e = writeImgFile(writer, f, hDPI, vDPI);
316 	delete writer;
317 	return e;
318 }
319 
writeImgFile(ImgWriter * writer,FILE * f,int hDPI,int vDPI)320 SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) {
321   if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8) {
322     error(-1, "unsupported SplashBitmap mode");
323     return splashErrGeneric;
324   }
325 
326   if (!writer->init(f, width, height, hDPI, vDPI)) {
327     return splashErrGeneric;
328   }
329 
330   switch (mode) {
331     case splashModeRGB8:
332     {
333       SplashColorPtr row;
334       unsigned char **row_pointers = new unsigned char*[height];
335       row = data;
336 
337       for (int y = 0; y < height; ++y) {
338         row_pointers[y] = row;
339         row += rowSize;
340       }
341       if (!writer->writePointers(row_pointers, height)) {
342         delete[] row_pointers;
343         return splashErrGeneric;
344       }
345       delete[] row_pointers;
346     }
347     break;
348 
349     case splashModeXBGR8:
350     {
351       unsigned char *row = new unsigned char[3 * width];
352       for (int y = 0; y < height; y++) {
353         // Convert into a PNG row
354         for (int x = 0; x < width; x++) {
355           row[3*x] = data[y * rowSize + x * 4 + 2];
356           row[3*x+1] = data[y * rowSize + x * 4 + 1];
357           row[3*x+2] = data[y * rowSize + x * 4];
358         }
359 
360         if (!writer->writeRow(&row)) {
361           delete[] row;
362           return splashErrGeneric;
363         }
364       }
365       delete[] row;
366     }
367     break;
368 
369     case splashModeMono8:
370     {
371       unsigned char *row = new unsigned char[3 * width];
372       for (int y = 0; y < height; y++) {
373         // Convert into a PNG row
374         for (int x = 0; x < width; x++) {
375           row[3*x] = data[y * rowSize + x];
376           row[3*x+1] = data[y * rowSize + x];
377           row[3*x+2] = data[y * rowSize + x];
378         }
379 
380         if (!writer->writeRow(&row)) {
381           delete[] row;
382           return splashErrGeneric;
383         }
384       }
385       delete[] row;
386     }
387     break;
388 
389     case splashModeMono1:
390     {
391       unsigned char *row = new unsigned char[3 * width];
392       for (int y = 0; y < height; y++) {
393         // Convert into a PNG row
394         for (int x = 0; x < width; x++) {
395           getPixel(x, y, &row[3*x]);
396           row[3*x+1] = row[3*x];
397           row[3*x+2] = row[3*x];
398         }
399 
400         if (!writer->writeRow(&row)) {
401           delete[] row;
402           return splashErrGeneric;
403         }
404       }
405       delete[] row;
406     }
407     break;
408 
409     default:
410     // can't happen
411     break;
412   }
413 
414   if (writer->close()) {
415     return splashErrGeneric;
416   }
417 
418   return splashOk;
419 }
420