diff options
Diffstat (limited to 'poppler/ArthurOutputDev.cc')
-rw-r--r-- | poppler/ArthurOutputDev.cc | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/poppler/ArthurOutputDev.cc b/poppler/ArthurOutputDev.cc new file mode 100644 index 00000000..7b804537 --- /dev/null +++ b/poppler/ArthurOutputDev.cc @@ -0,0 +1,604 @@ +//======================================================================== +// +// ArthurOutputDev.cc +// +// Copyright 2003 Glyph & Cog, LLC +// Copyright 2004 Red Hat, Inc +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include <math.h> + +#include "goo/gfile.h" +#include "GlobalParams.h" +#include "Error.h" +#include "Object.h" +#include "GfxState.h" +#include "GfxFont.h" +#include "Link.h" +#include "CharCodeToUnicode.h" +#include "FontEncodingTables.h" +#include <fofi/FoFiTrueType.h> +#include "ArthurOutputDev.h" + +#include <QtCore/QtDebug> +#include <QtGui/QPainterPath> +//------------------------------------------------------------------------ + +//------------------------------------------------------------------------ +// ArthurOutputDev +//------------------------------------------------------------------------ + +ArthurOutputDev::ArthurOutputDev(QPainter *painter): + m_painter(painter) +{ + m_currentBrush = QBrush(Qt::SolidPattern); +} + +ArthurOutputDev::~ArthurOutputDev() +{ +} + +void ArthurOutputDev::startDoc(XRef *xrefA) { +} + +void ArthurOutputDev::startPage(int pageNum, GfxState *state) +{ +} + +void ArthurOutputDev::endPage() { +} + +void ArthurOutputDev::drawLink(Link *link, Catalog *catalog) +{ +} + +void ArthurOutputDev::saveState(GfxState *state) +{ + m_painter->save(); +} + +void ArthurOutputDev::restoreState(GfxState *state) +{ + m_painter->restore(); +} + +void ArthurOutputDev::updateAll(GfxState *state) +{ + qDebug() << "updateAll"; +} + +void ArthurOutputDev::updateCTM(GfxState *state, double m11, double m12, + double m21, double m22, + double m31, double m32) +{ + qDebug() << "updateCTM"; +} + +void ArthurOutputDev::updateLineDash(GfxState *state) +{ + qDebug() << "updateLineDash"; +} + +void ArthurOutputDev::updateFlatness(GfxState *state) +{ + qDebug() << "updateFlatness"; +} + +void ArthurOutputDev::updateLineJoin(GfxState *state) +{ + switch (state->getLineJoin()) { + case 0: + m_currentPen.setJoinStyle(Qt::MiterJoin); + break; + case 1: + m_currentPen.setJoinStyle(Qt::RoundJoin); + break; + case 2: + m_currentPen.setJoinStyle(Qt::BevelJoin); + break; + } + m_painter->setPen(m_currentPen); +} + +void ArthurOutputDev::updateLineCap(GfxState *state) +{ + switch (state->getLineCap()) { + case 0: + m_currentPen.setCapStyle(Qt::FlatCap); + break; + case 1: + m_currentPen.setCapStyle(Qt::RoundCap); + break; + case 2: + m_currentPen.setCapStyle(Qt::SquareCap); + break; + } + m_painter->setPen(m_currentPen); +} + +void ArthurOutputDev::updateMiterLimit(GfxState *state) +{ +#if 0 + cairo_set_miter_limit (cairo, state->getMiterLimit()); +#endif +} + +void ArthurOutputDev::updateLineWidth(GfxState *state) +{ + m_currentPen.setWidthF(state->getTransformedLineWidth()); + m_painter->setPen(m_currentPen); +} + +void ArthurOutputDev::updateFillColor(GfxState *state) +{ + GfxRGB rgb; + QColor brushColour = m_currentBrush.color(); + state->getFillRGB(&rgb); + brushColour.setRgbF(rgb.r, rgb.g, rgb.b, brushColour.alphaF()); + m_currentBrush.setColor(brushColour); + m_painter->setBrush(m_currentBrush); +} + +void ArthurOutputDev::updateStrokeColor(GfxState *state) +{ + GfxRGB rgb; + QColor penColour = m_currentPen.color(); + state->getStrokeRGB(&rgb); + penColour.setRgbF(rgb.r, rgb.g, rgb.b, penColour.alphaF()); + m_currentPen.setColor(penColour); + m_painter->setPen(m_currentPen); +} + +void ArthurOutputDev::updateFillOpacity(GfxState *state) +{ + QColor brushColour= m_currentBrush.color(); + brushColour.setAlphaF(state->getFillOpacity()); + m_currentBrush.setColor(brushColour); + m_painter->setBrush(m_currentBrush); +} + +void ArthurOutputDev::updateStrokeOpacity(GfxState *state) +{ + QColor penColour= m_currentPen.color(); + penColour.setAlphaF(state->getStrokeOpacity()); + m_currentPen.setColor(penColour); + m_painter->setPen(m_currentPen); +} + +void ArthurOutputDev::updateFont(GfxState *state) +{ + // Something like + // currentFont.setPointSize( state->getFontSize() ); + // m_painter->setFont(currentFont); + // but with transformation matrices and such... + +#if 0 + cairo_font_face_t *font_face; + double m11, m12, m21, m22; + double w; + cairo_matrix_t matrix; + + 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); + + state->getFontTransMat(&m11, &m12, &m21, &m22); + m11 *= state->getHorizScaling(); + m12 *= state->getHorizScaling(); + + w = currentFont->getSubstitutionCorrection(state->getFont()); + m12 *= w; + m22 *= w; + + LOG(printf ("font matrix: %f %f %f %f\n", m11, m12, m21, m22)); + + font_face = currentFont->getFontFace(); + cairo_set_font_face (cairo, font_face); + + matrix.xx = m11; + matrix.xy = -m21; + matrix.yx = m12; + matrix.yy = -m22; + matrix.x0 = 0; + matrix.y0 = 0; + cairo_set_font_matrix (cairo, &matrix); +#endif +} + +static QPainterPath convertPath(GfxState *state, GfxPath *path) +{ + GfxSubpath *subpath; + double x1, y1, x2, y2, x3, y3; + int i, j; + + QPainterPath qPath; + for (i = 0; i < path->getNumSubpaths(); ++i) { + subpath = path->getSubpath(i); + if (subpath->getNumPoints() > 0) { + state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1); + qPath.moveTo(x1, y1); + j = 1; + while (j < subpath->getNumPoints()) { + if (subpath->getCurve(j)) { + state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1); + state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2); + state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3); + qPath.cubicTo( x1, y1, x2, y2, x3, y3); + j += 3; + } else { + state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1); + qPath.lineTo(x1, y1); + ++j; + } + } + if (subpath->isClosed()) { + qPath.closeSubpath(); + } + } + } + return qPath; +} + +void ArthurOutputDev::stroke(GfxState *state) +{ + m_painter->drawPath( convertPath( state, state->getPath() ) ); +} + +void ArthurOutputDev::fill(GfxState *state) +{ + m_painter->fillPath( convertPath( state, state->getPath() ), m_currentBrush ); +} + +void ArthurOutputDev::eoFill(GfxState *state) +{ +#if 0 + doPath (state, state->getPath(), gFalse); + cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD); + cairo_set_source_rgb (cairo, + fill_color.r, fill_color.g, fill_color.b); + LOG(printf ("fill-eo\n")); + cairo_fill (cairo); +#endif +} + +void ArthurOutputDev::clip(GfxState *state) +{ + qDebug() << "got clip"; + m_painter->setClipPath(convertPath( state, state->getPath() ) ); +} + +void ArthurOutputDev::eoClip(GfxState *state) +{ + qDebug() << "got eoClip"; +#if 0 + doPath (state, state->getPath(), gFalse); + cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD); + cairo_clip (cairo); + LOG (printf ("clip-eo\n")); +#endif +} + +void ArthurOutputDev::drawString(GfxState *state, GooString *s) +{ + GfxFont *font; + int wMode; + int render; + // the number of bytes in the string and not the number of glyphs? + int len = s->getLength(); + char *p = s->getCString(); + int count = 0; + double curX, curY; + double riseX, riseY; + + font = state->getFont(); + wMode = font->getWMode(); + + if (m_needFontUpdate) { + updateFont(state); + } + + // check for invisible text -- this is used by Acrobat Capture + render = state->getRender(); + if (render == 3) { + return; + } + + // ignore empty strings + if (len == 0) + return; + + state->textTransformDelta(0, state->getRise(), &riseX, &riseY); + curX = state->getCurX(); + curY = state->getCurY(); + while (len > 0) { + double x, y; + double x1, y1; + double dx, dy, tdx, tdy; + double originX, originY, tOriginX, tOriginY; + int n, uLen; + CharCode code; + Unicode u[8]; + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx, &dy, &originX, &originY); + if (wMode) { + dx *= state->getFontSize(); + dy = dy * state->getFontSize() + state->getCharSpace(); + if (n == 1 && *p == ' ') { + dy += state->getWordSpace(); + } + } else { + dx = dx * state->getFontSize() + state->getCharSpace(); + if (n == 1 && *p == ' ') { + dx += state->getWordSpace(); + } + dx *= state->getHorizScaling(); + dy *= state->getFontSize(); + } + originX *= state->getFontSize(); + originY *= state->getFontSize(); + state->textTransformDelta(dx, dy, &tdx, &tdy); + state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); + x = curX + riseX; + y = curY + riseY; + x -= tOriginX; + y -= tOriginY; + state->transform(x, y, &x1, &y1); + + //glyphs[count].index = currentFont->getGlyph (code, u, uLen); + m_painter->drawText(QPointF(x1,y1), QString(*p) ); + curX += tdx; + curY += tdy; + p += n; + len -= n; + count++; + } +#if 0 + // fill + if (!(render & 1)) { + LOG (printf ("fill string\n")); + cairo_set_source_rgb (cairo, + fill_color.r, fill_color.g, fill_color.b); + cairo_show_glyphs (cairo, glyphs, count); + } + + // stroke + if ((render & 3) == 1 || (render & 3) == 2) { + LOG (printf ("stroke string\n")); + cairo_set_source_rgb (cairo, + stroke_color.r, stroke_color.g, stroke_color.b); + cairo_glyph_path (cairo, glyphs, count); + cairo_stroke (cairo); + } + + // clip + if (render & 4) { + // FIXME: This is quite right yet, we need to accumulate all + // glyphs within one text object before we clip. Right now this + // just add this one string. + LOG (printf ("clip string\n")); + cairo_glyph_path (cairo, glyphs, count); + cairo_clip (cairo); + } +#endif +} + +GBool ArthurOutputDev::beginType3Char(GfxState *state, double x, double y, + double dx, double dy, + CharCode code, Unicode *u, int uLen) +{ + return gFalse; +} + +void ArthurOutputDev::endType3Char(GfxState *state) +{ +} + +void ArthurOutputDev::type3D0(GfxState *state, double wx, double wy) +{ +} + +void ArthurOutputDev::type3D1(GfxState *state, double wx, double wy, + double llx, double lly, double urx, double ury) +{ +} + +void ArthurOutputDev::endTextObject(GfxState *state) +{ +} + + +void ArthurOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg) +{ + qDebug() << "drawImageMask"; +#if 0 + unsigned char *buffer; + unsigned char *dest; + cairo_surface_t *image; + cairo_pattern_t *pattern; + int x, y; + ImageStream *imgStr; + Guchar *pix; + double *ctm; + cairo_matrix_t matrix; + int invert_bit; + int row_stride; + + row_stride = (width + 3) & ~3; + buffer = (unsigned char *) malloc (height * row_stride); + if (buffer == NULL) { + error(-1, "Unable to allocate memory for image."); + return; + } + + /* TODO: Do we want to cache these? */ + imgStr = new ImageStream(str, width, 1, 1); + imgStr->reset(); + + invert_bit = invert ? 1 : 0; + + for (y = 0; y < height; y++) { + pix = imgStr->getLine(); + dest = buffer + y * row_stride; + for (x = 0; x < width; x++) { + + if (pix[x] ^ invert_bit) + *dest++ = 0; + else + *dest++ = 255; + } + } + + image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_A8, + width, height, row_stride); + if (image == NULL) + return; + pattern = cairo_pattern_create_for_surface (image); + if (pattern == NULL) + return; + + ctm = state->getCTM(); + LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n", + width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5])); + matrix.xx = ctm[0] / width; + matrix.xy = -ctm[2] / height; + matrix.yx = ctm[1] / width; + matrix.yy = -ctm[3] / height; + matrix.x0 = ctm[2] + ctm[4]; + matrix.y0 = ctm[3] + ctm[5]; + cairo_matrix_invert (&matrix); + cairo_pattern_set_matrix (pattern, &matrix); + + cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST); + /* FIXME: Doesn't the image mask support any colorspace? */ + cairo_set_source_rgb (cairo, fill_color.r, fill_color.g, fill_color.b); + cairo_mask (cairo, pattern); + + cairo_pattern_destroy (pattern); + cairo_surface_destroy (image); + free (buffer); + delete imgStr; +#endif +} + +//TODO: lots more work here. +void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg) +{ + qDebug() << "drawImage"; + if (inlineImg == gTrue) { + qDebug() << "drawImage inline"; + } + unsigned char *buffer; + unsigned int *dest; + // cairo_surface_t *image; + // cairo_pattern_t *pattern; + int x, y; + ImageStream *imgStr; + Guchar *pix; + GfxRGB rgb; + int alpha, i; + double *ctm; + // cairo_matrix_t matrix; + QMatrix matrix; + int is_identity_transform; + + buffer = (unsigned char *)gmalloc (width * height * 4); + + /* TODO: Do we want to cache these? */ + imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); + + /* ICCBased color space doesn't do any color correction + * so check its underlying color space as well */ + is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB || + colorMap->getColorSpace()->getMode() == csICCBased && + ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB; + + if (maskColors) { + for (y = 0; y < height; y++) { + dest = (unsigned int *) (buffer + y * 4 * width); + pix = imgStr->getLine(); + colorMap->getRGBLine (pix, dest, width); + + for (x = 0; x < width; x++) { + for (i = 0; i < colorMap->getNumPixelComps(); ++i) { + + if (pix[i] < maskColors[2*i] * 255|| + pix[i] > maskColors[2*i+1] * 255) { + *dest = *dest | 0xff000000; + break; + } + } + pix += colorMap->getNumPixelComps(); + dest++; + } + } + + // image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_ARGB32, width, height, width * 4); + m_image = new QImage(buffer, width, height, QImage::Format_ARGB32); + } + else { + for (y = 0; y < height; y++) { + dest = (unsigned int *) (buffer + y * 4 * width); + pix = imgStr->getLine(); + colorMap->getRGBLine (pix, dest, width); + } + + // image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_RGB24, width, height, width * 4); + m_image = new QImage(buffer, width, height, QImage::Format_RGB32); + } + + if (m_image == NULL || m_image->isNull()) { + qDebug() << "Null image"; + return; + } +#if 0 + pattern = cairo_pattern_create_for_surface (image); + if (pattern == NULL) + return; + + ctm = state->getCTM(); + matrix.xx = ctm[0] / width; + matrix.xy = -ctm[2] / height; + matrix.yx = ctm[1] / width; + matrix.yy = -ctm[3] / height; + matrix.x0 = ctm[2] + ctm[4]; + matrix.y0 = ctm[3] + ctm[5]; + + cairo_matrix_invert (&matrix); + cairo_pattern_set_matrix (pattern, &matrix); + + cairo_pattern_set_filter (pattern, CAIRO_FILTER_BILINEAR); + cairo_set_source (cairo, pattern); + cairo_paint (cairo); + + cairo_pattern_destroy (pattern); + cairo_surface_destroy (image); +#endif + // TODO - figure out how to apply the matrix + + // verify image is correct. + m_image->save("m_image.png", "PNG"); + m_painter->drawImage( QPoint(0,0), *m_image ); + //free (buffer); + //delete imgStr; + +} |