Spaces:
Running
Running
//======================================================================== | |
// | |
// SplashBitmap.cc | |
// | |
//======================================================================== | |
//======================================================================== | |
// | |
// Modified under the Poppler project - http://poppler.freedesktop.org | |
// | |
// All changes made under the Poppler project to this file are licensed | |
// under GPL version 2 or later | |
// | |
// Copyright (C) 2006, 2009, 2010, 2012, 2015, 2018, 2019, 2021, 2022 Albert Astals Cid <[email protected]> | |
// Copyright (C) 2007 Ilmari Heikkinen <[email protected]> | |
// Copyright (C) 2009 Shen Liang <[email protected]> | |
// Copyright (C) 2009 Stefan Thomas <[email protected]> | |
// Copyright (C) 2010, 2012, 2017 Adrian Johnson <[email protected]> | |
// Copyright (C) 2010 Harry Roberts <[email protected]> | |
// Copyright (C) 2010 Christian Feuersänger <[email protected]> | |
// Copyright (C) 2010, 2015, 2019 William Bader <[email protected]> | |
// Copyright (C) 2011-2013 Thomas Freitag <[email protected]> | |
// Copyright (C) 2012 Anthony Wesley <[email protected]> | |
// Copyright (C) 2015, 2018 Adam Reichold <[email protected]> | |
// Copyright (C) 2016 Kenji Uno <[email protected]> | |
// Copyright (C) 2018 Martin Packman <[email protected]> | |
// Copyright (C) 2019 Christian Persch <[email protected]> | |
// Copyright (C) 2019 Oliver Sander <[email protected]> | |
// | |
// To see a description of the changes please see the Changelog file that | |
// came with your tarball or type make ChangeLog if you are building from git | |
// | |
//======================================================================== | |
//------------------------------------------------------------------------ | |
// SplashBitmap | |
//------------------------------------------------------------------------ | |
SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, SplashColorMode modeA, bool alphaA, bool topDown, const std::vector<GfxSeparationColorSpace *> *separationListA) | |
{ | |
width = widthA; | |
height = heightA; | |
mode = modeA; | |
rowPad = rowPadA; | |
switch (mode) { | |
case splashModeMono1: | |
if (width > 0) { | |
rowSize = (width + 7) >> 3; | |
} else { | |
rowSize = -1; | |
} | |
break; | |
case splashModeMono8: | |
if (width > 0) { | |
rowSize = width; | |
} else { | |
rowSize = -1; | |
} | |
break; | |
case splashModeRGB8: | |
case splashModeBGR8: | |
if (width > 0 && width <= INT_MAX / 3) { | |
rowSize = width * 3; | |
} else { | |
rowSize = -1; | |
} | |
break; | |
case splashModeXBGR8: | |
if (width > 0 && width <= INT_MAX / 4) { | |
rowSize = width * 4; | |
} else { | |
rowSize = -1; | |
} | |
break; | |
case splashModeCMYK8: | |
if (width > 0 && width <= INT_MAX / 4) { | |
rowSize = width * 4; | |
} else { | |
rowSize = -1; | |
} | |
break; | |
case splashModeDeviceN8: | |
if (width > 0 && width <= static_cast<int>(INT_MAX / splashMaxColorComps)) { | |
rowSize = width * splashMaxColorComps; | |
} else { | |
rowSize = -1; | |
} | |
break; | |
} | |
if (rowSize > 0) { | |
rowSize += rowPad - 1; | |
rowSize -= rowSize % rowPad; | |
} | |
data = (SplashColorPtr)gmallocn_checkoverflow(rowSize, height); | |
if (data != nullptr) { | |
if (!topDown) { | |
data += (height - 1) * rowSize; | |
rowSize = -rowSize; | |
} | |
if (alphaA) { | |
alpha = (unsigned char *)gmallocn_checkoverflow(width, height); | |
} else { | |
alpha = nullptr; | |
} | |
} else { | |
alpha = nullptr; | |
} | |
separationList = new std::vector<GfxSeparationColorSpace *>(); | |
if (separationListA != nullptr) { | |
for (const GfxSeparationColorSpace *separation : *separationListA) { | |
separationList->push_back((GfxSeparationColorSpace *)separation->copy()); | |
} | |
} | |
} | |
SplashBitmap *SplashBitmap::copy(const SplashBitmap *src) | |
{ | |
SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(), src->getMode(), src->getAlphaPtr() != nullptr, src->getRowSize() >= 0, src->getSeparationList()); | |
SplashColorConstPtr dataSource = src->getDataPtr(); | |
unsigned char *dataDest = result->getDataPtr(); | |
int amount = src->getRowSize(); | |
if (amount < 0) { | |
dataSource = dataSource + (src->getHeight() - 1) * amount; | |
dataDest = dataDest + (src->getHeight() - 1) * amount; | |
amount *= -src->getHeight(); | |
} else { | |
amount *= src->getHeight(); | |
} | |
memcpy(dataDest, dataSource, amount); | |
if (src->getAlphaPtr() != nullptr) { | |
memcpy(result->getAlphaPtr(), src->getAlphaPtr(), src->getWidth() * src->getHeight()); | |
} | |
return result; | |
} | |
SplashBitmap::~SplashBitmap() | |
{ | |
if (data) { | |
if (rowSize < 0) { | |
gfree(data + (height - 1) * rowSize); | |
} else { | |
gfree(data); | |
} | |
} | |
gfree(alpha); | |
for (auto entry : *separationList) { | |
delete entry; | |
} | |
delete separationList; | |
} | |
SplashError SplashBitmap::writePNMFile(char *fileName) | |
{ | |
FILE *f; | |
SplashError e; | |
if (!(f = openFile(fileName, "wb"))) { | |
return splashErrOpenFile; | |
} | |
e = this->writePNMFile(f); | |
fclose(f); | |
return e; | |
} | |
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 splashModeXBGR8: | |
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 += 4; | |
} | |
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; | |
case splashModeCMYK8: | |
case splashModeDeviceN8: | |
// PNM doesn't support CMYK | |
error(errInternal, -1, "unsupported SplashBitmap mode"); | |
return splashErrGeneric; | |
break; | |
} | |
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 || !data) { | |
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 splashModeXBGR8: | |
p = &data[y * rowSize + 4 * x]; | |
pixel[0] = p[2]; | |
pixel[1] = p[1]; | |
pixel[2] = p[0]; | |
pixel[3] = p[3]; | |
break; | |
case splashModeBGR8: | |
p = &data[y * rowSize + 3 * x]; | |
pixel[0] = p[2]; | |
pixel[1] = p[1]; | |
pixel[2] = p[0]; | |
break; | |
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; | |
case splashModeDeviceN8: | |
p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x]; | |
for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++) { | |
pixel[cp] = p[cp]; | |
} | |
break; | |
} | |
} | |
unsigned char SplashBitmap::getAlpha(int x, int y) | |
{ | |
return alpha[y * width + x]; | |
} | |
SplashColorPtr SplashBitmap::takeData() | |
{ | |
SplashColorPtr data2; | |
data2 = data; | |
data = nullptr; | |
return data2; | |
} | |
SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, const char *fileName, double hDPI, double vDPI, WriteImgParams *params) | |
{ | |
FILE *f; | |
SplashError e; | |
if (!(f = openFile(fileName, "wb"))) { | |
return splashErrOpenFile; | |
} | |
e = writeImgFile(format, f, hDPI, vDPI, params); | |
fclose(f); | |
return e; | |
} | |
void SplashBitmap::setJpegParams(ImgWriter *writer, WriteImgParams *params) | |
{ | |
if (params) { | |
static_cast<JpegWriter *>(writer)->setProgressive(params->jpegProgressive); | |
static_cast<JpegWriter *>(writer)->setOptimize(params->jpegOptimize); | |
if (params->jpegQuality >= 0) { | |
static_cast<JpegWriter *>(writer)->setQuality(params->jpegQuality); | |
} | |
} | |
} | |
SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, double hDPI, double vDPI, WriteImgParams *params) | |
{ | |
ImgWriter *writer; | |
SplashError e; | |
SplashColorMode imageWriterFormat = splashModeRGB8; | |
switch (format) { | |
case splashFormatPng: | |
writer = new PNGWriter(); | |
break; | |
case splashFormatJpegCMYK: | |
writer = new JpegWriter(JpegWriter::CMYK); | |
setJpegParams(writer, params); | |
break; | |
case splashFormatJpeg: | |
writer = new JpegWriter(); | |
setJpegParams(writer, params); | |
break; | |
case splashFormatTiff: | |
switch (mode) { | |
case splashModeMono1: | |
writer = new TiffWriter(TiffWriter::MONOCHROME); | |
imageWriterFormat = splashModeMono1; | |
break; | |
case splashModeMono8: | |
writer = new TiffWriter(TiffWriter::GRAY); | |
imageWriterFormat = splashModeMono8; | |
break; | |
case splashModeRGB8: | |
case splashModeBGR8: | |
writer = new TiffWriter(TiffWriter::RGB); | |
break; | |
case splashModeCMYK8: | |
case splashModeDeviceN8: | |
writer = new TiffWriter(TiffWriter::CMYK); | |
break; | |
default: | |
fprintf(stderr, "TiffWriter: Mode %d not supported\n", mode); | |
writer = new TiffWriter(); | |
} | |
if (writer && params) { | |
((TiffWriter *)writer)->setCompressionString(params->tiffCompression.c_str()); | |
} | |
break; | |
default: | |
// Not the greatest error message, but users of this function should | |
// have already checked whether their desired format is compiled in. | |
error(errInternal, -1, "Support for this image type not compiled in"); | |
return splashErrGeneric; | |
} | |
e = writeImgFile(writer, f, hDPI, vDPI, imageWriterFormat); | |
delete writer; | |
return e; | |
} | |
void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) | |
{ | |
SplashColor col; | |
double c, m, y, k, c1, m1, y1, k1, r, g, b; | |
for (int x = 0; x < width; x++) { | |
getPixel(x, yl, col); | |
c = byteToDbl(col[0]); | |
m = byteToDbl(col[1]); | |
y = byteToDbl(col[2]); | |
k = byteToDbl(col[3]); | |
if (separationList->size() > 0) { | |
for (std::size_t i = 0; i < separationList->size(); i++) { | |
if (col[i + 4] > 0) { | |
GfxCMYK cmyk; | |
GfxColor input; | |
input.c[0] = byteToCol(col[i + 4]); | |
GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]); | |
sepCS->getCMYK(&input, &cmyk); | |
col[0] = colToByte(cmyk.c); | |
col[1] = colToByte(cmyk.m); | |
col[2] = colToByte(cmyk.y); | |
col[3] = colToByte(cmyk.k); | |
c += byteToDbl(col[0]); | |
m += byteToDbl(col[1]); | |
y += byteToDbl(col[2]); | |
k += byteToDbl(col[3]); | |
} | |
} | |
if (c > 1) { | |
c = 1; | |
} | |
if (m > 1) { | |
m = 1; | |
} | |
if (y > 1) { | |
y = 1; | |
} | |
if (k > 1) { | |
k = 1; | |
} | |
} | |
c1 = 1 - c; | |
m1 = 1 - m; | |
y1 = 1 - y; | |
k1 = 1 - k; | |
cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); | |
*line++ = dblToByte(clip01(r)); | |
*line++ = dblToByte(clip01(g)); | |
*line++ = dblToByte(clip01(b)); | |
} | |
} | |
void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line, ConversionMode conversionMode) | |
{ | |
SplashColor col; | |
double c, m, y, k, c1, m1, y1, k1, r, g, b; | |
for (int x = 0; x < width; x++) { | |
getPixel(x, yl, col); | |
c = byteToDbl(col[0]); | |
m = byteToDbl(col[1]); | |
y = byteToDbl(col[2]); | |
k = byteToDbl(col[3]); | |
if (separationList->size() > 0) { | |
for (std::size_t i = 0; i < separationList->size(); i++) { | |
if (col[i + 4] > 0) { | |
GfxCMYK cmyk; | |
GfxColor input; | |
input.c[0] = byteToCol(col[i + 4]); | |
GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]); | |
sepCS->getCMYK(&input, &cmyk); | |
col[0] = colToByte(cmyk.c); | |
col[1] = colToByte(cmyk.m); | |
col[2] = colToByte(cmyk.y); | |
col[3] = colToByte(cmyk.k); | |
c += byteToDbl(col[0]); | |
m += byteToDbl(col[1]); | |
y += byteToDbl(col[2]); | |
k += byteToDbl(col[3]); | |
} | |
} | |
if (c > 1) { | |
c = 1; | |
} | |
if (m > 1) { | |
m = 1; | |
} | |
if (y > 1) { | |
y = 1; | |
} | |
if (k > 1) { | |
k = 1; | |
} | |
} | |
c1 = 1 - c; | |
m1 = 1 - m; | |
y1 = 1 - y; | |
k1 = 1 - k; | |
cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); | |
if (conversionMode == conversionAlphaPremultiplied) { | |
const double a = getAlpha(x, yl) / 255.0; | |
*line++ = dblToByte(clip01(b * a)); | |
*line++ = dblToByte(clip01(g * a)); | |
*line++ = dblToByte(clip01(r * a)); | |
} else { | |
*line++ = dblToByte(clip01(b)); | |
*line++ = dblToByte(clip01(g)); | |
*line++ = dblToByte(clip01(r)); | |
} | |
if (conversionMode != conversionOpaque) { | |
*line++ = getAlpha(x, yl); | |
} else { | |
*line++ = 255; | |
} | |
} | |
} | |
static inline unsigned char div255(int x) | |
{ | |
return (unsigned char)((x + (x >> 8) + 0x80) >> 8); | |
} | |
bool SplashBitmap::convertToXBGR(ConversionMode conversionMode) | |
{ | |
if (mode == splashModeXBGR8) { | |
if (conversionMode != conversionOpaque) { | |
// Copy the alpha channel into the fourth component so that XBGR becomes ABGR. | |
const SplashColorPtr dbegin = data; | |
const SplashColorPtr dend = data + rowSize * height; | |
unsigned char *const abegin = alpha; | |
unsigned char *const aend = alpha + width * height; | |
SplashColorPtr d = dbegin; | |
unsigned char *a = abegin; | |
if (conversionMode == conversionAlphaPremultiplied) { | |
for (; d < dend && a < aend; d += 4, a += 1) { | |
d[0] = div255(d[0] * *a); | |
d[1] = div255(d[1] * *a); | |
d[2] = div255(d[2] * *a); | |
d[3] = *a; | |
} | |
} else { | |
for (d += 3; d < dend && a < aend; d += 4, a += 1) { | |
*d = *a; | |
} | |
} | |
} | |
return true; | |
} | |
int newrowSize = width * 4; | |
SplashColorPtr newdata = (SplashColorPtr)gmallocn_checkoverflow(newrowSize, height); | |
if (newdata != nullptr) { | |
for (int y = 0; y < height; y++) { | |
unsigned char *row = newdata + y * newrowSize; | |
getXBGRLine(y, row, conversionMode); | |
} | |
if (rowSize < 0) { | |
gfree(data + (height - 1) * rowSize); | |
} else { | |
gfree(data); | |
} | |
data = newdata; | |
rowSize = newrowSize; | |
mode = splashModeXBGR8; | |
} | |
return newdata != nullptr; | |
} | |
void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) | |
{ | |
SplashColor col; | |
for (int x = 0; x < width; x++) { | |
getPixel(x, yl, col); | |
if (separationList->size() > 0) { | |
double c, m, y, k; | |
c = byteToDbl(col[0]); | |
m = byteToDbl(col[1]); | |
y = byteToDbl(col[2]); | |
k = byteToDbl(col[3]); | |
for (std::size_t i = 0; i < separationList->size(); i++) { | |
if (col[i + 4] > 0) { | |
GfxCMYK cmyk; | |
GfxColor input; | |
input.c[0] = byteToCol(col[i + 4]); | |
GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]); | |
sepCS->getCMYK(&input, &cmyk); | |
col[0] = colToByte(cmyk.c); | |
col[1] = colToByte(cmyk.m); | |
col[2] = colToByte(cmyk.y); | |
col[3] = colToByte(cmyk.k); | |
c += byteToDbl(col[0]); | |
m += byteToDbl(col[1]); | |
y += byteToDbl(col[2]); | |
k += byteToDbl(col[3]); | |
} | |
} | |
col[0] = dblToByte(clip01(c)); | |
col[1] = dblToByte(clip01(m)); | |
col[2] = dblToByte(clip01(y)); | |
col[3] = dblToByte(clip01(k)); | |
} | |
*line++ = col[0]; | |
*line++ = col[1]; | |
*line++ = col[2]; | |
*line++ = col[3]; | |
} | |
} | |
SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, double hDPI, double vDPI, SplashColorMode imageWriterFormat) | |
{ | |
if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 && mode != splashModeBGR8 && mode != splashModeCMYK8 && mode != splashModeDeviceN8) { | |
error(errInternal, -1, "unsupported SplashBitmap mode"); | |
return splashErrGeneric; | |
} | |
if (!writer->init(f, width, height, hDPI, vDPI)) { | |
return splashErrGeneric; | |
} | |
switch (mode) { | |
case splashModeCMYK8: | |
if (writer->supportCMYK()) { | |
SplashColorPtr row; | |
unsigned char **row_pointers = new unsigned char *[height]; | |
row = data; | |
for (int y = 0; y < height; ++y) { | |
row_pointers[y] = row; | |
row += rowSize; | |
} | |
if (!writer->writePointers(row_pointers, height)) { | |
delete[] row_pointers; | |
return splashErrGeneric; | |
} | |
delete[] row_pointers; | |
} else { | |
unsigned char *row = new unsigned char[3 * width]; | |
for (int y = 0; y < height; y++) { | |
getRGBLine(y, row); | |
if (!writer->writeRow(&row)) { | |
delete[] row; | |
return splashErrGeneric; | |
} | |
} | |
delete[] row; | |
} | |
break; | |
case splashModeDeviceN8: | |
if (writer->supportCMYK()) { | |
unsigned char *row = new unsigned char[4 * width]; | |
for (int y = 0; y < height; y++) { | |
getCMYKLine(y, row); | |
if (!writer->writeRow(&row)) { | |
delete[] row; | |
return splashErrGeneric; | |
} | |
} | |
delete[] row; | |
} else { | |
unsigned char *row = new unsigned char[3 * width]; | |
for (int y = 0; y < height; y++) { | |
getRGBLine(y, row); | |
if (!writer->writeRow(&row)) { | |
delete[] row; | |
return splashErrGeneric; | |
} | |
} | |
delete[] row; | |
} | |
break; | |
case splashModeRGB8: { | |
SplashColorPtr row; | |
unsigned char **row_pointers = new unsigned char *[height]; | |
row = data; | |
for (int y = 0; y < height; ++y) { | |
row_pointers[y] = row; | |
row += rowSize; | |
} | |
if (!writer->writePointers(row_pointers, height)) { | |
delete[] row_pointers; | |
return splashErrGeneric; | |
} | |
delete[] row_pointers; | |
} break; | |
case splashModeBGR8: { | |
unsigned char *row = new unsigned char[3 * width]; | |
for (int y = 0; y < height; y++) { | |
// Convert into a PNG row | |
for (int x = 0; x < width; x++) { | |
row[3 * x] = data[y * rowSize + x * 3 + 2]; | |
row[3 * x + 1] = data[y * rowSize + x * 3 + 1]; | |
row[3 * x + 2] = data[y * rowSize + x * 3]; | |
} | |
if (!writer->writeRow(&row)) { | |
delete[] row; | |
return splashErrGeneric; | |
} | |
} | |
delete[] row; | |
} break; | |
case splashModeXBGR8: { | |
unsigned char *row = new unsigned char[3 * width]; | |
for (int y = 0; y < height; y++) { | |
// Convert into a PNG row | |
for (int x = 0; x < width; x++) { | |
row[3 * x] = data[y * rowSize + x * 4 + 2]; | |
row[3 * x + 1] = data[y * rowSize + x * 4 + 1]; | |
row[3 * x + 2] = data[y * rowSize + x * 4]; | |
} | |
if (!writer->writeRow(&row)) { | |
delete[] row; | |
return splashErrGeneric; | |
} | |
} | |
delete[] row; | |
} break; | |
case splashModeMono8: { | |
if (imageWriterFormat == splashModeMono8) { | |
SplashColorPtr row; | |
unsigned char **row_pointers = new unsigned char *[height]; | |
row = data; | |
for (int y = 0; y < height; ++y) { | |
row_pointers[y] = row; | |
row += rowSize; | |
} | |
if (!writer->writePointers(row_pointers, height)) { | |
delete[] row_pointers; | |
return splashErrGeneric; | |
} | |
delete[] row_pointers; | |
} else if (imageWriterFormat == splashModeRGB8) { | |
unsigned char *row = new unsigned char[3 * width]; | |
for (int y = 0; y < height; y++) { | |
// Convert into a PNG row | |
for (int x = 0; x < width; x++) { | |
row[3 * x] = data[y * rowSize + x]; | |
row[3 * x + 1] = data[y * rowSize + x]; | |
row[3 * x + 2] = data[y * rowSize + x]; | |
} | |
if (!writer->writeRow(&row)) { | |
delete[] row; | |
return splashErrGeneric; | |
} | |
} | |
delete[] row; | |
} else { | |
// only splashModeMono8 or splashModeRGB8 | |
return splashErrGeneric; | |
} | |
} break; | |
case splashModeMono1: { | |
if (imageWriterFormat == splashModeMono1) { | |
SplashColorPtr row; | |
unsigned char **row_pointers = new unsigned char *[height]; | |
row = data; | |
for (int y = 0; y < height; ++y) { | |
row_pointers[y] = row; | |
row += rowSize; | |
} | |
if (!writer->writePointers(row_pointers, height)) { | |
delete[] row_pointers; | |
return splashErrGeneric; | |
} | |
delete[] row_pointers; | |
} else if (imageWriterFormat == splashModeRGB8) { | |
unsigned char *row = new unsigned char[3 * width]; | |
for (int y = 0; y < height; y++) { | |
// Convert into a PNG row | |
for (int x = 0; x < width; x++) { | |
getPixel(x, y, &row[3 * x]); | |
row[3 * x + 1] = row[3 * x]; | |
row[3 * x + 2] = row[3 * x]; | |
} | |
if (!writer->writeRow(&row)) { | |
delete[] row; | |
return splashErrGeneric; | |
} | |
} | |
delete[] row; | |
} else { | |
// only splashModeMono1 or splashModeRGB8 | |
return splashErrGeneric; | |
} | |
} break; | |
default: | |
// can't happen | |
break; | |
} | |
if (!writer->close()) { | |
return splashErrGeneric; | |
} | |
return splashOk; | |
} | |