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

Last change on this file since 134 was 134, checked in by Eugene Romanenko, 15 years ago

poppler updated to version 0.5.4

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