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