Added ImageCache.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3697 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,156 @@
|
|||||||
|
#include<unistd.h>
|
||||||
|
#include<sys/stat.h>
|
||||||
|
#include<Translator.h>
|
||||||
|
#include<TranslationUtils.h>
|
||||||
|
#include<TranslatorRoster.h>
|
||||||
|
#include<BitmapStream.h>
|
||||||
|
#include<File.h>
|
||||||
|
#include<Debug.h>
|
||||||
|
|
||||||
|
#include "ImageCache.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Implementation of Image
|
||||||
|
|
||||||
|
Image::Image(int imageID, const char* fileName, int width, int height, color_space colorSpace, int mask)
|
||||||
|
: fImageID(imageID)
|
||||||
|
, fFileName(fileName)
|
||||||
|
, fWidth(width)
|
||||||
|
, fHeight(height)
|
||||||
|
, fColorSpace(colorSpace)
|
||||||
|
, fMask(mask)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Image::Equals(BBitmap* bitmap) const {
|
||||||
|
BBitmap* bm = BTranslationUtils::GetBitmapFile(FileName());
|
||||||
|
bool equals = false;
|
||||||
|
if (bm) {
|
||||||
|
bm->Lock();
|
||||||
|
bitmap->Lock();
|
||||||
|
|
||||||
|
equals = bm->BitsLength() == bitmap->BitsLength() &&
|
||||||
|
bm->ColorSpace() == bitmap->ColorSpace() &&
|
||||||
|
memcmp(bm->Bits(), bitmap->Bits(), bm->BitsLength()) == 0;
|
||||||
|
|
||||||
|
bitmap->Unlock();
|
||||||
|
bm->Unlock();
|
||||||
|
delete bm;
|
||||||
|
}
|
||||||
|
return equals;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Implementation of ImageReference
|
||||||
|
|
||||||
|
ImageReference::ImageReference(Image* image)
|
||||||
|
: fImage(image)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Implementation of ImageCache
|
||||||
|
|
||||||
|
const char* kTemporaryPath = "/tmp/PDFWriter";
|
||||||
|
const char* kImageCachePath = "/tmp/PDFWriter/Cache";
|
||||||
|
const char* kImagePathPrefix = "/tmp/PDFWriter/Cache/Image";
|
||||||
|
|
||||||
|
ImageCache::ImageCache()
|
||||||
|
: fNextID(0)
|
||||||
|
{
|
||||||
|
mkdir(kTemporaryPath, 0777);
|
||||||
|
mkdir(kImageCachePath, 0777);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageCache::~ImageCache() {
|
||||||
|
rmdir(kImageCachePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCache::Flush(PDF* pdf) {
|
||||||
|
for (int32 i = 0; i < fCache.CountItems(); i ++) {
|
||||||
|
CachedImage* image = fCache.ItemAt(i);
|
||||||
|
if (dynamic_cast<Image*>(image) != NULL) {
|
||||||
|
PDF_close_image(pdf, image->ImageID());
|
||||||
|
unlink(image->FileName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImageCache::GetImage(PDF* pdf, BBitmap* bitmap, int mask) {
|
||||||
|
int id = fNextID ++;
|
||||||
|
CachedImage* image = fCache.ItemAt(id);
|
||||||
|
// In 2. pass for each bitmap an entry exists
|
||||||
|
if (image != NULL) {
|
||||||
|
return image->ImageID();
|
||||||
|
}
|
||||||
|
// In 1. pass we create an entry for each bitmap
|
||||||
|
image = Find(bitmap, mask);
|
||||||
|
// Bitmap not in cache
|
||||||
|
if (image == NULL) {
|
||||||
|
image = Store(pdf, id, bitmap, mask);
|
||||||
|
} else {
|
||||||
|
Image* im = dynamic_cast<Image*>(image);
|
||||||
|
ASSERT(im != NULL);
|
||||||
|
image = new ImageReference(im);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image == NULL) return -1; // error occured
|
||||||
|
|
||||||
|
fCache.AddItem(image);
|
||||||
|
ASSERT(fCache.CountItems() == fNextID);
|
||||||
|
return image->ImageID();
|
||||||
|
}
|
||||||
|
|
||||||
|
CachedImage* ImageCache::Find(BBitmap* bitmap, int mask) {
|
||||||
|
int w, h;
|
||||||
|
color_space cs;
|
||||||
|
bitmap->Lock();
|
||||||
|
w = bitmap->Bounds().IntegerWidth()+1;
|
||||||
|
h = bitmap->Bounds().IntegerHeight()+1;
|
||||||
|
cs = bitmap->ColorSpace();
|
||||||
|
bitmap->Unlock();
|
||||||
|
|
||||||
|
for (int32 i = 0; i < fCache.CountItems(); i ++) {
|
||||||
|
CachedImage* image = fCache.ItemAt(i);
|
||||||
|
if (dynamic_cast<ImageReference*>(image) != NULL) continue;
|
||||||
|
if (w != image->Width() || h != image->Height() ||
|
||||||
|
cs != image->ColorSpace() ||
|
||||||
|
mask != image->Mask()) continue;
|
||||||
|
if (image->Equals(bitmap)) {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CachedImage* ImageCache::Store(PDF* pdf, int id, BBitmap* bitmap, int mask) {
|
||||||
|
BString fileName(kImagePathPrefix);
|
||||||
|
fileName << id << ".png";
|
||||||
|
int w, h;
|
||||||
|
color_space cs;
|
||||||
|
bitmap->Lock();
|
||||||
|
w = bitmap->Bounds().IntegerWidth()+1;
|
||||||
|
h = bitmap->Bounds().IntegerHeight()+1;
|
||||||
|
cs = bitmap->ColorSpace();
|
||||||
|
bitmap->Unlock();
|
||||||
|
|
||||||
|
if (!StoreBitmap(fileName.String(), bitmap)) return NULL;
|
||||||
|
|
||||||
|
int image;
|
||||||
|
image = PDF_open_image_file(pdf, "png", fileName.String(),
|
||||||
|
mask == -1 ? "" : "masked", mask == -1 ? 0 : mask);
|
||||||
|
if (image < 0) return NULL;
|
||||||
|
|
||||||
|
return new Image(image, fileName.String(), w, h, cs, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImageCache::StoreBitmap(const char* fileName, BBitmap* bitmap) {
|
||||||
|
bool ok;
|
||||||
|
BTranslatorRoster *roster = BTranslatorRoster::Default();
|
||||||
|
BBitmapStream stream(bitmap); // init with contents of bitmap
|
||||||
|
BFile file(fileName, B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
|
||||||
|
ok = roster->Translate(&stream, NULL, NULL, &file, B_PNG_FORMAT) == B_OK;
|
||||||
|
BBitmap *bm = NULL; stream.DetachBitmap(&bm); // otherwise bitmap destructor crashes here!
|
||||||
|
ASSERT(bm == bitmap);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#ifndef _IMAGE_CACHE_H
|
||||||
|
#define _IMAGE_CACHE_H
|
||||||
|
|
||||||
|
#include <Bitmap.h>
|
||||||
|
#include <InterfaceDefs.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include "pdflib.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CachedImage {
|
||||||
|
public:
|
||||||
|
CachedImage() {};
|
||||||
|
virtual ~CachedImage() {};
|
||||||
|
virtual int ImageID() const = 0;
|
||||||
|
virtual const char* FileName() const = 0;
|
||||||
|
virtual int Width() const = 0;
|
||||||
|
virtual int Height() const = 0;
|
||||||
|
virtual color_space ColorSpace() const = 0;
|
||||||
|
virtual int Mask() const = 0;
|
||||||
|
virtual bool Equals(BBitmap* bitmap) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Image : public CachedImage {
|
||||||
|
public:
|
||||||
|
Image(int imageID, const char* fileName, int width, int height, color_space colorSpace, int mask);
|
||||||
|
|
||||||
|
int ImageID() const { return fImageID; };
|
||||||
|
const char* FileName() const { return fFileName.String(); };
|
||||||
|
int Width() const { return fWidth; };
|
||||||
|
int Height() const { return fHeight; };
|
||||||
|
color_space ColorSpace() const { return fColorSpace; };
|
||||||
|
int Mask() const { return fMask; };
|
||||||
|
bool Equals(BBitmap* bitmap) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fImageID;
|
||||||
|
BString fFileName;
|
||||||
|
int fWidth, fHeight;
|
||||||
|
color_space fColorSpace;
|
||||||
|
int fMask;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ImageReference : public CachedImage {
|
||||||
|
public:
|
||||||
|
ImageReference(Image* image);
|
||||||
|
|
||||||
|
int ImageID() const { return fImage->ImageID(); };
|
||||||
|
const char* FileName() const { return fImage->FileName(); };
|
||||||
|
int Width() const { return fImage->Width(); };
|
||||||
|
int Height() const { return fImage->Height(); };
|
||||||
|
color_space ColorSpace() const { return fImage->ColorSpace(); };
|
||||||
|
int Mask() const { return fImage->Mask(); };
|
||||||
|
bool Equals(BBitmap* bitmap) const { return fImage->Equals(bitmap); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Image* fImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ImageCache {
|
||||||
|
public:
|
||||||
|
ImageCache();
|
||||||
|
~ImageCache();
|
||||||
|
void Flush(PDF* pdf);
|
||||||
|
|
||||||
|
void ResetID() { fNextID = 0; }
|
||||||
|
int GetImage(PDF* pdf, BBitmap* bitmap, int mask);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CachedImage* Find(BBitmap* bitmap, int mask);
|
||||||
|
CachedImage* Store(PDF* pdf, int id, BBitmap* bitmap, int mask);
|
||||||
|
bool StoreBitmap(const char* fileName, BBitmap* bitmap);
|
||||||
|
|
||||||
|
int fNextID;
|
||||||
|
TList<CachedImage> fCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -117,10 +117,12 @@ PDFWriter::PrintPage(int32 pageNumber, int32 pageCount)
|
|||||||
fPage = pageNumber;
|
fPage = pageNumber;
|
||||||
|
|
||||||
if (pageNumber == 1) {
|
if (pageNumber == 1) {
|
||||||
if (MakesPattern())
|
if (MakesPattern()) {
|
||||||
REPORT(kDebug, fPage, ">>>>> Collecting patterns...");
|
REPORT(kDebug, fPage, ">>>>> Collecting patterns...");
|
||||||
else if (MakesPDF())
|
} else if (MakesPDF()) {
|
||||||
REPORT(kDebug, fPage, ">>>>> Generating PDF...");
|
REPORT(kDebug, fPage, ">>>>> Generating PDF...");
|
||||||
|
fImageCache.ResetID();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paperRect = JobMsg()->FindRect("paper_rect");
|
paperRect = JobMsg()->FindRect("paper_rect");
|
||||||
@@ -229,7 +231,8 @@ PDFWriter::EndJob()
|
|||||||
fprintf(fLog, ": %s\n", rr->Desc());
|
fprintf(fLog, ": %s\n", rr->Desc());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
fImageCache.Flush(fPdf);
|
||||||
|
|
||||||
PDF_close(fPdf);
|
PDF_close(fPdf);
|
||||||
REPORT(kDebug, 0, ">>>> PDF_close");
|
REPORT(kDebug, 0, ">>>> PDF_close");
|
||||||
|
|
||||||
@@ -262,12 +265,14 @@ PDFWriter::InitWriter()
|
|||||||
fStateDepth = 0;
|
fStateDepth = 0;
|
||||||
|
|
||||||
// pdflib scope: object
|
// pdflib scope: object
|
||||||
|
/*
|
||||||
const char* license_key;
|
const char* license_key;
|
||||||
if (JobMsg()->FindString("pdflib_license_key", &license_key) == B_OK &&
|
if (JobMsg()->FindString("pdflib_license_key", &license_key) == B_OK &&
|
||||||
license_key[0] != 0) {
|
license_key[0] != 0) {
|
||||||
REPORT(kDebug, 0, "license key found %s!", license_key);
|
REPORT(kDebug, 0, "license key found %s!", license_key);
|
||||||
PDF_set_parameter(fPdf, "license", license_key);
|
PDF_set_parameter(fPdf, "license", license_key);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
fPDFVersion = kPDF13;
|
fPDFVersion = kPDF13;
|
||||||
const char * compatibility;
|
const char * compatibility;
|
||||||
@@ -278,6 +283,7 @@ PDFWriter::InitWriter()
|
|||||||
else if (strcmp(compatibility, "1.5") == 0) fPDFVersion = kPDF15;
|
else if (strcmp(compatibility, "1.5") == 0) fPDFVersion = kPDF15;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// set user/master password
|
// set user/master password
|
||||||
BString master_password, user_password;
|
BString master_password, user_password;
|
||||||
if (JobMsg()->FindString("master_password", &master_password) == B_OK &&
|
if (JobMsg()->FindString("master_password", &master_password) == B_OK &&
|
||||||
@@ -293,6 +299,7 @@ PDFWriter::InitWriter()
|
|||||||
permissions.Length() > 0) {
|
permissions.Length() > 0) {
|
||||||
PDF_set_parameter(fPdf, "permissions", permissions.String());
|
PDF_set_parameter(fPdf, "permissions", permissions.String());
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
REPORT(kDebug, 0, ">>>> PDF_open_mem");
|
REPORT(kDebug, 0, ">>>> PDF_open_mem");
|
||||||
PDF_open_mem(fPdf, _WriteData); // use callback to stream PDF document data to printer transport
|
PDF_open_mem(fPdf, _WriteData); // use callback to stream PDF document data to printer transport
|
||||||
@@ -791,14 +798,18 @@ PDFWriter::CreatePattern()
|
|||||||
int pattern = PDF_begin_pattern(fPdf, 8, 8, 8, 8, 1);
|
int pattern = PDF_begin_pattern(fPdf, 8, 8, 8, 8, 1);
|
||||||
if (pattern == -1) {
|
if (pattern == -1) {
|
||||||
REPORT(kError, fPage, "CreatePattern could not create pattern");
|
REPORT(kError, fPage, "CreatePattern could not create pattern");
|
||||||
|
#if !USE_IMAGE_CACHE
|
||||||
PDF_close_image(fPdf, image);
|
PDF_close_image(fPdf, image);
|
||||||
|
#endif
|
||||||
if (mask != -1) PDF_close_image(fPdf, mask);
|
if (mask != -1) PDF_close_image(fPdf, mask);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PDF_setcolor(fPdf, "both", "rgb", 0, 0, 1, 0);
|
PDF_setcolor(fPdf, "both", "rgb", 0, 0, 1, 0);
|
||||||
PDF_place_image(fPdf, image, 0, 0, 1);
|
PDF_place_image(fPdf, image, 0, 0, 1);
|
||||||
PDF_end_pattern(fPdf);
|
PDF_end_pattern(fPdf);
|
||||||
|
#if !USE_IMAGE_CACHE
|
||||||
PDF_close_image(fPdf, image);
|
PDF_close_image(fPdf, image);
|
||||||
|
#endif
|
||||||
if (mask != -1) PDF_close_image(fPdf, mask);
|
if (mask != -1) PDF_close_image(fPdf, mask);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1612,8 +1623,13 @@ PDFWriter::GetImages(BRect src, int32 /*width*/, int32 /*height*/, int32 bytesPe
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mask) {
|
if (mask) {
|
||||||
*maskId = PDF_open_image(fPdf, "raw", "memory", (const char *) mask, length, width, height, 1, bpc, "mask");
|
// *maskId = PDF_open_image(fPdf, "raw", "memory", (const char *) mask, length, width, height, 1, bpc, "mask");
|
||||||
|
BString options;
|
||||||
|
PDF_create_pvf(fPdf, "mask", 0, mask, length, NULL);
|
||||||
|
options << "width " << width << " height " << height << " components 1 bpc " << bpc;
|
||||||
|
*maskId = PDF_load_image(fPdf, "raw", "mask", 0, options.String());
|
||||||
delete []mask;
|
delete []mask;
|
||||||
|
PDF_delete_pvf(fPdf, "mask", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BBitmap * bm = ConvertBitmap(src, bytesPerRow, pixelFormat, flags, data);
|
BBitmap * bm = ConvertBitmap(src, bytesPerRow, pixelFormat, flags, data);
|
||||||
@@ -1623,6 +1639,10 @@ PDFWriter::GetImages(BRect src, int32 /*width*/, int32 /*height*/, int32 bytesPe
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_IMAGE_CACHE
|
||||||
|
*image = fImageCache.GetImage(fPdf, bm, *maskId);
|
||||||
|
delete bm;
|
||||||
|
#else
|
||||||
char *pdfLibFormat = "png";
|
char *pdfLibFormat = "png";
|
||||||
char *bitmapFileName = "/tmp/pdfwriter.png";
|
char *bitmapFileName = "/tmp/pdfwriter.png";
|
||||||
const uint32 beosFormat = B_PNG_FORMAT;
|
const uint32 beosFormat = B_PNG_FORMAT;
|
||||||
@@ -1637,6 +1657,7 @@ PDFWriter::GetImages(BRect src, int32 /*width*/, int32 /*height*/, int32 bytesPe
|
|||||||
|
|
||||||
*image = PDF_open_image_file(fPdf, pdfLibFormat, bitmapFileName,
|
*image = PDF_open_image_file(fPdf, pdfLibFormat, bitmapFileName,
|
||||||
*maskId == -1 ? "" : "masked", *maskId == -1 ? 0 : *maskId);
|
*maskId == -1 ? "" : "masked", *maskId == -1 ? 0 : *maskId);
|
||||||
|
#endif
|
||||||
|
|
||||||
return *image >= 0;
|
return *image >= 0;
|
||||||
}
|
}
|
||||||
@@ -2111,7 +2132,6 @@ PDFWriter::DrawPixels(BRect src, BRect dest, int32 width, int32 height, int32 by
|
|||||||
width, height, bytesPerRow, pixelFormat, flags, data);
|
width, height, bytesPerRow, pixelFormat, flags, data);
|
||||||
|
|
||||||
SetColor();
|
SetColor();
|
||||||
if (!MakesPDF()) return;
|
|
||||||
|
|
||||||
if (IsClipping()) {
|
if (IsClipping()) {
|
||||||
REPORT(kError, fPage, "DrawPixels for clipping not implemented yet!");
|
REPORT(kError, fPage, "DrawPixels for clipping not implemented yet!");
|
||||||
@@ -2123,6 +2143,7 @@ PDFWriter::DrawPixels(BRect src, BRect dest, int32 width, int32 height, int32 by
|
|||||||
if (!GetImages(src, width, height, bytesPerRow, pixelFormat, flags, data, &maskId, &image)) {
|
if (!GetImages(src, width, height, bytesPerRow, pixelFormat, flags, data, &maskId, &image)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!MakesPDF()) return;
|
||||||
|
|
||||||
const float scaleX = (dest.Width()+1) / (src.Width()+1);
|
const float scaleX = (dest.Width()+1) / (src.Width()+1);
|
||||||
const float scaleY = (dest.Height()+1) / (src.Height()+1);
|
const float scaleY = (dest.Height()+1) / (src.Height()+1);
|
||||||
@@ -2146,7 +2167,9 @@ PDFWriter::DrawPixels(BRect src, BRect dest, int32 width, int32 height, int32 by
|
|||||||
|
|
||||||
if ( image >= 0 ) {
|
if ( image >= 0 ) {
|
||||||
PDF_place_image(fPdf, image, x, y, scale(1.0));
|
PDF_place_image(fPdf, image, x, y, scale(1.0));
|
||||||
|
#if !USE_IMAGE_CACHE
|
||||||
PDF_close_image(fPdf, image);
|
PDF_close_image(fPdf, image);
|
||||||
|
#endif
|
||||||
} else
|
} else
|
||||||
REPORT(kError, fPage, "PDF_open_image_file failed!");
|
REPORT(kError, fPage, "PDF_open_image_file failed!");
|
||||||
|
|
||||||
|
|||||||
@@ -45,9 +45,12 @@ THE SOFTWARE.
|
|||||||
#include "SubPath.h"
|
#include "SubPath.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "Link.h"
|
#include "Link.h"
|
||||||
|
#include "ImageCache.h"
|
||||||
|
|
||||||
#include "pdflib.h"
|
#include "pdflib.h"
|
||||||
|
|
||||||
|
#define USE_IMAGE_CACHE 1
|
||||||
|
|
||||||
#define RAD2DEGREE(r) (180.0 * r / PI)
|
#define RAD2DEGREE(r) (180.0 * r / PI)
|
||||||
#define DEGREE2RAD(d) (PI * d / 180.0)
|
#define DEGREE2RAD(d) (PI * d / 180.0)
|
||||||
|
|
||||||
@@ -310,6 +313,7 @@ class PDFWriter : public PrinterDriver, public PictureIterator
|
|||||||
TList<Pattern> fPatterns;
|
TList<Pattern> fPatterns;
|
||||||
TList<Transparency> fTransparencyCache;
|
TList<Transparency> fTransparencyCache;
|
||||||
TList<Transparency> fTransparencyStack;
|
TList<Transparency> fTransparencyStack;
|
||||||
|
ImageCache fImageCache;
|
||||||
int64 fEmbedMaxFontSize;
|
int64 fEmbedMaxFontSize;
|
||||||
BScreen *fScreen;
|
BScreen *fScreen;
|
||||||
Fonts *fFonts;
|
Fonts *fFonts;
|
||||||
|
|||||||
Reference in New Issue
Block a user