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

« back to all changes in this revision

Viewing changes to src/ipelib/ipeutils.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2005-02-24 22:09:16 UTC
  • mfrom: (2.1.1 hoary)
  • Revision ID: james.westby@ubuntu.com-20050224220916-9vxiiqjz066r5489
Tags: 6.0pre23-2
debian/control: Ipe should depend on exact version of libipe.
Closes: #296771.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
#include "ipeimage.h"
36
36
#include "ipetext.h"
37
37
 
 
38
#include <zlib.h>
 
39
 
38
40
// --------------------------------------------------------------------
39
41
 
40
 
/*\class IpeBitmapFinder
 
42
/*! \class IpeBitmapFinder
41
43
  \ingroup high
42
44
  \brief A visitor that recursively scans objects and collects all bitmaps.
43
45
*/
67
69
 
68
70
// --------------------------------------------------------------------
69
71
 
 
72
/*! \class IpeBBoxPainter
 
73
  \ingroup high
 
74
  \brief Paint objects using this painter to compute an accurate bounding box.
 
75
 
 
76
  The IpeObjct::BBox member function computes a bounding box useful
 
77
  for distance calculations and optimizations.  To find a bounding box
 
78
  that is accurate for the actual \b drawn object, paint the object
 
79
  using an IpeBBoxPainter, and retrieve the box with BBox.
 
80
*/
 
81
 
70
82
IpeBBoxPainter::IpeBBoxPainter(const IpeStyleSheet *style)
71
83
  : IpePainter(style)
72
84
{
73
85
  // nothing else
74
86
}
75
87
 
76
 
void IpeBBoxPainter::BeginPath(const IpeVector &v)
77
 
{
78
 
  iV = Matrix() * v;
79
 
  Add(iV);
80
 
}
81
 
 
82
 
void IpeBBoxPainter::BeginClosedPath(const IpeVector &v)
83
 
{
84
 
  iV = Matrix() * v;
85
 
  Add(iV);
86
 
}
87
 
 
88
 
void IpeBBoxPainter::LineTo(const IpeVector &v)
89
 
{
90
 
  iV = Matrix() * v;
91
 
  Add(iV);
92
 
}
93
 
 
94
 
void IpeBBoxPainter::CurveTo(const IpeVector &v1, const IpeVector &v2,
95
 
                            const IpeVector &v3)
 
88
void IpeBBoxPainter::DoMoveTo(const IpeVector &v)
 
89
{
 
90
  iV = Matrix() * v;
 
91
  Add(iV);
 
92
}
 
93
 
 
94
void IpeBBoxPainter::DoLineTo(const IpeVector &v)
 
95
{
 
96
  iV = Matrix() * v;
 
97
  Add(iV);
 
98
}
 
99
 
 
100
void IpeBBoxPainter::DoCurveTo(const IpeVector &v1, const IpeVector &v2,
 
101
                               const IpeVector &v3)
96
102
{
97
103
  IpeBezier bez(iV, Matrix() * v1, Matrix() * v2, Matrix() * v3);
98
104
  IpeRect bb = bez.BBox();
99
105
  double lw = 0.0;
100
106
  if (LineWidth())
101
 
    lw = Repository()->ToScalar(LineWidth());
 
107
    lw = Repository()->ToScalar(LineWidth()).ToDouble();
102
108
  iBBox.AddPoint(bb.Min() - IpeVector(lw, lw));
103
109
  iBBox.AddPoint(bb.Max() + IpeVector(lw, lw));
104
110
  iV = Matrix() * v3;
105
111
}
106
112
 
107
 
void IpeBBoxPainter::DrawBitmap(IpeBitmap)
 
113
void IpeBBoxPainter::DoDrawBitmap(IpeBitmap)
108
114
{
109
115
  iBBox.AddPoint(Matrix() * IpeVector(0.0, 0.0));
110
116
  iBBox.AddPoint(Matrix() * IpeVector(0.0, 1.0));
112
118
  iBBox.AddPoint(Matrix() * IpeVector(1.0, 0.0));
113
119
}
114
120
 
115
 
void IpeBBoxPainter::DrawText(const IpeText *text)
 
121
void IpeBBoxPainter::DoDrawText(const IpeText *text)
116
122
{
117
123
  iBBox.AddPoint(Matrix() * IpeVector(0,0));
118
124
  iBBox.AddPoint(Matrix() * IpeVector(0, text->TotalHeight()));
124
130
{
125
131
  double lw = 0.0;
126
132
  if (LineWidth())
127
 
    lw = Repository()->ToScalar(LineWidth());
 
133
    lw = Repository()->ToScalar(LineWidth()).ToDouble();
128
134
  iBBox.AddPoint(IpeVector(pos.iX - lw, pos.iY - lw));
129
135
  iBBox.AddPoint(IpeVector(pos.iX + lw, pos.iY + lw));
130
136
}
131
137
 
132
138
// --------------------------------------------------------------------
 
139
 
 
140
/*! \class IpeA85Stream
 
141
  \ingroup high
 
142
  \brief Filter stream adding ASCII85 encoding.
 
143
*/
 
144
 
 
145
inline uint A85Word(const uchar *p)
 
146
{
 
147
  return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
 
148
}
 
149
 
 
150
inline void A85Encode(uint w, char *p)
 
151
{
 
152
  p[4] = char(w % 85 + 33);
 
153
  w /= 85;
 
154
  p[3] = char(w % 85 + 33);
 
155
  w /= 85;
 
156
  p[2] = char(w % 85 + 33);
 
157
  w /= 85;
 
158
  p[1] = char(w % 85 + 33);
 
159
  p[0] = char(w / 85 + 33);
 
160
}
 
161
 
 
162
IpeA85Stream::IpeA85Stream(IpeStream &stream)
 
163
  : iStream(stream)
 
164
{
 
165
  iN = 0;
 
166
  iCol = 0;
 
167
}
 
168
 
 
169
void IpeA85Stream::PutChar(char ch)
 
170
{
 
171
  iCh[iN++] = ch;
 
172
  if (iN == 4) {
 
173
    // encode and write
 
174
    uint w = A85Word(iCh);
 
175
    if (w == 0) {
 
176
      iStream.PutChar('z');
 
177
      ++iCol;
 
178
    } else {
 
179
      char buf[6];
 
180
      buf[5] = '\0';
 
181
      A85Encode(w, buf);
 
182
      iStream.PutCString(buf);
 
183
      iCol += 5;
 
184
    }
 
185
    if (iCol > 70) {
 
186
      iStream.PutChar('\n');
 
187
      iCol = 0;
 
188
    }
 
189
    iN = 0;
 
190
  }
 
191
}
 
192
 
 
193
void IpeA85Stream::Close()
 
194
{
 
195
  if (iN) {
 
196
    for (int k = iN; k < 4; ++k)
 
197
      iCh[k] = 0;
 
198
    uint w = A85Word(iCh);
 
199
    char buf[6];
 
200
    A85Encode(w, buf);
 
201
    buf[iN + 1] = '\0';
 
202
    iStream.PutCString(buf);
 
203
  }
 
204
  iStream.PutCString("~>\n");
 
205
  iStream.Close();
 
206
}
 
207
 
 
208
// --------------------------------------------------------------------
 
209
 
 
210
/*! \class IpeA85Source
 
211
  \ingroup high
 
212
  \brief Filter source adding ASCII85 decoding.
 
213
*/
 
214
 
 
215
IpeA85Source::IpeA85Source(IpeDataSource &source)
 
216
  : iSource(source)
 
217
{
 
218
  iEof = false;
 
219
  iN = 0;     // number of characters buffered
 
220
  iIndex = 0;  // next character to return
 
221
}
 
222
 
 
223
int IpeA85Source::GetChar()
 
224
{
 
225
  if (iIndex < iN)
 
226
    return iBuf[iIndex++];
 
227
 
 
228
  if (iEof)
 
229
    return EOF;
 
230
 
 
231
  int ch;
 
232
  do {
 
233
    ch = iSource.GetChar();
 
234
  } while (ch == '\n' || ch == '\r' || ch == ' ');
 
235
 
 
236
  if (ch == '~' || ch == EOF) {
 
237
    iEof = true;
 
238
    iN = 0;      // no more data, immediate EOF
 
239
    return EOF;
 
240
  }
 
241
 
 
242
  iIndex = 1;
 
243
  iN = 4;
 
244
 
 
245
  if (ch == 'z') {
 
246
    iBuf[0] = iBuf[1] = iBuf[2] = iBuf[3] = 0;
 
247
    return iBuf[0];
 
248
  }
 
249
 
 
250
  int c[5];
 
251
  c[0] = ch;
 
252
  for (int k = 1; k < 5; ++k) {
 
253
    do {
 
254
      c[k] = iSource.GetChar();
 
255
    } while (c[k] == '\n' || c[k] == '\r' || c[k] == ' ');
 
256
    if (c[k] == '~' || c[k] == EOF) {
 
257
      iN = k - 1;
 
258
      iEof = true;
 
259
      break;
 
260
    }
 
261
  }
 
262
 
 
263
  for (int k = iN + 1; k < 5; ++k)
 
264
    c[k] = 0x21 + 84;
 
265
 
 
266
  uint t = 0;
 
267
  for (int k = 0; k < 5; ++k)
 
268
    t = t * 85 + (c[k] - 0x21);
 
269
 
 
270
  for (int k = 3; k >= 0; --k) {
 
271
    iBuf[k] = char(t & 0xff);
 
272
    t >>= 8;
 
273
  }
 
274
 
 
275
  return iBuf[0];
 
276
};
 
277
 
 
278
// --------------------------------------------------------------------
 
279
 
 
280
/*! \class IpeDeflateStream
 
281
  \ingroup high
 
282
  \brief Filter stream adding flate compression.
 
283
*/
 
284
 
 
285
struct IpeDeflateStream::Private {
 
286
  z_stream iFlate;
 
287
};
 
288
 
 
289
IpeDeflateStream::IpeDeflateStream(IpeStream &stream, int level)
 
290
  : iStream(stream), iIn(0x400), iOut(0x400) // create buffers
 
291
{
 
292
  iPriv = new Private;
 
293
  z_streamp z = &iPriv->iFlate;
 
294
 
 
295
  z->zalloc = 0;
 
296
  z->zfree = 0;
 
297
  z->opaque = 0;
 
298
 
 
299
  int err = deflateInit(z, level);
 
300
  if (err != Z_OK) {
 
301
    ipeDebug("deflateInit returns error %d", err);
 
302
    assert(false);
 
303
  }
 
304
 
 
305
  iN = 0;
 
306
}
 
307
 
 
308
IpeDeflateStream::~IpeDeflateStream()
 
309
{
 
310
  if (iPriv) {
 
311
    z_streamp z = &iPriv->iFlate;
 
312
    deflateEnd(z);
 
313
    delete iPriv;
 
314
  }
 
315
}
 
316
 
 
317
void IpeDeflateStream::PutChar(char ch)
 
318
{
 
319
  iIn[iN++] = ch;
 
320
  if (iN < iIn.size())
 
321
    return;
 
322
 
 
323
  // compress and write
 
324
  z_streamp z = &iPriv->iFlate;
 
325
  z->next_in = (Bytef *) iIn.data();
 
326
  z->avail_in = iIn.size();
 
327
  while (z->avail_in) {
 
328
    z->next_out = (Bytef *) iOut.data();
 
329
    z->avail_out = iOut.size();
 
330
    int err = deflate(z, Z_NO_FLUSH);
 
331
    if (err != Z_OK) {
 
332
      ipeDebug("deflate returns error %d", err);
 
333
      assert(false);
 
334
    }
 
335
    // save output
 
336
    iStream.PutRaw(iOut.data(), z->next_out - (Bytef *) iOut.data());
 
337
  }
 
338
  iN = 0;
 
339
}
 
340
 
 
341
void IpeDeflateStream::Close()
 
342
{
 
343
  // compress and write remaining data
 
344
  z_streamp z = &iPriv->iFlate;
 
345
  z->next_in = (Bytef *) iIn.data();
 
346
  z->avail_in = iN;
 
347
 
 
348
  int err;
 
349
  do {
 
350
    z->next_out = (Bytef *) iOut.data();
 
351
    z->avail_out = iOut.size();
 
352
    err = deflate(z, Z_FINISH);
 
353
    if (err != Z_OK && err != Z_STREAM_END) {
 
354
      ipeDebug("deflate returns error %d", err);
 
355
      assert(false);
 
356
    }
 
357
    iStream.PutRaw(iOut.data(), z->next_out - (Bytef *) iOut.data());
 
358
  } while (err == Z_OK);
 
359
 
 
360
  err = deflateEnd(z);
 
361
  if (err != Z_OK) {
 
362
    ipeDebug("deflateEnd returns error %d", err);
 
363
    assert(false);
 
364
  }
 
365
 
 
366
  delete iPriv;
 
367
  iPriv = 0; // make sure no more writing possible
 
368
  iStream.Close();
 
369
}
 
370
 
 
371
//! Deflate a buffer in a single run.
 
372
/*! The returned buffer may be larger than necessary: \a deflatedSize is set to
 
373
  the number of bytes actually used. */
 
374
IpeBuffer IpeDeflateStream::Deflate(const char *data, int size, int &deflatedSize, int compressLevel)
 
375
{
 
376
  ulong dfsize = ulong(size * 1.001 + 13);
 
377
  IpeBuffer deflatedData(dfsize);
 
378
  int err = compress2((Bytef *) deflatedData.data(), &dfsize,
 
379
                      (const Bytef *) data, size, compressLevel);
 
380
  if (err != Z_OK) {
 
381
    ipeDebug("Zlib compress2 returns errror %d", err);
 
382
    assert(false);
 
383
  }
 
384
  deflatedSize = dfsize;
 
385
  return deflatedData;
 
386
}
 
387
 
 
388
// --------------------------------------------------------------------
 
389
 
 
390
/*! \class IpeInflateSource
 
391
  \ingroup high
 
392
  \brief Filter source adding flate decompression.
 
393
*/
 
394
 
 
395
struct IpeInflateSource::Private {
 
396
  z_stream iFlate;
 
397
};
 
398
 
 
399
IpeInflateSource::IpeInflateSource(IpeDataSource &source)
 
400
  : iSource(source), iIn(0x400), iOut(0x400)
 
401
{
 
402
  iPriv = new Private;
 
403
  z_streamp z = &iPriv->iFlate;
 
404
 
 
405
  z->zalloc = Z_NULL;
 
406
  z->zfree = Z_NULL;
 
407
  z->opaque = Z_NULL;
 
408
 
 
409
  FillBuffer();
 
410
 
 
411
  int err = inflateInit(z);
 
412
  if (err != Z_OK) {
 
413
    ipeDebug("inflateInit returns error %d", err);
 
414
    delete iPriv;
 
415
    iPriv = 0;  // set EOF
 
416
    return;
 
417
  }
 
418
 
 
419
  iP = iOut.data();
 
420
  z->next_out = (Bytef *) iP;
 
421
}
 
422
 
 
423
IpeInflateSource::~IpeInflateSource()
 
424
{
 
425
  if (iPriv) {
 
426
    z_streamp z = &iPriv->iFlate;
 
427
    inflateEnd(z);
 
428
    delete iPriv;
 
429
  }
 
430
}
 
431
 
 
432
void IpeInflateSource::FillBuffer()
 
433
{
 
434
  char *p = iIn.data();
 
435
  char *p1 = iIn.data() + iIn.size();
 
436
  z_streamp z = &iPriv->iFlate;
 
437
  z->next_in = (Bytef *) p;
 
438
  z->avail_in = 0;
 
439
  while (p < p1) {
 
440
    int ch = iSource.GetChar();
 
441
    if (ch == EOF)
 
442
      return;
 
443
    *p++ = char(ch);
 
444
    z->avail_in++;
 
445
  }
 
446
}
 
447
 
 
448
//! Get one more character, or EOF.
 
449
int IpeInflateSource::GetChar()
 
450
{
 
451
  if (!iPriv)
 
452
    return EOF;
 
453
 
 
454
  z_streamp z = &iPriv->iFlate;
 
455
  if (iP < (char *) z->next_out)
 
456
    return *iP++;
 
457
 
 
458
  // next to decompress some data
 
459
  if (z->avail_in == 0)
 
460
    FillBuffer();
 
461
 
 
462
  if (z->avail_in > 0) {
 
463
    // data is available
 
464
    z->next_out = (Bytef *) iOut.data();
 
465
    z->avail_out = iOut.size();
 
466
    int err = inflate(z, Z_NO_FLUSH);
 
467
    if (err != Z_OK && err != Z_STREAM_END) {
 
468
      ipeDebug("inflate returns error %d", err);
 
469
      inflateEnd(z);
 
470
      delete iPriv;
 
471
      iPriv = 0;  // set EOF
 
472
      return EOF;
 
473
    }
 
474
    iP = iOut.data();
 
475
    if (iP < (char *) z->next_out)
 
476
      return *iP++;
 
477
    // didn't get any new data, must be EOF
 
478
  }
 
479
 
 
480
  // FillBuffer didn't get any data, must be EOF, so we are done
 
481
  inflateEnd(z);
 
482
  delete iPriv;
 
483
  iPriv = 0;
 
484
  return EOF;
 
485
}
 
486
 
 
487
// --------------------------------------------------------------------