Implemented dumb PostScript printer driver (monochrome and color).

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2759 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer 2003-02-19 18:00:31 +00:00
parent 3bfe34e2b1
commit 2dec20508d
7 changed files with 593 additions and 0 deletions

View File

@ -0,0 +1,15 @@
SubDir OBOS_TOP src add-ons print drivers postscript ;
SubDirHdrs [ FDirName $(OBOS_TOP) src add-ons print drivers canon_lips
libprint ] ;
AddResources PS\ Compatible : PS.rsrc ;
Addon PS\ Compatible : print :
PSEntry.cpp
PS.cpp
PSCap.cpp
;
LinkSharedOSLibs PS\ Compatible : be stdc++.r4 libprint.a ;

View File

@ -0,0 +1,287 @@
/*
* PS.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
* Copyright 2003 Michael Pfeiffer.
*/
#include <Alert.h>
#include <Bitmap.h>
#include <File.h>
#include <memory>
#include <stdio.h>
#include "PS.h"
#include "UIDriver.h"
#include "JobData.h"
#include "PrinterData.h"
#include "PSCap.h"
#include "PackBits.h"
#include "Halftone.h"
#include "ValidRect.h"
#include "DbgMsg.h"
#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE))
using namespace std;
#else
#define std
#endif
PSDriver::PSDriver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap)
: GraphicsDriver(msg, printer_data, printer_cap)
{
__printed_pages = 0;
__halftone = NULL;
}
bool PSDriver::startDoc()
{
try {
jobStart();
__halftone = new Halftone(getJobData()->getSurfaceType(), getJobData()->getGamma());
return true;
}
catch (TransportException &err) {
return false;
}
}
bool PSDriver::startPage(int page)
{
page ++;
writeSpoolString("%%%%Page: %d %d\n", page, page);
return true;
}
bool PSDriver::endPage(int)
{
try {
__printed_pages ++;
writeSpoolString("showpage\n");
return true;
}
catch (TransportException &err) {
return false;
}
}
bool PSDriver::endDoc(bool)
{
try {
if (__halftone) {
delete __halftone;
}
jobEnd();
return true;
}
catch (TransportException &err) {
return false;
}
}
inline uchar hex_digit(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, __halftone->getPalette(), &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", __halftone->getPixelDepth()));
uchar *ptr = (uchar *)bitmap->Bits()
+ rc.top * delta
+ (rc.left * __halftone->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++ = hex_digit((in[2]) >> 4);
*out++ = hex_digit((in[2]) & 15);
*out++ = hex_digit((in[1]) >> 4);
*out++ = hex_digit((in[1]) & 15);
*out++ = hex_digit((in[0]) >> 4);
*out++ = hex_digit((in[0]) & 15);
in += 4;
}
} else {
__halftone->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++ = hex_digit((*in) >> 4);
*out++ = hex_digit((*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->Go();
return false;
}
}
void PSDriver::jobStart()
{
// PostScript header
writeSpoolString("%%!PS-Adobe-3.0\n");
writeSpoolString("%%%%LanguageLevel: 1\n");
writeSpoolString("%%%%Title: %s\n", getSpoolMetaData()->getDescription().c_str());
writeSpoolString("%%%%Creator: %s\n", getSpoolMetaData()->getMimeType().c_str());
writeSpoolString("%%%%CreationDate: %s", getSpoolMetaData()->getCreationTime().c_str());
writeSpoolString("%%%%Pages: (atend)\n");
writeSpoolString("%%%%EndComments\n");
// setup CTM
writeSpoolString("%%%%BeginSetup\n");
// move origin from bottom left to top left
writeSpoolString("0 %f translate\n", getJobData()->getPaperRect().Height());
// y values increase from top to bottom
// units of measure is dpi
writeSpoolString("72 %d div 72 -%d div scale\n", getJobData()->getXres(), getJobData()->getYres());
writeSpoolString("%%%%EndSetup\n");
}
void PSDriver::startRasterGraphics(int x, int y, int width, int height, int widthByte)
{
bool color = getJobData()->getColor() == JobData::kCOLOR;
__compression_method = -1;
writeSpoolString("gsave\n");
writeSpoolString("/s %d string def\n", widthByte);
writeSpoolString("%d %d translate\n", x, y);
writeSpoolString("%d %d scale\n", width, height);
if (color) {
writeSpoolString("%d %d 8\n", width, height); // 8 bpp
} else {
writeSpoolString("%d %d 1\n", width, height); // 1 bpp
}
writeSpoolString("[%d 0 0 %d 0 0]\n", width, height);
writeSpoolString("{ currentfile s readhexstring pop }\n");
if (color) {
writeSpoolString("false 3\n"); // single data source, 3 color components
writeSpoolString("colorimage\n");
} else {
writeSpoolString("image\n\n");
}
}
void PSDriver::endRasterGraphics()
{
writeSpoolString("grestore\n");
}
void PSDriver::rasterGraphics(
int compression_method,
const uchar *buffer,
int size)
{
if (__compression_method != compression_method) {
__compression_method = compression_method;
}
writeSpoolData(buffer, size);
writeSpoolString("\n");
}
void PSDriver::jobEnd()
{
writeSpoolString("%%%%Pages: %d\n", __printed_pages);
writeSpoolString("%%%%EOF\n");
}

View File

@ -0,0 +1,40 @@
/*
* PS.h
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
*/
#ifndef __PS_H
#define __PS_H
#include "GraphicsDriver.h"
class Halftone;
class PSDriver : public GraphicsDriver {
public:
PSDriver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap);
protected:
virtual bool startDoc();
virtual bool startPage(int page);
virtual bool nextBand(BBitmap *bitmap, BPoint *offset);
virtual bool endPage(int page);
virtual bool endDoc(bool success);
private:
void jobStart();
float scale(int d);
void startRasterGraphics(int x, int y, int width, int height, int widthByte);
void endRasterGraphics();
void rasterGraphics(
int compression_method,
const uchar *buffer,
int size);
void jobEnd();
int __printed_pages;
int __compression_method;
Halftone *__halftone;
};
#endif /* __PS_H */

Binary file not shown.

View File

@ -0,0 +1,149 @@
/*
* PSCap.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
*/
#include "PrinterData.h"
#include "PSCap.h"
#define TO72DPI(a) (a * 72.0f / 600.0f)
const PaperCap a3(
"A3",
false,
JobData::A3,
BRect(0.0f, 0.0f, TO72DPI(7014.0f), TO72DPI(9920.0f)),
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(6894.0f), TO72DPI(9800.0f)));
const PaperCap a4(
"A4",
true,
JobData::A4,
BRect(0.0f, 0.0f, TO72DPI(4960.0f), TO72DPI(7014.0f)),
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4840.0f), TO72DPI(6894.0f)));
const PaperCap a5(
"A5",
false,
JobData::A5,
BRect(0.0f, 0.0f, TO72DPI(3506.0f), TO72DPI(4960.0f)),
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(3386.0f), TO72DPI(4840.0f)));
const PaperCap japanese_postcard(
"Japanese Postcard",
false,
JobData::JAPANESE_POSTCARD,
BRect(0.0f, 0.0f, TO72DPI(2362.0f), TO72DPI(3506.0f)),
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(2242.0f), TO72DPI(3386.0f)));
const PaperCap b4(
"B4",
false,
JobData::B4,
BRect(0.0f, 0.0f, TO72DPI(6070.0f), TO72DPI(8598.0f)),
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(5950.0f), TO72DPI(8478.0f)));
const PaperCap b5(
"B5",
false,
JobData::B5,
BRect(0.0f, 0.0f, TO72DPI(4298.0f), TO72DPI(6070.0f)),
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4178.0f), TO72DPI(5950.0f)));
const PaperCap letter(
"Letter",
false,
JobData::LETTER,
BRect(0.0f, 0.0f, TO72DPI(5100.0f), TO72DPI(6600.0f)),
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(6480.0f)));
const PaperCap legal(
"Legal",
false,
JobData::LEGAL,
BRect(0.0f, 0.0f, TO72DPI(5100.0f), TO72DPI(8400.0f)),
BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(8280.0f)));
const PaperSourceCap autobin("Auto", true, JobData::AUTO);
const ResolutionCap dpi300("300dpi", true, 300, 300);
const ResolutionCap dpi600("600dpi", false, 600, 600);
const ResolutionCap dpi1200("1200dpi", false, 1200, 1200);
const PaperCap *papers[] = {
&a4,
&a3,
&a5,
&b4,
&b5,
&letter,
&legal
};
const PaperSourceCap *papersources[] = {
&autobin,
};
const ResolutionCap *resolutions[] = {
&dpi300,
&dpi600,
&dpi1200,
};
const ColorCap color("Color", false, JobData::kCOLOR);
const ColorCap monochrome("Monochrome", true, JobData::kMONOCHROME);
const ColorCap *colors[] = {
&color,
&monochrome
};
PSCap::PSCap(const PrinterData *printer_data)
: PrinterCap(printer_data)
{
}
int PSCap::countCap(CAPID capid) const
{
switch (capid) {
case PAPER:
return sizeof(papers) / sizeof(papers[0]);
case PAPERSOURCE:
return sizeof(papersources) / sizeof(papersources[0]);
case RESOLUTION:
return sizeof(resolutions) / sizeof(resolutions[0]);
case COLOR:
return sizeof(colors) / sizeof(colors[0]);
default:
return 0;
}
}
const BaseCap **PSCap::enumCap(CAPID capid) const
{
switch (capid) {
case PAPER:
return (const BaseCap **)papers;
case PAPERSOURCE:
return (const BaseCap **)papersources;
case RESOLUTION:
return (const BaseCap **)resolutions;
case COLOR:
return (const BaseCap **)colors;
default:
return NULL;
}
}
bool PSCap::isSupport(CAPID capid) const
{
switch (capid) {
case PAPER:
case PAPERSOURCE:
case RESOLUTION:
case COLOR:
return true;
default:
return false;
}
}

View File

@ -0,0 +1,19 @@
/*
* PSCap.h
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
*/
#ifndef __PSCAP_H
#define __PSCAP_H
#include "PrinterCap.h"
class PSCap : public PrinterCap {
public:
PSCap(const PrinterData *printer_data);
virtual int countCap(CAPID) const;
virtual bool isSupport(CAPID) const;
virtual const BaseCap **enumCap(CAPID) const;
};
#endif /* __PSCAP_H */

View File

@ -0,0 +1,83 @@
/*
* PSEntry.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
* Copyright 2003 Michael Pfeiffer.
*/
#include <File.h>
#include <Message.h>
#include <Node.h>
#include "Exports.h"
#include "PS.h"
#include "PrinterData.h"
#include "PSCap.h"
#include "UIDriver.h"
#include "AboutBox.h"
#include "DbgMsg.h"
char *add_printer(char *printer_name)
{
DBGMSG((">PS: add_printer\n"));
DBGMSG(("\tprinter_name: %s\n", printer_name));
DBGMSG(("<PS: add_printer\n"));
return printer_name;
}
BMessage *config_page(BNode *node, BMessage *msg)
{
DBGMSG((">PS: config_page\n"));
DUMP_BMESSAGE(msg);
DUMP_BNODE(node);
PrinterData printer_data(node);
PSCap printer_cap(&printer_data);
UIDriver drv(msg, &printer_data, &printer_cap);
BMessage *result = drv.configPage();
DUMP_BMESSAGE(result);
DBGMSG(("<PS: config_page\n"));
return result;
}
BMessage *config_job(BNode *node, BMessage *msg)
{
DBGMSG((">PS: config_job\n"));
DUMP_BMESSAGE(msg);
DUMP_BNODE(node);
PrinterData printer_data(node);
PSCap printer_cap(&printer_data);
UIDriver drv(msg, &printer_data, &printer_cap);
BMessage *result = drv.configJob();
DUMP_BMESSAGE(result);
DBGMSG(("<PS: config_job\n"));
return result;
}
BMessage *take_job(BFile *spool, BNode *node, BMessage *msg)
{
DBGMSG((">PS: take_job\n"));
DUMP_BMESSAGE(msg);
DUMP_BNODE(node);
PrinterData printer_data(node);
PSCap printer_cap(&printer_data);
PSDriver drv(msg, &printer_data, &printer_cap);
BMessage *result = drv.takeJob(spool);
// DUMP_BMESSAGE(result);
DBGMSG(("<PS: take_job\n"));
return result;
}
int main()
{
AboutBox app("application/x-vnd.PS-compatible", "PS Compatible", "0.1",
"libprint Copyright © 1999-2000 Y.Takagi\n"
"PostScript driver Copyright © 2003 Michael Pfeiffer.\n"
"All Rights Reserved.");
app.Run();
return 0;
}