aboutsummaryrefslogtreecommitdiff
path: root/splash/SplashBitmap.cc
diff options
context:
space:
mode:
authorCalvin Morrison <calvin@pobox.com>2023-04-05 14:13:39 -0400
committerCalvin Morrison <calvin@pobox.com>2023-04-05 14:13:39 -0400
commit835e373b3eeaabcd0621ed6798ab500f37982fae (patch)
treedfa16b0e2e1b4956b38f693220eac4e607802133 /splash/SplashBitmap.cc
xpdf-no-select-disableHEADmaster
Diffstat (limited to 'splash/SplashBitmap.cc')
-rw-r--r--splash/SplashBitmap.cc288
1 files changed, 288 insertions, 0 deletions
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
new file mode 100644
index 0000000..db341d7
--- /dev/null
+++ b/splash/SplashBitmap.cc
@@ -0,0 +1,288 @@
+//========================================================================
+//
+// SplashBitmap.cc
+//
+// Copyright 2003-2013 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <limits.h>
+#include "gmem.h"
+#include "gmempp.h"
+#include "gfile.h"
+#include "Trace.h"
+#include "SplashErrorCodes.h"
+#include "SplashBitmap.h"
+
+//------------------------------------------------------------------------
+// SplashBitmap
+//------------------------------------------------------------------------
+
+SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
+ SplashColorMode modeA, GBool alphaA,
+ GBool topDown, SplashBitmap *parentA) {
+ // NB: this code checks that rowSize fits in a signed 32-bit
+ // integer, because some code (outside this class) makes that
+ // assumption
+ width = widthA;
+ height = heightA;
+ mode = modeA;
+ switch (mode) {
+ case splashModeMono1:
+ if (width <= 0) {
+ gMemError("invalid bitmap width");
+ }
+ rowSize = (width + 7) >> 3;
+ break;
+ case splashModeMono8:
+ if (width <= 0) {
+ gMemError("invalid bitmap width");
+ }
+ rowSize = width;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ if (width <= 0 || width > INT_MAX / 3) {
+ gMemError("invalid bitmap width");
+ }
+ rowSize = (SplashBitmapRowSize)width * 3;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ if (width <= 0 || width > INT_MAX / 4) {
+ gMemError("invalid bitmap width");
+ }
+ rowSize = (SplashBitmapRowSize)width * 4;
+ break;
+#endif
+ }
+ rowSize += rowPad - 1;
+ rowSize -= rowSize % rowPad;
+
+ traceAlloc(this, "alloc bitmap: %d x %d x %d %s -> %lld bytes",
+ width, height, splashColorModeNComps[mode],
+ alphaA ? "with alpha" : "without alpha",
+ height * rowSize + (alphaA ? height * width : 0));
+
+ parent = parentA;
+ oldData = NULL;
+ oldAlpha = NULL;
+ oldRowSize = 0;
+ oldAlphaRowSize = 0;
+ oldHeight = 0;
+ if (parent && parent->oldData &&
+ parent->oldRowSize == rowSize &&
+ parent->oldHeight == height) {
+ data = parent->oldData;
+ parent->oldData = NULL;
+ traceMessage("reusing bitmap memory");
+ } else {
+ data = (SplashColorPtr)gmallocn64(height, rowSize);
+ traceMessage("not reusing bitmap memory"
+ " (parent=%p parent->oldData=%p same-size=%d)",
+ parent, parent ? parent->oldData : NULL,
+ parent ? (parent->oldRowSize == rowSize &&
+ parent->oldHeight == height) : 0);
+ }
+ if (!topDown) {
+ data += (height - 1) * rowSize;
+ rowSize = -rowSize;
+ }
+ if (alphaA) {
+ alphaRowSize = width;
+ if (parent && parent->oldAlpha &&
+ parent->oldAlphaRowSize == alphaRowSize &&
+ parent->oldHeight == height) {
+ alpha = parent->oldAlpha;
+ parent->oldAlpha = NULL;
+ } else {
+ alpha = (Guchar *)gmallocn64(height, alphaRowSize);
+ }
+ } else {
+ alphaRowSize = 0;
+ alpha = NULL;
+ }
+}
+
+SplashBitmap::~SplashBitmap() {
+ traceFree(this, "free bitmap");
+ if (data && rowSize < 0) {
+ rowSize = -rowSize;
+ data -= (height - 1) * rowSize;
+ }
+ if (parent && rowSize > 4000000 / height) {
+ gfree(parent->oldData);
+ gfree(parent->oldAlpha);
+ parent->oldData = data;
+ parent->oldAlpha = alpha;
+ parent->oldRowSize = rowSize;
+ parent->oldAlphaRowSize = alphaRowSize;
+ parent->oldHeight = height;
+ } else {
+ gfree(data);
+ gfree(alpha);
+ }
+ gfree(oldData);
+ gfree(oldAlpha);
+}
+
+SplashError SplashBitmap::writePNMFile(char *fileName) {
+ FILE *f;
+ SplashError err;
+
+ if (!(f = openFile(fileName, "wb"))) {
+ return splashErrOpenFile;
+ }
+ err = writePNMFile(f);
+ fclose(f);
+ return err;
+}
+
+SplashError SplashBitmap::writePNMFile(FILE *f) {
+ SplashColorPtr row, p;
+ int x, y;
+
+ switch (mode) {
+
+ case splashModeMono1:
+ fprintf(f, "P4\n%d %d\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ p = row;
+ for (x = 0; x < width; x += 8) {
+ fputc(*p ^ 0xff, f);
+ ++p;
+ }
+ row += rowSize;
+ }
+ break;
+
+ case splashModeMono8:
+ fprintf(f, "P5\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ fwrite(row, 1, width, f);
+ row += rowSize;
+ }
+ break;
+
+ case splashModeRGB8:
+ fprintf(f, "P6\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ fwrite(row, 1, 3 * width, f);
+ row += rowSize;
+ }
+ break;
+
+ case splashModeBGR8:
+ fprintf(f, "P6\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ p = row;
+ for (x = 0; x < width; ++x) {
+ fputc(splashBGR8R(p), f);
+ fputc(splashBGR8G(p), f);
+ fputc(splashBGR8B(p), f);
+ p += 3;
+ }
+ row += rowSize;
+ }
+ break;
+
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ fprintf(f, "P7\n");
+ fprintf(f, "WIDTH %d\n", width);
+ fprintf(f, "HEIGHT %d\n", height);
+ fprintf(f, "DEPTH 4\n");
+ fprintf(f, "MAXVAL 255\n");
+ fprintf(f, "TUPLTYPE CMYK\n");
+ fprintf(f, "ENDHDR\n");
+ row = data;
+ for (y = 0; y < height; ++y) {
+ fwrite(row, 1, 4 * width, f);
+ row += rowSize;
+ }
+ break;
+#endif
+
+ }
+
+ return splashOk;
+}
+
+SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) {
+ FILE *f;
+
+ if (!alpha) {
+ return splashErrModeMismatch;
+ }
+ if (!(f = openFile(fileName, "wb"))) {
+ return splashErrOpenFile;
+ }
+ fprintf(f, "P5\n%d %d\n255\n", width, height);
+ fwrite(alpha, 1, width * height, f);
+ fclose(f);
+ return splashOk;
+}
+
+
+void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
+ SplashColorPtr p;
+
+ if (y < 0 || y >= height || x < 0 || x >= width) {
+ return;
+ }
+ switch (mode) {
+ case splashModeMono1:
+ p = &data[y * rowSize + (x >> 3)];
+ pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
+ break;
+ case splashModeMono8:
+ p = &data[y * rowSize + x];
+ pixel[0] = p[0];
+ break;
+ case splashModeRGB8:
+ p = &data[y * rowSize + 3 * x];
+ pixel[0] = p[0];
+ pixel[1] = p[1];
+ pixel[2] = p[2];
+ break;
+ case splashModeBGR8:
+ p = &data[y * rowSize + 3 * x];
+ pixel[0] = p[2];
+ pixel[1] = p[1];
+ pixel[2] = p[0];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ p = &data[y * rowSize + 4 * x];
+ pixel[0] = p[0];
+ pixel[1] = p[1];
+ pixel[2] = p[2];
+ pixel[3] = p[3];
+ break;
+#endif
+ }
+}
+
+Guchar SplashBitmap::getAlpha(int x, int y) {
+ return alpha[y * (size_t)width + x];
+}
+
+SplashColorPtr SplashBitmap::takeData() {
+ SplashColorPtr data2;
+
+ data2 = data;
+ data = NULL;
+ return data2;
+}
+