~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to krita/image/kis_transform_worker.cc

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2010-10-27 17:52:57 UTC
  • mfrom: (0.12.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20101027175257-s04zqqk5bs8ckm9o
Tags: 1:2.2.83-0ubuntu1
* Merge with Debian git remaining changes:
 - Add build-deps on librcps-dev, opengtl-dev, libqtgtl-dev, freetds-dev,
   create-resources, libspnav-dev
 - Remove needless build-dep on libwv2-dev
 - koffice-libs recommends create-resources
 - krita recommends pstoedit
 - Keep our patches
* New upstream release 2.3 beta 3
  - Remove debian/patches fixed by upstream
  - Update install files

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 *  Copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de> filters
3
3
 *  Copyright (c) 2005-2007 Casper Boemann <cbr@boemann.dk>
4
4
 *  Copyright (c) 2005, 2010 Boudewijn Rempt <boud@valdyas.org>
 
5
 *  Copyright (c) 2010 Marc Pegon <pe.marc@free.fr>
5
6
 *
6
7
 *  This program is free software; you can redistribute it and/or modify
7
8
 *  it under the terms of the GNU General Public License as published by
24
25
#include <KoProgressUpdater.h>
25
26
#include <KoColorSpace.h>
26
27
#include <KoCompositeOp.h>
 
28
#include <KoColor.h>
27
29
 
28
30
#include "kis_paint_device.h"
29
31
#include "kis_debug.h"
38
40
KisTransformWorker::KisTransformWorker(KisPaintDeviceSP dev,
39
41
                                       double xscale, double yscale,
40
42
                                       double xshear, double yshear,
 
43
                                       double xshearOrigin, double yshearOrigin,
41
44
                                       double rotation,
42
45
                                       qint32 xtranslate, qint32 ytranslate,
43
46
                                       KoUpdaterPtr progress,
49
52
    m_yscale = yscale;
50
53
    m_xshear = xshear;
51
54
    m_yshear = yshear;
 
55
    m_xshearOrigin = xshearOrigin;
 
56
    m_yshearOrigin = yshearOrigin;
52
57
    m_rotation = rotation,
53
 
                 m_xtranslate = xtranslate;
 
58
    m_xtranslate = xtranslate;
54
59
    m_ytranslate = ytranslate;
55
60
    m_progressUpdater = progress;
56
61
    m_filter = filter;
64
69
void KisTransformWorker::rotateNone(KisPaintDeviceSP src, KisPaintDeviceSP dst)
65
70
{
66
71
    qint32 pixelSize = src->pixelSize();
67
 
    QRect r;
 
72
    QRect r(m_boundRect);
68
73
    KoColorSpace *cs = src->colorSpace();
69
74
    Q_UNUSED(cs);
70
75
 
71
 
    r = src->exactBounds();
72
 
 
73
76
    KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), r.top(), r.width());
74
77
    KisHLineIterator vit = dst->createHLineIterator(r.x(), r.top(), r.width());
75
78
    for (qint32 i = 0; i < r.height(); ++i) {
97
100
void KisTransformWorker::rotateRight90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
98
101
{
99
102
    qint32 pixelSize = src->pixelSize();
100
 
    QRect r;
 
103
    QRect r(m_boundRect);
101
104
    KoColorSpace *cs = src->colorSpace();
102
105
    Q_UNUSED(cs);
103
 
    r = src->exactBounds();
104
106
 
105
107
    for (qint32 y = r.bottom(); y >= r.top(); --y) {
106
108
        KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width());
123
125
            break;
124
126
        }
125
127
    }
 
128
 
 
129
    m_boundRect = QRect(- r.bottom(), r.x(), r.height(), r.width());
126
130
}
127
131
 
128
132
void KisTransformWorker::rotateLeft90(KisPaintDeviceSP src, KisPaintDeviceSP dst)
129
133
{
130
134
    qint32 pixelSize = src->pixelSize();
131
 
    QRect r;
 
135
    QRect r(m_boundRect);
132
136
    KoColorSpace *cs = src->colorSpace();
133
137
    Q_UNUSED(cs);
134
 
    r = src->exactBounds();
135
138
 
136
139
    KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), r.top(), r.width());
137
140
 
148
151
        }
149
152
        hit.nextRow();
150
153
 
151
 
        //progress info
 
154
        // Progress info
152
155
        m_progressStep += r.width();
153
156
        if (m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps) {
154
157
            m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps;
158
161
            break;
159
162
        }
160
163
    }
 
164
 
 
165
    m_boundRect = QRect(r.top(), - r.x() - r.width(), r.height(), r.width());
161
166
}
162
167
 
163
168
void KisTransformWorker::rotate180(KisPaintDeviceSP src, KisPaintDeviceSP dst)
164
169
{
165
170
    qint32 pixelSize = src->pixelSize();
166
 
    QRect r;
 
171
    QRect r(m_boundRect);
167
172
    KoColorSpace *cs = src->colorSpace();
168
173
    Q_UNUSED(cs);
169
 
    r = src->exactBounds();
170
174
 
171
175
    KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), r.top(), r.width());
172
176
 
191
195
            break;
192
196
        }
193
197
    }
 
198
 
 
199
    m_boundRect = QRect(- r.x() - r.width(), - r.bottom(), r.width(), r.height());
194
200
}
195
201
 
196
202
template <class iter> iter createIterator(KisPaintDevice *dev, qint32 start, qint32 lineNum, qint32 len);
207
213
    return dev->createVLineIterator(lineNum, start, len);
208
214
}
209
215
 
210
 
template <class iter> void calcDimensions(KisPaintDevice *dev, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines);
 
216
template <class iter> void calcDimensions(QRect rc, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines);
211
217
 
212
218
template <> void calcDimensions <KisHLineIteratorPixel>
213
 
(KisPaintDevice *dev, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines)
 
219
(QRect rc, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines)
214
220
{
215
 
    QRect rc = dev->exactBounds();
216
221
    srcStart = rc.x();
217
222
    firstLine = rc.y();
218
223
    srcLen = rc.width();
220
225
}
221
226
 
222
227
template <> void calcDimensions <KisVLineIteratorPixel>
223
 
(KisPaintDevice *dev, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines)
 
228
(QRect rc, qint32 &srcStart, qint32 &srcLen, qint32 &firstLine, qint32 &numLines)
224
229
{
225
 
    QRect rc = dev->exactBounds();
226
230
    firstLine = rc.x();
227
231
    srcStart = rc.y();
228
232
    numLines = rc.width();
229
233
    srcLen = rc.height();
230
234
}
231
235
 
 
236
template <class iter> void updateBounds(QRect &boundRect, double floatscale, double shear, qint32 dx);
 
237
 
 
238
template <> void updateBounds <KisHLineIteratorPixel>
 
239
(QRect &boundRect, double floatscale, double shear, qint32 dx)
 
240
{
 
241
    QPoint topLeft(qFloor(boundRect.left() * floatscale + boundRect.top() * shear + dx), boundRect.top());
 
242
    QPoint topRight(qCeil(boundRect.right() * floatscale + boundRect.top() * shear + dx), boundRect.top());
 
243
    QPoint bottomRight(qCeil(boundRect.right() * floatscale + boundRect.bottom() * shear + dx), boundRect.bottom());
 
244
    QPoint bottomLeft(qFloor(boundRect.left() * floatscale + boundRect.bottom() * shear + dx), boundRect.bottom());
 
245
    QPolygon p;
 
246
    p << topLeft << topRight << bottomRight << bottomLeft;
 
247
    boundRect = p.boundingRect();
 
248
}
 
249
 
 
250
template <> void updateBounds <KisVLineIteratorPixel>
 
251
(QRect &boundRect, double floatscale, double shear, qint32 dx)
 
252
{
 
253
    QPoint topLeft(boundRect.left(), qFloor(boundRect.top() * floatscale + boundRect.left() * shear + dx));
 
254
    QPoint topRight(boundRect.right(), qFloor(boundRect.top() * floatscale + boundRect.right() * shear + dx));
 
255
    QPoint bottomRight(boundRect.right(), qCeil(boundRect.bottom() * floatscale + boundRect.right() * shear + dx));
 
256
    QPoint bottomLeft(boundRect.left(), qCeil(boundRect.bottom() * floatscale + boundRect.left() * shear + dx));
 
257
    QPolygon p;
 
258
    p << topLeft << topRight << bottomRight << bottomLeft;
 
259
    boundRect = p.boundingRect();
 
260
}
 
261
 
232
262
struct FilterValues {
233
263
    quint8 numWeights;
234
264
    qint16 *weight;
254
284
    qint32 shearFracOffset;
255
285
 
256
286
 
257
 
    calcDimensions <T>(src, srcStart, srcLen, firstLine, numLines);
 
287
    calcDimensions <T>(m_boundRect, srcStart, srcLen, firstLine, numLines);
258
288
 
259
289
    scale = int(floatscale * srcLen + 0.5);
 
290
    if (scale == 0) {
 
291
        dst->clear();
 
292
        return;
 
293
    }
 
294
 
260
295
    scaleDenom = srcLen;
261
296
 
262
 
    if (scaleDenom == 0)
 
297
    if (scaleDenom == 0) {
 
298
        updateBounds <T>(m_boundRect, floatscale, shear, dx);
263
299
        return;
 
300
    }
264
301
 
265
302
    qint32 support = filterStrategy->intSupport();
266
303
    qint32 dstLen, dstStart;
360
397
        while (i < srcLen + extraLen) {
361
398
            data = srcIt.rawData();
362
399
            memcpy(&tmpLine[i*pixelSize], data, pixelSize);
363
 
            cs->setOpacity(data, quint8(0), 1);
 
400
            memcpy(data, src->defaultPixel(), pixelSize);
364
401
            if (i < srcLen + extraLen - 1) // duplicate pixels along edge
365
402
                ++srcIt;
366
403
            i++;
426
463
    delete [] colors;
427
464
    delete [] tmpLine;
428
465
    delete [] filterWeights;
 
466
 
 
467
    updateBounds <T>(m_boundRect, floatscale, shear, dx);
429
468
}
430
469
 
431
470
bool KisTransformWorker::run()
432
471
{
433
 
//return false;
434
 
    //progress info
 
472
    /* Check for nonsense and let the user know, this helps debugging.
 
473
    Otherwise the program will crash at a later point, in a very obscure way, probably by division by zero */
 
474
    Q_ASSERT_X(m_xscale != 0, "KisTransformer::run() validation step", "xscale == 0");
 
475
    Q_ASSERT_X(m_yscale != 0, "KisTransformer::run() validation step", "yscale == 0");
 
476
    // Fallback safety line in case Krita is compiled without ASSERTS
 
477
    if (m_xscale == 0 || m_yscale == 0) return false;
 
478
    
 
479
    // Progress info
435
480
    m_progressTotalSteps = 0;
436
481
    m_progressStep = 0;
437
 
    QRect r = m_dev->exactBounds();
 
482
 
 
483
    KoColor defaultPixel(m_dev->defaultPixel(), m_dev->colorSpace());
 
484
    if (defaultPixel.opacityU8() != OPACITY_TRANSPARENT_U8)
 
485
        m_boundRect = m_dev->dataManager()->extent();
 
486
    else
 
487
        m_boundRect = m_dev->exactBounds();
 
488
 
 
489
    if (m_boundRect.isNull()) {
 
490
        if (!m_progressUpdater.isNull())
 
491
            m_progressUpdater->setProgress(100);
 
492
        return true;
 
493
    }
438
494
 
439
495
    KisPaintDeviceSP tmpdev1 = KisPaintDeviceSP(new KisPaintDevice(m_dev->colorSpace()));
440
496
    KisPaintDeviceSP srcdev = m_dev;
447
503
    qint32 xtranslate = m_xtranslate;
448
504
    qint32 ytranslate = m_ytranslate;
449
505
 
 
506
    m_progressTotalSteps = 0;
 
507
 
 
508
    // Apply shear X and Y
 
509
    if (xshear != 0 || yshear != 0) {
 
510
        m_progressTotalSteps += (yscale * m_boundRect.height() * (m_boundRect.width() + m_xshear * m_boundRect.height()));
 
511
        m_progressTotalSteps += (xscale * m_boundRect.width() * (m_boundRect.height() + m_yshear * m_boundRect.width()));
 
512
 
 
513
        int dx = - qRound(m_yshearOrigin * yscale * m_xshear);
 
514
        int dy = - qRound(m_xshearOrigin * xscale * m_yshear);
 
515
        transformPass <KisHLineIteratorPixel>(srcdev.data(), srcdev.data(), xscale, yscale *  m_xshear, dx, m_filter, m_fixBorderAlpha);
 
516
        transformPass <KisVLineIteratorPixel>(srcdev.data(), srcdev.data(), yscale, m_yshear, dy, m_filter, m_fixBorderAlpha);
 
517
        yscale = 1.;
 
518
        xscale = 1.;
 
519
    }
 
520
 
450
521
    if (rotation < 0.0)
451
522
        rotation = -fmod(-rotation, 2 * M_PI) + 2 * M_PI;
452
523
    else
458
529
    switch (rotQuadrant) {
459
530
    default: // just to shut up the compiler
460
531
    case 0:
461
 
        m_progressTotalSteps = 0;
 
532
        m_progressTotalSteps += 0;
462
533
        break;
463
534
    case 1:
464
535
        rotation -= M_PI / 2;
465
536
        tmp = xscale;
466
537
        xscale = yscale;
467
538
        yscale = tmp;
468
 
        m_progressTotalSteps = r.width() * r.height();
 
539
        m_progressTotalSteps += m_boundRect.width() * m_boundRect.height();
469
540
        break;
470
541
    case 2:
471
542
        rotation -= M_PI;
472
 
        m_progressTotalSteps = r.width() * r.height();
 
543
        m_progressTotalSteps += m_boundRect.width() * m_boundRect.height();
473
544
        break;
474
545
    case 3:
475
546
        rotation -= -M_PI / 2 + 2 * M_PI;
476
547
        tmp = xscale;
477
548
        xscale = yscale;
478
549
        yscale = tmp;
479
 
        m_progressTotalSteps = r.width() * r.height();
 
550
        m_progressTotalSteps += m_boundRect.width() * m_boundRect.height();
480
551
        break;
481
552
    }
482
553
 
483
 
    // Calculate some auxillary values
 
554
    //// Calculate some auxillary values
484
555
    yshear = sin(rotation);
485
556
    xshear = -tan(rotation / 2);
486
557
    xtranslate -= int(xshear * ytranslate);
487
558
 
488
559
    // Calculate progress steps
489
 
    m_progressTotalSteps += int(yscale * r.width() * r.height());
490
 
    m_progressTotalSteps += int(xscale * r.width() * (r.height() * yscale + r.width() * yshear));
491
 
 
492
 
    m_lastProgressReport = 0;
 
560
    m_progressTotalSteps += int(yscale * m_boundRect.width() * m_boundRect.height());
 
561
    m_progressTotalSteps += int(xscale * m_boundRect.width() * (m_boundRect.height() * yscale + m_boundRect.width() * yshear));
493
562
 
494
563
    // Now that we have everything in place it's time to do the actual right angle rotations
495
564
    switch (rotQuadrant) {
513
582
        break;
514
583
    }
515
584
 
516
 
    // Handle simple move case possibly with rotation of 90,180,270
 
585
    //// Handle simple move case possibly with rotation of 90,180,270
517
586
    if (rotation == 0.0 && xscale == 1.0 && yscale == 1.0) {
 
587
        m_boundRect.translate(xtranslate, ytranslate);
518
588
        if (rotQuadrant == 0) {
519
589
            // When we didn't move the m_dev to a temp device we can simply just move its coords
520
590
            srcdev->move(srcdev->x() + xtranslate, srcdev->y() + ytranslate);
524
594
        }
525
595
        //progress info
526
596
        if (!m_progressUpdater.isNull()) m_progressUpdater->setProgress(100);
527
 
        return false;
528
 
 
 
597
        return true;
529
598
    }
530
599
 
531
600
    if (!m_progressUpdater.isNull() && m_progressUpdater->interrupted()) {
533
602
        return false;
534
603
    }
535
604
 
 
605
    // First pass
536
606
    transformPass <KisHLineIteratorPixel>(srcdev.data(), srcdev.data(), xscale, yscale*xshear, 0, m_filter, m_fixBorderAlpha);
537
607
 
538
608
    if (!m_progressUpdater.isNull() && m_progressUpdater->interrupted()) {
548
618
        return false;
549
619
    }
550
620
 
551
 
    if (xshear != 0.0)
 
621
    if (xshear != 0.0) {
552
622
        transformPass <KisHLineIteratorPixel>(srcdev.data(), m_dev.data(), 1.0, xshear, xtranslate, m_filter, m_fixBorderAlpha);
553
 
    else {
 
623
    } else {
554
624
        // No need to filter again when we are only scaling
555
625
        srcdev->move(srcdev->x() + xtranslate, srcdev->y());
556
626
        if (rotQuadrant != 0)  // no need to copy back if we have not copied the device in the first place
559
629
 
560
630
    //CBRm_dev->setDirty();
561
631
 
562
 
    //progress info
 
632
    // Progress info
563
633
    if (!m_progressUpdater.isNull()) m_progressUpdater->setProgress(100);
564
 
 
565
634
    if (!m_progressUpdater.isNull()) return m_progressUpdater->interrupted();
 
635
    
566
636
    return true;
567
637
}
568
638
 
575
645
    if (selection) {
576
646
        r = selection->selectedExactRect();
577
647
    } else {
578
 
        r = dev->exactBounds();
 
648
        KoColor defaultPixel(dev->defaultPixel(), dev->colorSpace());
 
649
        if (defaultPixel.opacityU8() != OPACITY_TRANSPARENT_U8)
 
650
            r = dev->dataManager()->extent();
 
651
        else
 
652
            r = dev->exactBounds();
579
653
    }
580
654
    {
581
655
        KisHLineConstIteratorPixel srcIt = dev->createHLineConstIterator(r.x(), r.top(), r.width(), selection);
621
695
    if (selection) {
622
696
        r = selection->selectedExactRect();
623
697
    } else {
624
 
        r = dev->exactBounds();
 
698
        KoColor defaultPixel(dev->defaultPixel(), dev->colorSpace());
 
699
        if (defaultPixel.opacityU8() != OPACITY_TRANSPARENT_U8)
 
700
            r = dev->dataManager()->extent();
 
701
        else
 
702
            r = dev->exactBounds();
625
703
    }
626
704
    {
627
705
        qint32 y1, y2;