source: trunk/poppler/mypoppler/poppler/CairoOutputDev.cc @ 44

Last change on this file since 44 was 44, checked in by Eugene Romanenko, 16 years ago

poppler updated to version 0.5.3, related changes

File size: 23.4 KB
Line 
1//========================================================================
2//
3// CairoOutputDev.cc
4//
5// Copyright 2003 Glyph & Cog, LLC
6// Copyright 2004 Red Hat, Inc
7//
8//========================================================================
9
10#include <config.h>
11
12#ifdef USE_GCC_PRAGMAS
13#pragma implementation
14#endif
15
16#include <string.h>
17#include <math.h>
18#include <cairo.h>
19
20#include "goo/gfile.h"
21#include "GlobalParams.h"
22#include "Error.h"
23#include "Object.h"
24#include "GfxState.h"
25#include "GfxFont.h"
26#include "Link.h"
27#include "CharCodeToUnicode.h"
28#include "FontEncodingTables.h"
29#include <fofi/FoFiTrueType.h>
30#include <splash/SplashBitmap.h>
31#include "CairoOutputDev.h"
32#include "CairoFontEngine.h"
33
34//------------------------------------------------------------------------
35
36// #define LOG_CAIRO
37
38#ifdef LOG_CAIRO
39#define LOG(x) (x)
40#else
41#define LOG(x)
42#endif
43
44
45//------------------------------------------------------------------------
46// CairoOutputDev
47//------------------------------------------------------------------------
48
49CairoOutputDev::CairoOutputDev() {
50  xref = NULL;
51
52  FT_Init_FreeType(&ft_lib);
53  fontEngine = NULL;
54  glyphs = NULL;
55  fill_pattern = NULL;
56  stroke_pattern = NULL;
57  stroke_opacity = 1.0;
58  fill_opacity = 1.0;
59  textClipPath = NULL;
60  cairo = NULL;
61}
62
63CairoOutputDev::~CairoOutputDev() {
64  if (fontEngine) {
65    delete fontEngine;
66  }
67  FT_Done_FreeType(ft_lib);
68 
69  if (cairo)
70    cairo_destroy (cairo);
71  cairo_pattern_destroy (stroke_pattern);
72  cairo_pattern_destroy (fill_pattern);
73}
74
75void CairoOutputDev::setCairo(cairo_t *cairo)
76{
77  if (this->cairo != NULL)
78    cairo_destroy (this->cairo);
79  if (cairo != NULL)
80    this->cairo = cairo_reference (cairo);
81  else
82    this->cairo = NULL;
83}
84
85void CairoOutputDev::startDoc(XRef *xrefA) {
86  xref = xrefA;
87  if (fontEngine) {
88    delete fontEngine;
89  }
90  fontEngine = new CairoFontEngine(ft_lib);
91}
92
93void CairoOutputDev::drawLink(Link *link, Catalog *catalog) {
94}
95
96void CairoOutputDev::saveState(GfxState *state) {
97  LOG(printf ("save\n"));
98  cairo_save (cairo);
99}
100
101void CairoOutputDev::restoreState(GfxState *state) {
102  LOG(printf ("restore\n"));
103  cairo_restore (cairo);
104
105  /* These aren't restored by cairo_restore() since we keep them in
106   * the output device. */
107  updateFillColor(state);
108  updateStrokeColor(state);
109  updateFillOpacity(state);
110  updateStrokeOpacity(state);
111}
112
113void CairoOutputDev::updateAll(GfxState *state) {
114  updateLineDash(state);
115  updateLineJoin(state);
116  updateLineCap(state);
117  updateLineWidth(state);
118  updateFlatness(state);
119  updateMiterLimit(state);
120  updateFillColor(state);
121  updateStrokeColor(state);
122  updateFillOpacity(state);
123  updateStrokeOpacity(state);
124  needFontUpdate = gTrue;
125}
126
127void CairoOutputDev::updateCTM(GfxState *state, double m11, double m12,
128                                double m21, double m22,
129                                double m31, double m32) {
130  updateLineDash(state);
131  updateLineJoin(state);
132  updateLineCap(state);
133  updateLineWidth(state);
134}
135
136void CairoOutputDev::updateLineDash(GfxState *state) {
137  double *dashPattern;
138  int dashLength;
139  double dashStart;
140  double *transformedDash;
141  double transformedStart;
142  int i;
143
144  state->getLineDash(&dashPattern, &dashLength, &dashStart);
145
146  transformedDash = new double[dashLength];
147 
148  for (i = 0; i < dashLength; ++i) {
149    transformedDash[i] =  state->transformWidth(dashPattern[i]);
150  }
151  transformedStart = state->transformWidth(dashStart);
152  cairo_set_dash (cairo, transformedDash, dashLength, transformedStart);
153  delete [] transformedDash;
154}
155
156void CairoOutputDev::updateFlatness(GfxState *state) {
157  // cairo_set_tolerance (cairo, state->getFlatness());
158}
159
160void CairoOutputDev::updateLineJoin(GfxState *state) {
161  switch (state->getLineJoin()) {
162  case 0:
163    cairo_set_line_join (cairo, CAIRO_LINE_JOIN_MITER);
164    break;
165  case 1:
166    cairo_set_line_join (cairo, CAIRO_LINE_JOIN_ROUND);
167    break;
168  case 2:
169    cairo_set_line_join (cairo, CAIRO_LINE_JOIN_BEVEL);
170    break;
171  }
172}
173
174void CairoOutputDev::updateLineCap(GfxState *state) {
175  switch (state->getLineCap()) {
176  case 0:
177    cairo_set_line_cap (cairo, CAIRO_LINE_CAP_BUTT);
178    break;
179  case 1:
180    cairo_set_line_cap (cairo, CAIRO_LINE_CAP_ROUND);
181    break;
182  case 2:
183    cairo_set_line_cap (cairo, CAIRO_LINE_CAP_SQUARE);
184    break;
185  }
186}
187
188void CairoOutputDev::updateMiterLimit(GfxState *state) {
189  cairo_set_miter_limit (cairo, state->getMiterLimit());
190}
191
192void CairoOutputDev::updateLineWidth(GfxState *state) {
193  LOG(printf ("line width: %f\n", state->getTransformedLineWidth()));
194  if (state->getTransformedLineWidth() == 0.0) {
195      cairo_set_line_width (cairo, 72.0/300.0);
196  } else {
197      cairo_set_line_width (cairo, state->getTransformedLineWidth());
198  }
199}
200
201void CairoOutputDev::updateFillColor(GfxState *state) {
202  state->getFillRGB(&fill_color);
203
204  cairo_pattern_destroy(fill_pattern);
205  fill_pattern = cairo_pattern_create_rgba(fill_color.r / 65535.0,
206                                           fill_color.g / 65535.0,
207                                           fill_color.b / 65535.0,
208                                           fill_opacity);
209
210  LOG(printf ("fill color: %d %d %d\n",
211              fill_color.r, fill_color.g, fill_color.b));
212}
213
214void CairoOutputDev::updateStrokeColor(GfxState *state) {
215  state->getStrokeRGB(&stroke_color);
216
217  cairo_pattern_destroy(stroke_pattern);
218  stroke_pattern = cairo_pattern_create_rgba(stroke_color.r / 65535.0,
219                                             stroke_color.g / 65535.0,
220                                             stroke_color.b / 65535.0,
221                                             stroke_opacity);
222 
223  LOG(printf ("stroke color: %d %d %d\n",
224              stroke_color.r, stroke_color.g, stroke_color.b));
225}
226
227void CairoOutputDev::updateFillOpacity(GfxState *state) {
228  fill_opacity = state->getFillOpacity();
229
230  cairo_pattern_destroy(fill_pattern);
231  fill_pattern = cairo_pattern_create_rgba(fill_color.r / 65535.0,
232                                           fill_color.g / 65535.0,
233                                           fill_color.b / 65535.0,
234                                           fill_opacity);
235
236  LOG(printf ("fill opacity: %f\n", fill_opacity));
237}
238
239void CairoOutputDev::updateStrokeOpacity(GfxState *state) {
240  stroke_opacity = state->getStrokeOpacity();
241
242  cairo_pattern_destroy(stroke_pattern);
243  stroke_pattern = cairo_pattern_create_rgba(stroke_color.r / 65535.0,
244                                             stroke_color.g / 65535.0,
245                                             stroke_color.b / 65535.0,
246                                             stroke_opacity);
247 
248  LOG(printf ("stroke opacity: %f\n", stroke_opacity));
249}
250
251void CairoOutputDev::updateFont(GfxState *state) {
252  cairo_font_face_t *font_face;
253  double m11, m12, m21, m22;
254  double w;
255  cairo_matrix_t matrix;
256
257  LOG(printf ("updateFont() font=%s\n", state->getFont()->getName()->getCString()));
258
259  needFontUpdate = gFalse;
260
261  if (state->getFont()->getType() == fontType3) 
262    return;
263
264  currentFont = fontEngine->getFont (state->getFont(), xref);
265
266  if (!currentFont)
267    return;
268  state->getFontTransMat(&m11, &m12, &m21, &m22);
269  m11 *= state->getHorizScaling();
270  m12 *= state->getHorizScaling();
271
272  LOG(printf ("font matrix: %f %f %f %f\n", m11, m12, m21, m22));
273 
274  font_face = currentFont->getFontFace();
275  cairo_set_font_face (cairo, font_face);
276
277  matrix.xx = m11;
278  matrix.xy = -m21;
279  matrix.yx = m12;
280  matrix.yy = -m22;
281  matrix.x0 = 0;
282  matrix.y0 = 0;
283  cairo_set_font_matrix (cairo, &matrix);
284}
285
286void CairoOutputDev::doPath(GfxState *state, GfxPath *path) {
287  GfxSubpath *subpath;
288  double x1, y1, x2, y2, x3, y3;
289  int i, j;
290
291  for (i = 0; i < path->getNumSubpaths(); ++i) {
292    subpath = path->getSubpath(i);
293    if (subpath->getNumPoints() > 0) {
294      state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1);
295      cairo_move_to (cairo, x1, y1);
296      LOG (printf ("move_to %f, %f\n", x1, y1));
297      j = 1;
298      while (j < subpath->getNumPoints()) {
299        if (subpath->getCurve(j)) {
300          state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
301          state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2);
302          state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3);
303          cairo_curve_to (cairo, 
304                          x1, y1,
305                          x2, y2,
306                          x3, y3);
307          LOG (printf ("curve_to %f, %f  %f, %f  %f, %f\n", x1, y1, x2, y2, x3, y3));
308          j += 3;
309        } else {
310          state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
311          cairo_line_to (cairo, x1, y1);
312          LOG(printf ("line_to %f, %f\n", x1, y1));
313          ++j;
314        }
315      }
316      if (subpath->isClosed()) {
317        LOG (printf ("close\n"));
318        cairo_close_path (cairo);
319      }
320    }
321  }
322}
323
324void CairoOutputDev::stroke(GfxState *state) {
325  doPath (state, state->getPath());
326  cairo_set_source (cairo, stroke_pattern);
327  LOG(printf ("stroke\n"));
328  cairo_stroke (cairo);
329}
330
331void CairoOutputDev::fill(GfxState *state) {
332  doPath (state, state->getPath());
333  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
334  cairo_set_source (cairo, fill_pattern);
335  LOG(printf ("fill\n"));
336  cairo_fill (cairo);
337}
338
339void CairoOutputDev::eoFill(GfxState *state) {
340  doPath (state, state->getPath());
341  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD);
342  cairo_set_source (cairo, fill_pattern);
343  LOG(printf ("fill-eo\n"));
344  cairo_fill (cairo);
345}
346
347void CairoOutputDev::clip(GfxState *state) {
348  doPath (state, state->getPath());
349  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
350  cairo_clip (cairo);
351  LOG (printf ("clip\n"));
352}
353
354void CairoOutputDev::eoClip(GfxState *state) {
355  doPath (state, state->getPath());
356  cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD);
357  cairo_clip (cairo);
358  LOG (printf ("clip-eo\n"));
359}
360
361void CairoOutputDev::beginString(GfxState *state, GooString *s)
362{
363  int len = s->getLength();
364
365  if (needFontUpdate)
366    updateFont(state);
367
368  glyphs = (cairo_glyph_t *) gmalloc (len * sizeof (cairo_glyph_t));
369  glyphCount = 0;
370}
371
372void CairoOutputDev::drawChar(GfxState *state, double x, double y,
373                              double dx, double dy,
374                              double originX, double originY,
375                              CharCode code, int nBytes, Unicode *u, int uLen)
376{
377  double tx, ty;
378
379  if (!currentFont)
380    return;
381 
382  glyphs[glyphCount].index = currentFont->getGlyph (code, u, uLen);
383  state->transform(x - originX, y - originY, &tx, &ty);
384  glyphs[glyphCount].x = tx;
385  glyphs[glyphCount].y = ty;
386  glyphCount++;
387}
388
389void CairoOutputDev::endString(GfxState *state)
390{
391  int render;
392
393  if (!currentFont)
394    return;
395   
396  // ignore empty strings and invisible text -- this is used by
397  // Acrobat Capture
398  render = state->getRender();
399  if (render == 3 || glyphCount == 0) {
400    gfree(glyphs);
401    glyphs = NULL;
402    return;
403  }
404 
405  if (!(render & 1)) {
406    LOG (printf ("fill string\n"));
407    cairo_set_source (cairo, fill_pattern);
408    cairo_show_glyphs (cairo, glyphs, glyphCount);
409  }
410 
411  // stroke
412  if ((render & 3) == 1 || (render & 3) == 2) {
413    LOG (printf ("stroke string\n"));
414    cairo_set_source (cairo, stroke_pattern);
415    cairo_glyph_path (cairo, glyphs, glyphCount);
416    cairo_stroke (cairo);
417  }
418
419  // clip
420  if (render & 4) {
421    LOG (printf ("clip string\n"));
422    // append the glyph path to textClipPath.
423
424    // set textClipPath as the currentPath
425    if (textClipPath) {
426      cairo_append_path (cairo, textClipPath);
427      cairo_path_destroy (textClipPath);
428    }
429   
430    // append the glyph path
431    cairo_glyph_path (cairo, glyphs, glyphCount);
432   
433    // move the path back into textClipPath
434    // and clear the current path
435    textClipPath = cairo_copy_path (cairo);
436    cairo_new_path (cairo);
437  }
438 
439  gfree (glyphs);
440  glyphs = NULL;
441}
442
443GBool CairoOutputDev::beginType3Char(GfxState *state, double x, double y,
444                                      double dx, double dy,
445                                      CharCode code, Unicode *u, int uLen) {
446  return gFalse;
447}
448
449void CairoOutputDev::endType3Char(GfxState *state) {
450}
451
452void CairoOutputDev::type3D0(GfxState *state, double wx, double wy) {
453}
454
455void CairoOutputDev::type3D1(GfxState *state, double wx, double wy,
456                             double llx, double lly, double urx, double ury) {
457}
458
459void CairoOutputDev::endTextObject(GfxState *state) {
460  if (textClipPath) {
461    // clip the accumulated text path
462    cairo_append_path (cairo, textClipPath);
463    cairo_clip (cairo);
464    cairo_path_destroy (textClipPath);
465    textClipPath = NULL;
466  }
467
468}
469
470
471void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
472                                    int width, int height, GBool invert,
473                                    GBool inlineImg) {
474  unsigned char *buffer;
475  unsigned char *dest;
476  cairo_surface_t *image;
477  cairo_pattern_t *pattern;
478  int x, y;
479  ImageStream *imgStr;
480  Guchar *pix;
481  double *ctm;
482  cairo_matrix_t matrix;
483  int invert_bit;
484  int row_stride;
485
486  ctm = state->getCTM();
487  LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
488               width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
489  matrix.xx = ctm[0] / width;
490  matrix.xy = -ctm[2] / height;
491  matrix.yx = ctm[1] / width;
492  matrix.yy = -ctm[3] / height;
493  matrix.x0 = ctm[2] + ctm[4];
494  matrix.y0 = ctm[3] + ctm[5];
495
496  /* work around a cairo bug when scaling 1x1 surfaces */
497  if (width == 1 && height == 1) {
498    cairo_save (cairo);
499    cairo_set_matrix (cairo, &matrix);
500    cairo_rectangle (cairo, 0., 0., 1., 1.);
501    cairo_fill (cairo);
502    cairo_restore (cairo);
503    return;
504  }
505
506  row_stride = (width + 3) & ~3;
507  buffer = (unsigned char *) malloc (height * row_stride);
508  if (buffer == NULL) {
509    error(-1, "Unable to allocate memory for image.");
510    return;
511  }
512
513  /* TODO: Do we want to cache these? */
514  imgStr = new ImageStream(str, width, 1, 1);
515  imgStr->reset();
516
517  invert_bit = invert ? 1 : 0;
518
519  for (y = 0; y < height; y++) {
520    pix = imgStr->getLine();
521    dest = buffer + y * row_stride;
522    for (x = 0; x < width; x++) {
523
524      if (pix[x] ^ invert_bit)
525        *dest++ = 0;
526      else
527        *dest++ = 255;
528    }
529  }
530
531  image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_A8,
532                                               width, height, row_stride);
533  if (image == NULL) {
534    delete imgStr;
535    return;
536  }
537  pattern = cairo_pattern_create_for_surface (image);
538  if (pattern == NULL) {
539    delete imgStr;
540    return;
541  }
542
543  cairo_matrix_invert (&matrix);
544  cairo_pattern_set_matrix (pattern, &matrix);
545
546  /* we should actually be using CAIRO_FILTER_NEAREST here. However,
547   * cairo doesn't yet do minifaction filtering causing scaled down
548   * images with CAIRO_FILTER_NEAREST to look really bad */
549  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);
550
551  /* FIXME: Doesn't the image mask support any colorspace? */
552  cairo_set_source (cairo, fill_pattern);
553  cairo_mask (cairo, pattern);
554
555  cairo_pattern_destroy (pattern);
556  cairo_surface_destroy (image);
557  free (buffer);
558  delete imgStr;
559}
560
561void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref,
562                                Stream *str, int width, int height,
563                                GfxImageColorMap *colorMap,
564                                Stream *maskStr, int maskWidth,
565                                int maskHeight, GBool maskInvert)
566{
567  ImageStream *maskImgStr;
568  maskImgStr = new ImageStream(maskStr, maskWidth, 1, 1);
569  maskImgStr->reset();
570
571  int row_stride = (maskWidth + 3) & ~3;
572  unsigned char *maskBuffer;
573  maskBuffer = (unsigned char *)gmalloc (row_stride * maskHeight);
574  unsigned char *maskDest;
575  cairo_surface_t *maskImage;
576  cairo_pattern_t *maskPattern;
577  Guchar *pix;
578  int x, y;
579
580  int invert_bit;
581 
582  invert_bit = maskInvert ? 1 : 0;
583
584  for (y = 0; y < height; y++) {
585    pix = maskImgStr->getLine();
586    maskDest = maskBuffer + y * row_stride;
587    for (x = 0; x < width; x++) {
588      if (pix[x] ^ invert_bit)
589        *maskDest++ = 0;
590      else
591        *maskDest++ = 255;
592    }
593  }
594
595  maskImage = cairo_image_surface_create_for_data (maskBuffer, CAIRO_FORMAT_A8,
596                                                 maskWidth, maskHeight, row_stride);
597
598  delete maskImgStr;
599  maskStr->close();
600
601  unsigned char *buffer;
602  unsigned int *dest;
603  cairo_surface_t *image;
604  cairo_pattern_t *pattern;
605  ImageStream *imgStr;
606  GfxRGB rgb;
607  int alpha, i;
608  double *ctm;
609  cairo_matrix_t matrix;
610  cairo_matrix_t maskMatrix;
611  int is_identity_transform;
612
613  buffer = (unsigned char *)gmalloc (width * height * 4);
614
615  /* TODO: Do we want to cache these? */
616  imgStr = new ImageStream(str, width,
617                           colorMap->getNumPixelComps(),
618                           colorMap->getBits());
619  imgStr->reset();
620 
621  /* ICCBased color space doesn't do any color correction
622   * so check its underlying color space as well */
623  is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
624                  colorMap->getColorSpace()->getMode() == csICCBased && 
625                  ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB;
626
627  for (y = 0; y < height; y++) {
628    dest = (unsigned int *) (buffer + y * 4 * width);
629    pix = imgStr->getLine();
630    colorMap->getRGBLine (pix, dest, width);
631  }
632
633  image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_RGB24,
634                                                 width, height, width * 4);
635
636  if (image == NULL) {
637    delete imgStr;
638    return;
639  }
640  pattern = cairo_pattern_create_for_surface (image);
641  maskPattern = cairo_pattern_create_for_surface (maskImage);
642  if (pattern == NULL) {
643    delete imgStr;
644    return;
645  }
646
647  ctm = state->getCTM();
648  LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
649               width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
650  matrix.xx = ctm[0] / width;
651  matrix.xy = -ctm[2] / height;
652  matrix.yx = ctm[1] / width;
653  matrix.yy = -ctm[3] / height;
654  matrix.x0 = ctm[2] + ctm[4];
655  matrix.y0 = ctm[3] + ctm[5];
656
657  maskMatrix.xx = ctm[0] / maskWidth;
658  maskMatrix.xy = -ctm[2] / maskHeight;
659  maskMatrix.yx = ctm[1] / maskWidth;
660  maskMatrix.yy = -ctm[3] / maskHeight;
661  maskMatrix.x0 = ctm[2] + ctm[4];
662  maskMatrix.y0 = ctm[3] + ctm[5];
663
664  cairo_matrix_invert (&matrix);
665  cairo_matrix_invert (&maskMatrix);
666
667  cairo_pattern_set_matrix (pattern, &matrix);
668  cairo_pattern_set_matrix (maskPattern, &maskMatrix);
669
670  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BILINEAR);
671  cairo_set_source (cairo, pattern);
672  cairo_mask (cairo, maskPattern);
673
674  cairo_pattern_destroy (maskPattern);
675  cairo_surface_destroy (maskImage);
676  cairo_pattern_destroy (pattern);
677  cairo_surface_destroy (image);
678  free (buffer);
679  free (maskBuffer);
680  delete imgStr;
681}
682
683void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
684                                int width, int height,
685                                GfxImageColorMap *colorMap,
686                                Stream *maskStr,
687                                int maskWidth, int maskHeight,
688                                GfxImageColorMap *maskColorMap)
689{
690  ImageStream *maskImgStr;
691  maskImgStr = new ImageStream(maskStr, maskWidth,
692                                       maskColorMap->getNumPixelComps(),
693                                       maskColorMap->getBits());
694  maskImgStr->reset();
695
696  int row_stride = (maskWidth + 3) & ~3;
697  unsigned char *maskBuffer;
698  maskBuffer = (unsigned char *)gmalloc (row_stride * maskHeight);
699  unsigned char *maskDest;
700  cairo_surface_t *maskImage;
701  cairo_pattern_t *maskPattern;
702  Guchar *pix;
703  int x, y;
704  for (y = 0; y < maskHeight; y++) {
705    maskDest = (unsigned char *) (maskBuffer + y * row_stride);
706    pix = maskImgStr->getLine();
707    maskColorMap->getGrayLine (pix, maskDest, maskWidth);
708  }
709
710  maskImage = cairo_image_surface_create_for_data (maskBuffer, CAIRO_FORMAT_A8,
711                                                 maskWidth, maskHeight, row_stride);
712
713  delete maskImgStr;
714  maskStr->close();
715
716  unsigned char *buffer;
717  unsigned int *dest;
718  cairo_surface_t *image;
719  cairo_pattern_t *pattern;
720  ImageStream *imgStr;
721  GfxRGB rgb;
722  int alpha, i;
723  double *ctm;
724  cairo_matrix_t matrix;
725  cairo_matrix_t maskMatrix;
726  int is_identity_transform;
727
728  buffer = (unsigned char *)gmalloc (width * height * 4);
729
730  /* TODO: Do we want to cache these? */
731  imgStr = new ImageStream(str, width,
732                           colorMap->getNumPixelComps(),
733                           colorMap->getBits());
734  imgStr->reset();
735 
736  /* ICCBased color space doesn't do any color correction
737   * so check its underlying color space as well */
738  is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
739                  colorMap->getColorSpace()->getMode() == csICCBased && 
740                  ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB;
741
742  for (y = 0; y < height; y++) {
743    dest = (unsigned int *) (buffer + y * 4 * width);
744    pix = imgStr->getLine();
745    colorMap->getRGBLine (pix, dest, width);
746  }
747
748  image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_RGB24,
749                                                 width, height, width * 4);
750
751  if (image == NULL) {
752    delete imgStr;
753    return;
754  }
755  pattern = cairo_pattern_create_for_surface (image);
756  maskPattern = cairo_pattern_create_for_surface (maskImage);
757  if (pattern == NULL) {
758    delete imgStr;
759    return;
760  }
761
762  ctm = state->getCTM();
763  LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
764               width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
765  matrix.xx = ctm[0] / width;
766  matrix.xy = -ctm[2] / height;
767  matrix.yx = ctm[1] / width;
768  matrix.yy = -ctm[3] / height;
769  matrix.x0 = ctm[2] + ctm[4];
770  matrix.y0 = ctm[3] + ctm[5];
771
772  maskMatrix.xx = ctm[0] / maskWidth;
773  maskMatrix.xy = -ctm[2] / maskHeight;
774  maskMatrix.yx = ctm[1] / maskWidth;
775  maskMatrix.yy = -ctm[3] / maskHeight;
776  maskMatrix.x0 = ctm[2] + ctm[4];
777  maskMatrix.y0 = ctm[3] + ctm[5];
778
779  cairo_matrix_invert (&matrix);
780  cairo_matrix_invert (&maskMatrix);
781
782  cairo_pattern_set_matrix (pattern, &matrix);
783  cairo_pattern_set_matrix (maskPattern, &maskMatrix);
784
785  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BILINEAR);
786  cairo_set_source (cairo, pattern);
787  cairo_mask (cairo, maskPattern);
788
789  cairo_pattern_destroy (maskPattern);
790  cairo_surface_destroy (maskImage);
791  cairo_pattern_destroy (pattern);
792  cairo_surface_destroy (image);
793  free (buffer);
794  free (maskBuffer);
795  delete imgStr;
796}
797void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
798                                int width, int height,
799                                GfxImageColorMap *colorMap,
800                                int *maskColors, GBool inlineImg)
801{
802  unsigned char *buffer;
803  unsigned int *dest;
804  cairo_surface_t *image;
805  cairo_pattern_t *pattern;
806  int x, y;
807  ImageStream *imgStr;
808  Guchar *pix;
809  GfxRGB rgb;
810  int alpha, i;
811  double *ctm;
812  cairo_matrix_t matrix;
813  int is_identity_transform;
814 
815  buffer = (unsigned char *)gmalloc (width * height * 4);
816
817  /* TODO: Do we want to cache these? */
818  imgStr = new ImageStream(str, width,
819                           colorMap->getNumPixelComps(),
820                           colorMap->getBits());
821  imgStr->reset();
822 
823  /* ICCBased color space doesn't do any color correction
824   * so check its underlying color space as well */
825  is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
826                  colorMap->getColorSpace()->getMode() == csICCBased && 
827                  ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB;
828
829  if (maskColors) {
830    for (y = 0; y < height; y++) {
831      dest = (unsigned int *) (buffer + y * 4 * width);
832      pix = imgStr->getLine();
833      colorMap->getRGBLine (pix, dest, width);
834
835      for (x = 0; x < width; x++) {
836        for (i = 0; i < colorMap->getNumPixelComps(); ++i) {
837         
838          if (pix[i] < maskColors[2*i] * 255||
839              pix[i] > maskColors[2*i+1] * 255) {
840            *dest = *dest | 0xff000000;
841            break;
842          }
843        }
844        pix += colorMap->getNumPixelComps();
845        dest++;
846      }
847    }
848
849    image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_ARGB32,
850                                                 width, height, width * 4);
851  }
852  else {
853    for (y = 0; y < height; y++) {
854      dest = (unsigned int *) (buffer + y * 4 * width);
855      pix = imgStr->getLine();
856      colorMap->getRGBLine (pix, dest, width);
857    }
858
859    image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_RGB24,
860                                                 width, height, width * 4);
861  }
862
863  if (image == NULL) {
864   delete imgStr;
865   return;
866  }
867  pattern = cairo_pattern_create_for_surface (image);
868  if (pattern == NULL) {
869    delete imgStr;
870    return;
871  }
872
873  ctm = state->getCTM();
874  LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
875               width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
876  matrix.xx = ctm[0] / width;
877  matrix.xy = -ctm[2] / height;
878  matrix.yx = ctm[1] / width;
879  matrix.yy = -ctm[3] / height;
880  matrix.x0 = ctm[2] + ctm[4];
881  matrix.y0 = ctm[3] + ctm[5];
882
883  cairo_matrix_invert (&matrix);
884  cairo_pattern_set_matrix (pattern, &matrix);
885
886  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BILINEAR);
887  cairo_set_source (cairo, pattern);
888  cairo_paint (cairo);
889
890  cairo_pattern_destroy (pattern);
891  cairo_surface_destroy (image);
892  free (buffer);
893  delete imgStr;
894}
Note: See TracBrowser for help on using the repository browser.