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