source: trunk/poppler/mypoppler/poppler/ArthurOutputDev.cc @ 2

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

First import

File size: 18.5 KB
Line 
1//========================================================================
2//
3// ArthurOutputDev.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
19#include "goo/gfile.h"
20#include "GlobalParams.h"
21#include "Error.h"
22#include "Object.h"
23#include "GfxState.h"
24#include "GfxFont.h"
25#include "Link.h"
26#include "CharCodeToUnicode.h"
27#include "FontEncodingTables.h"
28#include <fofi/FoFiTrueType.h>
29#include "ArthurOutputDev.h"
30
31#include <QtCore/QtDebug>
32#include <QtGui/QPainterPath>
33//------------------------------------------------------------------------
34
35#include "splash/SplashFontFileID.h"
36#include "splash/SplashFontFile.h"
37#include "splash/SplashFontEngine.h"
38#include "splash/SplashFont.h"
39#include "splash/SplashMath.h"
40#include "splash/SplashPath.h"
41#include "splash/SplashGlyphBitmap.h"
42//------------------------------------------------------------------------
43// SplashOutFontFileID
44//------------------------------------------------------------------------
45
46class SplashOutFontFileID: public SplashFontFileID {
47public:
48
49  SplashOutFontFileID(Ref *rA) { r = *rA; }
50
51  ~SplashOutFontFileID() {}
52
53  GBool matches(SplashFontFileID *id) {
54    return ((SplashOutFontFileID *)id)->r.num == r.num &&
55           ((SplashOutFontFileID *)id)->r.gen == r.gen;
56  }
57
58private:
59
60  Ref r;
61};
62
63
64
65//------------------------------------------------------------------------
66// ArthurOutputDev
67//------------------------------------------------------------------------
68
69ArthurOutputDev::ArthurOutputDev(QPainter *painter):
70  m_painter(painter)
71{
72  m_currentBrush = QBrush(Qt::SolidPattern);
73  m_fontEngine = 0;
74}
75
76ArthurOutputDev::~ArthurOutputDev()
77{
78}
79
80void ArthurOutputDev::startDoc(XRef *xrefA) {
81  int i;
82
83  xref = xrefA;
84  if (m_fontEngine) {
85    delete m_fontEngine;
86  }
87  m_fontEngine = new SplashFontEngine(
88#if HAVE_T1LIB_H
89                                    globalParams->getEnableT1lib(),
90#endif
91#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
92                                    globalParams->getEnableFreeType(),
93#endif
94                                    globalParams->getAntialias());
95}
96
97void ArthurOutputDev::startPage(int pageNum, GfxState *state)
98{
99  // fill page with white background.
100  int w = static_cast<int>(state->getPageWidth());
101  int h = static_cast<int>(state->getPageHeight());
102  QColor fillColour(Qt::white);
103  QBrush fill(fillColour);
104  m_painter->save();
105  m_painter->setPen(fillColour);
106  m_painter->setBrush(fill);
107  m_painter->drawRect(0, 0, w, h);
108  m_painter->restore();
109}
110
111void ArthurOutputDev::endPage() {
112}
113
114void ArthurOutputDev::drawLink(Link *link, Catalog *catalog)
115{
116}
117
118void ArthurOutputDev::saveState(GfxState *state)
119{
120  m_painter->save();
121}
122
123void ArthurOutputDev::restoreState(GfxState *state)
124{
125  m_painter->restore();
126}
127
128void ArthurOutputDev::updateAll(GfxState *state)
129{
130  updateLineDash(state);
131  updateLineJoin(state);
132  updateLineCap(state);
133  updateLineWidth(state);
134  updateFlatness(state);
135  updateMiterLimit(state);
136  updateFillColor(state);
137  updateStrokeColor(state);
138  updateFillOpacity(state);
139  updateStrokeOpacity(state);
140  m_needFontUpdate = gTrue;
141}
142
143// This looks wrong - why aren't adjusting the matrix?
144void ArthurOutputDev::updateCTM(GfxState *state, double m11, double m12,
145                                double m21, double m22,
146                                double m31, double m32)
147{
148  updateLineDash(state);
149  updateLineJoin(state);
150  updateLineCap(state);
151  updateLineWidth(state);
152}
153
154void ArthurOutputDev::updateLineDash(GfxState *state)
155{
156  // qDebug() << "updateLineDash";
157}
158
159void ArthurOutputDev::updateFlatness(GfxState *state)
160{
161  // qDebug() << "updateFlatness";
162}
163
164void ArthurOutputDev::updateLineJoin(GfxState *state)
165{
166  switch (state->getLineJoin()) {
167  case 0:
168    m_currentPen.setJoinStyle(Qt::MiterJoin);
169    break;
170  case 1:
171    m_currentPen.setJoinStyle(Qt::RoundJoin);
172    break;
173  case 2:
174    m_currentPen.setJoinStyle(Qt::BevelJoin);
175    break;
176  }
177  m_painter->setPen(m_currentPen);
178}
179
180void ArthurOutputDev::updateLineCap(GfxState *state)
181{
182  switch (state->getLineCap()) {
183  case 0:
184    m_currentPen.setCapStyle(Qt::FlatCap);
185    break;
186  case 1:
187    m_currentPen.setCapStyle(Qt::RoundCap);
188    break;
189  case 2:
190    m_currentPen.setCapStyle(Qt::SquareCap);
191    break;
192  }
193  m_painter->setPen(m_currentPen);
194}
195
196void ArthurOutputDev::updateMiterLimit(GfxState *state)
197{
198  // We can't do mitre (or Miter) limit with Qt4 yet.
199  // the limit is in state->getMiterLimit() when we get there
200}
201
202void ArthurOutputDev::updateLineWidth(GfxState *state)
203{
204  m_currentPen.setWidthF(state->getTransformedLineWidth());
205  m_painter->setPen(m_currentPen);
206}
207
208void ArthurOutputDev::updateFillColor(GfxState *state)
209{
210  GfxRGB rgb;
211  QColor brushColour = m_currentBrush.color();
212  state->getFillRGB(&rgb);
213  brushColour.setRgbF(rgb.r, rgb.g, rgb.b, brushColour.alphaF());
214  m_currentBrush.setColor(brushColour);
215}
216
217void ArthurOutputDev::updateStrokeColor(GfxState *state)
218{
219  GfxRGB rgb;
220  QColor penColour = m_currentPen.color();
221  state->getStrokeRGB(&rgb);
222  penColour.setRgbF(rgb.r, rgb.g, rgb.b, penColour.alphaF());
223  m_currentPen.setColor(penColour);
224  m_painter->setPen(m_currentPen);
225}
226
227void ArthurOutputDev::updateFillOpacity(GfxState *state)
228{
229  QColor brushColour= m_currentBrush.color();
230  brushColour.setAlphaF(state->getFillOpacity());
231  m_currentBrush.setColor(brushColour);
232}
233
234void ArthurOutputDev::updateStrokeOpacity(GfxState *state)
235{
236  QColor penColour= m_currentPen.color();
237  penColour.setAlphaF(state->getStrokeOpacity());
238  m_currentPen.setColor(penColour);
239  m_painter->setPen(m_currentPen);
240}
241
242void ArthurOutputDev::updateFont(GfxState *state)
243{
244  GfxFont *gfxFont;
245  GfxFontType fontType;
246  SplashOutFontFileID *id;
247  SplashFontFile *fontFile;
248  SplashFontSrc *fontsrc;
249  FoFiTrueType *ff;
250  Ref embRef;
251  Object refObj, strObj;
252  GooString *fileName, *substName;
253  char *tmpBuf;
254  int tmpBufLen;
255  Gushort *codeToGID;
256  DisplayFontParam *dfp;
257  double m11, m12, m21, m22, w1, w2;
258  SplashCoord mat[4];
259  char *name;
260  int c, substIdx, n, code;
261
262  m_needFontUpdate = false;
263  m_font = NULL;
264  fileName = NULL;
265  tmpBuf = NULL;
266  substIdx = -1;
267
268  if (!(gfxFont = state->getFont())) {
269    goto err1;
270  }
271  fontType = gfxFont->getType();
272  if (fontType == fontType3) {
273    goto err1;
274  }
275
276  // check the font file cache
277  id = new SplashOutFontFileID(gfxFont->getID());
278  if ((fontFile = m_fontEngine->getFontFile(id))) {
279    delete id;
280
281  } else {
282
283    // if there is an embedded font, write it to disk
284    if (gfxFont->getEmbeddedFontID(&embRef)) {
285      tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
286      if (! tmpBuf)
287        goto err2;
288    // if there is an external font file, use it
289    } else if (!(fileName = gfxFont->getExtFontFile())) {
290
291      // look for a display font mapping or a substitute font
292      dfp = NULL;
293      if (gfxFont->getName()) {
294        dfp = globalParams->getDisplayFont(gfxFont);
295      }
296      if (!dfp) {
297        error(-1, "Couldn't find a font for '%s'",
298              gfxFont->getName() ? gfxFont->getName()->getCString()
299                                 : "(unnamed)");
300        goto err2;
301      }
302      switch (dfp->kind) {
303      case displayFontT1:
304        fileName = dfp->t1.fileName;
305        fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
306        break;
307      case displayFontTT:
308        fileName = dfp->tt.fileName;
309        fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
310        break;
311      }
312    }
313
314    fontsrc = new SplashFontSrc;
315    if (fileName)
316      fontsrc->setFile(fileName, gFalse);
317    else
318      fontsrc->setBuf(tmpBuf, tmpBufLen, gFalse);
319
320    // load the font file
321    switch (fontType) {
322    case fontType1:
323      if (!(fontFile = m_fontEngine->loadType1Font(
324                           id,
325                           fontsrc,
326                           ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
327        error(-1, "Couldn't create a font for '%s'",
328              gfxFont->getName() ? gfxFont->getName()->getCString()
329                                 : "(unnamed)");
330        goto err2;
331      }
332      break;
333    case fontType1C:
334      if (!(fontFile = m_fontEngine->loadType1CFont(
335                           id,
336                           fontsrc,
337                           ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
338        error(-1, "Couldn't create a font for '%s'",
339              gfxFont->getName() ? gfxFont->getName()->getCString()
340                                 : "(unnamed)");
341        goto err2;
342      }
343      break;
344    case fontTrueType:
345      if (!(ff = FoFiTrueType::load(fileName->getCString()))) {
346        goto err2;
347      }
348      codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
349      delete ff;
350      if (!(fontFile = m_fontEngine->loadTrueTypeFont(
351                           id,
352                           fontsrc,
353                           codeToGID, 256))) {
354        error(-1, "Couldn't create a font for '%s'",
355              gfxFont->getName() ? gfxFont->getName()->getCString()
356                                 : "(unnamed)");
357        goto err2;
358      }
359      break;
360    case fontCIDType0:
361    case fontCIDType0C:
362      if (!(fontFile = m_fontEngine->loadCIDFont(
363                           id,
364                           fontsrc))) {
365        error(-1, "Couldn't create a font for '%s'",
366              gfxFont->getName() ? gfxFont->getName()->getCString()
367                                 : "(unnamed)");
368        goto err2;
369      }
370      break;
371    case fontCIDType2:
372      n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
373      codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
374      memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
375             n * sizeof(Gushort));
376      if (!(fontFile = m_fontEngine->loadTrueTypeFont(
377                           id,
378                           fontsrc,
379                           codeToGID, n))) {
380        error(-1, "Couldn't create a font for '%s'",
381              gfxFont->getName() ? gfxFont->getName()->getCString()
382                                 : "(unnamed)");
383        goto err2;
384      }
385      break;
386    default:
387      // this shouldn't happen
388      goto err2;
389    }
390  }
391
392  // get the font matrix
393  state->getFontTransMat(&m11, &m12, &m21, &m22);
394  m11 *= state->getHorizScaling();
395  m12 *= state->getHorizScaling();
396
397  // create the scaled font
398  mat[0] = m11;  mat[1] = -m12;
399  mat[2] = m21;  mat[3] = -m22;
400  m_font = m_fontEngine->getFont(fontFile, mat);
401
402  return;
403
404 err2:
405  delete id;
406 err1:
407  return;
408}
409
410static QPainterPath convertPath(GfxState *state, GfxPath *path, Qt::FillRule fillRule)
411{
412  GfxSubpath *subpath;
413  double x1, y1, x2, y2, x3, y3;
414  int i, j;
415
416  QPainterPath qPath;
417  qPath.setFillRule(fillRule);
418  for (i = 0; i < path->getNumSubpaths(); ++i) {
419    subpath = path->getSubpath(i);
420    if (subpath->getNumPoints() > 0) {
421      state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1);
422      qPath.moveTo(x1, y1);
423      j = 1;
424      while (j < subpath->getNumPoints()) {
425        if (subpath->getCurve(j)) {
426          state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
427          state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2);
428          state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3);
429          qPath.cubicTo( x1, y1, x2, y2, x3, y3);
430          j += 3;
431        } else {
432          state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
433          qPath.lineTo(x1, y1);
434          ++j;
435        }
436      }
437      if (subpath->isClosed()) {
438        qPath.closeSubpath();
439      }
440    }
441  }
442  return qPath;
443}
444
445void ArthurOutputDev::stroke(GfxState *state)
446{
447  m_painter->drawPath( convertPath( state, state->getPath(), Qt::OddEvenFill ) );
448}
449
450void ArthurOutputDev::fill(GfxState *state)
451{
452  m_painter->fillPath( convertPath( state, state->getPath(), Qt::WindingFill ), m_currentBrush );
453}
454
455void ArthurOutputDev::eoFill(GfxState *state)
456{
457  m_painter->fillPath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentBrush );
458}
459
460void ArthurOutputDev::clip(GfxState *state)
461{
462  m_painter->setClipPath(convertPath( state, state->getPath(), Qt::WindingFill ) );
463}
464
465void ArthurOutputDev::eoClip(GfxState *state)
466{
467  m_painter->setClipPath(convertPath( state, state->getPath(), Qt::OddEvenFill ) );
468}
469
470void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
471                               double dx, double dy,
472                               double originX, double originY,
473                               CharCode code, int nBytes, Unicode *u, int uLen) {
474  double x1, y1;
475//   SplashPath *path;
476  int render;
477
478  if (m_needFontUpdate) {
479    updateFont(state);
480  }
481  if (!m_font) {
482    return;
483  }
484
485  // check for invisible text -- this is used by Acrobat Capture
486  render = state->getRender();
487  if (render == 3) {
488    return;
489  }
490
491  x -= originX;
492  y -= originY;
493  state->transform(x, y, &x1, &y1);
494
495  // fill
496  if (!(render & 1)) {
497    int x0, y0, xFrac, yFrac;
498    SplashGlyphBitmap glyph;
499
500    x0 = static_cast<int>(floor(x1));
501    xFrac = splashFloor((x1 - x0) * splashFontFraction);
502    y0 = static_cast<int>(floor(y1));
503    yFrac = splashFloor((y1 - y0) * splashFontFraction);
504    SplashPath * fontPath;
505    fontPath = m_font->getGlyphPath(code);
506    if (fontPath) {
507      QPainterPath qPath;
508      qPath.setFillRule(Qt::WindingFill);
509      for (int i = 0; i < fontPath->length; ++i) {
510        if (fontPath->flags[i] & splashPathFirst) {
511          qPath.moveTo(x0+fontPath->pts[i].x, y0+fontPath->pts[i].y);
512        } else if (fontPath->flags[i] & splashPathCurve) {
513          qPath.quadTo(x0+fontPath->pts[i].x, y0+fontPath->pts[i].y,
514                       x0+fontPath->pts[i+1].x, y0+fontPath->pts[i+1].y);
515          ++i;
516        } else if (fontPath->flags[i] & splashPathArcCW) {
517          qDebug() << "Need to implement arc";
518        } else {
519          qPath.lineTo(x0+fontPath->pts[i].x, y0+fontPath->pts[i].y);
520        }
521        if (fontPath->flags[i] & splashPathLast) {
522          qPath.closeSubpath();
523        }
524      }
525      m_painter->save();
526      GfxRGB rgb;
527      QColor brushColour = m_currentBrush.color();
528      state->getFillRGB(&rgb);
529      brushColour.setRgbF(rgb.r, rgb.g, rgb.b, state->getFillOpacity());
530      m_painter->setBrush(brushColour);
531      QColor penColour = m_currentPen.color();
532      state->getStrokeRGB(&rgb);
533      penColour.setRgbF(rgb.r, rgb.g, rgb.b, state->getStrokeOpacity());
534      m_painter->setPen(penColour);
535      m_painter->drawPath( qPath );
536      m_painter->restore();
537    }
538  }
539
540  // stroke
541  if ((render & 3) == 1 || (render & 3) == 2) {
542    qDebug() << "no stroke";
543    /*
544    if ((path = m_font->getGlyphPath(code))) {
545      path->offset((SplashCoord)x1, (SplashCoord)y1);
546      splash->stroke(path);
547      delete path;
548    }
549    */
550  }
551
552  // clip
553  if (render & 4) {
554    qDebug() << "no clip";
555    /*
556    path = m_font->getGlyphPath(code);
557    path->offset((SplashCoord)x1, (SplashCoord)y1);
558    if (textClipPath) {
559      textClipPath->append(path);
560      delete path;
561    } else {
562      textClipPath = path;
563    }
564    */
565  }
566}
567
568GBool ArthurOutputDev::beginType3Char(GfxState *state, double x, double y,
569                                      double dx, double dy,
570                                      CharCode code, Unicode *u, int uLen)
571{
572  return gFalse;
573}
574
575void ArthurOutputDev::endType3Char(GfxState *state)
576{
577}
578
579void ArthurOutputDev::type3D0(GfxState *state, double wx, double wy)
580{
581}
582
583void ArthurOutputDev::type3D1(GfxState *state, double wx, double wy,
584                              double llx, double lly, double urx, double ury)
585{
586}
587
588void ArthurOutputDev::endTextObject(GfxState *state)
589{
590}
591
592
593void ArthurOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
594                                    int width, int height, GBool invert,
595                                    GBool inlineImg)
596{
597  qDebug() << "drawImageMask";
598#if 0
599  unsigned char *buffer;
600  unsigned char *dest;
601  cairo_surface_t *image;
602  cairo_pattern_t *pattern;
603  int x, y;
604  ImageStream *imgStr;
605  Guchar *pix;
606  double *ctm;
607  cairo_matrix_t matrix;
608  int invert_bit;
609  int row_stride;
610
611  row_stride = (width + 3) & ~3;
612  buffer = (unsigned char *) malloc (height * row_stride);
613  if (buffer == NULL) {
614    error(-1, "Unable to allocate memory for image.");
615    return;
616  }
617
618  /* TODO: Do we want to cache these? */
619  imgStr = new ImageStream(str, width, 1, 1);
620  imgStr->reset();
621
622  invert_bit = invert ? 1 : 0;
623
624  for (y = 0; y < height; y++) {
625    pix = imgStr->getLine();
626    dest = buffer + y * row_stride;
627    for (x = 0; x < width; x++) {
628
629      if (pix[x] ^ invert_bit)
630        *dest++ = 0;
631      else
632        *dest++ = 255;
633    }
634  }
635
636  image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_A8,
637                                          width, height, row_stride);
638  if (image == NULL)
639    return;
640  pattern = cairo_pattern_create_for_surface (image);
641  if (pattern == NULL)
642    return;
643
644  ctm = state->getCTM();
645  LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
646               width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
647  matrix.xx = ctm[0] / width;
648  matrix.xy = -ctm[2] / height;
649  matrix.yx = ctm[1] / width;
650  matrix.yy = -ctm[3] / height;
651  matrix.x0 = ctm[2] + ctm[4];
652  matrix.y0 = ctm[3] + ctm[5];
653  cairo_matrix_invert (&matrix);
654  cairo_pattern_set_matrix (pattern, &matrix);
655
656  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);
657  /* FIXME: Doesn't the image mask support any colorspace? */
658  cairo_set_source_rgb (cairo, fill_color.r, fill_color.g, fill_color.b);
659  cairo_mask (cairo, pattern);
660
661  cairo_pattern_destroy (pattern);
662  cairo_surface_destroy (image);
663  free (buffer);
664  delete imgStr;
665#endif
666}
667
668//TODO: lots more work here.
669void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
670                                int width, int height,
671                                GfxImageColorMap *colorMap,
672                                int *maskColors, GBool inlineImg)
673{
674  unsigned char *buffer;
675  unsigned int *dest;
676  int x, y;
677  ImageStream *imgStr;
678  Guchar *pix;
679  GfxRGB rgb;
680  int alpha, i;
681  double *ctm;
682  QMatrix matrix;
683  int is_identity_transform;
684 
685  buffer = (unsigned char *)gmalloc (width * height * 4);
686
687  /* TODO: Do we want to cache these? */
688  imgStr = new ImageStream(str, width,
689                           colorMap->getNumPixelComps(),
690                           colorMap->getBits());
691  imgStr->reset();
692 
693  /* ICCBased color space doesn't do any color correction
694   * so check its underlying color space as well */
695  is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
696                  colorMap->getColorSpace()->getMode() == csICCBased && 
697                  ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB;
698
699  if (maskColors) {
700    for (y = 0; y < height; y++) {
701      dest = (unsigned int *) (buffer + y * 4 * width);
702      pix = imgStr->getLine();
703      colorMap->getRGBLine (pix, dest, width);
704
705      for (x = 0; x < width; x++) {
706        for (i = 0; i < colorMap->getNumPixelComps(); ++i) {
707         
708          if (pix[i] < maskColors[2*i] * 255||
709              pix[i] > maskColors[2*i+1] * 255) {
710            *dest = *dest | 0xff000000;
711            break;
712          }
713        }
714        pix += colorMap->getNumPixelComps();
715        dest++;
716      }
717    }
718
719    m_image = new QImage(buffer, width, height, QImage::Format_ARGB32);
720  }
721  else {
722    for (y = 0; y < height; y++) {
723      dest = (unsigned int *) (buffer + y * 4 * width);
724      pix = imgStr->getLine();
725      colorMap->getRGBLine (pix, dest, width);
726    }
727
728    m_image = new QImage(buffer, width, height, QImage::Format_RGB32);
729  }
730
731  if (m_image == NULL || m_image->isNull()) {
732    qDebug() << "Null image";
733    return;
734  }
735  ctm = state->getCTM();
736  matrix.setMatrix(ctm[0] / width, ctm[1] / width, -ctm[2] / height, -ctm[3] / height, ctm[2] + ctm[4], ctm[3] + ctm[5]);
737
738  m_painter->setMatrix(matrix, true);
739  m_painter->drawImage( QPoint(0,0), *m_image );
740  free (buffer);
741  delete imgStr;
742
743}
Note: See TracBrowser for help on using the repository browser.