* Added Gutenprint printer driver add-on to image.

* This is still work in progress:
  Printing should work with the following restrictions:
  - Color printing is untested.
  - Some configuration options provided by Gutenprint are missing.
  - Error reporting is missing. 
  - The page margins should at least to increased to 1 cm
    or 0.4 Inch.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39216 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer 2010-10-30 18:05:09 +00:00
parent c0710fb94e
commit 9295cd647f
28 changed files with 2636 additions and 0 deletions

View File

@ -142,6 +142,7 @@ SYSTEM_ADD_ONS_MEDIA_PLUGINS = $(X86_ONLY)ffmpeg raw_decoder ;
SYSTEM_ADD_ONS_PRINT =
Canon\ LIPS3\ Compatible
Canon\ LIPS4\ Compatible
Gutenprint
PCL5\ Compatible
PCL6\ Compatible
PDF\ Writer

View File

@ -1,6 +1,7 @@
SubDir HAIKU_TOP src add-ons print drivers ;
SubInclude HAIKU_TOP src add-ons print drivers canon_lips ;
SubInclude HAIKU_TOP src add-ons print drivers gutenprint ;
SubInclude HAIKU_TOP src add-ons print drivers pcl5 ;
SubInclude HAIKU_TOP src add-ons print drivers pcl6 ;
SubInclude HAIKU_TOP src add-ons print drivers pdf ;

View File

@ -0,0 +1,84 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include<Debug.h>
template<typename TYPE>
GPArray<TYPE>::GPArray()
:
fArray(NULL),
fSize(0)
{
}
template<typename TYPE>
GPArray<TYPE>::~GPArray()
{
if (fArray != NULL) {
for (int i = 0; i < fSize; i ++)
delete fArray[i];
delete[] fArray;
fArray = NULL;
}
}
template<typename TYPE>
void
GPArray<TYPE>::SetSize(int size)
{
ASSERT(fSize == NULL);
fArray = new PointerType[size];
if (fArray == NULL)
return;
fSize = size;
for (int i = 0; i < size; i ++) {
fArray[i] = NULL;
}
}
template<typename TYPE>
int
GPArray<TYPE>::Size() const
{
return fSize;
}
template<typename TYPE>
void
GPArray<TYPE>::DecreaseSize()
{
ASSERT(fArray != NULL);
ASSERT(fArray[fSize-1] == NULL);
fSize --;
}
template<typename TYPE>
TYPE**
GPArray<TYPE>::Array()
{
return fArray;
}
template<typename TYPE>
TYPE ** const
GPArray<TYPE>::Array() const
{
return fArray;
}
template<typename TYPE>
bool
GPArray<TYPE>::IsEmpty() const
{
return fSize == 0;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef GP_ARRAY_H
#define GP_ARRAY_H
template<typename TYPE>
class GPArray
{
public:
typedef TYPE* PointerType;
GPArray();
virtual ~GPArray();
void SetSize(int size);
int Size() const;
void DecreaseSize();
TYPE** Array();
TYPE** const Array() const;
bool IsEmpty() const;
private:
TYPE** fArray;
int fSize;
};
#include "GPArray.cpp"
#endif

View File

@ -0,0 +1,34 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "GPBand.h"
GPBand::GPBand(BBitmap* bitmap, BRect validRect, BPoint where)
:
fBitmap(*bitmap),
fValidRect(validRect),
fWhere(where)
{
}
BRect
GPBand::GetBoundingRectangle() const
{
BRect rect = fValidRect;
rect.OffsetTo(fWhere);
return rect;
}
bool
GPBand::ContainsLine(int line) const
{
int y = line - (int)fWhere.y;
return 0 <= y && y <= fValidRect.IntegerHeight();
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef GP_BAND_H
#define GP_BAND_H
#include <Bitmap.h>
class GPBand
{
public:
GPBand(BBitmap* bitmap, BRect validRect, BPoint where);
BRect GetBoundingRectangle() const;
bool ContainsLine(int line) const;
BBitmap fBitmap;
BRect fValidRect;
BPoint fWhere;
};
#endif

View File

@ -0,0 +1,229 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "GPBinding.h"
#include <list>
#include <set>
#include <string>
#include <gutenprint/gutenprint.h>
#include "GPCapabilityExtractor.h"
using namespace std;
// printer manufacturer
static const char* kManufacturerId = "id";
static const char* kManufacturerDisplayName = "name";
// printer model
static const char* kModelDisplayName = "model";
static const char* kModelDriver = "driver";
GPBinding::GPBinding()
:
fInitialized(false),
fOutputStream(NULL)
{
}
GPBinding::~GPBinding()
{
DeleteBands();
}
status_t
GPBinding::GetPrinterManufacturers(BMessage& manufacturers)
{
InitGutenprint();
list<string> ids;
set<string> manufacturerSet;
for (int i = 0; i < stp_printer_model_count(); i ++) {
const stp_printer_t* printer = stp_get_printer_by_index(i);
string manufacturer = stp_printer_get_manufacturer(printer);
// ignore unnamed manufacturers
if (manufacturer == "")
continue;
// add manufacturer only once
if (manufacturerSet.find(manufacturer) != manufacturerSet.end())
continue;
manufacturerSet.insert(manufacturer);
ids.push_back(manufacturer);
}
ids.sort();
list<string>::iterator it = ids.begin();
for (; it != ids.end(); it ++) {
string manufacturer = *it;
const char* id = manufacturer.c_str();
const char* name = manufacturer.c_str();
AddManufacturer(manufacturers, id, name);
}
return B_OK;
}
bool
GPBinding::ExtractManufacturer(const BMessage& manufacturers, int32 index,
BString& id, BString& displayName)
{
if (manufacturers.FindString(kManufacturerId, index, &id) != B_OK)
return false;
if (manufacturers.FindString(kManufacturerDisplayName, index, &displayName)
!= B_OK)
return false;
return true;
}
void
GPBinding::AddManufacturer(BMessage& manufacturers, const char* id,
const char* displayName)
{
manufacturers.AddString(kManufacturerId, id);
manufacturers.AddString(kManufacturerDisplayName, displayName);
}
status_t
GPBinding::GetPrinterModels(const char* manufacturer, BMessage& models)
{
for (int i = 0; i < stp_printer_model_count(); i ++) {
const stp_printer_t* printer = stp_get_printer_by_index(i);
if (strcmp(manufacturer, stp_printer_get_manufacturer(printer)) != 0)
continue;
const char* displayName = stp_printer_get_long_name(printer);
const char* driver = stp_printer_get_driver(printer);
AddModel(models, displayName, driver);
}
return B_OK;
}
bool
GPBinding::ExtractModel(const BMessage& models, int32 index, BString& displayName,
BString& driver)
{
if (models.FindString(kModelDisplayName, index, &displayName) != B_OK)
return false;
if (models.FindString(kModelDriver, index, &driver) != B_OK)
return false;
return true;
}
void
GPBinding::AddModel(BMessage& models, const char* displayName, const char* driver)
{
models.AddString(kModelDisplayName, displayName);
models.AddString(kModelDriver, driver);
}
status_t
GPBinding::GetCapabilities(const char* driver, GPCapabilities* capabilities)
{
InitGutenprint();
const stp_printer_t* printer = stp_get_printer_by_driver(driver);
if (printer == NULL)
return B_ERROR;
GPCapabilityExtractor extractor(capabilities);
extractor.Visit(printer);
return B_OK;
}
status_t
GPBinding::BeginJob(GPJobConfiguration* configuration,
OutputStream* outputStream)
throw(TransportException)
{
fOutputStream = outputStream;
fJob.SetApplicationName("Gutenprint");
fJob.SetConfiguration(configuration);
fJob.SetOutputStream(outputStream);
return fJob.Begin();
}
void
GPBinding::EndJob() throw(TransportException)
{
fJob.End();
fOutputStream = NULL;
}
void
GPBinding::BeginPage() throw(TransportException)
{
}
void
GPBinding::EndPage() throw(TransportException)
{
status_t status = fJob.PrintPage(fBands);
DeleteBands();
if (status != B_OK)
throw TransportException("I/O Error");
}
void
GPBinding::AddBitmapToPage(BBitmap* bitmap, BRect validRect, BPoint where)
{
GPBand* band = new(nothrow) GPBand(bitmap, validRect, where);
if (band == NULL) {
// TODO report error
return;
}
fBands.push_back(band);
}
void
GPBinding::InitGutenprint()
{
if (fInitialized)
return;
fInitialized = true;
// TODO make sure this creates no memory leaks,
// as there is no "destroy" counter part
stp_init();
stp_set_output_codeset("UTF-8");
}
void
GPBinding::DeleteBands()
{
list<GPBand*>::iterator it = fBands.begin();
for (; it != fBands.end(); it ++) {
GPBand* band = *it;
delete band;
}
fBands.clear();
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef GP_BINDING_H
#define GP_BINDING_H
#include <Bitmap.h>
#include <Message.h>
#include <list>
#include "GPBand.h"
#include "GPJob.h"
#include "GPJobConfiguration.h"
#include "OutputStream.h"
#include "ValidRect.h"
class GPCapabilities;
class GPBinding
{
public:
GPBinding();
~GPBinding();
status_t GetPrinterManufacturers(BMessage& manufacturers);
bool ExtractManufacturer(const BMessage& manufacturers, int32 index,
BString& id, BString& displayName);
void AddManufacturer(BMessage& manufacturers, const char* id,
const char* name);
status_t GetPrinterModels(const char* manufacturer, BMessage& models);
bool ExtractModel(const BMessage& models, int32 index,
BString& displayName, BString& driver);
void AddModel(BMessage& models, const char* displayName,
const char* driver);
status_t GetCapabilities(const char* driver,
GPCapabilities* capabilities);
status_t BeginJob(GPJobConfiguration* configuration,
OutputStream* outputStream) throw(TransportException);
void EndJob() throw(TransportException);
void BeginPage() throw(TransportException);
void EndPage() throw(TransportException);
void AddBitmapToPage(BBitmap* bitmap, BRect validRect, BPoint where);
private:
void InitGutenprint();
void DeleteBands();
bool fInitialized;
OutputStream* fOutputStream;
list<GPBand*> fBands;
GPJob fJob;
};
#endif

View File

@ -0,0 +1,124 @@
/*
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "GPCapabilities.h"
#include "GPBinding.h"
#include "GPData.h"
#include "PrinterData.h"
GPCapabilities::GPCapabilities(const PrinterData* printer_data)
:
PrinterCap(printer_data)
{
InitCapabilitiesFromGutenprint();
}
GPCapabilities::~GPCapabilities()
{
}
int
GPCapabilities::countCap(CapID category) const
{
const GPArray<struct BaseCap>* capabilities;
switch (category) {
case kPaper:
return fPageSizes.Size();
case kPaperSource:
return fInputSlots.Size();
case kResolution:
return fResolutions.Size();
case kColor:
return fPrintingModes.Size();
case kDriverSpecificCapabilities:
return fDriverSpecificCategories.Size();
default:
capabilities = DriverSpecificCapabilities(category);
if (capabilities == NULL)
return 0;
return capabilities->Size();
}
}
const BaseCap**
GPCapabilities::enumCap(CapID category) const
{
typedef const BaseCap** ArrayType;
const GPArray<struct BaseCap>* capabilities;
switch (category) {
case kPaper:
return (ArrayType)fPageSizes.Array();
case kPaperSource:
return (ArrayType)fInputSlots.Array();
case kResolution:
return (ArrayType)fResolutions.Array();
case kColor:
return (ArrayType)fPrintingModes.Array();
case kDriverSpecificCapabilities:
return (ArrayType)fDriverSpecificCategories.Array();
default:
capabilities = DriverSpecificCapabilities(category);
if (capabilities == NULL)
return NULL;
return (ArrayType)capabilities->Array();
}
}
bool
GPCapabilities::isSupport(CapID category) const
{
switch (category) {
case kPaper:
case kPaperSource:
case kResolution:
case kColor:
return true;
default:
return countCap(category) > 0;
}
}
void
GPCapabilities::InitCapabilitiesFromGutenprint()
{
const GPData* data = dynamic_cast<const GPData*>(getPrinterData());
ASSERT(data != NULL);
// capabilities are available only after printer model
// has been selected
if (data->fGutenprintDriverName == "")
return;
GPBinding binding;
binding.GetCapabilities(data->fGutenprintDriverName.String(), this);
}
const GPArray<struct BaseCap>*
GPCapabilities::DriverSpecificCapabilities(int32 category) const
{
DriverSpecificCapabilitiesType::const_iterator it =
fDriverSpecificCapabilities.find(category);
if (it == fDriverSpecificCapabilities.end())
return NULL;
return &it->second;
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*
*/
#ifndef GP_CAPABILITIES_H
#define GP_CAPABILITIES_H
#include "PrinterCap.h"
#include "GPArray.h"
#include <map>
class GPCapabilityExtractor;
class GPCapabilities : public PrinterCap {
public:
GPCapabilities(const PrinterData* printer_data);
~GPCapabilities();
virtual int countCap(CapID) const;
virtual bool isSupport(CapID) const;
virtual const BaseCap **enumCap(CapID) const;
private:
void InitCapabilitiesFromGutenprint();
const GPArray<struct BaseCap>*
DriverSpecificCapabilities(int32 category) const;
GPArray<struct BaseCap> fPageSizes;
GPArray<struct BaseCap> fResolutions;
GPArray<struct BaseCap> fInputSlots;
GPArray<struct BaseCap> fPrintingModes;
GPArray<struct BaseCap> fDriverSpecificCategories;
typedef map<int32, GPArray<struct BaseCap> > DriverSpecificCapabilitiesType;
DriverSpecificCapabilitiesType fDriverSpecificCapabilities;
friend class GPCapabilityExtractor;
};
#endif

View File

@ -0,0 +1,255 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "GPCapabilityExtractor.h"
#include "PrinterCap.h"
const char* kInputSlot = "InputSlot";
#if 1
#define GP_PRINT(...) \
fprintf(stderr, __VA_ARGS__)
#else
#define GP_PRINT(...) \
{}
#endif
GPCapabilityExtractor::GPCapabilityExtractor(GPCapabilities* capabilities)
:
fState(kIgnoreParameter),
fCapabilities(capabilities),
fIndex(0),
fNextDriverSpecificCategoryID(PrinterCap::kDriverSpecificCapabilitiesBegin)
{
}
bool
GPCapabilityExtractor::BeginParameter(const char* name, const char* displayName,
stp_parameter_class_t parameterClass)
{
fState = kIgnoreParameter;
if (strcmp(kPageSize, name) == 0) {
GP_PRINT("Supported parameter: %s\n", name);
fState = kExtractPageSizeParameter;
} else if (strcmp(kResolution, name) == 0) {
GP_PRINT("Supported parameter: %s\n", name);
fState = kExtractResolutionParameter;
} else if (strcmp(kInputSlot, name) == 0) {
GP_PRINT("Supported parameter: %s\n", name);
fState = kExtractInputSlotParameter;
} else if (strcmp(kPrintingMode, name) == 0) {
GP_PRINT("Supported parameter: %s\n", name);
fState = kExtractPrintingModeParameter;
} else {
GP_PRINT("Parameter: %s - %s\n", name, displayName);
bool recordParameter = parameterClass == STP_PARAMETER_CLASS_FEATURE ||
parameterClass == STP_PARAMETER_CLASS_OUTPUT;
if (!recordParameter)
return false;
fState = kExtractParameter;
DriverSpecificCap* capability = new DriverSpecificCap(displayName,
fNextDriverSpecificCategoryID, DriverSpecificCap::kList);
capability->fKey = name;
fDriverSpecificCategories.push_back(capability);
}
return true;
}
void
GPCapabilityExtractor::DefaultStringParameter(const char* name,
const char* key)
{
if (key == NULL)
fDefaultKey = "";
else
fDefaultKey = key;
}
void
GPCapabilityExtractor::StringParameterSize(const char* name, int size)
{
fIndex = 0;
switch (fState) {
case kExtractPageSizeParameter:
fCapabilities->fPageSizes.SetSize(size);
break;
case kExtractResolutionParameter:
fCapabilities->fResolutions.SetSize(size);
break;
case kExtractInputSlotParameter:
fCapabilities->fInputSlots.SetSize(size);
break;
case kExtractPrintingModeParameter:
fCapabilities->fPrintingModes.SetSize(size);
break;
case kExtractParameter:
fState = kExtractListParameter;
fCapabilities->fDriverSpecificCapabilities[
fNextDriverSpecificCategoryID].SetSize(size);
break;
default:
break;
}
}
void
GPCapabilityExtractor::StringParameter(const char* name, const char* key,
const char* displayName)
{
bool isDefault = fDefaultKey == key;
BaseCap* capability;
switch (fState) {
case kExtractResolutionParameter:
GP_PRINT("GPCapabilityExtractor: ResolutionParameter expected\n");
break;
case kExtractInputSlotParameter:
capability = new PaperSourceCap(displayName, isDefault,
static_cast<JobData::PaperSource>(fIndex));
AddCapability(fCapabilities->fInputSlots, capability, key);
break;
case kExtractPrintingModeParameter:
capability = new ColorCap(displayName, isDefault,
static_cast<JobData::Color>(fIndex));
AddCapability(fCapabilities->fPrintingModes, capability, key);
break;
case kExtractListParameter:
capability = new ListItemCap(displayName, isDefault, fIndex);
AddCapability(fCapabilities->fDriverSpecificCapabilities[
fNextDriverSpecificCategoryID], capability, key);
break;
default:
break;
}
}
void
GPCapabilityExtractor::ResolutionParameter(const char* name, const char* key,
const char* displayName, int x, int y)
{
bool isDefault = fDefaultKey == key;
BaseCap* capability;
switch (fState) {
case kExtractResolutionParameter:
if (x <= 0 || y <= 0) {
// usually this is the entry for the "Default" resolution
// if we want to show this in the UI, we need a way to
// determine the resolution (x and y) for it, because
// libprint needs it for rasterization
fCapabilities->fResolutions.DecreaseSize();
break;
}
capability = new ResolutionCap(displayName, isDefault, fIndex,
x, y);
AddCapability(fCapabilities->fResolutions, capability, key);
break;
default:
break;
}
}
void
GPCapabilityExtractor::PageSizeParameter(const char* name, const char* key,
const char* displayName, BSize pageSize, BRect imageableArea)
{
bool isDefault = fDefaultKey == key;
BaseCap* capability;
switch (fState) {
case kExtractPageSizeParameter:
capability = new PaperCap(displayName, isDefault,
static_cast<JobData::Paper>(fIndex),
BRect(0, 0, pageSize.width, pageSize.height),
imageableArea);
AddCapability(fCapabilities->fPageSizes, capability, key);
break;
default:
break;
}
}
void
GPCapabilityExtractor::EndParameter(const char* name)
{
if (fState == kExtractListParameter) {
fNextDriverSpecificCategoryID ++;
}
}
void
GPCapabilityExtractor::EndVisit()
{
if (fCapabilities->fInputSlots.Size() == 0)
AddDefaultInputSlot();
SetDriverSpecificCategories();
}
void
GPCapabilityExtractor::AddDefaultInputSlot()
{
BeginParameter(kInputSlot, "Input Slot", STP_PARAMETER_CLASS_FEATURE);
DefaultStringParameter(kInputSlot, "");
StringParameterSize(kInputSlot, 1);
StringParameter(kInputSlot, "", "Default");
EndParameter(kInputSlot);
}
void
GPCapabilityExtractor::SetDriverSpecificCategories()
{
int size = fDriverSpecificCategories.size();
if (size == 0)
return;
fCapabilities->fDriverSpecificCategories.SetSize(size);
struct BaseCap** array = fCapabilities->fDriverSpecificCategories.Array();
list<DriverSpecificCap*>::iterator it = fDriverSpecificCategories.begin();
for (int index = 0; it != fDriverSpecificCategories.end(); it ++,
index ++) {
array[index] = *it;
}
}
void
GPCapabilityExtractor::AddCapability(GPArray<struct BaseCap>& array,
BaseCap* capability, const char* key)
{
capability->fKey = key;
array.Array()[fIndex] = capability;
fIndex ++;
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef GP_CAPABILITY_EXTRACTOR_H
#define GP_CAPABILITY_EXTRACTOR_H
#include "GPParameterVisitor.h"
#include <list>
#include "GPCapabilities.h"
enum GPCapabilityExtractorState {
kIgnoreParameter,
kExtractPageSizeParameter,
kExtractResolutionParameter,
kExtractInputSlotParameter,
kExtractPrintingModeParameter,
kExtractParameter,
kExtractListParameter,
};
class GPCapabilityExtractor : public GPParameterVisitor
{
public:
GPCapabilityExtractor(GPCapabilities* cap);
bool BeginParameter(const char* name, const char* displayName,
stp_parameter_class_t parameterClass);
void DefaultStringParameter(const char* name,
const char* key);
void StringParameterSize(const char* name, int size);
void StringParameter(const char* name, const char* key,
const char* displayName);
void ResolutionParameter(const char* name, const char* key,
const char* displayName, int x, int y);
void PageSizeParameter(const char* name, const char* key,
const char* displayName, BSize pageSize, BRect imageableArea);
void EndParameter(const char* name);
void EndVisit();
protected:
void AddDefaultInputSlot();
void SetDriverSpecificCategories();
void AddCapability(GPArray<struct BaseCap>& array, BaseCap* capability,
const char* key);
private:
GPCapabilityExtractorState fState;
GPCapabilities* fCapabilities;
int fIndex;
BString fDefaultKey;
list<DriverSpecificCap*> fDriverSpecificCategories;
int32 fNextDriverSpecificCategoryID;
};
#endif

View File

@ -0,0 +1,32 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ithamar R. Adema <ithamar.adema@team-embedded.nl>
*/
#include "GPData.h"
#include <Node.h>
#define PD_PRINTER_DRIVER_ATTRIBUTE "gutenprint:driver-name"
void
GPData::load()
{
PrinterData::load();
fNode->ReadAttrString(PD_PRINTER_DRIVER_ATTRIBUTE,
&fGutenprintDriverName);
}
void
GPData::save()
{
PrinterData::save();
fNode->WriteAttrString(PD_PRINTER_DRIVER_ATTRIBUTE,
&fGutenprintDriverName);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ithamar R. Adema <ithamar.adema@team-embedded.nl>
* Michael Pfeiffer
*/
#ifndef GP_DATA_H
#define GP_DATA_H
#include "PrinterData.h"
#include <String.h>
class BNode;
class GPData : public PrinterData {
public:
GPData(BNode* node)
:
PrinterData(node)
{
}
// PrinterData overrides
virtual void load();
virtual void save();
BString fGutenprintDriverName;
};
#endif // PSDATA_H

View File

@ -0,0 +1,239 @@
/*
* GP.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
* Copyright 2010 Michael Pfeiffer.
*/
#include "GPDriver.h"
#include <memory>
#include <Alert.h>
#include <Bitmap.h>
#include <Debug.h>
#include <File.h>
#include "DbgMsg.h"
#include "Halftone.h"
#include "JobData.h"
#include "PackBits.h"
#include "GPCapabilities.h"
#include "GPData.h"
#include "PrinterData.h"
#include "UIDriver.h"
#include "ValidRect.h"
using namespace std;
GPDriver::GPDriver(BMessage* msg, PrinterData* printer_data,
const PrinterCap* printer_cap)
:
GraphicsDriver(msg, printer_data, printer_cap)
{
}
void
GPDriver::Write(const void *buffer, size_t size)
throw(TransportException)
{
writeSpoolData(buffer, size);
}
bool
GPDriver::startDoc()
{
try {
const GPData* data = dynamic_cast<const GPData*>(getPrinterData());
ASSERT(data != NULL);
fConfiguration.fDriver = data->fGutenprintDriverName;
SetParameter(fConfiguration.fPageSize, PrinterCap::kPaper,
getJobData()->getPaper());
SetParameter(fConfiguration.fResolution, PrinterCap::kResolution,
getJobData()->getResolutionID());
fConfiguration.fXDPI = getJobData()->getXres();
fConfiguration.fYDPI = getJobData()->getYres();
SetParameter(fConfiguration.fInputSlot, PrinterCap::kPaperSource,
getJobData()->getPaperSource());
SetParameter(fConfiguration.fPrintingMode, PrinterCap::kColor,
getJobData()->getColor());
if (getPrinterCap()->isSupport(PrinterCap::kDriverSpecificCapabilities))
SetDriverSpecificSettings();
fprintf(stderr, "Driver: %s\n", fConfiguration.fDriver.String());
fprintf(stderr, "PageSize %s\n", fConfiguration.fPageSize.String());
fprintf(stderr, "Resolution %s\n", fConfiguration.fResolution.String());
fprintf(stderr, "InputSlot %s\n", fConfiguration.fInputSlot.String());
fprintf(stderr, "PrintingMode %s\n", fConfiguration.fPrintingMode.String());
return fBinding.BeginJob(&fConfiguration, this) == B_OK;
}
catch (TransportException& err) {
return false;
}
}
void
GPDriver::SetParameter(BString& parameter, PrinterCap::CapID category,
int value)
{
const BaseCap* capability;
capability = getPrinterCap()->findCap(category, value);
if (capability != NULL && capability->fKey != "")
parameter = capability->Key();
}
void
GPDriver::SetDriverSpecificSettings()
{
PrinterCap::CapID category = PrinterCap::kDriverSpecificCapabilities;
int count = getPrinterCap()->countCap(category);
const BaseCap** capabilities = getPrinterCap()->enumCap(category);
for (int i = 0; i < count; i++) {
const BaseCap* capability = capabilities[i];
PrinterCap::CapID id = static_cast<PrinterCap::CapID>(capability->ID());
AddDriverSpecificSetting(id, capability->fKey.c_str());
}
}
void
GPDriver::AddDriverSpecificSetting(PrinterCap::CapID category, const char* key) {
const BaseCap* capability = NULL;
if (getJobData()->HasDriverSpecificSetting(key))
{
const string& value = getJobData()->DriverSpecificSetting(key);
capability = getPrinterCap()->findCapWithKey(category, value.c_str());
}
if (capability == NULL) {
// job data should contain a value;
// try to use the default value anyway
capability = getPrinterCap()->getDefaultCap(category);
}
if (capability == NULL) {
// should not reach here!
return;
}
fConfiguration.fDriverSpecificSettings[key] = capability->fKey;
}
bool
GPDriver::startPage(int)
{
fBinding.BeginPage();
return true;
}
bool
GPDriver::endPage(int)
{
try {
fBinding.EndPage();
return true;
}
catch (TransportException& err) {
return false;
}
}
bool
GPDriver::endDoc(bool)
{
try {
fBinding.EndJob();
return true;
}
catch (TransportException& err) {
return false;
}
}
bool
GPDriver::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;
/*
int width = rc.right - rc.left + 1;
int height = rc.bottom - rc.top + 1;
int delta = bitmap->BytesPerRow();
DBGMSG(("width = %d\n", width));
DBGMSG(("height = %d\n", height));
DBGMSG(("delta = %d\n", delta));
DBGMSG(("renderobj->get_pixel_depth() = %d\n", fHalftone->getPixelDepth()));
*/
int width = rc.right - rc.left + 1;
int height = rc.bottom - rc.top + 1;
fprintf(stderr, "GPDriver nextBand x %d, y %d, width %d,"
" height %d\n",
x, y, width, height);
BRect imageRect(rc.left, rc.top, rc.right, rc.bottom);
fBinding.AddBitmapToPage(bitmap, imageRect, BPoint(x, y));
} 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;
}
}

View File

@ -0,0 +1,43 @@
/*
* GP.h
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
*/
#ifndef __GP_H
#define __GP_H
#include "GPBinding.h"
#include "GPCapabilities.h"
#include "GraphicsDriver.h"
#include "OutputStream.h"
class Halftone;
class GPDriver : public GraphicsDriver, public OutputStream
{
public:
GPDriver(BMessage* msg, PrinterData* printer_data,
const PrinterCap* printer_cap);
void Write(const void *buffer, size_t size)
throw(TransportException);
protected:
bool startDoc();
void SetParameter(BString& parameter, PrinterCap::CapID category,
int value);
void SetDriverSpecificSettings();
void AddDriverSpecificSetting(PrinterCap::CapID category,
const char* key);
bool startPage(int page);
bool nextBand(BBitmap* bitmap, BPoint* offset);
bool endPage(int page);
bool endDoc(bool success);
private:
GPBinding fBinding;
GPJobConfiguration fConfiguration;
};
#endif // __GP_H

View File

@ -0,0 +1,503 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "GPJob.h"
#include <Debug.h>
GPJob::GPJob()
:
fApplicationName(),
fOutputStream(NULL),
fConfiguration(NULL),
fFirstPage(true),
fVariables(NULL),
fBands(NULL),
fCachedBand(NULL),
fWriteError(B_OK)
{
fImage.init = ImageInit;
fImage.reset = ImageReset;
fImage.width = ImageWidth;
fImage.height = ImageHeight;
fImage.get_row = ImageGetRow;
fImage.get_appname = ImageGetAppname;
fImage.conclude = ImageConclude;
fImage.rep = this;
}
GPJob::~GPJob()
{
}
void
GPJob::SetApplicationName(const BString& applicationName)
{
fApplicationName = applicationName;
}
void
GPJob::SetConfiguration(GPJobConfiguration* configuration)
{
fConfiguration = configuration;
}
void
GPJob::SetOutputStream(OutputStream* outputStream)
{
fOutputStream = outputStream;
}
status_t
GPJob::Begin()
{
fWriteError = B_OK;
stp_init();
fPrinter = stp_get_printer_by_driver(fConfiguration->fDriver);
if (fPrinter == NULL) {
fprintf(stderr, "GPJob Begin: driver %s not found!\n",
fConfiguration->fDriver.String());
return B_ERROR;
}
fVariables = stp_vars_create();
if (fVariables == NULL) {
fprintf(stderr, "GPJob Begin: out of memory\n");
return B_NO_MEMORY;
}
stp_set_printer_defaults(fVariables, fPrinter);
stp_set_outfunc(fVariables, OutputFunction);
stp_set_errfunc(fVariables, ErrorFunction);
stp_set_outdata(fVariables, this);
stp_set_errdata(fVariables, this);
stp_set_string_parameter(fVariables, "PageSize",
fConfiguration->fPageSize);
if (fConfiguration->fResolution != "")
stp_set_string_parameter(fVariables, "Resolution",
fConfiguration->fResolution);
stp_set_string_parameter(fVariables, "InputSlot",
fConfiguration->fInputSlot);
stp_set_string_parameter(fVariables, "PrintingMode",
fConfiguration->fPrintingMode);
map<string, string>::iterator it = fConfiguration->fDriverSpecificSettings.
begin();
for (; it != fConfiguration->fDriverSpecificSettings.end(); it ++) {
stp_set_string_parameter(fVariables, it->first.c_str(),
it->second.c_str());
}
stp_set_string_parameter(fVariables, "InputImageType",
"RGB");
stp_set_string_parameter(fVariables, "ChannelBitDepth",
"8");
stp_set_float_parameter(fVariables, "Density",
1.0f);
stp_set_string_parameter(fVariables, "JobMode", "Job");
stp_set_printer_defaults_soft(fVariables, fPrinter);
return B_OK;
}
void
GPJob::End()
{
if (fVariables == NULL)
return;
if (!fFirstPage)
stp_end_job(fVariables, &fImage);
stp_vars_destroy(fVariables);
fVariables = NULL;
}
static int
gcd(int a, int b)
{
// Euclidean algorithm for greatest common divisor
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
static int
to72dpiFloor(int value, int fromUnit) {
// proper rounding is important in this formula
// do not "optimize"
const int toUnit = 72;
int g = gcd(toUnit, fromUnit);
int n = toUnit / g;
int m = fromUnit / g;
return (value / m) * n;
}
static int
to72dpiCeiling(int value, int fromUnit) {
// proper rounding is important in this formula
// do not "optimize"
const int toUnit = 72;
int g = gcd(toUnit, fromUnit);
int n = toUnit / g;
int m = fromUnit / g;
return ((value + m - 1) / m) * n;
}
static int
from72dpi(int value, int toUnit)
{
const int fromUnit = 72;
return value * toUnit / fromUnit;
}
status_t
GPJob::PrintPage(list<GPBand*>& bands) {
if (fWriteError != B_OK)
return fWriteError;
fPrintRect = GetPrintRectangle(bands);
fBands = &bands;
fCachedBand = NULL;
{
int left;
int top;
int right;
int bottom;
stp_get_imageable_area(fVariables, &left, &right, &bottom, &top);
fprintf(stderr, "GPJob imageable area left %d, top %d, right %d, "
"bottom %d\n",
left, top, right, bottom);
}
{
int left = (int)fPrintRect.left;
int top = (int)fPrintRect.top;
int width = fPrintRect.IntegerWidth() + 1;
int height = fPrintRect.IntegerHeight() + 1;
fprintf(stderr, "GPJob raw image dimensions left %d, top %d, width %d, height %d\n",
left, top, width, height);
}
int xDPI = fConfiguration->fXDPI;
int yDPI = fConfiguration->fYDPI;
// left, top of the image on the page in 1/72 Inches
int left = static_cast<int>(fPrintRect.left);
left = to72dpiFloor(left, xDPI);
int top = static_cast<int>(fPrintRect.top);
top = to72dpiFloor(top, yDPI);
// because of rounding in the previous step,
// now the image left, top has to be synchronized
fPrintRect.left = from72dpi(left, xDPI);
fPrintRect.top = from72dpi(top, yDPI);
// width and height of the image on the page in 1/72 Inches
int width = fPrintRect.IntegerWidth() + 1;
width = to72dpiCeiling(width, xDPI);
int height = fPrintRect.IntegerHeight() + 1;
height = to72dpiCeiling(height, yDPI);
// synchronize image right and bottom too
fPrintRect.right = fPrintRect.left + from72dpi(width, xDPI);
fPrintRect.bottom = fPrintRect.top + from72dpi(height, yDPI);
{
int left = (int)fPrintRect.left;
int top = (int)fPrintRect.top;
int width = fPrintRect.IntegerWidth() + 1;
int height = fPrintRect.IntegerHeight() + 1;
fprintf(stderr, "GPJob image dimensions left %d, top %d, width %d, height %d\n",
left, top, width, height);
}
fprintf(stderr, "GPJob image dimensions in 1/72 Inches:\n"
"left %d, top %d, width %d, height %d\n",
left, top, width, height);
stp_set_width(fVariables, width);
stp_set_height(fVariables, height);
stp_set_left(fVariables, left);
stp_set_top(fVariables, top);
stp_merge_printvars(fVariables, stp_printer_get_defaults(fPrinter));
if (!stp_verify(fVariables)) {
// TODO report error
fprintf(stderr, "GPJob PrintPage: invalid variables\n");
return B_ERROR;
}
if (fFirstPage) {
fFirstPage = false;
stp_start_job(fVariables, &fImage);
}
stp_print(fVariables, &fImage);
return fWriteError;
}
BRect
GPJob::GetPrintRectangle(list<GPBand*>& bands)
{
list<GPBand*>::iterator it = bands.begin();
if (it == bands.end())
return BRect(0, 0, 0, 0);
GPBand* first = *it;
BRect rect = first->GetBoundingRectangle();
for (it ++; it != bands.end(); it ++) {
GPBand* band = *it;
rect = rect | band->GetBoundingRectangle();
}
return rect;
}
void
GPJob::Init()
{
}
void
GPJob::Reset()
{
}
int
GPJob::Width()
{
return static_cast<int>(fPrintRect.IntegerWidth() + 1);
}
int
GPJob::Height()
{
return static_cast<int>(fPrintRect.IntegerHeight() + 1);
}
stp_image_status_t
GPJob::GetRow(unsigned char* data, size_t size, int row)
{
if (fWriteError != B_OK)
return STP_IMAGE_STATUS_ABORT;
// row is relative to left, top of image
// convert it to absolute value
int line = static_cast<int>(fPrintRect.top) + row;
FillWhite(data, size);
GPBand* band = FindBand(line);
if (band != NULL)
FillRow(band, data, size, line);
return STP_IMAGE_STATUS_OK;
}
GPBand*
GPJob::FindBand(int line)
{
if (fCachedBand != NULL && fCachedBand->ContainsLine(line))
return fCachedBand;
list<GPBand*>::iterator it = fBands->begin();
for (; it != fBands->end(); it ++) {
GPBand* band = *it;
if (band->ContainsLine(line)) {
fCachedBand = band;
return band;
}
}
fCachedBand = NULL;
return NULL;
}
void
GPJob::FillRow(GPBand* band, unsigned char* data, size_t size, int line)
{
int imageTop = line - static_cast<int>(band->fWhere.y -
band->fValidRect.top);
int imageLeft = static_cast<int>(band->fValidRect.left);
const int sourceDelta = band->fBitmap.BytesPerRow();
const int kSourceBytesPerPixel = 4; // BGRA
const unsigned char* source =
static_cast<unsigned char*>(band->fBitmap.Bits())
+ imageTop * sourceDelta
+ imageLeft * kSourceBytesPerPixel;
int dataLeft = static_cast<int>(band->fWhere.x - fPrintRect.left);
const int kTargetBytesPerPixel = 3; // RGB
unsigned char* target = &data[dataLeft * kTargetBytesPerPixel];
const int width = band->fValidRect.IntegerWidth() + 1;
ASSERT(0 <= imageTop && imageTop <= band->fValidRect.IntegerHeight());
ASSERT((dataLeft + width) * kTargetBytesPerPixel <= size);
for (int i = 0; i < width; i ++) {
target[0] = source[2];
target[1] = source[1];
target[2] = source[0];
target += kTargetBytesPerPixel;
source += kSourceBytesPerPixel;
}
}
void
GPJob::FillWhite(unsigned char* data, size_t size)
{
for (size_t i = 0; i < size; i ++)
data[i] = 0xff;
}
const char*
GPJob::GetAppname()
{
return fApplicationName.String();
}
void
GPJob::Conclude()
{
// nothing to do
}
void
GPJob::Write(const char* data, size_t size)
{
try {
fOutputStream->Write(data, size);
} catch (TransportException e) {
fWriteError = B_IO_ERROR;
}
}
void
GPJob::ReportError(const char* data, size_t size)
{
// TODO report error in printer add-on
fprintf(stderr, "GPJob Gutenprint Error: %*s\n", (int)size, data);
}
void
GPJob::ImageInit(stp_image_t* image)
{
GPJob* job = static_cast<GPJob*>(image->rep);
job->Init();
}
void
GPJob::ImageReset(stp_image_t* image)
{
GPJob* job = static_cast<GPJob*>(image->rep);
job->Reset();
}
int
GPJob::ImageWidth(stp_image_t* image)
{
GPJob* job = static_cast<GPJob*>(image->rep);
return job->Width();
}
int
GPJob::ImageHeight(stp_image_t *image)
{
GPJob* job = static_cast<GPJob*>(image->rep);
return job->Height();
}
stp_image_status_t
GPJob::ImageGetRow(stp_image_t* image, unsigned char* data, size_t size,
int row)
{
GPJob* job = static_cast<GPJob*>(image->rep);
return job->GetRow(data, size, row);
}
const char*
GPJob::ImageGetAppname(stp_image_t* image)
{
GPJob* job = static_cast<GPJob*>(image->rep);
return job->GetAppname();
}
void
GPJob::ImageConclude(stp_image_t *image)
{
GPJob* job = static_cast<GPJob*>(image->rep);
job->Conclude();
}
void
GPJob::OutputFunction(void *cookie, const char *data, size_t size)
{
GPJob* job = static_cast<GPJob*>(cookie);
job->Write(data, size);
}
void
GPJob::ErrorFunction(void *cookie, const char *data, size_t size)
{
GPJob* job = static_cast<GPJob*>(cookie);
job->ReportError(data, size);
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef GP_JOB_H
#define GP_JOB_H
#include<gutenprint/gutenprint.h>
#include<list>
#include<String.h>
#include "GPBand.h"
#include "GPJobConfiguration.h"
#include "OutputStream.h"
class GPJob
{
public:
GPJob();
~GPJob();
void SetApplicationName(const BString& applicationName);
void SetConfiguration(GPJobConfiguration* configuration);
void SetOutputStream(OutputStream* outputStream);
status_t Begin();
void End();
status_t PrintPage(list<GPBand*>& bands);
private:
BRect GetPrintRectangle(list<GPBand*>& bands);
GPBand* FindBand(int line);
void FillRow(GPBand* band, unsigned char* data, size_t size,
int line);
void FillWhite(unsigned char* data, size_t size);
void Init();
void Reset();
int Width();
int Height();
stp_image_status_t GetRow(unsigned char* data, size_t size, int row);
const char* GetAppname();
void Conclude();
void Write(const char* data, size_t size);
void ReportError(const char* data, size_t size);
static void ImageInit(stp_image_t* image);
static void ImageReset(stp_image_t* image);
static int ImageWidth(stp_image_t* image);
static int ImageHeight(stp_image_t *image);
static stp_image_status_t ImageGetRow(stp_image_t* image,
unsigned char* data, size_t size, int row);
static const char* ImageGetAppname(stp_image_t* image);
static void ImageConclude(stp_image_t *image);
static void OutputFunction(void *cookie, const char *data,
size_t size);
static void ErrorFunction(void *cookie, const char *data,
size_t size);
BString fApplicationName;
OutputStream* fOutputStream;
GPJobConfiguration* fConfiguration;
bool fFirstPage;
stp_image_t fImage;
stp_vars_t* fVariables;
const stp_printer_t* fPrinter;
BRect fPrintRect;
list<GPBand*>* fBands;
GPBand* fCachedBand;
status_t fWriteError;
};
#endif

View File

@ -0,0 +1,21 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "GPJobConfiguration.h"
GPJobConfiguration::GPJobConfiguration()
:
fDriver(),
fPageSize(),
fResolution(),
fInputSlot(),
fPrintingMode(),
fXDPI(600),
fYDPI(600)
{
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef GP_JOB_CONFIGURATION_H
#define GP_JOB_CONFIGURATION_H
#include<String.h>
#include <map>
#include <string>
using namespace std;
class GPJobConfiguration
{
public:
GPJobConfiguration();
BString fDriver;
BString fPageSize;
BString fResolution;
BString fInputSlot;
BString fPrintingMode;
int fXDPI;
int fYDPI;
map<string, string> fDriverSpecificSettings;
};
#endif

View File

@ -0,0 +1,215 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#include "GPParameterVisitor.h"
#include <String.h>
const char* kJobMode = "JobMode";
const char* kJob = "Job";
const char* kPrintingMode = "PrintingMode";
const char* kColor = "Color";
const char* kBlackAndWhite = "BW";
const char* kResolution = "Resolution";
const char* kFakeResolutionKey = "";
const char* kPageSize = "PageSize";
const char* kChannelBitDepth = "ChannelBitDepth";
GPParameterVisitor::GPParameterVisitor()
:
fVariables(NULL),
fHasResolutionParameter(false)
{
}
GPParameterVisitor::~GPParameterVisitor()
{
}
void
GPParameterVisitor::Visit(const stp_printer_t* printer)
{
// this code is based on Gutenprint printer_options.c
const stp_vars_t* defaultVariables = stp_printer_get_defaults(printer);
stp_vars_t* variables = stp_vars_create_copy(defaultVariables);
fVariables = variables;
stp_set_string_parameter(variables, kJobMode, kJob);
stp_parameter_t printingMode;
stp_describe_parameter(variables, kPrintingMode, &printingMode);
bool isColorPrinter = stp_string_list_is_present(printingMode.bounds.str,
kColor) != 0;
stp_parameter_description_destroy(&printingMode);
if (isColorPrinter)
stp_set_string_parameter(variables, kPrintingMode, kColor);
else
stp_set_string_parameter(variables, kPrintingMode, kBlackAndWhite);
stp_set_string_parameter(variables, kChannelBitDepth, "8");
stp_parameter_list_t list = stp_get_parameter_list(variables);
int size = stp_parameter_list_count(list);
for (int i = 0; i < size; i ++) {
const stp_parameter_t* parameter = stp_parameter_list_param(list, i);
stp_parameter_t description;
stp_describe_parameter(fVariables, parameter->name, &description);
VisitParameter(list, parameter, &description);
stp_parameter_description_destroy(&description);
}
// TODO check if this can really happen
if (!fHasResolutionParameter) {
AddMissingResolution();
}
EndVisit();
stp_parameter_list_destroy(list);
stp_vars_destroy(variables);
fVariables = NULL;
}
void
GPParameterVisitor::AddMissingResolution()
{
// some printer definitions don't have resolution parameter
// however "libprint" needs to know it for rasterization
// TODO find out if other parameters influence the resolution
// e.g. color vs black and white
int x, y;
stp_describe_resolution(fVariables, &x, &y);
BeginParameter(kResolution, "Resolution", STP_PARAMETER_CLASS_FEATURE);
DefaultStringParameter(kResolution, kFakeResolutionKey);
StringParameterSize(kResolution, 1);
if (x <= 0 || y <= 0) {
// TODO decide if more resolutions (150, 600) should be possible
x = 300;
y = 300;
}
BString displayName;
if (x != y)
displayName << x << " x " << y << " DPI";
else
displayName << x << " DPI";
ResolutionParameter(kResolution, kFakeResolutionKey, displayName.String(),
x, y);
EndParameter(kResolution);
}
void
GPParameterVisitor::VisitParameter(stp_parameter_list_t list,
const stp_parameter_t* parameter, stp_parameter_t* description)
{
// TODO decide which parameters should be revealed to user
// e.g. up to STP_PARAMETER_LEVEL_ADVANCED4;
const stp_parameter_level_t kMaxLevel = STP_PARAMETER_LEVEL_BASIC;
stp_parameter_class_t parameterClass = parameter->p_class;
if (parameter->read_only ||
(parameter->p_level > kMaxLevel
&& strcmp(parameter->name, kResolution) != 0)
|| parameterClass != STP_PARAMETER_CLASS_OUTPUT
&& parameterClass != STP_PARAMETER_CLASS_CORE
&& parameterClass != STP_PARAMETER_CLASS_FEATURE)
return;
if (!description->is_active)
return;
switch (description->p_type) {
case STP_PARAMETER_TYPE_STRING_LIST:
if (!BeginParameter(description->name, description->text,
parameterClass))
return;
VisitStringList(description);
EndParameter(description->name);
break;
case STP_PARAMETER_TYPE_BOOLEAN:
break;
case STP_PARAMETER_TYPE_DOUBLE:
break;
case STP_PARAMETER_TYPE_INT:
break;
case STP_PARAMETER_TYPE_DIMENSION:
break;
default:
break;
}
}
void
GPParameterVisitor::VisitStringList(stp_parameter_t* parameter)
{
stp_string_list_t* list = parameter->bounds.str;
int count = stp_string_list_count(list);
if (count <= 0)
return;
const char* name = parameter->name;
if (parameter->is_mandatory)
DefaultStringParameter(name, parameter->deflt.str);
else
DefaultStringParameter(name, NULL);
StringParameterSize(name, count);
for (int i = 0; i < count; i ++) {
const stp_param_string_t* entry = stp_string_list_param(list, i);
const char* key = entry->name;
const char* displayName = entry->text;
if (strcmp(name, kResolution) == 0) {
stp_set_string_parameter(fVariables, kResolution, key);
int x, y;
stp_describe_resolution(fVariables, &x, &y);
ResolutionParameter(name, key, displayName, x, y);
fHasResolutionParameter = true;
} else if (strcmp(name, kPageSize) == 0) {
stp_set_string_parameter(fVariables, kPageSize, key);
int width;
int height;
stp_get_media_size(fVariables, &width, &height);
BSize pageSize(width, height);
int left, right, top, bottom;
stp_get_imageable_area(fVariables, &left, &right, &bottom, &top);
BRect imageableArea(left, top, right, bottom);
PageSizeParameter(name, key, displayName, pageSize, imageableArea);
} else {
StringParameter(name, key, displayName);
}
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef GP_PARAMETER_VISITOR_H
#define GP_PARAMETER_VISITOR_H
#include <gutenprint/gutenprint.h>
#include <Size.h>
#include <Rect.h>
extern const char* kJobMode;
extern const char* kJob;
extern const char* kPrintingMode;
extern const char* kColor;
extern const char* kBlackAndWhite;
extern const char* kResolution;
extern const char* kFakeResolutionKey;
extern const char* kPageSize;
extern const char* kChannelBitDepth;
class GPParameterVisitor
{
public:
GPParameterVisitor();
virtual ~GPParameterVisitor();
void Visit(const stp_printer_t* printer);
void VisitParameter(stp_parameter_list_t list,
const stp_parameter_t* parameter, stp_parameter_t* description);
void VisitStringList(stp_parameter_t* parameter);
virtual bool BeginParameter(const char* name, const char* displayName,
stp_parameter_class_t parameterClass) = 0;
// key is null if there is no default value
virtual void DefaultStringParameter(const char* name,
const char* key) = 0;
virtual void StringParameterSize(const char* name, int size) = 0;
virtual void StringParameter(const char* name, const char* key,
const char* displayName) = 0;
virtual void ResolutionParameter(const char* name, const char* key,
const char* displayName, int x, int y) = 0;
virtual void PageSizeParameter(const char* name, const char* key,
const char* displayName, BSize pageSize,
BRect imageableArea) = 0;
virtual void EndParameter(const char* name) = 0;
virtual void EndVisit() = 0;
private:
void AddMissingResolution();
stp_vars_t* fVariables;
bool fHasResolutionParameter;
};
#endif

View File

@ -0,0 +1,82 @@
/*
* GPEntry.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
* Copyright 2010 Michael Pfeiffer.
*/
#include <Debug.h>
#include "GPDriver.h"
#include "GPCapabilities.h"
#include "GPData.h"
#include "PrinterDriver.h"
#include "SelectPrinterDialog.h"
class GPPrinterDriver : public PrinterDriver
{
public:
GPPrinterDriver(BNode* printerFolder)
:
PrinterDriver(printerFolder)
{
}
const char* GetSignature() const
{
return "application/x-vnd.gutenprint";
}
const char* GetDriverName() const
{
return "Gutenprint";
}
const char* GetVersion() const
{
return "1.0";
}
const char* GetCopyright() const
{
return "Gutenprint driver "
"Copyright © 2010 Michael Pfeiffer.\n";
}
char* AddPrinter(char *printerName)
{
GPData* data = dynamic_cast<GPData*>(GetPrinterData());
ASSERT(data != NULL);
SelectPrinterDialog* dialog =
new SelectPrinterDialog(data);
if (dialog->Go() != B_OK)
return NULL;
return printerName;
}
PrinterData* InstantiatePrinterData(BNode* node)
{
return new GPData(node);
}
PrinterCap* InstantiatePrinterCap(PrinterData* printerData)
{
return new GPCapabilities(printerData);
}
GraphicsDriver* InstantiateGraphicsDriver(BMessage* settings,
PrinterData* printerData, PrinterCap* printerCap)
{
return new GPDriver(settings, printerData, printerCap);
}
};
PrinterDriver* instantiate_printer_driver(BNode* printerFolder)
{
return new GPPrinterDriver(printerFolder);
}

View File

@ -0,0 +1,38 @@
resource app_signature "application/x-vnd.gutenprint";
resource app_flags B_SINGLE_LAUNCH;
resource app_version {
major = 0,
middle = 0,
minor = 1,
variety = B_APPV_DEVELOPMENT,
internal = 0,
short_info = "Gutenprint add-on",
long_info = "Gutenprint add-on for Haiku\nCopyright 1999 Y.Takagi\nCopyright 2010 Michael Pfeiffer\nAll Rights Reserved."
};
resource vector_icon {
$"6E6369660B050002001602B76E71BBF8593D1210B8A7674742A04ABEFB00AEFF"
$"E1053802001603373333B9333339333337333348E54F4B555400FFBFE5FF9B02"
$"00160336C6F3B9284239E397376BB94A71BE484A25005346B5FFFF02001602B5"
$"00003A6000BA6000B500004A2E244AB9D001C0FF9A020116023AA41339C70ABC"
$"27003D026E4ACAB74AC8AB0183FFAD020106023600000000000000003700004A"
$"10004AB0000035FF06FB1E9303020106023600000000000000003700004A1000"
$"4AB00000FFE3E3FFDD05050101000073020116023E1E41BC9E393B21B93C88A6"
$"4824E3485D850090FF3C0B0606BE023A5F485C46584C5E5656525A5656604C58"
$"483A0608EFB6302E302E25372248223A2248465A4A59485B4A59584B41573E58"
$"3F563D543C0608AAFF503A4E3C3231342F302E302E25372248223A2248465A46"
$"5A464C543C4A46543C0606FF06573E583F563D543C543C4A46465A464C465A4A"
$"59485B4A59584B410604DB4A594A4F4A59584B41563F563F4E470A0426484256"
$"4252264406057A0322513A5E42543C58425452B77BC262B77BC262254A080228"
$"5038580A06542A3C22353135324C3B4C3A0202404A3E4C4248434D454B414F02"
$"0332332B3332334B3E4B3E453E3547444E26400F0A090100000A000301060810"
$"01178400040A010102000A0001051001178200040A020105000A030106000A04"
$"0108000A050103000A060104000A08010920251C0A0701092022210A00010730"
$"241C01178100040A00010730221E01178100040A0001071815FF01178100040A"
$"0A010A00"
};

View File

@ -0,0 +1,25 @@
SubDir HAIKU_TOP src add-ons print drivers gutenprint ;
SubDirSysHdrs [ FDirName $(HAIKU_TOP) src libs print libgutenprint include ] ;
SubDirHdrs [ FDirName $(HAIKU_TOP) headers libs print libprint ] ;
AddResources Gutenprint : Gutenprint.rdef ;
Addon Gutenprint :
GPBand.cpp
GPBinding.cpp
GPCapabilities.cpp
GPCapabilityExtractor.cpp
GPData.cpp
GPDriver.cpp
GPJob.cpp
GPJobConfiguration.cpp
GPParameterVisitor.cpp
GPPrinterDriver.cpp
SelectPrinterDialog.cpp
:
be
libgutenprint.a
libprint.a
$(TARGET_LIBSTDC++)
;

View File

@ -0,0 +1,22 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
*/
#ifndef OUTPUT_STREAM_H
#define OUTPUT_STREAM_H
#include "Transport.h"
class OutputStream
{
public:
virtual void Write(const void *buffer, size_t size)
throw(TransportException) = 0;
};
#endif

View File

@ -0,0 +1,196 @@
/*
* Copyright 2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ithamar R. Adema <ithamar.adema@team-embedded.nl>
* Michael Pfeiffer
*/
#include "SelectPrinterDialog.h"
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <Button.h>
#include <Debug.h>
#include <Directory.h>
#include <Entry.h>
#include <ListView.h>
#include <Message.h>
#include <Path.h>
#include <ScrollBar.h>
#include <ScrollView.h>
#include <String.h>
#include <StringItem.h>
#include "GPBinding.h"
enum {
kMsgCancel = 'stop',
kMsgOK = 'okok',
kMsgManufacturerSelected = 'msel',
kMsgPrinterSelected = 'psel',
};
class StringValueItem : public BStringItem {
public:
StringValueItem(const BString& text, const BString& value)
:
BStringItem(text.String()),
fValue(value)
{
}
BString fValue;
};
SelectPrinterDialog::SelectPrinterDialog(GPData* data)
:
DialogWindow(BRect(10, 10, 400, 400),
"Select Printer", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS),
fData(data)
{
SetResult(B_ERROR);
BButton* ok;
BButton* cancel;
ok = new BButton("btn:ok", "OK", new BMessage(kMsgOK));
ok->MakeDefault(true);
ok->SetEnabled(false);
fOKButton = ok;
cancel = new BButton("btn:cancel", "Cancel", new BMessage(kMsgCancel));
BScrollView* manuScroller, *printerScroller;
fManufacturersListView = new BListView("olv:manufacturers");
manuScroller = new BScrollView("scr:manufacturers", fManufacturersListView,
0, false, true);
fPrintersListView = new BListView("olv:printers");
printerScroller = new BScrollView("scr:printers", fPrintersListView, 0,
false, true);
fPrintersListView->SetSelectionMessage(new BMessage(kMsgPrinterSelected));
fManufacturersListView->SetSelectionMessage(
new BMessage(kMsgManufacturerSelected));
PopulateManufacturers();
// Build the layout
SetLayout(new BGroupLayout(B_VERTICAL));
AddChild(BGroupLayoutBuilder(B_VERTICAL, 10)
.AddGroup(B_HORIZONTAL, 5, 1.0f)
.Add(manuScroller)
.Add(printerScroller)
.End()
.AddGroup(B_HORIZONTAL, 5, 2.0f)
.AddGlue()
.Add(cancel)
.Add(ok)
.End()
.SetInsets(10, 10, 10, 10)
);
}
void
SelectPrinterDialog::PopulateManufacturers()
{
BMessage manufacturers;
GPBinding binding;
binding.GetPrinterManufacturers(manufacturers);
BString id;
BString displayName;
for (int32 index = 0; binding.ExtractManufacturer(manufacturers, index, id,
displayName); index ++) {
fManufacturersListView->AddItem(new StringValueItem(id, displayName));
}
}
void
SelectPrinterDialog::PopulatePrinters()
{
BString manufacturer = GetSelectedItemValue(fManufacturersListView).String();
if (manufacturer.Length() == 0)
return;
BMessage models;
GPBinding binding;
binding.GetPrinterModels(manufacturer, models);
BString displayName;
BString driver;
for (int32 index = 0; binding.ExtractModel(models, index, displayName, driver);
index ++) {
StringValueItem* item = new StringValueItem(displayName, driver);
fPrintersListView->AddItem(item);
}
}
BString
SelectPrinterDialog::GetSelectedItemValue(BListView* listView)
{
int32 index = listView->CurrentSelection();
// Bail out if no manufacturer is selected
if (index < 0)
return "";
BListItem* item = listView->ItemAt(index);
StringValueItem* valueItem = dynamic_cast<StringValueItem*>(item);
ASSERT(valueItem != NULL);
return valueItem->fValue;
}
void
SelectPrinterDialog::PrinterSelected()
{
int32 index = fPrintersListView->CurrentSelection();
fOKButton->SetEnabled(index >= 0);
}
void
SelectPrinterDialog::Save()
{
BString driverName = GetSelectedItemValue(fPrintersListView);
fData->fGutenprintDriverName = driverName;
fData->save();
}
void
SelectPrinterDialog::MessageReceived(BMessage* msg)
{
switch (msg->what) {
case kMsgManufacturerSelected:
fPrintersListView->MakeEmpty();
PopulatePrinters();
PrinterSelected();
break;
case kMsgPrinterSelected:
PrinterSelected();
break;
case kMsgOK:
Save();
SetResult(B_NO_ERROR);
PostMessage(B_QUIT_REQUESTED);
break;
case kMsgCancel:
PostMessage(B_QUIT_REQUESTED);
break;
default:
DialogWindow::MessageReceived(msg);
break;
}
}

View File

@ -0,0 +1,35 @@
#ifndef SELECT_PRINTER_DIALOG_H
#define SELECT_PRINTER_DIALOG_H
#include <storage/FindDirectory.h>
#include "DialogWindow.h"
#include "GPData.h"
class BListView;
class BButton;
class PSData;
class SelectPrinterDialog : public DialogWindow {
public:
SelectPrinterDialog(GPData* data);
void MessageReceived(BMessage* msg);
private:
void PopulateManufacturers();
void PopulatePrinters();
BString GetSelectedItemValue(BListView* listView);
void PrinterSelected();
void Save();
BListView* fManufacturersListView;
BListView* fPrintersListView;
BButton* fOKButton;
GPData* fData;
};
#endif // SELECTPPDDLG_H