/*
* PCL6.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
* Copyright 2003 Michael Pfeiffer.
*/
#include "PCL6.h"
#include <memory.h>
#include <Alert.h>
#include <Bitmap.h>
#include <File.h>
#include "DbgMsg.h"
#include "DeltaRowCompression.h"
#include "Halftone.h"
#include "JobData.h"
#include "PackBits.h"
#include "PCL6Cap.h"
#include "PCL6Config.h"
#include "PCL6Rasterizer.h"
#include "PrinterData.h"
#include "UIDriver.h"
#include "ValidRect.h"
// DeltaRowStreamCompressor writes the delta row directly to the
// in the contructor specified stream.
class DeltaRowStreamCompressor : public AbstractDeltaRowCompressor
{
public:
DeltaRowStreamCompressor(int rowSize, uchar initialSeed,
PCL6Writer* writer)
:
AbstractDeltaRowCompressor(rowSize, initialSeed),
fWriter(writer)
{}
protected:
void AppendByteToDeltaRow(uchar byte)
{
fWriter->Append(byte);
}
private:
PCL6Writer* fWriter;
};
PCL6Driver::PCL6Driver(BMessage* message, PrinterData* printerData,
const PrinterCap* printerCap)
:
GraphicsDriver(message, printerData, printerCap),
fWriter(NULL),
fMediaSide(PCL6Writer::kFrontMediaSide),
fHalftone(NULL)
{
}
void
PCL6Driver::Write(const uint8* data, uint32 size)
{
WriteSpoolData(data, size);
}
bool
PCL6Driver::StartDocument()
{
try {
_JobStart();
fHalftone = new Halftone(GetJobData()->GetSurfaceType(),
GetJobData()->GetGamma(), GetJobData()->GetInkDensity(),
GetJobData()->GetDitherType());
return true;
}
catch (TransportException& err) {
return false;
}
}
bool
PCL6Driver::EndDocument(bool)
{
try {
if (fHalftone)
delete fHalftone;
_JobEnd();
return true;
}
catch (TransportException& err) {
return false;
}
}
bool
PCL6Driver::NextBand(BBitmap* bitmap, BPoint* offset)
{
DBGMSG(("> nextBand\n"));
try {
int y = (int)offset->y;
PCL6Rasterizer* rasterizer;
if (_UseColorMode()) {
#if COLOR_DEPTH == 8
rasterizer = new ColorRGBRasterizer(fHalftone);
#elif COLOR_DEPTH == 1
rasterizer = new ColorRasterizer(fHalftone);
#else
#error COLOR_DEPTH must be either 1 or 8!
#endif
} else
rasterizer = new MonochromeRasterizer(fHalftone);
auto_ptr<Rasterizer> _rasterizer(rasterizer);
bool valid = rasterizer->SetBitmap((int)offset->x, (int)offset->y,
bitmap, GetPageHeight());
if (valid) {
rasterizer->InitializeBuffer();
// Use compressor to calculate delta row size
DeltaRowCompressor* deltaRowCompressor = NULL;
if (_SupportsDeltaRowCompression()) {
deltaRowCompressor =
new DeltaRowCompressor(rasterizer->GetOutRowSize(), 0);
if (deltaRowCompressor->InitCheck() != B_OK) {
delete deltaRowCompressor;
return false;
}
}
auto_ptr<DeltaRowCompressor>_deltaRowCompressor(deltaRowCompressor);
int deltaRowSize = 0;
// remember position
int xPage = rasterizer->GetX();
int yPage = rasterizer->GetY();
while (rasterizer->HasNextLine()) {
const uchar* rowBuffer =
static_cast<const uchar*>(rasterizer->RasterizeNextLine());
if (deltaRowCompressor != NULL) {
int size =
deltaRowCompressor->CalculateSize(rowBuffer, true);
deltaRowSize += size + 2;
// two bytes for the row byte count
}
}
y = rasterizer->GetY();
uchar* outBuffer = rasterizer->GetOutBuffer();
int outBufferSize = rasterizer->GetOutBufferSize();
int outRowSize = rasterizer->GetOutRowSize();
int width = rasterizer->GetWidth();
int height = rasterizer->GetHeight();
_WriteBitmap(outBuffer, outBufferSize, outRowSize, xPage, yPage,
width, height, deltaRowSize);
}
if (y >= GetPageHeight()) {
offset->x = -1.0;
offset->y = -1.0;
} else {
offset->y += bitmap->Bounds().IntegerHeight()+1;
}
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
PCL6Driver::_WriteBitmap(const uchar* buffer, int outSize, int rowSize, int x,
int y, int width, int height, int deltaRowSize)
{
// choose the best compression method
PCL6Writer::Compression compressionMethod = PCL6Writer::kNoCompression;
int dataSize = outSize;
#if ENABLE_DELTA_ROW_COMPRESSION
if (_SupportsDeltaRowCompression() && deltaRowSize < dataSize) {
compressionMethod = PCL6Writer::kDeltaRowCompression;
dataSize = deltaRowSize;
}
#endif
#if ENABLE_RLE_COMPRESSION
if (_SupportsRLECompression()) {
int rleSize = pack_bits_size(buffer, outSize);
if (rleSize < dataSize) {
compressionMethod = PCL6Writer::kRLECompression;
dataSize = rleSize;
}
}
#endif
// write bitmap
_Move(x, y);
_StartRasterGraphics(x, y, width, height, compressionMethod);
_RasterGraphics(buffer, outSize, dataSize, rowSize, height,
compressionMethod);
_EndRasterGraphics();
#if DISPLAY_COMPRESSION_STATISTICS
fprintf(stderr, "Out Size %d %2.2f\n", (int)outSize, 100.0);
#if ENABLE_RLE_COMPRESSION
fprintf(stderr, "RLE Size %d %2.2f\n", (int)rleSize,
100.0 * rleSize / outSize);
#endif
#if ENABLE_DELTA_ROW_COMPRESSION
fprintf(stderr, "Delta Row Size %d %2.2f\n", (int)deltaRowSize,
100.0 * deltaRowSize / outSize);
#endif
fprintf(stderr, "Data Size %d %2.2f\n", (int)dataSize,
100.0 * dataSize / outSize);
#endif
}
void
PCL6Driver::_JobStart()
{
// PCL6 begin
fWriter = new PCL6Writer(this);
PCL6Writer::ProtocolClass pc =
(PCL6Writer::ProtocolClass)GetProtocolClass();
fWriter->PJLHeader(pc, GetJobData()->GetXres(),
"Copyright (c) 2003 - 2010 Haiku");
fWriter->BeginSession(GetJobData()->GetXres(), GetJobData()->GetYres(),
PCL6Writer::kInch, PCL6Writer::kBackChAndErrPage);
fWriter->OpenDataSource();
fMediaSide = PCL6Writer::kFrontMediaSide;
}
bool
PCL6Driver::StartPage(int)
{
PCL6Writer::Orientation orientation = PCL6Writer::kPortrait;
if (GetJobData()->GetOrientation() == JobData::kLandscape) {
orientation = PCL6Writer::kLandscape;
}
PCL6Writer::MediaSize mediaSize =
_MediaSize(GetJobData()->GetPaper());
PCL6Writer::MediaSource mediaSource =
_MediaSource(GetJobData()->GetPaperSource());
if (GetJobData()->GetPrintStyle() == JobData::kSimplex) {
fWriter->BeginPage(orientation, mediaSize, mediaSource);
} else if (GetJobData()->GetPrintStyle() == JobData::kDuplex) {
// TODO move duplex binding option to UI
fWriter->BeginPage(orientation, mediaSize, mediaSource,
PCL6Writer::kDuplexVerticalBinding, fMediaSide);
if (fMediaSide == PCL6Writer::kFrontMediaSide)
fMediaSide = PCL6Writer::kBackMediaSide;
else
fMediaSide = PCL6Writer::kFrontMediaSide;
} else
return false;
// PageOrigin from Windows NT printer driver
int x = 142 * GetJobData()->GetXres() / 600;
int y = 100 * GetJobData()->GetYres() / 600;
fWriter->SetPageOrigin(x, y);
fWriter->SetColorSpace(_UseColorMode() ? PCL6Writer::kRGB
: PCL6Writer::kGray);
fWriter->SetPaintTxMode(PCL6Writer::kOpaque);
fWriter->SetSourceTxMode(PCL6Writer::kOpaque);
fWriter->SetROP(204);
return true;
}
void
PCL6Driver::_StartRasterGraphics(int x, int y, int width, int height,
PCL6Writer::Compression compressionMethod)
{
PCL6Writer::ColorDepth colorDepth;
if (_UseColorMode()) {
#if COLOR_DEPTH == 8
colorDepth = PCL6Writer::k8Bit;
#elif COLOR_DEPTH == 1
colorDepth = PCL6Writer::k1Bit;
#else
#error COLOR_DEPTH must be either 1 or 8!
#endif
} else
colorDepth = PCL6Writer::k1Bit;
fWriter->BeginImage(PCL6Writer::kDirectPixel, colorDepth, width, height,
width, height);
fWriter->ReadImage(compressionMethod, 0, height);
}
void
PCL6Driver::_EndRasterGraphics()
{
fWriter->EndImage();
}
void
PCL6Driver::_RasterGraphics(const uchar* buffer, int bufferSize, int dataSize,
int rowSize, int height, int compressionMethod)
{
// write bitmap byte size
fWriter->EmbeddedDataPrefix32(dataSize);
// write data
if (compressionMethod == PCL6Writer::kRLECompression) {
// use RLE compression
uchar* outBuffer = new uchar[dataSize];
pack_bits(outBuffer, buffer, bufferSize);
fWriter->Append(outBuffer, dataSize);
delete[] outBuffer;
return;
} else if (compressionMethod == PCL6Writer::kDeltaRowCompression) {
// use delta row compression
DeltaRowStreamCompressor compressor(rowSize, 0, fWriter);
if (compressor.InitCheck() != B_OK) {
return;
}
const uint8* row = buffer;
for (int i = 0; i < height; i ++) {
// write row byte count
int32 size = compressor.CalculateSize(row);
fWriter->Append((uint16)size);
if (size > 0) {
// write delta row
compressor.Compress(row);
}
row += rowSize;
}
} else {
// write raw data
fWriter->Append(buffer, bufferSize);
}
}
bool
PCL6Driver::EndPage(int)
{
try {
fWriter->EndPage(GetJobData()->GetCopies());
return true;
}
catch (TransportException& err) {
return false;
}
}
void
PCL6Driver::_JobEnd()
{
fWriter->CloseDataSource();
fWriter->EndSession();
fWriter->PJLFooter();
fWriter->Flush();
delete fWriter;
fWriter = NULL;
}
void
PCL6Driver::_Move(int x, int y)
{
fWriter->SetCursor(x, y);
}
bool
PCL6Driver::_SupportsRLECompression()
{
return GetJobData()->GetColor() != JobData::kColorCompressionDisabled;
}
bool
PCL6Driver::_SupportsDeltaRowCompression()
{
return GetProtocolClass() >= PCL6Writer::kProtocolClass2_1
&& GetJobData()->GetColor() != JobData::kColorCompressionDisabled;
}
bool
PCL6Driver::_UseColorMode()
{
return GetJobData()->GetColor() != JobData::kMonochrome;
}
PCL6Writer::MediaSize
PCL6Driver::_MediaSize(JobData::Paper paper)
{
switch (paper) {
case JobData::kLetter:
return PCL6Writer::kLetterPaper;
case JobData::kLegal:
return PCL6Writer::kLegalPaper;
case JobData::kA4:
return PCL6Writer::kA4Paper;
case JobData::kExecutive:
return PCL6Writer::kExecPaper;
case JobData::kLedger:
return PCL6Writer::kLedgerPaper;
case JobData::kA3:
return PCL6Writer::kA3Paper;
case JobData::kB5:
return PCL6Writer::kB5Paper;
case JobData::kJapanesePostcard:
return PCL6Writer::kJPostcard;
case JobData::kA5:
return PCL6Writer::kA5Paper;
case JobData::kB4:
return PCL6Writer::kJB4Paper;
/*
case : return PCL6Writer::kCOM10Envelope;
case : return PCL6Writer::kMonarchEnvelope;
case : return PCL6Writer::kC5Envelope;
case : return PCL6Writer::kDLEnvelope;
case : return PCL6Writer::kJB4Paper;
case : return PCL6Writer::kJB5Paper;
case : return PCL6Writer::kB5Envelope;
case : return PCL6Writer::kJPostcard;
case : return PCL6Writer::kJDoublePostcard;
case : return PCL6Writer::kA5Paper;
case : return PCL6Writer::kA6Paper;
case : return PCL6Writer::kJB6Paper;
case : return PCL6Writer::kJIS8KPaper;
case : return PCL6Writer::kJIS16KPaper;
case : return PCL6Writer::kJISExecPaper;
*/
default:
return PCL6Writer::kLegalPaper;
}
}
PCL6Writer::MediaSource
PCL6Driver::_MediaSource(JobData::PaperSource source)
{
switch (source) {
case JobData::kAuto:
return PCL6Writer::kAutoSelect;
case JobData::kCassette1:
return PCL6Writer::kDefaultSource;
case JobData::kCassette2:
return PCL6Writer::kEnvelopeTray;
case JobData::kLower:
return PCL6Writer::kLowerCassette;
case JobData::kUpper:
return PCL6Writer::kUpperCassette;
case JobData::kMiddle:
return PCL6Writer::kThirdCassette;
case JobData::kManual:
return PCL6Writer::kManualFeed;
case JobData::kCassette3:
return PCL6Writer::kMultiPurposeTray;
default:
return PCL6Writer::kAutoSelect;
}
}
↑ V773 The function was exited without releasing the 'alert' pointer. A memory leak is possible.