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;
|
||||
|
||||
if (pageNumber == 1) {
|
||||
if (MakesPattern())
|
||||
if (MakesPattern()) {
|
||||
REPORT(kDebug, fPage, ">>>>> Collecting patterns...");
|
||||
else if (MakesPDF())
|
||||
} else if (MakesPDF()) {
|
||||
REPORT(kDebug, fPage, ">>>>> Generating PDF...");
|
||||
fImageCache.ResetID();
|
||||
}
|
||||
}
|
||||
|
||||
paperRect = JobMsg()->FindRect("paper_rect");
|
||||
@@ -229,7 +231,8 @@ PDFWriter::EndJob()
|
||||
fprintf(fLog, ": %s\n", rr->Desc());
|
||||
}
|
||||
#endif
|
||||
|
||||
fImageCache.Flush(fPdf);
|
||||
|
||||
PDF_close(fPdf);
|
||||
REPORT(kDebug, 0, ">>>> PDF_close");
|
||||
|
||||
@@ -262,12 +265,14 @@ PDFWriter::InitWriter()
|
||||
fStateDepth = 0;
|
||||
|
||||
// pdflib scope: object
|
||||
/*
|
||||
const char* license_key;
|
||||
if (JobMsg()->FindString("pdflib_license_key", &license_key) == B_OK &&
|
||||
license_key[0] != 0) {
|
||||
REPORT(kDebug, 0, "license key found %s!", license_key);
|
||||
PDF_set_parameter(fPdf, "license", license_key);
|
||||
}
|
||||
*/
|
||||
|
||||
fPDFVersion = kPDF13;
|
||||
const char * compatibility;
|
||||
@@ -278,6 +283,7 @@ PDFWriter::InitWriter()
|
||||
else if (strcmp(compatibility, "1.5") == 0) fPDFVersion = kPDF15;
|
||||
}
|
||||
|
||||
/*
|
||||
// set user/master password
|
||||
BString master_password, user_password;
|
||||
if (JobMsg()->FindString("master_password", &master_password) == B_OK &&
|
||||
@@ -293,6 +299,7 @@ PDFWriter::InitWriter()
|
||||
permissions.Length() > 0) {
|
||||
PDF_set_parameter(fPdf, "permissions", permissions.String());
|
||||
}
|
||||
*/
|
||||
|
||||
REPORT(kDebug, 0, ">>>> PDF_open_mem");
|
||||
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);
|
||||
if (pattern == -1) {
|
||||
REPORT(kError, fPage, "CreatePattern could not create pattern");
|
||||
#if !USE_IMAGE_CACHE
|
||||
PDF_close_image(fPdf, image);
|
||||
#endif
|
||||
if (mask != -1) PDF_close_image(fPdf, mask);
|
||||
return;
|
||||
}
|
||||
PDF_setcolor(fPdf, "both", "rgb", 0, 0, 1, 0);
|
||||
PDF_place_image(fPdf, image, 0, 0, 1);
|
||||
PDF_end_pattern(fPdf);
|
||||
#if !USE_IMAGE_CACHE
|
||||
PDF_close_image(fPdf, image);
|
||||
#endif
|
||||
if (mask != -1) PDF_close_image(fPdf, mask);
|
||||
#endif
|
||||
|
||||
@@ -1612,8 +1623,13 @@ PDFWriter::GetImages(BRect src, int32 /*width*/, int32 /*height*/, int32 bytesPe
|
||||
}
|
||||
|
||||
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;
|
||||
PDF_delete_pvf(fPdf, "mask", 0);
|
||||
}
|
||||
|
||||
BBitmap * bm = ConvertBitmap(src, bytesPerRow, pixelFormat, flags, data);
|
||||
@@ -1623,6 +1639,10 @@ PDFWriter::GetImages(BRect src, int32 /*width*/, int32 /*height*/, int32 bytesPe
|
||||
return false;
|
||||
}
|
||||
|
||||
#if USE_IMAGE_CACHE
|
||||
*image = fImageCache.GetImage(fPdf, bm, *maskId);
|
||||
delete bm;
|
||||
#else
|
||||
char *pdfLibFormat = "png";
|
||||
char *bitmapFileName = "/tmp/pdfwriter.png";
|
||||
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,
|
||||
*maskId == -1 ? "" : "masked", *maskId == -1 ? 0 : *maskId);
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
SetColor();
|
||||
if (!MakesPDF()) return;
|
||||
|
||||
if (IsClipping()) {
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
if (!MakesPDF()) return;
|
||||
|
||||
const float scaleX = (dest.Width()+1) / (src.Width()+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 ) {
|
||||
PDF_place_image(fPdf, image, x, y, scale(1.0));
|
||||
#if !USE_IMAGE_CACHE
|
||||
PDF_close_image(fPdf, image);
|
||||
#endif
|
||||
} else
|
||||
REPORT(kError, fPage, "PDF_open_image_file failed!");
|
||||
|
||||
|
||||
@@ -45,9 +45,12 @@ THE SOFTWARE.
|
||||
#include "SubPath.h"
|
||||
#include "Utils.h"
|
||||
#include "Link.h"
|
||||
#include "ImageCache.h"
|
||||
|
||||
#include "pdflib.h"
|
||||
|
||||
#define USE_IMAGE_CACHE 1
|
||||
|
||||
#define RAD2DEGREE(r) (180.0 * r / PI)
|
||||
#define DEGREE2RAD(d) (PI * d / 180.0)
|
||||
|
||||
@@ -310,6 +313,7 @@ class PDFWriter : public PrinterDriver, public PictureIterator
|
||||
TList<Pattern> fPatterns;
|
||||
TList<Transparency> fTransparencyCache;
|
||||
TList<Transparency> fTransparencyStack;
|
||||
ImageCache fImageCache;
|
||||
int64 fEmbedMaxFontSize;
|
||||
BScreen *fScreen;
|
||||
Fonts *fFonts;
|
||||
|
||||
Reference in New Issue
Block a user