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

« back to all changes in this revision

Viewing changes to src/ipelets/image/image.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2009-12-11 21:22:35 UTC
  • mfrom: (4.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20091211212235-5iio4nzpra64snab
Tags: 7.0.10-1
* New upstream.  Closes: #551192.
  - New build-depends: libcairo2-dev, liblua5.1-0-dev, gsfonts
  - patches/config.diff: Remove.  Upstream build system replaced.
  - Runtime lib package changed to libipe7.0.10 from libipe1c2a
  - Devel package renamed to libipe-dev (from libipe1-dev)
  - Package ipe depends on lua5.1 due to ipe-update-master.

* rules: Re-write to use dh.

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
/*
5
5
 
6
6
    This file is part of the extensible drawing editor Ipe.
7
 
    Copyright (C) 1993-2007  Otfried Cheong
 
7
    Copyright (C) 1993-2009  Otfried Cheong
8
8
 
9
9
    Ipe is free software; you can redistribute it and/or modify it
10
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
 
11
    the Free Software Foundation; either version 3 of the License, or
12
12
    (at your option) any later version.
13
13
 
14
14
    As a special exception, you have permission to link Ipe with the
37
37
#include <QClipboard>
38
38
#include <QApplication>
39
39
 
 
40
using namespace ipe;
 
41
 
40
42
// --------------------------------------------------------------------
41
43
 
42
44
/*
134
136
 
135
137
class ImageIpelet : public Ipelet {
136
138
public:
137
 
  virtual int IpelibVersion() const { return IPELIB_VERSION; }
138
 
  virtual int NumFunctions() const { return 3; }
139
 
  virtual const char *SubLabel(int function) const;
140
 
  virtual const char *Label() const { return "Insert image"; }
141
 
  virtual void Run(int, IpePage *page, IpeletHelper *helper);
142
 
private:
143
 
  void InsertBitmap(IpePage *page, IpeletHelper *helper, QString name);
144
 
  void InsertJpeg(IpePage *page, IpeletHelper *helper, QString name);
145
 
  void Fail(QString msg);
146
 
  void Fail(const char *msg) { Fail(QLatin1String(msg)); }
147
 
  bool ReadJpegInfo(QFile &file);
148
 
  IpeRect ComputeRect(IpeletHelper *helper);
149
 
private:
 
139
  virtual int ipelibVersion() const { return IPELIB_VERSION; }
 
140
  virtual bool run(int fn, IpeletData *data, IpeletHelper *helper);
 
141
 
 
142
private:
 
143
  bool insertBitmap(QString name);
 
144
  bool insertJpeg(QString name);
 
145
  void fail(QString msg);
 
146
  void fail(const char *msg) { fail(QLatin1String(msg)); }
 
147
  bool readJpegInfo(QFile &file);
 
148
  Rect computeRect();
 
149
 
 
150
private:
 
151
  IpeletData *iData;
150
152
  int iWidth;
151
153
  int iHeight;
152
 
  IpeBitmap::TColorSpace iColorSpace;
 
154
  Bitmap::TColorSpace iColorSpace;
153
155
  int iBitsPerComponent;
154
 
  IpeVector iDotsPerInch;
 
156
  Vector iDotsPerInch;
155
157
};
156
158
 
157
159
// --------------------------------------------------------------------
158
160
 
159
 
const char * const sublabel[] = {
160
 
  "Insert JPEG image",
161
 
  "Insert bitmap image",
162
 
  "Insert bitmap from clipboard"
163
 
};
164
 
 
165
 
const char *ImageIpelet::SubLabel(int function) const
166
 
{
167
 
  return sublabel[function];
168
 
}
169
 
 
170
 
void ImageIpelet::Run(int fn, IpePage *page, IpeletHelper *helper)
171
 
{
 
161
bool ImageIpelet::run(int fn, IpeletData *data, IpeletHelper *helper)
 
162
{
 
163
  iData = data;
172
164
  QString name;
173
165
  if (fn != 2) {
174
166
    name = QFileDialog::getOpenFileName();
175
167
    if (name.isNull())
176
 
      return;
 
168
      return false;
177
169
  }
178
170
  switch (fn) {
179
 
  case 0: // JPEG
180
 
    InsertJpeg(page, helper, name);
181
 
    break;
182
 
  case 1: // bitmap
183
 
    InsertBitmap(page, helper, name);
184
 
    break;
 
171
  case 0: // bitmap
 
172
    return insertBitmap(name);
 
173
  case 1: // JPEG
 
174
    return insertJpeg(name);
185
175
  case 2: // bitmap from clipboard
186
 
    InsertBitmap(page, helper, QString::null);
187
 
    break;
 
176
    return insertBitmap(QString::null);
188
177
  default:
189
 
    break;
 
178
    return false;
190
179
  }
191
180
}
192
181
 
193
 
void ImageIpelet::Fail(QString msg)
 
182
void ImageIpelet::fail(QString msg)
194
183
{
195
 
  QMessageBox::information(0, QLatin1String("Insert image ipelet"),
196
 
                           QLatin1String("<qt>") + msg
197
 
                           + QLatin1String("</qt>"), QLatin1String("Dismiss"));
 
184
  QMessageBox::warning(0, QLatin1String("Insert image ipelet"),
 
185
                       QLatin1String("<qt>") + msg
 
186
                       + QLatin1String("</qt>"),
 
187
                       QLatin1String("Dismiss"));
198
188
}
199
189
 
200
190
// --------------------------------------------------------------------
201
191
 
202
 
IpeRect ImageIpelet::ComputeRect(IpeletHelper *helper)
 
192
Rect ImageIpelet::computeRect()
203
193
{
204
 
  IpeVector frame = helper->Document()->layout().iFrameSize;
 
194
  Vector frame = iData->iDoc->cascade()->findLayout()->iFrameSize;
205
195
 
206
 
  double dx = (iWidth * 72.0) / iDotsPerInch.iX;
207
 
  double dy = (iHeight * 72.0) / iDotsPerInch.iY;
 
196
  double dx = (iWidth * 72.0) / iDotsPerInch.x;
 
197
  double dy = (iHeight * 72.0) / iDotsPerInch.y;
208
198
 
209
199
  double xfactor = 1.0;
210
 
  if (dx > frame.iX)
211
 
    xfactor = frame.iX / dx;
 
200
  if (dx > frame.x)
 
201
    xfactor = frame.x / dx;
212
202
  double yfactor = 1.0;
213
 
  if (dy > frame.iY)
214
 
    yfactor = frame.iY / dy;
 
203
  if (dy > frame.y)
 
204
    yfactor = frame.y / dy;
215
205
  double factor = (xfactor < yfactor) ? xfactor : yfactor;
216
 
  IpeRect rect(IpeVector::Zero, factor * IpeVector(dx, dy));
217
 
  IpeVector v = 0.5 * IpeVector(frame.iX - (rect.Min().iX + rect.Max().iX),
218
 
                                frame.iY - (rect.Min().iY + rect.Max().iY));
219
 
  return IpeRect(rect.Min() + v, rect.Max() + v);
 
206
  Rect rect(Vector::ZERO, factor * Vector(dx, dy));
 
207
  Vector v = 0.5 * Vector(frame.x - (rect.left() + rect.right()),
 
208
                          frame.y - (rect.bottom() + rect.top()));
 
209
  return Rect(rect.bottomLeft() + v, rect.topRight() + v);
220
210
}
221
211
 
222
212
// --------------------------------------------------------------------
224
214
// 72 points per inch
225
215
const double InchPerMeter = (1000.0 / 25.4);
226
216
 
227
 
void ImageIpelet::InsertBitmap(IpePage *page, IpeletHelper *helper,
228
 
                               QString name)
 
217
bool ImageIpelet::insertBitmap(QString name)
229
218
{
230
 
  qDebug("InsertBitmap");
 
219
  ipeDebug("insertBitmap");
231
220
  QImage im;
232
221
  if (name.isNull()) {
233
222
    QClipboard *cb = QApplication::clipboard();
234
 
    qDebug("about to retrieve image");
 
223
    ipeDebug("about to retrieve image");
235
224
    im = cb->image();
236
 
    qDebug("image retrieved %d", im.width());
 
225
    ipeDebug("image retrieved %d", im.width());
237
226
    if (im.isNull()) {
238
 
      Fail("The clipboard contains no image, or perhaps\n"
 
227
      fail("The clipboard contains no image, or perhaps\n"
239
228
           "an image in a format not supported by Qt.");
240
 
      return;
 
229
      return false;
241
230
    }
242
231
  } else {
243
232
    if (!im.load(name)) {
244
 
      Fail("The image could not be loaded.\n"
 
233
      fail("The image could not be loaded.\n"
245
234
           "Perhaps the format is not supported by Qt.");
246
 
      return;
 
235
      return false;
247
236
    }
248
237
  }
249
 
  QImage im1 = im.convertToFormat(QImage::Format_RGB32);
 
238
  QImage im1 = im.convertToFormat(QImage::Format_ARGB32);
250
239
  iWidth = im1.width();
251
240
  iHeight = im1.height();
252
 
  iDotsPerInch = IpeVector(72, 72);
 
241
  iDotsPerInch = Vector(72, 72);
253
242
 
254
243
  if (im1.dotsPerMeterX())
255
 
    iDotsPerInch.iX = double(im1.dotsPerMeterX()) / InchPerMeter;
 
244
    iDotsPerInch.x = double(im1.dotsPerMeterX()) / InchPerMeter;
256
245
  if (im1.dotsPerMeterY())
257
 
    iDotsPerInch.iY = double(im1.dotsPerMeterY()) / InchPerMeter;
 
246
    iDotsPerInch.y = double(im1.dotsPerMeterY()) / InchPerMeter;
258
247
 
259
248
  bool isGray = im1.allGray();
260
 
  iColorSpace = isGray ? IpeBitmap::EDeviceGray : IpeBitmap::EDeviceRGB;
 
249
  bool hasAlpha = false;
 
250
  uint colorKey = 0;
 
251
 
 
252
  iColorSpace = isGray ? Bitmap::EDeviceGray : Bitmap::EDeviceRGB;
261
253
  int datalen = iWidth * iHeight * (isGray ? 1 : 3);
262
 
  IpeBuffer data(datalen);
 
254
  Buffer data(datalen);
263
255
  char *d = data.data();
264
256
  for (int y = 0; y < iHeight; ++y) {
265
257
    uint *p = (uint *) im1.scanLine(y);
266
258
    for (int x = 0; x < iWidth; ++x) {
 
259
      if (qAlpha(*p) != 0xff) {
 
260
        hasAlpha = true;
 
261
        colorKey = (*p & 0x00ffffff);
 
262
      }
267
263
      if (isGray) {
268
264
        *d++ = qRed(*p++);
269
265
      } else {
274
270
    }
275
271
  }
276
272
 
277
 
  IpeBitmap bitmap(iWidth, iHeight, iColorSpace, 8, data,
278
 
                   IpeBitmap::EDirect, true);
279
 
  IpeImage *obj = new IpeImage(ComputeRect(helper), bitmap);
280
 
  page->push_back(IpePgObject(IpePgObject::ESecondary,
281
 
                              helper->CurrentLayer(), obj));
 
273
  // determine if image has a color key
 
274
  bool hasColorKey = hasAlpha;
 
275
  if (hasAlpha) {
 
276
    for (int y = 0; hasColorKey && y < iHeight; ++y) {
 
277
      uint *p = (uint *) im1.scanLine(y);
 
278
      for (int x = 0; hasColorKey && x < iWidth; ++x, ++p) {
 
279
        int alpha = qAlpha(*p);
 
280
        if ((alpha == 0 && *p != colorKey) ||
 
281
            (alpha != 0 && alpha != 0xff) ||
 
282
            (alpha == 0xff && (*p & 0x00ffffff) == colorKey))
 
283
          hasColorKey = false;
 
284
      }
 
285
    }
 
286
  }
 
287
 
 
288
  ipeDebug("hasAlpha: %d, colorkeyed %d: %x", hasAlpha, hasColorKey, colorKey);
 
289
 
 
290
  Bitmap bitmap(iWidth, iHeight, iColorSpace, 8, data, Bitmap::EDirect, true);
 
291
  if (hasColorKey)
 
292
    bitmap.setColorKey(colorKey);
 
293
 
 
294
  Image *obj = new Image(computeRect(), bitmap);
 
295
  iData->iPage->append(ESecondarySelected, iData->iLayer, obj);
 
296
  return true;
282
297
}
283
298
 
284
299
// --------------------------------------------------------------------
285
300
 
286
 
bool ImageIpelet::ReadJpegInfo(QFile &file)
 
301
bool ImageIpelet::readJpegInfo(QFile &file)
287
302
{
288
303
  static char jpg_id[] = "JFIF";
289
304
  char units;
292
307
  int fpos;
293
308
  char ch;
294
309
 
295
 
  iDotsPerInch = IpeVector(72.0, 72.0);
 
310
  iDotsPerInch = Vector(72.0, 72.0);
296
311
 
297
312
  file.seek(0);
298
313
  if (read2bytes(file) != 0xFFD8) {
299
 
    Fail("The file does not appear to be a JPEG image");
 
314
    fail("The file does not appear to be a JPEG image");
300
315
    return false;
301
316
  }
302
317
  if (read2bytes(file) == 0xFFE0) { /* JFIF APP0 */
304
319
    for (int i = 0; i < 5; i++) {
305
320
      file.getChar(&ch);
306
321
      if (ch != jpg_id[i]) {
307
 
        Fail("Reading JPEG image failed");
 
322
        fail("Reading JPEG image failed");
308
323
        return false;
309
324
      }
310
325
    }
315
330
    if (xres != 0 && yres != 0) {
316
331
      switch (units) {
317
332
      case 1: /* pixels per inch */
318
 
        iDotsPerInch = IpeVector(xres, yres);
 
333
        iDotsPerInch = Vector(xres, yres);
319
334
        break;
320
335
      case 2: /* pixels per cm */
321
 
        iDotsPerInch = IpeVector(xres * 2.54, yres * 2.54);
 
336
        iDotsPerInch = Vector(xres * 2.54, yres * 2.54);
322
337
        break;
323
338
      default:
324
339
        break;
329
344
  file.seek(0);
330
345
  while(1) {
331
346
    if (file.atEnd() || (file.getChar(&ch), ch != char(0xFF))) {
332
 
      Fail("Reading JPEG image failed");
 
347
      fail("Reading JPEG image failed");
333
348
      return false;
334
349
    }
335
350
    file.getChar(&ch);
343
358
    case M_SOF13:
344
359
    case M_SOF14:
345
360
    case M_SOF15:
346
 
      Fail("Unsupported type of JPEG compression");
 
361
      fail("Unsupported type of JPEG compression");
347
362
      return false;
348
363
    case M_SOF2:
349
364
      //if (cfgpar(cfgpdf12compliantcode) > 0)
359
374
      file.getChar(&ch);
360
375
      switch (ch & 0xff) {
361
376
      case JPG_GRAY:
362
 
        iColorSpace = IpeBitmap::EDeviceGray;
 
377
        iColorSpace = Bitmap::EDeviceGray;
363
378
        break;
364
379
      case JPG_RGB:
365
 
        iColorSpace = IpeBitmap::EDeviceRGB;
 
380
        iColorSpace = Bitmap::EDeviceRGB;
366
381
        break;
367
382
      case JPG_CMYK:
368
 
        iColorSpace = IpeBitmap::EDeviceCMYK;
 
383
        iColorSpace = Bitmap::EDeviceCMYK;
369
384
        // pdf_puts("/DeviceCMYK\n/Decode [1 0 1 0 1 0 1 0]\n");
370
385
        break;
371
386
      default:
372
 
        Fail("Unsupported color space in JPEG image");
 
387
        fail("Unsupported color space in JPEG image");
373
388
        return false;
374
389
      }
375
390
      file.seek(0);
394
409
  }
395
410
}
396
411
 
397
 
void ImageIpelet::InsertJpeg(IpePage *page, IpeletHelper *helper,
398
 
                             QString name)
 
412
bool ImageIpelet::insertJpeg(QString name)
399
413
{
400
414
  QFile file(name);
401
415
  if (!file.open(QIODevice::ReadOnly)) {
402
 
    Fail(QString(QLatin1String("Could not open file '%1'")).arg(name));
403
 
    return;
 
416
    fail(QString(QLatin1String("Could not open file '%1'")).arg(name));
 
417
    return false;
404
418
  }
405
 
  if (!ReadJpegInfo(file))
406
 
    return;
 
419
  if (!readJpegInfo(file))
 
420
    return false;
407
421
 
408
422
  QByteArray a = file.readAll();
409
423
  file.close();
410
424
 
411
 
  IpeBitmap bitmap(iWidth, iHeight, iColorSpace,
412
 
                   iBitsPerComponent, IpeBuffer(a.data(), a.size()),
413
 
                   IpeBitmap::EDCTDecode);
414
 
  IpeImage *obj = new IpeImage(ComputeRect(helper), bitmap);
415
 
  page->push_back(IpePgObject(IpePgObject::ESecondary,
416
 
                              helper->CurrentLayer(), obj));
 
425
  Bitmap bitmap(iWidth, iHeight, iColorSpace,
 
426
                iBitsPerComponent, Buffer(a.data(), a.size()),
 
427
                Bitmap::EDCTDecode);
 
428
  Image *obj = new Image(computeRect(), bitmap);
 
429
  iData->iPage->append(ESecondarySelected, iData->iLayer, obj);
 
430
  return true;
417
431
}
418
432
 
419
433
// --------------------------------------------------------------------
420
434
 
421
 
IPELET_DECLARE Ipelet *NewIpelet()
 
435
IPELET_DECLARE Ipelet *newIpelet()
422
436
{
423
437
  return new ImageIpelet;
424
438
}