Files
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

289 lines
6.4 KiB
C++

//========================================================================
//
// 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;
}