~ubuntu-branches/ubuntu/precise/ipe/precise

« back to all changes in this revision

Viewing changes to src/tools/pdftoipe/xmloutputdev.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2004-06-08 00:44:02 UTC
  • Revision ID: james.westby@ubuntu.com-20040608004402-72yu51xlh7vt6p9m
Tags: upstream-6.0pre16
ImportĀ upstreamĀ versionĀ 6.0pre16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// --------------------------------------------------------------------
 
2
// Output device writing XML stream
 
3
// --------------------------------------------------------------------
 
4
/*
 
5
 
 
6
    This file is part of the extensible drawing editor Ipe.
 
7
    Copyright (C) 1993-2004  Otfried Cheong
 
8
 
 
9
    Ipe is free software; you can redistribute it and/or modify it
 
10
    under the terms of the GNU General Public License as published by
 
11
    the Free Software Foundation; either version 2 of the License, or
 
12
    (at your option) any later version.
 
13
 
 
14
    As a special exception, you have permission to link Ipe with the
 
15
    CGAL library and distribute executables, as long as you follow the
 
16
    requirements of the Gnu General Public License in regard to all of
 
17
    the software in the executable aside from CGAL.
 
18
 
 
19
    Ipe is distributed in the hope that it will be useful, but WITHOUT
 
20
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
21
    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 
22
    License for more details.
 
23
 
 
24
    You should have received a copy of the GNU General Public License
 
25
    along with Ipe; if not, you can find it at
 
26
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
 
27
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
28
 
 
29
*/
 
30
 
 
31
#include <stdio.h>
 
32
#include "ocfile.h"
 
33
#include <stddef.h>
 
34
#include <stdarg.h>
 
35
#include "gstring.h"
 
36
#include "config.h"
 
37
#include "globalparams.h"
 
38
#include "object.h"
 
39
#include "error.h"
 
40
#include "gfx.h"
 
41
#include "gfxstate.h"
 
42
#include "gfxfont.h"
 
43
#include "charcodetounicode.h"
 
44
#include "unicodemap.h"
 
45
#include "fontfile.h"
 
46
#include "catalog.h"
 
47
#include "page.h"
 
48
#include "stream.h"
 
49
#include "xmloutputdev.h"
 
50
 
 
51
#include <vector>
 
52
 
 
53
#ifdef __BORLANDC__
 
54
// assignment in condition
 
55
#pragma warn -8060
 
56
#endif
 
57
 
 
58
//------------------------------------------------------------------------
 
59
// XmlOutputDev
 
60
//------------------------------------------------------------------------
 
61
 
 
62
XmlOutputDev::XmlOutputDev(char *fileName, XRef *xrefA, Catalog *,
 
63
                           int /* firstPage */, int /* lastPage */,
 
64
                           GBool isMath)
 
65
{
 
66
  OCFILE *f;
 
67
 
 
68
  if (!(f = ocfopen(fileName, "w"))) {
 
69
    error(-1, "Couldn't open output file '%s'", fileName);
 
70
    ok = gFalse;
 
71
    return;
 
72
  }
 
73
  outputStream = f;
 
74
 
 
75
  // initialize
 
76
  ok = gTrue;
 
77
  xref = xrefA;
 
78
  inText = false;
 
79
  iIsMath = isMath;
 
80
 
 
81
  writePSFmt("<ipe creator=\"pdftoipe %s\">\n", PDFTOIPE_VERSION);
 
82
  // initialize sequential page number
 
83
  seqPage = 1;
 
84
}
 
85
 
 
86
XmlOutputDev::~XmlOutputDev()
 
87
{
 
88
  if (ok) {
 
89
    finishText();
 
90
    writePS("</ipe>\n");
 
91
  }
 
92
  fclose(outputStream);
 
93
}
 
94
 
 
95
// ----------------------------------------------------------
 
96
 
 
97
void XmlOutputDev::startPage(int pageNum, GfxState *state)
 
98
{
 
99
  int x1, y1, x2, y2;
 
100
 
 
101
  writePSFmt("<-- Page: %d %d -->\n", pageNum, seqPage);
 
102
 
 
103
  // rotate, translate, and scale page
 
104
  x1 = (int)(state->getX1() + 0.5);
 
105
  y1 = (int)(state->getY1() + 0.5);
 
106
  x2 = (int)(state->getX2() + 0.5);
 
107
  y2 = (int)(state->getY2() + 0.5);
 
108
  writePSFmt("<page mediabox=\"%d %d %d %d\">\n", x1, y1, x2, y2);
 
109
  ++seqPage;
 
110
}
 
111
 
 
112
void XmlOutputDev::endPage()
 
113
{
 
114
  finishText();
 
115
  writePS("</page>\n");
 
116
}
 
117
 
 
118
// --------------------------------------------------------------------
 
119
 
 
120
void XmlOutputDev::stroke(GfxState *state)
 
121
{
 
122
  finishText();
 
123
  GfxRGB rgb;
 
124
  state->getStrokeRGB(&rgb);
 
125
  writePSFmt("<path stroke=\"%g %g %g\"", rgb.r, rgb.g, rgb.b);
 
126
  writePSFmt(" pen=\"%g\"", state->getTransformedLineWidth());
 
127
 
 
128
  double *dash;
 
129
  double start;
 
130
  int length, i;
 
131
 
 
132
  state->getLineDash(&dash, &length, &start);
 
133
  if (length) {
 
134
    writePS(" dash=\"[");
 
135
    for (i = 0; i < length; ++i)
 
136
      writePSFmt("%g%s", state->transformWidth(dash[i]),
 
137
                 (i == length-1) ? "" : " ");
 
138
    writePSFmt("] %g\"", state->transformWidth(start));
 
139
  }
 
140
 
 
141
  if (state->getLineJoin() > 0)
 
142
    writePSFmt(" join=\"%d\"", state->getLineJoin());
 
143
  if (state->getLineCap())
 
144
    writePSFmt(" cap=\"%d\"", state->getLineCap());
 
145
 
 
146
  writePS(">\n");
 
147
  doPath(state);
 
148
  writePS("</path>\n");
 
149
}
 
150
 
 
151
void XmlOutputDev::fill(GfxState *state)
 
152
{
 
153
  finishText();
 
154
  GfxRGB rgb;
 
155
  state->getFillRGB(&rgb);
 
156
  writePSFmt("<path fill=\"%g %g %g\" fillrule=\"wind\">\n",
 
157
             rgb.r, rgb.g, rgb.b);
 
158
  doPath(state);
 
159
  writePS("</path>\n");
 
160
}
 
161
 
 
162
void XmlOutputDev::eoFill(GfxState *state)
 
163
{
 
164
  finishText();
 
165
  GfxRGB rgb;
 
166
  state->getFillRGB(&rgb);
 
167
  writePSFmt("<path fill=\"%g %g %g\">\n", rgb.r, rgb.g, rgb.b);
 
168
  doPath(state);
 
169
  writePS("</path>\n");
 
170
}
 
171
 
 
172
void XmlOutputDev::doPath(GfxState *state)
 
173
{
 
174
  GfxPath *path = state->getPath();
 
175
  GfxSubpath *subpath;
 
176
  int n, m, i, j;
 
177
 
 
178
  n = path->getNumSubpaths();
 
179
 
 
180
  double x, y, x1, y1, x2, y2;
 
181
  for (i = 0; i < n; ++i) {
 
182
    subpath = path->getSubpath(i);
 
183
    m = subpath->getNumPoints();
 
184
    state->transform(subpath->getX(0), subpath->getY(0), &x, &y);
 
185
    writePSFmt("%g %g m\n", x, y);
 
186
    j = 1;
 
187
    while (j < m) {
 
188
      if (subpath->getCurve(j)) {
 
189
        state->transform(subpath->getX(j), subpath->getY(j), &x, &y);
 
190
        state->transform(subpath->getX(j+1), subpath->getY(j+1), &x1, &y1);
 
191
        state->transform(subpath->getX(j+2), subpath->getY(j+2), &x2, &y2);
 
192
        writePSFmt("%g %g %g %g %g %g c\n", x, y, x1, y1, x2, y2);
 
193
        j += 3;
 
194
      } else {
 
195
        state->transform(subpath->getX(j), subpath->getY(j), &x, &y);
 
196
        writePSFmt("%g %g l\n", x, y);
 
197
        ++j;
 
198
      }
 
199
    }
 
200
    if (subpath->isClosed()) {
 
201
      writePS("h\n");
 
202
    }
 
203
  }
 
204
}
 
205
 
 
206
// --------------------------------------------------------------------
 
207
 
 
208
void XmlOutputDev::updateTextPos(GfxState *)
 
209
{
 
210
  finishText();
 
211
}
 
212
 
 
213
void XmlOutputDev::drawChar(GfxState *state, double /*x*/, double /*y*/,
 
214
                            double /*dx*/, double /*dy*/,
 
215
                            double /*originX*/, double /*originY*/,
 
216
                            CharCode, Unicode *u, int uLen)
 
217
{
 
218
  // check for invisible text -- this is used by Acrobat Capture
 
219
  if ((state->getRender() & 3) == 3) {
 
220
    return;
 
221
  }
 
222
 
 
223
  // get the font
 
224
  GfxFont *font;
 
225
  if (!(font = state->getFont())) {
 
226
    return;
 
227
  }
 
228
  (void) font; // placate compiler
 
229
 
 
230
  // begin text object
 
231
  if (!inText) {
 
232
    double *mat;
 
233
    mat = state->getTextMat();
 
234
    double x = state->getLineX();
 
235
    double y = state->getLineY();
 
236
    // writePSFmt("%g %g %g %g %g %g %g %g\n",
 
237
    // mat[0], mat[1], mat[2], mat[3], mat[4], mat[5], x, y);
 
238
    double tx = mat[0] * x + mat[2] * y + mat[4];
 
239
    double ty = mat[1] * x + mat[3] * y + mat[5];
 
240
 
 
241
    GfxRGB rgb;
 
242
    state->getFillRGB(&rgb);
 
243
 
 
244
    writePSFmt("<text stroke=\"%g %g %g\" pos=\"%g %g\" size=\"normal\">",
 
245
               rgb.r, rgb.g, rgb.b, tx, ty);
 
246
    if (iIsMath)
 
247
      writePS("$");
 
248
  }
 
249
  inText = true;
 
250
 
 
251
  for (int i = 0; i < uLen; ++i)
 
252
    writePSChar(u[i]);
 
253
}
 
254
 
 
255
void XmlOutputDev::finishText()
 
256
{
 
257
  if (inText) {
 
258
    if (iIsMath)
 
259
      writePS("$");
 
260
    writePS("</text>\n");
 
261
  }
 
262
  inText = false;
 
263
}
 
264
 
 
265
// --------------------------------------------------------------------
 
266
 
 
267
void XmlOutputDev::drawImageMask(GfxState *, Object */*ref*/, Stream */*str*/,
 
268
                                 int /*width*/, int /*height*/,
 
269
                                 GBool /*invert*/, GBool /*inlineImg*/)
 
270
{
 
271
  // mask is a one-bit image
 
272
  // not yet implemented
 
273
}
 
274
 
 
275
void XmlOutputDev::drawImage(GfxState *state, Object * /*ref*/, Stream *str,
 
276
                             int width, int height, GfxImageColorMap *colorMap,
 
277
                             int * /*maskColors*/, GBool inlineImg)
 
278
{
 
279
  ImageStream *imgStr;
 
280
  Guchar *p;
 
281
  GfxRGB rgb;
 
282
  int x, y;
 
283
  int c;
 
284
 
 
285
  writePSFmt("<image width=\"%d\" height=\"%d\"", width, height);
 
286
 
 
287
  double *mat;
 
288
  mat = state->getCTM();
 
289
  double tx = mat[0] + mat[2] + mat[4];
 
290
  double ty = mat[1] + mat[3] + mat[5];
 
291
  writePSFmt(" rect=\"%g %g %g %g\"", mat[4], mat[5], tx, ty);
 
292
 
 
293
  if (str->getKind() == strDCT && !inlineImg &&
 
294
      3 <= colorMap->getNumPixelComps() && colorMap->getNumPixelComps() <= 4) {
 
295
    // dump JPEG stream
 
296
    std::vector<char> buffer;
 
297
    // initialize stream
 
298
    str = ((DCTStream *)str)->getRawStream();
 
299
    str->reset();
 
300
    // copy the stream
 
301
    while ((c = str->getChar()) != EOF)
 
302
      buffer.push_back(char(c));
 
303
    str->close();
 
304
 
 
305
    if (colorMap->getNumPixelComps() == 3)
 
306
      writePS(" ColorSpace=\"DeviceRGB\"");
 
307
    else
 
308
      writePS(" ColorSpace=\"DeviceCMYK\"");
 
309
    writePS(" BitsPerComponent=\"8\"");
 
310
    writePS(" Filter=\"DCTDecode\"");
 
311
    writePSFmt(" length=\"%d\"", buffer.size());
 
312
    writePS(">\n");
 
313
 
 
314
    for (unsigned int i = 0; i < buffer.size(); ++i)
 
315
      writePSFmt("%02x", buffer[i] & 0xff);
 
316
 
 
317
#if 0
 
318
  } else if (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1) {
 
319
    // 1 bit depth -- not implemented in Ipe
 
320
 
 
321
    // initialize stream
 
322
    str->reset();
 
323
    // copy the stream
 
324
    size = height * ((width + 7) / 8);
 
325
    for (i = 0; i < size; ++i) {
 
326
      writePSFmt("%02x", (str->getChar() ^ 0xff));
 
327
    }
 
328
    str->close();
 
329
#endif
 
330
  } else if (colorMap->getNumPixelComps() == 1) {
 
331
    // write as gray level image
 
332
    writePS(" ColorSpace=\"DeviceGray\"");
 
333
    writePS(" BitsPerComponent=\"8\"");
 
334
    writePS(">\n");
 
335
 
 
336
    // initialize stream
 
337
    imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
 
338
                             colorMap->getBits());
 
339
    imgStr->reset();
 
340
 
 
341
    // for each line...
 
342
    for (y = 0; y < height; ++y) {
 
343
 
 
344
      // write the line
 
345
      p = imgStr->getLine();
 
346
      for (x = 0; x < width; ++x) {
 
347
        double gray;
 
348
        colorMap->getGray(p, &gray);
 
349
        writePSFmt("%02x", (int)(gray * 255 + 0.5));
 
350
        p += colorMap->getNumPixelComps();
 
351
      }
 
352
    }
 
353
    delete imgStr;
 
354
 
 
355
  } else {
 
356
    // write as RGB image
 
357
    writePS(" ColorSpace=\"DeviceRGB\"");
 
358
    writePS(" BitsPerComponent=\"8\"");
 
359
    writePS(">\n");
 
360
 
 
361
    // initialize stream
 
362
    imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
 
363
                             colorMap->getBits());
 
364
    imgStr->reset();
 
365
 
 
366
    // for each line...
 
367
    for (y = 0; y < height; ++y) {
 
368
 
 
369
      // write the line
 
370
      p = imgStr->getLine();
 
371
      for (x = 0; x < width; ++x) {
 
372
        colorMap->getRGB(p, &rgb);
 
373
        writePSFmt("%02x", (int)(rgb.r * 255 + 0.5));
 
374
        writePSFmt("%02x", (int)(rgb.g * 255 + 0.5));
 
375
        writePSFmt("%02x", (int)(rgb.b * 255 + 0.5));
 
376
        p += colorMap->getNumPixelComps();
 
377
      }
 
378
    }
 
379
    delete imgStr;
 
380
  }
 
381
  writePS("\n</image>\n");
 
382
}
 
383
 
 
384
// --------------------------------------------------------------------
 
385
 
 
386
void XmlOutputDev::writePSChar(int code)
 
387
{
 
388
  if (code == '<')
 
389
    writePS("&lt;");
 
390
  else if (code == '>')
 
391
    writePS("&gt;");
 
392
  else if (code == '&')
 
393
    writePS("&amp;");
 
394
  else if (code < 0x80)
 
395
    writePSFmt("%c", code);
 
396
  else if (code < 0x800) {
 
397
    writePSFmt("%c%c",
 
398
               (((code & 0x7c0) >> 6) | 0xc0),
 
399
               ((code & 0x03f) | 0x80));
 
400
  } else {
 
401
    // Do we never need to write UCS larger than 0x10000?
 
402
    writePSFmt("%c%c%c",
 
403
               (((code & 0x0f000) >> 12) | 0xe0),
 
404
               (((code & 0xfc0) >> 6) | 0x80),
 
405
               ((code & 0x03f) | 0x80));
 
406
  }
 
407
}
 
408
 
 
409
void XmlOutputDev::writePS(char *s)
 
410
{
 
411
  fwrite(s, 1, strlen(s), outputStream);
 
412
}
 
413
 
 
414
void XmlOutputDev::writePSFmt(const char *fmt, ...)
 
415
{
 
416
  va_list args;
 
417
  char buf[512];
 
418
 
 
419
  va_start(args, fmt);
 
420
  vsprintf(buf, fmt, args);
 
421
  va_end(args);
 
422
  fwrite(buf, 1, strlen(buf), outputStream);
 
423
}
 
424
 
 
425
// --------------------------------------------------------------------