Commit 409f2a9c authored by Albert Astals Cid's avatar Albert Astals Cid

* glib/poppler-page.cc:

        * glib/poppler-page.h:
        * glib/poppler-private.h:
        * glib/poppler.h:
        * glib/test-poppler-glib.c:
        * poppler/CairoOutputDev.cc:
        * poppler/CairoOutputDev.h: Extend CairoOutputdev to do
        image caching when rendering
parent afd11ec6
2007-05-21 Carlos Garcia Campos <carlosgc@gnome.org>
* glib/poppler-page.cc:
* glib/poppler-page.h:
* glib/poppler-private.h:
* glib/poppler.h:
* glib/test-poppler-glib.c:
* poppler/CairoOutputDev.cc:
* poppler/CairoOutputDev.h: Extend CairoOutputdev to do
image caching when rendering
2007-05-21 Pino Toscano <pino@kde.org>
reviewed by: Albert Astals Cid <aacid@kde.org>
......
......@@ -73,7 +73,10 @@ poppler_page_finalize (GObject *object)
delete page->gfx;
if (page->text_dev != NULL)
delete page->text_dev;
#if defined (HAVE_CAIRO)
if (page->image_dev != NULL)
delete page->image_dev;
#endif
/* page->page is owned by the document */
}
......@@ -282,9 +285,9 @@ poppler_page_prepare_output_dev (PopplerPage *page,
}
static void
poppler_page_copy_to_pixbuf (PopplerPage *page,
GdkPixbuf *pixbuf,
OutputDevData *output_dev_data)
copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
unsigned char *data,
GdkPixbuf *pixbuf)
{
int cairo_width, cairo_height, cairo_rowstride;
unsigned char *pixbuf_data, *dst, *cairo_data;
......@@ -292,10 +295,10 @@ poppler_page_copy_to_pixbuf (PopplerPage *page,
unsigned int *src;
int x, y;
cairo_width = cairo_image_surface_get_width (output_dev_data->surface);
cairo_height = cairo_image_surface_get_height (output_dev_data->surface);
cairo_width = cairo_image_surface_get_width (surface);
cairo_height = cairo_image_surface_get_height (surface);
cairo_rowstride = cairo_width * 4;
cairo_data = output_dev_data->cairo_data;
cairo_data = data;
pixbuf_data = gdk_pixbuf_get_pixels (pixbuf);
pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
......@@ -320,7 +323,17 @@ poppler_page_copy_to_pixbuf (PopplerPage *page,
src++;
}
}
}
static void
poppler_page_copy_to_pixbuf (PopplerPage *page,
GdkPixbuf *pixbuf,
OutputDevData *output_dev_data)
{
copy_cairo_surface_to_pixbuf (output_dev_data->surface,
output_dev_data->cairo_data,
pixbuf);
page->document->output_dev->setCairo (NULL);
cairo_surface_destroy (output_dev_data->surface);
cairo_destroy (output_dev_data->cairo);
......@@ -468,7 +481,7 @@ poppler_page_render_to_pixbuf (PopplerPage *page,
src_width, src_height,
gFalse, /* printing */
page->document->doc->getCatalog ());
poppler_page_copy_to_pixbuf (page, pixbuf, &data);
}
......@@ -478,6 +491,8 @@ poppler_page_get_text_output_dev (PopplerPage *page)
if (page->text_dev == NULL) {
page->text_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
if (page->gfx)
delete page->gfx;
page->gfx = page->page->createGfx(page->text_dev,
72.0, 72.0, 0,
gFalse, /* useMediaBox */
......@@ -858,6 +873,136 @@ poppler_page_find_text (PopplerPage *page,
return g_list_reverse (matches);
}
#if defined (HAVE_CAIRO)
static CairoImageOutputDev *
poppler_page_get_image_output_dev (PopplerPage *page)
{
if (page->image_dev == NULL) {
page->image_dev = new CairoImageOutputDev ();
if (page->gfx)
delete page->gfx;
page->gfx = page->page->createGfx(page->image_dev,
72.0, 72.0, 0,
gFalse, /* useMediaBox */
gTrue, /* Crop */
-1, -1, -1, -1,
NULL, /* links */
page->document->doc->getCatalog (),
NULL, NULL, NULL, NULL);
page->page->display(page->gfx);
}
return page->image_dev;
}
static GdkPixbuf *
poppler_page_image_pixbuf_create (PopplerPage *page,
CairoImage *image)
{
GdkPixbuf *pixbuf;
cairo_surface_t *surface;
surface = image->getImage ();
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
FALSE, 8,
cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface));
copy_cairo_surface_to_pixbuf (surface,
cairo_image_surface_get_data (surface),
pixbuf);
return pixbuf;
}
/**
* poppler_page_get_image_mapping:
* @page: A #PopplerPage
*
* Returns a list of #PopplerImageMapping items that map from a
* location on @page to a #GdkPixbuf. This list must be freed
* with poppler_page_free_image_mapping() when done.
*
* Return value: A #GList of #PopplerImageMapping
**/
GList *
poppler_page_get_image_mapping (PopplerPage *page)
{
GList *map_list = NULL;
CairoImageOutputDev *out;
gint i;
g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
out = poppler_page_get_image_output_dev (page);
for (i = 0; i < out->getNumImages (); i++) {
PopplerImageMapping *mapping;
CairoImage *image;
image = out->getImage (i);
/* Create the mapping */
mapping = g_new (PopplerImageMapping, 1);
image->getRect (&(mapping->area.x1), &(mapping->area.y1),
&(mapping->area.x2), &(mapping->area.y2));
mapping->image = poppler_page_image_pixbuf_create (page, image);
mapping->area.x1 -= page->page->getCropBox()->x1;
mapping->area.x2 -= page->page->getCropBox()->x1;
mapping->area.y1 -= page->page->getCropBox()->y1;
mapping->area.y2 -= page->page->getCropBox()->y1;
map_list = g_list_prepend (map_list, mapping);
}
return map_list;
}
static void
poppler_images_mapping_free (PopplerImageMapping *mapping)
{
g_object_unref (mapping->image);
g_free (mapping);
}
/**
* poppler_page_free_image_mapping:
* @list: A list of #PopplerImageMapping<!-- -->s
*
* Frees a list of #PopplerImageMapping<!-- -->s allocated by
* poppler_page_get_image_mapping().
**/
void
poppler_page_free_image_mapping (GList *list)
{
if (list == NULL)
return;
g_list_foreach (list, (GFunc) (poppler_images_mapping_free), NULL);
g_list_free (list);
}
#else
GList *
poppler_page_get_image_mapping (PopplerPage *page)
{
return NULL;
}
void
poppler_page_free_image_mapping (GList *list)
{
}
#endif /* HAVE_CAIRO */
/**
* poppler_page_render_to_ps:
* @page: a #PopplerPage
......
......@@ -71,6 +71,8 @@ char *poppler_page_get_text (PopplerPage *pa
PopplerRectangle *rect);
GList *poppler_page_get_link_mapping (PopplerPage *page);
void poppler_page_free_link_mapping (GList *list);
GList *poppler_page_get_image_mapping (PopplerPage *page);
void poppler_page_free_image_mapping (GList *list);
GdkRegion *poppler_page_get_selection_region (PopplerPage *page,
gdouble scale,
PopplerRectangle *selection);
......@@ -137,6 +139,14 @@ PopplerPageTransition *poppler_page_transition_new (void);
PopplerPageTransition *poppler_page_transition_copy (PopplerPageTransition *transition);
void poppler_page_transition_free (PopplerPageTransition *transition);
/* Mapping between areas on the current page and images */
#define POPPLER_TYPE_IMAGE_MAPPING (poppler_image_mapping_get_type ())
struct _PopplerImageMapping
{
PopplerRectangle area;
GdkPixbuf *image;
};
/* FormField */
#define POPPLER_TYPE_FORM_FIELD (poppler_form_field_get_type ())
struct _PopplerTextField
......
......@@ -59,6 +59,9 @@ struct _PopplerPage
int index;
TextOutputDev *text_dev;
Gfx *gfx;
#if defined (HAVE_CAIRO)
CairoImageOutputDev *image_dev;
#endif
};
PopplerFormField *_form_field_new_from_widget (FormWidget* field);
......
......@@ -36,10 +36,10 @@ typedef enum
typedef enum
{
POPPLER_ORIENTATION_PORTRAIT,
POPPLER_ORIENTATION_LANDSCAPE,
POPPLER_ORIENTATION_UPSIDEDOWN,
POPPLER_ORIENTATION_SEASCAPE
POPPLER_ORIENTATION_PORTRAIT,
POPPLER_ORIENTATION_LANDSCAPE,
POPPLER_ORIENTATION_UPSIDEDOWN,
POPPLER_ORIENTATION_SEASCAPE
} PopplerOrientation;
typedef enum
......@@ -85,6 +85,7 @@ typedef struct _PopplerFontsIter PopplerFontsIter;
typedef struct _PopplerRectangle PopplerRectangle;
typedef struct _PopplerLinkMapping PopplerLinkMapping;
typedef struct _PopplerPageTransition PopplerPageTransition;
typedef struct _PopplerImageMapping PopplerImageMapping;
typedef struct _PopplerFormField PopplerFormField;
typedef struct _PopplerPage PopplerPage;
typedef struct _PopplerFontInfo PopplerFontInfo;
......
......@@ -174,6 +174,7 @@ int main (int argc, char *argv[])
char *text;
double duration;
PopplerRectangle area;
gint num_images;
if (argc != 3)
FAIL ("usage: test-poppler-glib file://FILE PAGE");
......@@ -236,8 +237,12 @@ int main (int argc, char *argv[])
gdk_pixbuf_save (pixbuf, "slice.png", "png", &error, NULL);
printf ("\tslice:\t\tsaved 200x200 slice at (100, 100) as slice.png\n");
if (error != NULL)
if (error != NULL) {
FAIL (error->message);
g_error_free (error);
}
g_object_unref (G_OBJECT (pixbuf));
area.x1 = 0;
area.y1 = 0;
......@@ -266,6 +271,26 @@ int main (int argc, char *argv[])
printf (" (%f,%f)-(%f,%f)\n", rect->x1, rect->y1, rect->x2, rect->y2);
}
list = poppler_page_get_image_mapping (page);
num_images = g_list_length (list);
printf ("\n");
if (num_images > 0)
printf ("\tFound %d images at positions:\n", num_images);
else
printf ("\tNo images found\n");
for (l = list; l != NULL; l = l->next)
{
PopplerImageMapping *mapping;
mapping = (PopplerImageMapping *)l->data;
printf ("\t\t(%f, %f) - (%f, %f)\n",
mapping->area.x1,
mapping->area.y1,
mapping->area.x2,
mapping->area.y2);
}
poppler_page_free_image_mapping (list);
if (poppler_document_has_attachments (document))
{
int i = 0;
......
......@@ -41,6 +41,23 @@
#define LOG(x)
#endif
//------------------------------------------------------------------------
// CairoImage
//------------------------------------------------------------------------
CairoImage::CairoImage (cairo_surface_t *image,
double x1, double y1, double x2, double y2) {
this->image = cairo_surface_reference (image);
this->x1 = x1;
this->y1 = y1;
this->x2 = x2;
this->y2 = y2;
}
CairoImage::~CairoImage () {
if (image)
cairo_surface_destroy (image);
}
//------------------------------------------------------------------------
// CairoOutputDev
......@@ -871,3 +888,201 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
free (buffer);
delete imgStr;
}
//------------------------------------------------------------------------
// ImageOutputDev
//------------------------------------------------------------------------
CairoImageOutputDev::CairoImageOutputDev()
{
images = NULL;
numImages = 0;
size = 0;
}
CairoImageOutputDev::~CairoImageOutputDev()
{
int i;
for (i = 0; i < numImages; i++)
delete images[i];
gfree (images);
}
void CairoImageOutputDev::saveImage(CairoImage *image)
{
if (numImages >= size) {
size += 16;
images = (CairoImage **) greallocn (images, size, sizeof (CairoImage *));
}
images[numImages++] = image;
}
void CairoImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
int width, int height, GBool invert,
GBool inlineImg)
{
cairo_t *cr;
cairo_surface_t *surface;
double x1, y1, x2, y2;
double *ctm;
double mat[6];
CairoImage *image;
ctm = state->getCTM();
mat[0] = ctm[0];
mat[1] = ctm[1];
mat[2] = -ctm[2];
mat[3] = -ctm[3];
mat[4] = ctm[2] + ctm[4];
mat[5] = ctm[3] + ctm[5];
x1 = mat[4];
y1 = mat[5];
x2 = x1 + width;
y2 = y1 + height;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create (surface);
setCairo (cr);
cairo_translate (cr, 0, height);
cairo_scale (cr, width, -height);
CairoOutputDev::drawImageMask(state, ref, str, width, height, invert, inlineImg);
image = new CairoImage (surface, x1, y1, x2, y2);
saveImage (image);
setCairo (NULL);
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
void CairoImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
int *maskColors, GBool inlineImg)
{
cairo_t *cr;
cairo_surface_t *surface;
double x1, y1, x2, y2;
double *ctm;
double mat[6];
CairoImage *image;
ctm = state->getCTM();
mat[0] = ctm[0];
mat[1] = ctm[1];
mat[2] = -ctm[2];
mat[3] = -ctm[3];
mat[4] = ctm[2] + ctm[4];
mat[5] = ctm[3] + ctm[5];
x1 = mat[4];
y1 = mat[5];
x2 = x1 + width;
y2 = y1 + height;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create (surface);
setCairo (cr);
cairo_translate (cr, 0, height);
cairo_scale (cr, width, -height);
CairoOutputDev::drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
image = new CairoImage (surface, x1, y1, x2, y2);
saveImage (image);
setCairo (NULL);
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
void CairoImageOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
int width, int height,
GfxImageColorMap *colorMap,
Stream *maskStr,
int maskWidth, int maskHeight,
GfxImageColorMap *maskColorMap)
{
cairo_t *cr;
cairo_surface_t *surface;
double x1, y1, x2, y2;
double *ctm;
double mat[6];
CairoImage *image;
ctm = state->getCTM();
mat[0] = ctm[0];
mat[1] = ctm[1];
mat[2] = -ctm[2];
mat[3] = -ctm[3];
mat[4] = ctm[2] + ctm[4];
mat[5] = ctm[3] + ctm[5];
x1 = mat[4];
y1 = mat[5];
x2 = x1 + width;
y2 = y1 + height;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create (surface);
setCairo (cr);
cairo_translate (cr, 0, height);
cairo_scale (cr, width, -height);
CairoOutputDev::drawSoftMaskedImage(state, ref, str, width, height, colorMap,
maskStr, maskWidth, maskHeight, maskColorMap);
image = new CairoImage (surface, x1, y1, x2, y2);
saveImage (image);
setCairo (NULL);
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
void CairoImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
int width, int height,
GfxImageColorMap *colorMap,
Stream *maskStr,
int maskWidth, int maskHeight,
GBool maskInvert)
{
cairo_t *cr;
cairo_surface_t *surface;
double x1, y1, x2, y2;
double *ctm;
double mat[6];
CairoImage *image;
ctm = state->getCTM();
mat[0] = ctm[0];
mat[1] = ctm[1];
mat[2] = -ctm[2];
mat[3] = -ctm[3];
mat[4] = ctm[2] + ctm[4];
mat[5] = ctm[3] + ctm[5];
x1 = mat[4];
y1 = mat[5];
x2 = x1 + width;
y2 = y1 + height;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create (surface);
setCairo (cr);
cairo_translate (cr, 0, height);
cairo_scale (cr, width, -height);
CairoOutputDev::drawMaskedImage(state, ref, str, width, height, colorMap,
maskStr, maskWidth, maskHeight, maskInvert);
image = new CairoImage (surface, x1, y1, x2, y2);
saveImage (image);
setCairo (NULL);
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
......@@ -28,6 +28,31 @@ class CairoFont;
//------------------------------------------------------------------------
//------------------------------------------------------------------------
// CairoImage
//------------------------------------------------------------------------
class CairoImage {
public:
// Constructor.
CairoImage (cairo_surface_t *image, double x1, double y1, double x2, double y2);
// Destructor.
~CairoImage ();
// Get the image cairo surface
cairo_surface_t *getImage () const { return image; }
// Get the image rectangle
void getRect (double *xa1, double *ya1, double *xa2, double *ya2)
{ *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; }
private:
cairo_surface_t *image; // image cairo surface
double x1, y1; // upper left corner
double x2, y2; // lower right corner
};
//------------------------------------------------------------------------
// CairoOutputDev
//------------------------------------------------------------------------
......@@ -168,4 +193,101 @@ protected:
cairo_path_t *textClipPath;
};
//------------------------------------------------------------------------
// CairoImageOutputDev
//------------------------------------------------------------------------
class CairoImageOutputDev: public CairoOutputDev {
public:
// Constructor.
CairoImageOutputDev();
// Destructor.
virtual ~CairoImageOutputDev();
//----- get info about output device
// Does this device use upside-down coordinates?
// (Upside-down means (0,0) is the top left corner of the page.)
virtual GBool upsideDown() { return gTrue; }
// Does this device use drawChar() or drawString()?
virtual GBool useDrawChar() { return gFalse; }
// Does this device use beginType3Char/endType3Char? Otherwise,
// text in Type 3 fonts will be drawn with drawChar/drawString.
virtual GBool interpretType3Chars() { return gFalse; }
// Does this device need non-text content?
virtual GBool needNonText() { return gTrue; }
//----- link borders
virtual void drawLink(Link *link, Catalog *catalog) { }
//----- save/restore graphics state
virtual void saveState(GfxState *state) { }
virtual void restoreState(GfxState *state) { }
//----- update graphics state
virtual void updateAll(GfxState *state) { }
virtual void setDefaultCTM(double *ctm) { }
virtual void updateCTM(GfxState *state, double m11, double m12,
double m21, double m22, double m31, double m32) { }
virtual void updateLineDash(GfxState *state) { }
virtual void updateFlatness(GfxState *state) { }
virtual void updateLineJoin(GfxState *state) { }
virtual void updateLineCap(GfxState *state) { }
virtual void updateMiterLimit(GfxState *state) { }
virtual void updateLineWidth(GfxState *state) { }
virtual void updateFillColor(GfxState *state) { }
virtual void updateStrokeColor(GfxState *state) { }
virtual void updateFillOpacity(GfxState *state) { }
virtual void updateStrokeOpacity(GfxState *state) { }
//----- update text state
virtual void updateFont(GfxState *state) { }
//----- path painting
virtual void stroke(GfxState *state) { }
virtual void fill(GfxState *state) { }
virtual void eoFill(GfxState *state) { }
//----- path clipping
virtual void clip(GfxState *state) { }
virtual void eoClip(GfxState *state) { }
//----- image drawing
virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
int width, int height, GBool invert,
GBool inlineImg);
virtual void drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
int *maskColors, GBool inlineImg);
virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
int width, int height,
GfxImageColorMap *colorMap,
Stream *maskStr,
int maskWidth, int maskHeight,
GfxImageColorMap *maskColorMap);
virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
int width, int height,
GfxImageColorMap *colorMap,
Stream *maskStr,
int maskWidth, int maskHeight,
GBool maskInvert);
//----- Image list
// Iterate through list of images.
int getNumImages() const { return numImages; }
CairoImage *getImage(int i) const { return images[i]; }
private:
void saveImage(CairoImage *image);
CairoImage **images;
int numImages;
int size;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment