1 //========================================================================
2 //
3 // SplashBitmap.cc
4 //
5 // Copyright 2003-2013 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 #include <aconf.h>
10 
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14 
15 #include <stdio.h>
16 #include <limits.h>
17 #include "gmem.h"
18 #include "gmempp.h"
19 #include "gfile.h"
20 #include "Trace.h"
21 #include "SplashErrorCodes.h"
22 #include "SplashBitmap.h"
23 
24 //------------------------------------------------------------------------
25 // SplashBitmap
26 //------------------------------------------------------------------------
27 
SplashBitmap(int widthA,int heightA,int rowPad,SplashColorMode modeA,GBool alphaA,GBool topDown,SplashBitmap * parentA)28 SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
29 			   SplashColorMode modeA, GBool alphaA,
30 			   GBool topDown, SplashBitmap *parentA) {
31   // NB: this code checks that rowSize fits in a signed 32-bit
32   // integer, because some code (outside this class) makes that
33   // assumption
34   width = widthA;
35   height = heightA;
36   mode = modeA;
37   switch (mode) {
38   case splashModeMono1:
39     if (width <= 0) {
40       gMemError("invalid bitmap width");
41     }
42     rowSize = (width + 7) >> 3;
43     break;
44   case splashModeMono8:
45     if (width <= 0) {
46       gMemError("invalid bitmap width");
47     }
48     rowSize = width;
49     break;
50   case splashModeRGB8:
51   case splashModeBGR8:
52     if (width <= 0 || width > INT_MAX / 3) {
53       gMemError("invalid bitmap width");
54     }
55     rowSize = (SplashBitmapRowSize)width * 3;
56     break;
57 #if SPLASH_CMYK
58   case splashModeCMYK8:
59     if (width <= 0 || width > INT_MAX / 4) {
60       gMemError("invalid bitmap width");
61     }
62     rowSize = (SplashBitmapRowSize)width * 4;
63     break;
64 #endif
65   }
66   rowSize += rowPad - 1;
67   rowSize -= rowSize % rowPad;
68 
69   traceAlloc(this, "alloc bitmap: %d x %d x %d %s -> %lld bytes",
70 	     width, height, splashColorModeNComps[mode],
71 	     alphaA ? "with alpha" : "without alpha",
72 	     height * rowSize + (alphaA ? height * width : 0));
73 
74   parent = parentA;
75   oldData = NULL;
76   oldAlpha = NULL;
77   oldRowSize = 0;
78   oldAlphaRowSize = 0;
79   oldHeight = 0;
80   if (parent && parent->oldData &&
81       parent->oldRowSize == rowSize &&
82       parent->oldHeight == height) {
83     data = parent->oldData;
84     parent->oldData = NULL;
85     traceMessage("reusing bitmap memory");
86   } else {
87     data = (SplashColorPtr)gmallocn64(height, rowSize);
88     traceMessage("not reusing bitmap memory"
89 		 " (parent=%p parent->oldData=%p same-size=%d)",
90 		 parent, parent ? parent->oldData : NULL,
91 		 parent ? (parent->oldRowSize == rowSize &&
92 			   parent->oldHeight == height) : 0);
93   }
94   if (!topDown) {
95     data += (height - 1) * rowSize;
96     rowSize = -rowSize;
97   }
98   if (alphaA) {
99     alphaRowSize = width;
100     if (parent && parent->oldAlpha &&
101 	parent->oldAlphaRowSize == alphaRowSize &&
102 	parent->oldHeight == height) {
103       alpha = parent->oldAlpha;
104       parent->oldAlpha = NULL;
105     } else {
106       alpha = (Guchar *)gmallocn64(height, alphaRowSize);
107     }
108   } else {
109     alphaRowSize = 0;
110     alpha = NULL;
111   }
112 }
113 
~SplashBitmap()114 SplashBitmap::~SplashBitmap() {
115   traceFree(this, "free bitmap");
116   if (data && rowSize < 0) {
117     rowSize = -rowSize;
118     data -= (height - 1) * rowSize;
119   }
120   if (parent && rowSize > 4000000 / height) {
121     gfree(parent->oldData);
122     gfree(parent->oldAlpha);
123     parent->oldData = data;
124     parent->oldAlpha = alpha;
125     parent->oldRowSize = rowSize;
126     parent->oldAlphaRowSize = alphaRowSize;
127     parent->oldHeight = height;
128   } else {
129     gfree(data);
130     gfree(alpha);
131   }
132   gfree(oldData);
133   gfree(oldAlpha);
134 }
135 
writePNMFile(char * fileName)136 SplashError SplashBitmap::writePNMFile(char *fileName) {
137   FILE *f;
138   SplashError err;
139 
140   if (!(f = openFile(fileName, "wb"))) {
141     return splashErrOpenFile;
142   }
143   err = writePNMFile(f);
144   fclose(f);
145   return err;
146 }
147 
writePNMFile(FILE * f)148 SplashError SplashBitmap::writePNMFile(FILE *f) {
149   SplashColorPtr row, p;
150   int x, y;
151 
152   switch (mode) {
153 
154   case splashModeMono1:
155     fprintf(f, "P4\n%d %d\n", width, height);
156     row = data;
157     for (y = 0; y < height; ++y) {
158       p = row;
159       for (x = 0; x < width; x += 8) {
160 	fputc(*p ^ 0xff, f);
161 	++p;
162       }
163       row += rowSize;
164     }
165     break;
166 
167   case splashModeMono8:
168     fprintf(f, "P5\n%d %d\n255\n", width, height);
169     row = data;
170     for (y = 0; y < height; ++y) {
171       fwrite(row, 1, width, f);
172       row += rowSize;
173     }
174     break;
175 
176   case splashModeRGB8:
177     fprintf(f, "P6\n%d %d\n255\n", width, height);
178     row = data;
179     for (y = 0; y < height; ++y) {
180       fwrite(row, 1, 3 * width, f);
181       row += rowSize;
182     }
183     break;
184 
185   case splashModeBGR8:
186     fprintf(f, "P6\n%d %d\n255\n", width, height);
187     row = data;
188     for (y = 0; y < height; ++y) {
189       p = row;
190       for (x = 0; x < width; ++x) {
191 	fputc(splashBGR8R(p), f);
192 	fputc(splashBGR8G(p), f);
193 	fputc(splashBGR8B(p), f);
194 	p += 3;
195       }
196       row += rowSize;
197     }
198     break;
199 
200 #if SPLASH_CMYK
201   case splashModeCMYK8:
202     fprintf(f, "P7\n");
203     fprintf(f, "WIDTH %d\n", width);
204     fprintf(f, "HEIGHT %d\n", height);
205     fprintf(f, "DEPTH 4\n");
206     fprintf(f, "MAXVAL 255\n");
207     fprintf(f, "TUPLTYPE CMYK\n");
208     fprintf(f, "ENDHDR\n");
209     row = data;
210     for (y = 0; y < height; ++y) {
211       fwrite(row, 1, 4 * width, f);
212       row += rowSize;
213     }
214     break;
215 #endif
216 
217   }
218 
219   return splashOk;
220 }
221 
writeAlphaPGMFile(char * fileName)222 SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) {
223   FILE *f;
224 
225   if (!alpha) {
226     return splashErrModeMismatch;
227   }
228   if (!(f = openFile(fileName, "wb"))) {
229     return splashErrOpenFile;
230   }
231   fprintf(f, "P5\n%d %d\n255\n", width, height);
232   fwrite(alpha, 1, width * height, f);
233   fclose(f);
234   return splashOk;
235 }
236 
237 
getPixel(int x,int y,SplashColorPtr pixel)238 void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
239   SplashColorPtr p;
240 
241   if (y < 0 || y >= height || x < 0 || x >= width) {
242     return;
243   }
244   switch (mode) {
245   case splashModeMono1:
246     p = &data[y * rowSize + (x >> 3)];
247     pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
248     break;
249   case splashModeMono8:
250     p = &data[y * rowSize + x];
251     pixel[0] = p[0];
252     break;
253   case splashModeRGB8:
254     p = &data[y * rowSize + 3 * x];
255     pixel[0] = p[0];
256     pixel[1] = p[1];
257     pixel[2] = p[2];
258     break;
259   case splashModeBGR8:
260     p = &data[y * rowSize + 3 * x];
261     pixel[0] = p[2];
262     pixel[1] = p[1];
263     pixel[2] = p[0];
264     break;
265 #if SPLASH_CMYK
266   case splashModeCMYK8:
267     p = &data[y * rowSize + 4 * x];
268     pixel[0] = p[0];
269     pixel[1] = p[1];
270     pixel[2] = p[2];
271     pixel[3] = p[3];
272     break;
273 #endif
274   }
275 }
276 
getAlpha(int x,int y)277 Guchar SplashBitmap::getAlpha(int x, int y) {
278   return alpha[y * (size_t)width + x];
279 }
280 
takeData()281 SplashColorPtr SplashBitmap::takeData() {
282   SplashColorPtr data2;
283 
284   data2 = data;
285   data = NULL;
286   return data2;
287 }
288 
289