Commit b15a8caf authored by Kristian Høgsberg's avatar Kristian Høgsberg

2005-06-29 Kristian Høgsberg <krh@redhat.com>

        * configure.ac:
        * glib/poppler-page.cc:
        * glib/poppler-page.h:
        * glib/poppler-private.h:
        * poppler/CairoOutputDev.cc:
        * poppler/CairoOutputDev.h:
        * poppler/Page.cc:
        * poppler/Page.h:
        * poppler/TextOutputDev.cc:
        * poppler/TextOutputDev.h: Add support for rendering real
        selection (based on text flow).
parent 3b5e2046
2005-06-28 Albert Astals Cid <aacid@kde.org>
2005-06-29 Kristian Høgsberg <krh@redhat.com>
* configure.ac:
* glib/poppler-page.cc:
* glib/poppler-page.h:
* glib/poppler-private.h:
* poppler/CairoOutputDev.cc:
* poppler/CairoOutputDev.h:
* poppler/Page.cc:
* poppler/Page.h:
* poppler/TextOutputDev.cc:
* poppler/TextOutputDev.h: Add support for rendering real
selection (based on text flow).
2005-06-28 Albert Astals Cid <aacid@kde.org>
* poppler/FontInfo.[cc,h]: Add FontInfo::getType()
2005-06-28 Albert Astals Cid <aacid@kde.org>
2005-06-28 Albert Astals Cid <aacid@kde.org>
* poppler/ArthurOutputDev.cc: use transformation matrix for image
rendering
......
......@@ -202,9 +202,9 @@ AC_ARG_ENABLE(poppler-glib,
enable_poppler_glib=$enableval,
enable_poppler_glib="try")
if test x$enable_poppler_glib = xyes; then
PKG_CHECK_MODULES(POPPLER_GLIB, gdk-pixbuf-2.0 glib-2.0 >= 2.4.0 fontconfig)
PKG_CHECK_MODULES(POPPLER_GLIB, gdk-2.0 >= 2.4.0 fontconfig)
elif test x$enable_poppler_glib = xtry; then
PKG_CHECK_MODULES(POPPLER_GLIB, gdk-pixbuf-2.0 glib-2.0 >= 2.4.0 fontconfig,
PKG_CHECK_MODULES(POPPLER_GLIB, gdk-2.0 >= 2.4.0 fontconfig,
[enable_poppler_glib="yes"],
[enable_poppler_glib="no"])
fi
......
......@@ -88,6 +88,13 @@ _poppler_page_new (PopplerDocument *document, Page *page, int index)
static void
poppler_page_finalize (GObject *object)
{
PopplerPage *page = POPPLER_PAGE (object);
if (page->gfx != NULL)
delete page->gfx;
if (page->text_dev != NULL)
delete page->text_dev;
/* page->page is owned by the document */
}
......@@ -157,82 +164,100 @@ poppler_page_get_index (PopplerPage *page)
#if defined (HAVE_CAIRO)
typedef struct {
unsigned char *cairo_data;
cairo_surface_t *surface;
} OutputDevData;
static void
cairo_render_to_pixbuf (PopplerPage *page,
int src_x, int src_y,
int src_width, int src_height,
double scale,
GdkPixbuf *pixbuf,
int dest_x, int dest_y)
poppler_page_prepare_output_dev (PopplerPage *page,
double scale,
gboolean transparent,
OutputDevData *output_dev_data)
{
CairoOutputDev *output_dev;
int cairo_width, cairo_height, cairo_rowstride;
int pixbuf_rowstride, pixbuf_n_channels;
guchar *pixbuf_data, *cairo_data, *dst;
cairo_surface_t *surface;
int x, y;
int cairo_width, cairo_height, cairo_rowstride;
unsigned char *cairo_data;
output_dev = page->document->output_dev;
cairo_width = MAX ((int)(page->page->getWidth() * scale + 0.5), 1);
cairo_height = MAX ((int)(page->page->getHeight() * scale + 0.5), 1);
cairo_rowstride = cairo_width * 4;
cairo_data = (guchar *) gmalloc (cairo_height * cairo_rowstride);
memset (cairo_data, 0xff, cairo_height * cairo_rowstride);
if (transparent)
memset (cairo_data, 0x00, cairo_height * cairo_rowstride);
else
memset (cairo_data, 0xff, cairo_height * cairo_rowstride);
surface = cairo_image_surface_create_for_data(cairo_data,
CAIRO_FORMAT_ARGB32,
cairo_width, cairo_height,
cairo_rowstride);
output_dev_data->cairo_data = cairo_data;
output_dev_data->surface = surface;
output_dev->setSurface (surface);
}
page->page->displaySlice(output_dev, 72.0 * scale, 72.0 * scale,
poppler_page_get_rotate (page),
gTrue, /* Crop */
src_x, src_y,
src_width, src_height,
NULL, /* links */
page->document->doc->getCatalog ());
void
poppler_page_copy_to_pixbuf (PopplerPage *page,
GdkPixbuf *pixbuf,
OutputDevData *output_dev_data)
{
int cairo_width, cairo_height, cairo_rowstride;
unsigned char *pixbuf_data, *dst, *cairo_data;
int pixbuf_rowstride, pixbuf_n_channels;
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_rowstride = cairo_width * 4;
cairo_data = output_dev_data->cairo_data;
pixbuf_data = gdk_pixbuf_get_pixels (pixbuf);
pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf);
if (dest_x + cairo_width > gdk_pixbuf_get_width (pixbuf))
cairo_width = gdk_pixbuf_get_width (pixbuf) - dest_x;
if (dest_y + cairo_height > gdk_pixbuf_get_height (pixbuf))
cairo_height = gdk_pixbuf_get_height (pixbuf) - dest_y;
for (y = 0; y < cairo_height; y++)
{
unsigned int *src;
src = (unsigned int *) (cairo_data + y * cairo_rowstride);
dst = pixbuf_data + (dest_y + y) * pixbuf_rowstride +
dest_x * pixbuf_n_channels;
dst = pixbuf_data + y * pixbuf_rowstride;
for (x = 0; x < cairo_width; x++)
{
dst[0] = (*src >> 16) & 0xff;
dst[1] = (*src >> 8) & 0xff;
dst[2] = (*src >> 0) & 0xff;
if (pixbuf_n_channels == 4)
dst[3] = (*src >> 24) & 0xff;
dst += pixbuf_n_channels;
src++;
}
}
output_dev->setSurface (NULL);
cairo_surface_destroy (surface);
gfree (cairo_data);
page->document->output_dev->setSurface (NULL);
cairo_surface_destroy (output_dev_data->surface);
gfree (output_dev_data->cairo_data);
}
#elif defined (HAVE_SPLASH)
typedef struct {
} OutputDevData;
static void
splash_render_to_pixbuf (PopplerPage *page,
int src_x, int src_y,
int src_width, int src_height,
double scale,
GdkPixbuf *pixbuf,
int dest_x, int dest_y)
poppler_page_prepare_output_dev (PopplerPage *page,
double scale,
gboolean transparent,
OutputDevData *output_dev_data)
{
/* pft */
}
poppler_page_copy_to_pixbuf(PopplerPage *page,
GdkPixbuf *pixbuf,
OutputDevData *data)
{
SplashOutputDev *output_dev;
SplashBitmap *bitmap;
......@@ -244,14 +269,6 @@ splash_render_to_pixbuf (PopplerPage *page,
output_dev = page->document->output_dev;
page->page->displaySlice(output_dev, 72.0 * scale, 72.0 * scale,
poppler_page_get_rotate (page),
gTrue, /* Crop */
src_x, src_y,
src_width, src_height,
NULL, /* links */
page->document->doc->getCatalog ());
bitmap = output_dev->getBitmap ();
color_ptr = bitmap->getDataPtr ();
......@@ -314,22 +331,121 @@ poppler_page_render_to_pixbuf (PopplerPage *page,
GdkPixbuf *pixbuf,
int dest_x, int dest_y)
{
OutputDevData data;
g_return_if_fail (POPPLER_IS_PAGE (page));
g_return_if_fail (scale > 0.0);
g_return_if_fail (pixbuf != NULL);
#if defined(HAVE_CAIRO)
cairo_render_to_pixbuf (page, src_x, src_y, src_width, src_height,
scale, pixbuf, dest_x, dest_y);
#elif defined(HAVE_SPLASH)
splash_render_to_pixbuf (page, src_x, src_y, src_width, src_height,
scale, pixbuf, dest_x, dest_y);
#else
#error No rendering backend available
#endif
poppler_page_prepare_output_dev (page, scale, FALSE, &data);
page->page->displaySlice(page->document->output_dev,
72.0 * scale, 72.0 * scale,
poppler_page_get_rotate (page),
gTrue, /* Crop */
src_x, src_y,
src_width, src_height,
NULL, /* links */
page->document->doc->getCatalog ());
poppler_page_copy_to_pixbuf (page, pixbuf, &data);
}
static TextOutputDev *
poppler_page_get_text_output_dev (PopplerPage *page)
{
if (page->text_dev == NULL) {
page->text_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
page->gfx = page->page->createGfx(page->text_dev,
72.0, 72.0,
poppler_page_get_rotate (page),
gTrue, /* Crop */
-1, -1, -1, -1,
NULL, /* links */
page->document->doc->getCatalog (),
NULL, NULL, NULL, NULL);
page->page->display(page->gfx);
page->text_dev->endPage();
}
return page->text_dev;
}
GdkRegion *
poppler_page_get_selection_region (PopplerPage *page,
gdouble scale,
PopplerRectangle *selection)
{
TextOutputDev *text_dev;
PDFRectangle poppler_selection;
GooList *list;
GdkRectangle rect;
GdkRegion *region;
int i;
poppler_selection.x1 = selection->x1;
poppler_selection.y1 = selection->y1;
poppler_selection.x2 = selection->x2;
poppler_selection.y2 = selection->y2;
text_dev = poppler_page_get_text_output_dev (page);
list = text_dev->getSelectionRegion(&poppler_selection, scale);
region = gdk_region_new();
for (i = 0; i < list->getLength(); i++) {
PDFRectangle *selection_rect = (PDFRectangle *) list->get(i);
rect.x = (gint) selection_rect->x1;
rect.y = (gint) selection_rect->y1;
rect.width = (gint) (selection_rect->x2 - selection_rect->x1);
rect.height = (gint) (selection_rect->y2 - selection_rect->y1);
gdk_region_union_with_rect (region, &rect);
delete selection_rect;
}
delete list;
return region;
}
void
poppler_page_render_selection (PopplerPage *page,
gdouble scale,
GdkPixbuf *pixbuf,
PopplerRectangle *selection,
PopplerRectangle *old_selection)
{
TextOutputDev *text_dev;
CairoOutputDev *output_dev;
cairo_surface_t *surface;
unsigned char *cairo_data;
OutputDevData data;
PDFRectangle pdf_selection(selection->x1, selection->y1,
selection->x2, selection->y2);
text_dev = poppler_page_get_text_output_dev (page);
output_dev = page->document->output_dev;
poppler_page_prepare_output_dev (page, scale, TRUE, &data);
text_dev->drawSelection (output_dev, scale, &pdf_selection);
poppler_page_copy_to_pixbuf (page, pixbuf, &data);
/* We'll need a function to destroy page->text_dev and page->gfx
* when the application wants to get rid of them.
*
* Two improvements: 1) make GfxFont refcounted and let TextPage and
* friends hold a reference to the GfxFonts they need so we can free
* up Gfx early. 2) use a TextPage directly when rendering the page
* so we don't have to use TextOutputDev and render a second
* time. */
}
static void
destroy_thumb_data (guchar *pixels, gpointer data)
{
......
......@@ -20,6 +20,7 @@
#define __POPPLER_PAGE_H__
#include <glib-object.h>
#include <gdk/gdkregion.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "poppler.h"
......@@ -33,34 +34,42 @@ G_BEGIN_DECLS
GType poppler_page_get_type (void) G_GNUC_CONST;
void poppler_page_render_to_pixbuf (PopplerPage *page,
int src_x,
int src_y,
int src_width,
int src_height,
double scale,
GdkPixbuf *pixbuf,
int dest_x,
int dest_y);
void poppler_page_get_size (PopplerPage *page,
double *width,
double *height);
PopplerOrientation poppler_page_get_orientation (PopplerPage *page);
void poppler_page_set_orientation (PopplerPage *page,
PopplerOrientation orientation);
int poppler_page_get_index (PopplerPage *page);
GdkPixbuf *poppler_page_get_thumbnail (PopplerPage *page);
gboolean poppler_page_get_thumbnail_size (PopplerPage *page,
int *width,
int *height);
GList *poppler_page_find_text (PopplerPage *page,
const char *text);
void poppler_page_render_to_ps (PopplerPage *page,
PopplerPSFile *ps_file);
char *poppler_page_get_text (PopplerPage *page,
PopplerRectangle *rect);
GList *poppler_page_get_link_mapping (PopplerPage *page);
void poppler_page_free_link_mapping (GList *list);
void poppler_page_render_to_pixbuf (PopplerPage *page,
int src_x,
int src_y,
int src_width,
int src_height,
double scale,
GdkPixbuf *pixbuf,
int dest_x,
int dest_y);
void poppler_page_get_size (PopplerPage *page,
double *width,
double *height);
PopplerOrientation poppler_page_get_orientation (PopplerPage *page);
void poppler_page_set_orientation (PopplerPage *page,
PopplerOrientation orientation);
int poppler_page_get_index (PopplerPage *page);
GdkPixbuf *poppler_page_get_thumbnail (PopplerPage *page);
gboolean poppler_page_get_thumbnail_size (PopplerPage *page,
int *width,
int *height);
GList *poppler_page_find_text (PopplerPage *page,
const char *text);
void poppler_page_render_to_ps (PopplerPage *page,
PopplerPSFile *ps_file);
char *poppler_page_get_text (PopplerPage *page,
PopplerRectangle *rect);
GList *poppler_page_get_link_mapping (PopplerPage *page);
void poppler_page_free_link_mapping (GList *list);
GdkRegion * poppler_page_get_selection_region (PopplerPage *page,
gdouble scale,
PopplerRectangle *selection);
void poppler_page_render_selection (PopplerPage *page,
gdouble scale,
GdkPixbuf *pixbuf,
PopplerRectangle *selection,
PopplerRectangle *old_selection);
/* A rectangle on a page, with coordinates in PDF points. */
......
......@@ -5,6 +5,7 @@
#include <PDFDoc.h>
#include <PSOutputDev.h>
#include <Link.h>
#include <Gfx.h>
#include <FontInfo.h>
#if defined (HAVE_CAIRO)
......@@ -44,6 +45,8 @@ struct _PopplerPage
Page *page;
int index;
PopplerOrientation orientation;
TextOutputDev *text_dev;
Gfx *gfx;
};
PopplerPage *_poppler_page_new (PopplerDocument *document,
......
......@@ -53,6 +53,7 @@ CairoOutputDev::CairoOutputDev() {
FT_Init_FreeType(&ft_lib);
fontEngine = NULL;
glyphs = NULL;
surface = NULL;
}
......@@ -219,7 +220,6 @@ void CairoOutputDev::updateFont(GfxState *state) {
LOG(printf ("updateFont() font=%s\n", state->getFont()->getName()->getCString()));
/* Needs to be rethough, since fonts are now handled by cairo */
needFontUpdate = gFalse;
currentFont = fontEngine->getFont (state->getFont(), xref);
......@@ -342,6 +342,9 @@ void CairoOutputDev::beginString(GfxState *state, GooString *s)
{
int len = s->getLength();
if (needFontUpdate)
updateFont(state);
glyphs = (cairo_glyph_t *) gmalloc (len * sizeof (cairo_glyph_t));
glyphCount = 0;
}
......@@ -364,8 +367,6 @@ void CairoOutputDev::endString(GfxState *state)
{
int render;
if (needFontUpdate)
updateFont(state);
if (!currentFont)
return;
......@@ -375,8 +376,11 @@ void CairoOutputDev::endString(GfxState *state)
return;
// ignore empty strings
if (glyphCount == 0)
if (glyphCount == 0) {
gfree(glyphs);
glyphs = NULL;
return;
}
if (!(render & 1)) {
LOG (printf ("fill string\n"));
......@@ -405,6 +409,7 @@ void CairoOutputDev::endString(GfxState *state)
}
gfree (glyphs);
glyphs = NULL;
}
GBool CairoOutputDev::beginType3Char(GfxState *state, double x, double y,
......
......@@ -146,7 +146,7 @@ protected:
FT_Library ft_lib;
CairoFontEngine *fontEngine;
cairo_t *cairo;
GBool needFontUpdate; // set when the font needs to be updated
GBool needFontUpdate; // set when the font needs to be updated
cairo_surface_t *surface;
cairo_glyph_t *glyphs;
int glyphCount;
......
......@@ -25,6 +25,7 @@
#include "Gfx.h"
#include "GfxState.h"
#include "Annot.h"
#include "TextOutputDev.h"
#endif
#include "Error.h"
#include "Page.h"
......@@ -250,23 +251,18 @@ void Page::display(OutputDev *out, double hDPI, double vDPI,
annotDisplayDecideCbk, annotDisplayDecideCbkData);
}
void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
int rotate, GBool crop,
int sliceX, int sliceY, int sliceW, int sliceH,
Links *links, Catalog *catalog,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData,
GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
void *annotDisplayDecideCbkData) {
#ifndef PDF_PARSER_ONLY
Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
int rotate, GBool crop,
int sliceX, int sliceY, int sliceW, int sliceH,
Links *links, Catalog *catalog,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData,
GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
void *annotDisplayDecideCbkData) {
PDFRectangle *mediaBox, *cropBox;
PDFRectangle box;
Gfx *gfx;
Object obj;
Link *link;
Annots *annotList;
double kx, ky;
int i;
rotate += getRotate();
if (rotate >= 360) {
......@@ -338,6 +334,30 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
gfx = new Gfx(xref, out, num, attrs->getResourceDict(),
hDPI, vDPI, &box, crop && isCropped(), cropBox, rotate,
abortCheckCbk, abortCheckCbkData);
return gfx;
}
void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
int rotate, GBool crop,
int sliceX, int sliceY, int sliceW, int sliceH,
Links *links, Catalog *catalog,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData,
GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
void *annotDisplayDecideCbkData) {
Gfx *gfx;
Object obj;
Link *link;
Annots *annotList;
int i;
gfx = createGfx(out, hDPI, vDPI, rotate, crop,
sliceX, sliceY, sliceW, sliceH,
links, catalog,
abortCheckCbk, abortCheckCbkData,
annotDisplayDecideCbk, annotDisplayDecideCbkData);
contents.fetch(xref, &obj);
if (!obj.isNull()) {
gfx->saveState();
......@@ -378,7 +398,18 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
delete annotList;
delete gfx;
#endif
}
void Page::display(Gfx *gfx) {
Object obj;
contents.fetch(xref, &obj);
if (!obj.isNull()) {
gfx->saveState();
gfx->display(&obj);
gfx->restoreState();
}
obj.free();
}
GBool Page::loadThumb(unsigned char **data_out,
......
......@@ -22,6 +22,7 @@ class Links;
class Catalog;
class Annots;
class Annot;
class Gfx;
//------------------------------------------------------------------------
......@@ -147,6 +148,15 @@ public:
// Get transition.
Object *getTrans(Object *obj) { return trans.fetch(xref, obj); }
Gfx *createGfx(OutputDev *out, double hDPI, double vDPI,
int rotate, GBool crop,
int sliceX, int sliceY, int sliceW, int sliceH,
Links *links, Catalog *catalog,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData,
GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
void *annotDisplayDecideCbkData);
// Display a page.
void display(OutputDev *out, double hDPI, double vDPI,
int rotate, GBool crop,
......@@ -166,6 +176,8 @@ public:
GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
void *annotDisplayDecideCbkData = NULL);
void display(Gfx *gfx);
private:
XRef *xref; // the xref table for this PDF file
......
This diff is collapsed.
......@@ -21,12 +21,14 @@
class GooString;
class GooList;
class Gfx;
class GfxFont;
class GfxState;
class UnicodeMap;
class TextBlock;
class TextPage;
class TextLineFrag;
class TextSelectionVisitor;
//------------------------------------------------------------------------
......@@ -53,6 +55,7 @@ private:
friend class TextWord;
friend class TextPage;
friend class TextSelectionPainter;
};
//------------------------------------------------------------------------
......@@ -71,7 +74,7 @@ public:
// Add a character to the word.
void addChar(GfxState *state, double x, double y,
double dx, double dy, Unicode u);
double dx, double dy, CharCode c, Unicode u);
// Merge <word> onto the end of <this>.
void merge(TextWord *word);
......@@ -86,6 +89,9 @@ public:
static int cmpYX(const void *p1, const void *p2);
void visitSelection(TextSelectionVisitor *visitor,
PDFRectangle *selection);
#if TEXTOUT_WORD_LIST
int getLength() { return len; }
Unicode getChar(int idx) { return text[idx]; }
......@@ -107,6 +113,7 @@ private:
double yMin, yMax; // bounding box y coordinates
double base; // baseline x or y coordinate
Unicode *text; // the text
CharCode *charcode; // glyph indices
double *edge; // "near" edge x or y coord of each char
// (plus one extra entry for the last char)
int len; // length of text and edge arrays
......@@ -132,6 +139,7 @@ private:
friend class TextFlow;
friend class TextWordList;
friend class TextPage;
friend class TextSelectionPainter;
};
//------------------------------------------------------------------------
......@@ -164,6 +172,8 @@ private:
friend class TextPage;
};
struct TextFlowData;
//------------------------------------------------------------------------
// TextLine
//------------------------------------------------------------------------
......@@ -195,6 +205,9 @@ public:
void coalesce(UnicodeMap *uMap);
void visitSelection(TextSelectionVisitor *visitor,
PDFRectangle *selection);
private:
TextBlock *blk; // parent block
......@@ -219,6 +232,9 @@ private:
friend class TextFlow;
friend class TextWordList;
friend class TextPage;
friend class TextSelectionPainter;
friend class TextSelectionSizer;
};
//------------------------------------------------------------------------
......@@ -250,6 +266,9 @@ public:
// primary rotation.
GBool isBelow(TextBlock *blk);
void visitSelection(TextSelectionVisitor *visitor,
PDFRectangle *selection);
private:
TextPage *page; // the parent page
......@@ -275,6 +294,7 @@ private:
friend class TextFlow;
friend class TextWordList;
friend class TextPage;
friend class TextSelectionPainter;
};
//------------------------------------------------------------------------
......@@ -394,7 +414,16 @@ public:
// Get the text which is inside the specified rectangle.
GooString *getText(double xMin, double yMin,
double xMax, double yMax);
double xMax, double yMax);
void visitSelection(TextSelectionVisitor *visitor,
PDFRectangle *selection);
void drawSelection(OutputDev *out,
double scale,
PDFRectangle *selection);
GooList *getSelectionRegion(PDFRectangle *selection, double scale);
// Find a string by character position and length. If found, sets
// the text bounding rectangle and returns true; otherwise returns
......@@ -457,6 +486,7 @@ private:
friend class TextBlock;
friend class TextFlow;
friend class TextWordList;
friend class TextSelectionPainter;
};
//------------------------------------------------------------------------
......@@ -548,6 +578,10 @@ public:
double *xMin, double *yMin,
double *xMax, double *yMax);