/*
* PS.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
* Copyright 2003 Michael Pfeiffer.
* Copyright 2010 Ithamar Adema.
*/
#include "PS.h"
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <Alert.h>
#include <Bitmap.h>
#include <File.h>
#include <Path.h>
#include "DbgMsg.h"
#include "FilterIO.h"
#include "Halftone.h"
#include "JobData.h"
#include "PackBits.h"
#include "PPDParser.h"
#include "PrinterData.h"
#include "PSCap.h"
#include "PSData.h"
#include "UIDriver.h"
#include "ValidRect.h"
PSDriver::PSDriver(BMessage* message, PrinterData* printerData,
const PrinterCap* printerCap)
:
GraphicsDriver(message, printerData, printerCap),
fPrintedPages(0),
fCompressionMethod(0),
fHalftone(NULL),
fFilterIO(NULL)
{
}
void
PSDriver::_StartFilterIfNeeded()
{
const PSData* data = dynamic_cast<const PSData*>(GetPrinterData());
PPDParser parser(BPath(data->fPPD.String()));
if (parser.InitCheck() == B_OK) {
BString param = parser.GetParameter("FoomaticRIPCommandLine");
char str[3] = "%?";
// for now, we don't have any extra substitutions to do...
// (will be added once we support configuration options from the PPD)
for (str[1] = 'A'; str[1] <= 'Z'; str[1]++)
param.ReplaceAll(str, "");
if (param.Length())
fFilterIO = new FilterIO(param);
if (!fFilterIO || fFilterIO->InitCheck() != B_OK) {
delete fFilterIO;
fFilterIO = NULL;
}
}
}
void
PSDriver::_FlushFilterIfNeeded()
{
if (fFilterIO) {
char buffer[1024];
ssize_t len;
while ((len = fFilterIO->Read(buffer, sizeof(buffer))) > 0)
WriteSpoolData(buffer, len);
}
}
void
PSDriver::_WritePSString(const char* format, ...)
{
char str[256];
va_list ap;
va_start(ap, format);
vsprintf(str, format, ap);
if (fFilterIO)
fFilterIO->Write(str, strlen(str));
else
WriteSpoolData(str, strlen(str));
va_end(ap);
}
void
PSDriver::_WritePSData(const void* data, size_t size)
{
if (fFilterIO)
fFilterIO->Write(data, size);
else
WriteSpoolData(data, size);
}
bool
PSDriver::StartDocument()
{
try {
_StartFilterIfNeeded();
_JobStart();
fHalftone = new Halftone(GetJobData()->GetSurfaceType(),
GetJobData()->GetGamma(), GetJobData()->GetInkDensity(),
GetJobData()->GetDitherType());
return true;
}
catch (TransportException& err) {
return false;
}
}
bool
PSDriver::StartPage(int page)
{
page ++;
_WritePSString("%%%%Page: %d %d\n", page, page);
_WritePSString("gsave\n");
_SetupCTM();
return true;
}
bool
PSDriver::EndPage(int)
{
try {
fPrintedPages ++;
_WritePSString("grestore\n");
_WritePSString("showpage\n");
_FlushFilterIfNeeded();
return true;
}
catch (TransportException& err) {
return false;
}
}
void
PSDriver::_SetupCTM()
{
const float leftMargin = GetJobData()->GetPrintableRect().left;
const float topMargin = GetJobData()->GetPrintableRect().top;
if (GetJobData()->GetOrientation() == JobData::kPortrait) {
// move origin from bottom left to top left
// and set margin
_WritePSString("%f %f translate\n", leftMargin,
GetJobData()->GetPaperRect().Height()-topMargin);
} else {
// landscape:
// move origin from bottom left to margin top and left
// and rotate page contents
_WritePSString("%f %f translate\n", topMargin, leftMargin);
_WritePSString("90 rotate\n");
}
// y values increase from top to bottom
// units of measure is dpi
_WritePSString("72 %d div 72 -%d div scale\n", GetJobData()->GetXres(),
GetJobData()->GetYres());
}
bool
PSDriver::EndDocument(bool)
{
try {
if (fHalftone) {
delete fHalftone;
fHalftone = NULL;
}
_JobEnd();
return true;
}
catch (TransportException& err) {
return false;
}
}
static inline uchar
ToHexDigit(uchar value)
{
if (value <= 9) return '0' + value;
else return 'a' + (value - 10);
}
bool
PSDriver::NextBand(BBitmap* bitmap, BPoint* offset)
{
DBGMSG(("> nextBand\n"));
try {
BRect bounds = bitmap->Bounds();
RECT rc;
rc.left = (int)bounds.left;
rc.top = (int)bounds.top;
rc.right = (int)bounds.right;
rc.bottom = (int)bounds.bottom;
int height = rc.bottom - rc.top + 1;
int x = (int)offset->x;
int y = (int)offset->y;
int page_height = GetPageHeight();
if (y + height > page_height) {
height = page_height - y;
}
rc.bottom = height - 1;
DBGMSG(("height = %d\n", height));
DBGMSG(("x = %d\n", x));
DBGMSG(("y = %d\n", y));
if (get_valid_rect(bitmap, &rc)) {
DBGMSG(("validate rect = %d, %d, %d, %d\n",
rc.left, rc.top, rc.right, rc.bottom));
x = rc.left;
y += rc.top;
bool color = GetJobData()->GetColor() == JobData::kColor;
int width = rc.right - rc.left + 1;
int widthByte = (width + 7) / 8;
// byte boundary
int height = rc.bottom - rc.top + 1;
int in_size = color ? width : widthByte;
int out_size = color ? width * 6: widthByte * 2;
int delta = bitmap->BytesPerRow();
DBGMSG(("width = %d\n", width));
DBGMSG(("widthByte = %d\n", widthByte));
DBGMSG(("height = %d\n", height));
DBGMSG(("out_size = %d\n", out_size));
DBGMSG(("delta = %d\n", delta));
DBGMSG(("renderobj->Get_pixel_depth() = %d\n",
fHalftone->GetPixelDepth()));
uchar* ptr = static_cast<uchar*>(bitmap->Bits())
+ rc.top * delta
+ (rc.left * fHalftone->GetPixelDepth()) / 8;
int compression_method;
int compressed_size;
const uchar* buffer;
uchar* in_buffer = new uchar[in_size];
// gray values
uchar* out_buffer = new uchar[out_size];
// gray values in hexadecimal
auto_ptr<uchar> _in_buffer(in_buffer);
auto_ptr<uchar> _out_buffer(out_buffer);
DBGMSG(("move\n"));
int size = color ? width * 3 : in_size;
_StartRasterGraphics(x, y, width, height, size);
for (int i = rc.top; i <= rc.bottom; i++) {
if (color) {
uchar* out = out_buffer;
uchar* in = ptr;
for (int w = width; w > 0; w --) {
*out++ = ToHexDigit((in[2]) >> 4);
*out++ = ToHexDigit((in[2]) & 15);
*out++ = ToHexDigit((in[1]) >> 4);
*out++ = ToHexDigit((in[1]) & 15);
*out++ = ToHexDigit((in[0]) >> 4);
*out++ = ToHexDigit((in[0]) & 15);
in += 4;
}
} else {
fHalftone->Dither(in_buffer, ptr, x, y, width);
uchar* in = in_buffer;
uchar* out = out_buffer;
for (int w = in_size; w > 0; w --, in ++) {
*in = ~*in; // invert pixels
*out++ = ToHexDigit((*in) >> 4);
*out++ = ToHexDigit((*in) & 15);
}
}
{
compression_method = 0; // uncompressed
buffer = out_buffer;
compressed_size = out_size;
}
_RasterGraphics(
compression_method,
buffer,
compressed_size);
ptr += delta;
y++;
}
_EndRasterGraphics();
} else
DBGMSG(("band bitmap is clean.\n"));
if (y >= page_height) {
offset->x = -1.0;
offset->y = -1.0;
} else
offset->y += height;
DBGMSG(("< nextBand\n"));
return true;
}
catch (TransportException& err) {
BAlert* alert = new BAlert("", err.What(), "OK");
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
return false;
}
}
void
PSDriver::_JobStart()
{
// PostScript header
_WritePSString("%%!PS-Adobe-3.0\n");
_WritePSString("%%%%LanguageLevel: 1\n");
_WritePSString("%%%%Title: %s\n",
GetSpoolMetaData()->GetDescription().c_str());
_WritePSString("%%%%Creator: %s\n",
GetSpoolMetaData()->GetMimeType().c_str());
_WritePSString("%%%%CreationDate: %s",
GetSpoolMetaData()->GetCreationTime().c_str());
_WritePSString("%%%%DocumentMedia: Plain %d %d white 0 ( )\n",
GetJobData()->GetPaperRect().IntegerWidth(),
GetJobData()->GetPaperRect().IntegerHeight());
_WritePSString("%%%%Pages: (atend)\n");
_WritePSString("%%%%EndComments\n");
_WritePSString("%%%%BeginDefaults\n");
_WritePSString("%%%%PageMedia: Plain\n");
_WritePSString("%%%%EndDefaults\n");
}
void
PSDriver::_StartRasterGraphics(int x, int y, int width, int height,
int widthByte)
{
bool color = GetJobData()->GetColor() == JobData::kColor;
fCompressionMethod = -1;
_WritePSString("gsave\n");
_WritePSString("/s %d string def\n", widthByte);
_WritePSString("%d %d translate\n", x, y);
_WritePSString("%d %d scale\n", width, height);
if (color)
_WritePSString("%d %d 8\n", width, height); // 8 bpp
else
_WritePSString("%d %d 1\n", width, height); // 1 bpp
_WritePSString("[%d 0 0 %d 0 0]\n", width, height);
_WritePSString("{ currentfile s readhexstring pop }\n");
if (color) {
_WritePSString("false 3\n"); // single data source, 3 color components
_WritePSString("colorimage\n");
} else
_WritePSString("image\n\n");
}
void
PSDriver::_EndRasterGraphics()
{
_WritePSString("grestore\n");
}
void
PSDriver::_RasterGraphics(int compression_method, const uchar* buffer,
int size)
{
if (fCompressionMethod != compression_method) {
fCompressionMethod = compression_method;
}
_WritePSData(buffer, size);
_WritePSString("\n");
}
void
PSDriver::_JobEnd()
{
_WritePSString("%%%%Pages: %d\n", fPrintedPages);
_WritePSString("%%%%EOF\n");
_FlushFilterIfNeeded();
}
↑ V773 The function was exited without releasing the 'alert' pointer. A memory leak is possible.