Added ImageCache.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3697 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer
2003-06-27 17:20:57 +00:00
parent 3759446ddd
commit a952b1a530
4 changed files with 271 additions and 5 deletions
@@ -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;