2
Copyright (C) 1998, 1999, 2001, 2002, 2004, 2005, 2007
3
Daniel M. Duley <daniel.duley@verizon.net>
4
(C) 2000 Josef Weidendorfer <weidendo@in.tum.de>
5
(C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
7
Redistribution and use in source and binary forms, with or without
8
modification, are permitted provided that the following conditions
11
1. Redistributions of source code must retain the above copyright
12
notice, this list of conditions and the following disclaimer.
13
2. Redistributions in binary form must reproduce the above copyright
14
notice, this list of conditions and the following disclaimer in the
15
documentation and/or other materials provided with the distribution.
17
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
#include "qimageblitz.h"
31
#include <config-processor.h>
32
#include "private/inlinehsv.h"
33
#include "private/blitz_p.h"
37
#if defined(__i386__) && ( defined(__GNUC__) || defined(__INTEL_COMPILER) )
38
# if defined(HAVE_MMX )
39
# define USE_MMX_INLINE_ASM
44
* Precalculated increment values for HSV contrast. Saves some expensive
45
* floating point math. These are half the integer results of:
47
* alpha*(alpha*(sin(M_PI*(brightness-alpha))+1.0)-brightness)
49
* where alpha is 0.5+M_EPSILON and brightness is the percentage for values
50
* ranging from 0 to 255, (Qt compatible HSV brightness values). The other
51
* half of the lookup table is the inverse of these values. I am so clever :)
54
static char contrast_table[128] = {
55
0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9,
56
10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17,
57
17, 18, 18, 19, 19, 19, 20, 20, 21, 21, 21, 22, 22, 22, 23,
58
23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 25, 26, 26, 26, 26,
59
26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
60
27, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 24, 24, 24,
61
23, 23, 23, 22, 22, 21, 21, 20, 20, 20, 19, 18, 18, 17, 17,
62
16, 16, 15, 14, 14, 13, 12, 11, 11, 10, 9, 8, 7, 7, 6, 5,
66
bool Blitz::grayscale(QImage &img, bool reduceDepth)
71
if(img.format() == QImage::Format_ARGB32_Premultiplied)
72
img = img.convertToFormat(QImage::Format_ARGB32);
73
else if(img.depth() < 8)
74
img = img.convertToFormat(QImage::Format_Indexed8);
76
#ifdef USE_MMX_INLINE_ASM
78
#warning Using MMX grayscale
80
if(BlitzCPUInfo::haveExtension(BlitzCPUInfo::IntegerSSE)){
81
MMX::Pack4 packedmult = {{5, 16, 11, 1}};
82
MMX::Pack4 alphamask = {{0x0000, 0x0000, 0x0000, 0xFFFF}};
83
MMX::Pack4 noalphamask = {{0xFFFF, 0xFFFF, 0xFFFF, 0x0000}};
85
if(reduceDepth && !img.hasAlphaChannel()){
86
int y, w = img.width(), h = img.height();
87
QImage buffer(w, h, QImage::Format_Indexed8);
89
QVector<QRgb> cTable(256);
90
unsigned int *src = cTable.data();
91
for(y=0; y < 256; ++y)
92
*src++ = qRgb(y, y, y);
93
buffer.setColorTable(cTable);
95
src = (unsigned int *)img.scanLine(0);
96
unsigned char *end, *dest;
99
("pxor %%mm7, %%mm7\n\t"
100
"movq (%0), %%mm4\n\t"
101
"movq (%1), %%mm5\n\t"
102
"movq (%2), %%mm6\n\t"
103
: : "r"(&packedmult), "r"(&alphamask), "r"(&noalphamask));
104
for(y=0; y < h; ++y){
105
dest = buffer.scanLine(y);
109
("movd (%0), %%mm0\n\t" // load pixel
110
"punpcklbw %%mm7, %%mm0\n\t" // upgrade to quad
111
"pand %%mm6, %%mm0\n\t" // zero alpha so we can use pmaddwd
113
"pmaddwd %%mm4, %%mm0\n\t" // 2 multiplies and sum BG, RA
114
"pshufw $0xE4, %%mm0, %%mm1\n\t"
115
"punpckhwd %%mm7, %%mm1\n\t" // sum R
116
"paddw %%mm1, %%mm0\n\t"
117
"psrlw $0x05, %%mm0\n\t" // divide by 32
118
"movd %%mm0, %%eax\n\t"
119
"movb %%al, (%1)\n\t"
120
: : "r"(src), "r"(dest) : "%eax");
125
__asm__ __volatile__ ("emms\n\t" : :);
129
// 8bpp or 32bpp w/ no conversion
130
int count = img.depth() > 8 ? img.width()*img.height() : img.numColors();
132
QVector<QRgb> cTable;
134
cTable = img.colorTable();
136
unsigned int *data = (img.depth() > 8) ?
137
(unsigned int *)img.scanLine(0) : cTable.data();
138
unsigned int *end = data+count;
141
("pxor %%mm7, %%mm7\n\t"
142
"movq (%0), %%mm4\n\t"
143
"movq (%1), %%mm5\n\t"
144
"movq (%2), %%mm6\n\t"
145
: : "r"(&packedmult), "r"(&alphamask), "r"(&noalphamask));
148
("movd (%0), %%mm0\n\t" // load pixel
149
"punpcklbw %%mm7, %%mm0\n\t" // upgrade to quad
150
"pshufw $0xE4, %%mm0, %%mm2\n\t" // copy for alpha later
151
"pand %%mm6, %%mm0\n\t" // zero alpha so we can use pmaddwd
153
"pmaddwd %%mm4, %%mm0\n\t" // 2 multiplies and sum BG, RA
154
"pshufw $0xE4, %%mm0, %%mm1\n\t"
155
"punpckhwd %%mm7, %%mm1\n\t" // sum R
156
"paddw %%mm1, %%mm0\n\t"
157
"psrlw $0x05, %%mm0\n\t" // divide by 32
159
"pshufw $0x00, %%mm0, %%mm0\n\t" // copy to all pixels
160
"pand %%mm6, %%mm0\n\t" // reset original alpha
161
"pand %%mm5, %%mm2\n\t"
162
"por %%mm2, %%mm0\n\t"
164
"packuswb %%mm0, %%mm0\n\t" // pack and write
165
"movd %%mm0, (%0)\n\t"
169
__asm__ __volatile__ ("emms\n\t" : :);
171
img.setColorTable(cTable);
178
if(reduceDepth && img.format() == QImage::Format_RGB32){
179
// 32bpp w/ conversion to palette
180
int y, w = img.width(), h = img.height();
181
QImage buffer(w, h, QImage::Format_Indexed8);
183
QVector<QRgb> cTable(256);
184
unsigned int *src = cTable.data();
185
for(y=0; y < 256; ++y)
186
*src++ = qRgb(y, y, y);
187
buffer.setColorTable(cTable);
189
src = (unsigned int *)img.scanLine(0);
190
unsigned char *end, *dest;
192
for(y=0; y < h; ++y){
193
dest = buffer.scanLine(y);
197
*dest++ = qGray(qRed(pixel), qGreen(pixel), qBlue(pixel));
203
// 8bpp or 32bpp w/ no conversion
204
int count = img.depth() > 8 ? img.width()*img.height() : img.numColors();
206
QVector<QRgb> cTable;
208
cTable = img.colorTable();
210
unsigned int *data = (img.depth() > 8) ?
211
(unsigned int *)img.scanLine(0) : cTable.data();
212
unsigned int *end = data+count;
217
c = qGray(qRed(pixel), qGreen(pixel), qBlue(pixel));
218
*data++ = qRgba(c, c, c, qAlpha(pixel));
221
img.setColorTable(cTable);
227
bool Blitz::invert(QImage &img, QImage::InvertMode mode)
232
#ifdef USE_MMX_INLINE_ASM
234
#warning Using MMX invert
236
if(BlitzCPUInfo::haveExtension(BlitzCPUInfo::MMX)){
237
if(img.format() == QImage::Format_ARGB32_Premultiplied)
238
img = img.convertToFormat(QImage::Format_ARGB32);
239
else if(img.depth() < 8)
240
img = img.convertToFormat(QImage::Format_Indexed8);
242
unsigned int mask = (mode == QImage::InvertRgba ? 0xFFFFFFFF :
244
MMX::Pack2 packedmask = {{mask, mask}};
246
int remainder, count;
247
unsigned int *data, *end;
248
QVector<QRgb> cTable;
250
if(img.depth() <= 8){
251
cTable = img.colorTable();
252
remainder = img.numColors() % 4;
253
count = img.numColors()-remainder;
254
data = (unsigned int *)cTable.data();
257
remainder = (img.width()*img.height()) % 4;
258
count = (img.width()*img.height())-remainder;
259
data = (unsigned int *)img.scanLine(0);
263
__asm__ __volatile__ ("movq (%0), %%mm7\n\t" : : "r"(&packedmask));
266
("movq (%0), %%mm0\n\t"
267
"pxor %%mm7, %%mm0\n\t"
268
"movq %%mm0, (%0)\n\t"
275
("movd (%0), %%mm0\n\t"
276
"pxor %%mm7, %%mm0\n\t"
277
"movd %%mm0, (%0)\n\t"
281
__asm__ __volatile__ ("emms\n\t" : :);
283
img.setColorTable(cTable);
288
img.invertPixels(mode);
293
QImage& Blitz::contrast(QImage &img, bool sharpen, int weight)
298
if(img.format() == QImage::Format_ARGB32_Premultiplied)
299
img = img.convertToFormat(QImage::Format_ARGB32);
300
else if(img.depth() < 8)
301
img = img.convertToFormat(QImage::Format_Indexed8);
303
QVector<QRgb> cTable;
305
cTable = img.colorTable();
307
unsigned int *end, *data;
310
count = img.width()*img.height();
311
data = (unsigned int *)img.scanLine(0);
314
count = img.numColors();
315
data = (unsigned int *)cTable.data();
323
hsv.convertRGB2HSV(*data);
326
v += contrast_table[v-128]+weight;
330
v -= contrast_table[v]+weight;
334
hsv.convertHSV2RGB();
335
*data = qRgba(hsv.red(), hsv.green(), hsv.blue(), qAlpha(*data));
341
hsv.convertRGB2HSV(*data);
344
v -= contrast_table[v-128]+weight;
348
v += contrast_table[v]+weight;
352
hsv.convertHSV2RGB();
353
*data = qRgba(hsv.red(), hsv.green(), hsv.blue(), qAlpha(*data));
359
img.setColorTable(cTable);
363
QImage& Blitz::intensity(QImage &img, float percent)
368
if(img.format() == QImage::Format_ARGB32_Premultiplied)
369
img = img.convertToFormat(QImage::Format_ARGB32);
370
else if(img.depth() < 8)
371
img = img.convertToFormat(QImage::Format_Indexed8);
373
QVector<QRgb> colorTable;
374
int segmentColors, pixels;
377
if(img.format() == QImage::Format_Indexed8){
378
segmentColors = pixels = img.numColors();
379
colorTable = img.colorTable();
380
data = colorTable.data();
384
pixels = img.width()*img.height();
385
data = (unsigned int *)img.scanLine(0);
388
percent = qBound(-1.0f, percent, 1.0f);
389
bool brighten = (percent >= 0);
393
#ifdef USE_MMX_INLINE_ASM
395
#warning Using MMX intensity
397
if(BlitzCPUInfo::haveExtension(BlitzCPUInfo::IntegerSSE)){
398
unsigned int rem = pixels % 4;
400
quint32 *end = ( data + pixels );
402
quint16 p = (quint16)(256.0f*(percent));
403
MMX::Pack4 mult = {{p,p,p,0}};
405
__asm__ __volatile__(
406
"pxor %%mm7, %%mm7\n\t" // zero mm7 for unpacking
407
"movq (%0), %%mm6\n\t" // copy intensity change to mm6
408
: : "r"(&mult), "m"(mult));
411
while ( data != end ) {
412
__asm__ __volatile__(
413
"movq (%0), %%mm0\n\t"
414
"movq 8(%0), %%mm4\n\t" // copy 4 pixels of data to mm0 and mm4
415
"movq %%mm0, %%mm1\n\t"
416
"movq %%mm0, %%mm3\n\t"
417
"movq %%mm4, %%mm5\n\t" // copy to registers for unpacking
418
"punpcklbw %%mm7, %%mm0\n\t"
419
"punpckhbw %%mm7, %%mm1\n\t" // unpack the two pixels from mm0
420
"pmullw %%mm6, %%mm0\n\t"
421
"punpcklbw %%mm7, %%mm4\n\t"
422
"pmullw %%mm6, %%mm1\n\t" // multiply by intensity*256
423
"psrlw $8, %%mm0\n\t" // divide by 256
424
"pmullw %%mm6, %%mm4\n\t"
425
"psrlw $8, %%mm1\n\t"
426
"psrlw $8, %%mm4\n\t"
427
"packuswb %%mm1, %%mm0\n\t" // pack solution into mm0. saturates at 255
428
"movq %%mm5, %%mm1\n\t"
430
"punpckhbw %%mm7, %%mm1\n\t" // unpack 4th pixel in mm1
432
"pmullw %%mm6, %%mm1\n\t"
433
"paddusb %%mm3, %%mm0\n\t" // add intesity result to original of mm0
434
"psrlw $8, %%mm1\n\t"
435
"packuswb %%mm1, %%mm4\n\t" // pack upper two pixels into mm4
437
"movq %%mm0, (%0)\n\t" // rewrite to memory lower two pixels
438
"paddusb %%mm5, %%mm4\n\t"
439
"movq %%mm4, 8(%0)\n\t" // rewrite upper two pixels
445
while ( data != end ) {
446
__asm__ __volatile__(
447
"movd (%0), %%mm0\n\t" // repeat above but for
448
"punpcklbw %%mm7, %%mm0\n\t" // one pixel at a time
449
"movq %%mm0, %%mm3\n\t"
450
"pmullw %%mm6, %%mm0\n\t"
451
"psrlw $8, %%mm0\n\t"
452
"paddw %%mm3, %%mm0\n\t"
453
"packuswb %%mm0, %%mm0\n\t"
454
"movd %%mm0, (%0)\n\t"
461
while ( data != end ) {
462
__asm__ __volatile__(
463
"movq (%0), %%mm0\n\t"
464
"movq 8(%0), %%mm4\n\t"
465
"movq %%mm0, %%mm1\n\t"
466
"movq %%mm0, %%mm3\n\t"
468
"movq %%mm4, %%mm5\n\t"
470
"punpcklbw %%mm7, %%mm0\n\t"
471
"punpckhbw %%mm7, %%mm1\n\t"
472
"pmullw %%mm6, %%mm0\n\t"
473
"punpcklbw %%mm7, %%mm4\n\t"
474
"pmullw %%mm6, %%mm1\n\t"
475
"psrlw $8, %%mm0\n\t"
476
"pmullw %%mm6, %%mm4\n\t"
477
"psrlw $8, %%mm1\n\t"
478
"psrlw $8, %%mm4\n\t"
479
"packuswb %%mm1, %%mm0\n\t"
480
"movq %%mm5, %%mm1\n\t"
482
"punpckhbw %%mm7, %%mm1\n\t"
484
"pmullw %%mm6, %%mm1\n\t"
485
"psubusb %%mm0, %%mm3\n\t" // subtract darkening amount
486
"psrlw $8, %%mm1\n\t"
487
"packuswb %%mm1, %%mm4\n\t"
489
"movq %%mm3, (%0)\n\t"
490
"psubusb %%mm4, %%mm5\n\t" // only change for this version is
491
"movq %%mm5, 8(%0)\n\t" // subtraction here as we are darkening image
497
while ( data != end ) {
498
__asm__ __volatile__(
499
"movd (%0), %%mm0\n\t"
500
"punpcklbw %%mm7, %%mm0\n\t"
501
"movq %%mm0, %%mm3\n\t"
502
"pmullw %%mm6, %%mm0\n\t"
503
"psrlw $8, %%mm0\n\t"
504
"psubusw %%mm0, %%mm3\n\t"
505
"packuswb %%mm3, %%mm3\n\t"
506
"movd %%mm3, (%0)\n\t"
511
__asm__ __volatile__("emms"); // clear mmx state
514
#endif // USE_MMX_INLINE_ASM
516
unsigned char *segmentTable = new unsigned char[segmentColors];
518
for(int i=0; i < segmentColors; ++i)
519
segmentTable[i] = qMin((int)(i*percent), 255);
522
for(int i=0; i < pixels; ++i){
526
data[i] = qRgba(qMin(255, r+segmentTable[r]),
527
qMin(255, g+segmentTable[g]),
528
qMin(255, b+segmentTable[b]), qAlpha(data[i]));
532
for(int i=0; i < segmentColors; ++i)
533
segmentTable[i] = qMax((int)(i*percent), 0);
536
for(int i=0; i < pixels; ++i){
540
data[i] = qRgba(qMax(0, r-segmentTable[r]),
541
qMax(0, g-segmentTable[g]),
542
qMax(0, b-segmentTable[b]), qAlpha(data[i]));
545
delete[] segmentTable;
549
img.setColorTable(colorTable);
553
QImage& Blitz::channelIntensity(QImage &img, float percent, RGBChannel channel)
555
if(img.isNull() || (channel != Red && channel != Blue &&
558
if(img.format() == QImage::Format_ARGB32_Premultiplied)
559
img = img.convertToFormat(QImage::Format_ARGB32);
560
else if(img.depth() < 8)
561
img = img.convertToFormat(QImage::Format_Indexed8);
563
QVector<QRgb> colorTable;
564
int segmentColors, pixels;
567
if(img.format() == QImage::Format_Indexed8){
568
segmentColors = pixels = img.numColors();
569
colorTable = img.colorTable();
570
data = colorTable.data();
574
pixels = img.width()*img.height();
575
data = (unsigned int *)img.scanLine(0);
578
percent = qBound(-1.0f, percent, 1.0f);
579
bool brighten = (percent >= 0);
583
unsigned char *segmentTable = new unsigned char[segmentColors];
585
for(int i=0; i < segmentColors; ++i)
586
segmentTable[i] = qMin((int)(i*percent), 255);
589
if(channel == Red){ // and here ;-)
590
for(int i=0; i < pixels; ++i){
591
color = qRed(data[i]);
592
data[i] = qRgba(qMin(255, color+segmentTable[color]),
593
qGreen(data[i]), qBlue(data[i]),
597
else if(channel == Green){
598
for(int i=0; i < pixels; ++i){
599
color = qGreen(data[i]);
600
data[i] = qRgba(qRed(data[i]),
601
qMin(255, color+segmentTable[color]),
602
qBlue(data[i]), qAlpha(data[i]));
606
for(int i=0; i < pixels; ++i){
607
color = qBlue(data[i]);
608
data[i] = qRgba(qRed(data[i]), qGreen(data[i]),
609
qMin(255, color+segmentTable[color]),
615
for(int i=0; i < segmentColors; ++i)
616
segmentTable[i] = qMax((int)(i*percent), 0);
620
for(int i=0; i < pixels; ++i){
621
color = qRed(data[i]);
622
data[i] = qRgba(qMax(0, color-segmentTable[color]),
623
qGreen(data[i]), qBlue(data[i]),
627
else if(channel == Green){
628
for(int i=0; i < pixels; ++i){
629
color = qGreen(data[i]);
630
data[i] = qRgba(qRed(data[i]),
631
qMax(0, color-segmentTable[color]),
632
qBlue(data[i]), qAlpha(data[i]));
636
for(int i=0; i < pixels; ++i){
637
color = qBlue(data[i]);
638
data[i] = qRgba(qRed(data[i]), qGreen(data[i]),
639
qMax(0, color-segmentTable[color]),
644
delete[] segmentTable;
645
if(img.format() == QImage::Format_Indexed8)
646
img.setColorTable(colorTable);
650
QImage& Blitz::desaturate(QImage &img, float desat)
655
img = img.convertToFormat(QImage::Format_Indexed8);
657
desat = qBound(0.0f, desat, 1.0f);
659
unsigned int *data, *end;
661
if(img.format() == QImage::Format_ARGB32 ||
662
img.format() == QImage::Format_RGB32 ||
663
img.format() == QImage::Format_Indexed8){
664
QVector<QRgb> cTable;
665
if(img.format() == QImage::Format_Indexed8){
666
cTable = img.colorTable();
667
data = (unsigned int *)cTable.data();
668
end = data + img.numColors();
672
data = (unsigned int *)img.scanLine(0);
673
end = data + (img.width()*img.height());
676
hsv.convertRGB2HSV(*data);
677
hsv.setSaturation((int)(hsv.saturation() * (1.0 - desat)));
678
hsv.convertHSV2RGB();
679
*data = qRgba(hsv.red(), hsv.green(), hsv.blue(), qAlpha(*data));
682
if(img.format() == QImage::Format_Indexed8)
683
img.setColorTable(cTable);
686
else if(img.format() == QImage::Format_ARGB32_Premultiplied){
687
data = (unsigned int *)img.scanLine(0);
688
end = data + (img.width()*img.height());
690
hsv.convertRGB2HSV(BlitzPrivate::convertFromPremult(*data));
691
hsv.setSaturation((int)(hsv.saturation() * (1.0 - desat)));
692
hsv.convertHSV2RGB();
693
*data = BlitzPrivate::convertToPremult(qRgba(hsv.red(), hsv.green(),
694
hsv.blue(), qAlpha(*data)));
702
QImage Blitz::threshold(QImage &img, unsigned char thresholdValue,
703
RGBChannel channel, unsigned int c_on,
708
else if(img.depth() < 8)
709
img = img.convertToFormat(QImage::Format_Indexed8);
712
w = img.width(); h = img.height();
713
QImage buffer(img.width(), img.height(), QImage::Format_Indexed8);
715
QVector<QRgb> cTable(2);
716
cTable[0] = c_off; cTable[1] = c_on;
717
buffer.setColorTable(cTable);
720
if(img.format() == QImage::Format_RGB32 ||
721
img.format() == QImage::Format_ARGB32){
722
QRgb *src = (QRgb *)img.scanLine(0);
726
for(y=0; y < h; ++y){
727
dest = buffer.scanLine(y);
729
*dest++ = (qGray(*src++) >= thresholdValue) ? 1 : 0;
734
for(y=0; y < h; ++y){
735
dest = buffer.scanLine(y);
737
*dest++ = (BlitzPrivate::brightness(*src++) >= thresholdValue) ? 1 : 0;
742
for(y=0; y < h; ++y){
743
dest = buffer.scanLine(y);
745
*dest++ = (qRed(*src++) >= thresholdValue) ? 1 : 0;
750
for(y=0; y < h; ++y){
751
dest = buffer.scanLine(y);
753
*dest++ = (qGreen(*src++) >= thresholdValue) ? 1 : 0;
758
for(y=0; y < h; ++y){
759
dest = buffer.scanLine(y);
761
*dest++ = (qBlue(*src++) >= thresholdValue) ? 1 : 0;
766
for(y=0; y < h; ++y){
767
dest = buffer.scanLine(y);
769
*dest++ = (qAlpha(*src++) >= thresholdValue) ? 1 : 0;
775
else if(img.format() == QImage::Format_ARGB32_Premultiplied){
776
QRgb *src = (QRgb *)img.scanLine(0);
780
for(y=0; y < h; ++y){
781
dest = buffer.scanLine(y);
782
for(x=0; x < w; ++x, ++src)
783
*dest++ = (qGray(BlitzPrivate::convertFromPremult(*src)) >=
784
thresholdValue) ? 1 : 0;
789
for(y=0; y < h; ++y){
790
dest = buffer.scanLine(y);
791
for(x=0; x < w; ++x, ++src)
792
*dest++ = (BlitzPrivate::brightness(BlitzPrivate::convertFromPremult(*src)) >=
793
thresholdValue) ? 1 : 0;
798
for(y=0; y < h; ++y){
799
dest = buffer.scanLine(y);
800
for(x=0; x < w; ++x, ++src)
801
*dest++ = (qRed(BlitzPrivate::convertFromPremult(*src)) >=
802
thresholdValue) ? 1 : 0;
807
for(y=0; y < h; ++y){
808
dest = buffer.scanLine(y);
809
for(x=0; x < w; ++x, ++src)
810
*dest++ = (qGreen(BlitzPrivate::convertFromPremult(*src)) >=
811
thresholdValue) ? 1 : 0;
816
for(y=0; y < h; ++y){
817
dest = buffer.scanLine(y);
818
for(x=0; x < w; ++x, ++src)
819
*dest++ = (qBlue(BlitzPrivate::convertFromPremult(*src)) >=
820
thresholdValue) ? 1 : 0;
825
for(y=0; y < h; ++y){
826
dest = buffer.scanLine(y);
827
for(x=0; x < w; ++x, ++src)
828
*dest++ = (qAlpha(BlitzPrivate::convertFromPremult(*src)) >=
829
thresholdValue) ? 1 : 0;
836
// would be quicker to just threshold the color table, but we return
837
// images w/ only 2 colors for easy conversion to bitmap
838
QVector<QRgb> srcTable(img.colorTable());
843
for(y=0; y < h; ++y){
844
src = img.scanLine(y); dest = buffer.scanLine(y);
845
for(x=0; x < w; ++x){
846
*dest++ = (qGray(srcTable[*src++]) >= thresholdValue) ?
853
for(y=0; y < h; ++y){
854
src = img.scanLine(y); dest = buffer.scanLine(y);
855
for(x=0; x < w; ++x){
856
*dest++ = (BlitzPrivate::brightness(srcTable[*src++]) >= thresholdValue) ?
863
for(y=0; y < h; ++y){
864
src = img.scanLine(y); dest = buffer.scanLine(y);
865
for(x=0; x < w; ++x){
866
*dest++ = (qRed(srcTable[*src++]) >= thresholdValue) ?
873
for(y=0; y < h; ++y){
874
src = img.scanLine(y); dest = buffer.scanLine(y);
875
for(x=0; x < w; ++x){
876
*dest++ = (qGreen(srcTable[*src++]) >= thresholdValue) ?
883
for(y=0; y < h; ++y){
884
src = img.scanLine(y); dest = buffer.scanLine(y);
885
for(x=0; x < w; ++x){
886
*dest++ = (qBlue(srcTable[*src++]) >= thresholdValue) ?
893
for(y=0; y < h; ++y){
894
src = img.scanLine(y); dest = buffer.scanLine(y);
895
for(x=0; x < w; ++x){
896
*dest++ = (qAlpha(srcTable[*src++]) >= thresholdValue) ?
908
QImage& Blitz::fade(QImage &img, float val, const QColor &color)
910
if(img.isNull() || img.depth() == 1)
913
val = qBound(0.0f, val, 1.0f);
914
unsigned char tbl[256];
915
for(int i=0; i < 256; ++i)
916
tbl[i] = (int)(val * i + 0.5);
918
int red = color.red();
919
int green = color.green();
920
int blue = color.blue();
924
QVector<QRgb> cTable;
926
if(img.format() == QImage::Format_Indexed8){
927
cTable = img.colorTable();
928
data = (unsigned int *)cTable.data();
929
end = data + img.numColors();
933
data = (unsigned int *)img.scanLine(0);
934
end = data + (img.width()*img.height());
937
if(img.format() == QImage::Format_ARGB32_Premultiplied){
940
col = BlitzPrivate::convertFromPremult(*data);
941
r = qRed(col); g = qGreen(col); b = qBlue(col);
943
BlitzPrivate::convertToPremult(qRgba((r > red) ? r - tbl[r - red] : r + tbl[red - r],
944
(g > green) ? g - tbl[g - green] : g + tbl[green - g],
945
(b > blue) ? b - tbl[b - blue] : b + tbl[blue - b],
951
r = qRed(*data); g = qGreen(*data); b = qBlue(*data);
952
*data = qRgba((r > red) ? r - tbl[r - red] : r + tbl[red - r],
953
(g > green) ? g - tbl[g - green] : g + tbl[green - g],
954
(b > blue) ? b - tbl[b - blue] : b + tbl[blue - b],
959
if(img.format() == QImage::Format_Indexed8)
960
img.setColorTable(cTable);
964
QImage& Blitz::flatten(QImage &img, const QColor &ca, const QColor &cb)
969
if(img.depth() == 1) {
970
img.setColor(0, ca.rgb());
971
img.setColor(1, cb.rgb());
975
int r1 = ca.red(); int r2 = cb.red();
976
int g1 = ca.green(); int g2 = cb.green();
977
int b1 = ca.blue(); int b2 = cb.blue();
978
int min = 0, max = 255;
981
QVector<QRgb> cTable;
982
if(img.format() == QImage::Format_Indexed8){
983
cTable = img.colorTable();
984
data = (unsigned int *)cTable.data();
985
end = data + img.numColors();
989
data = (unsigned int *)img.scanLine(0);
990
end = data + (img.width()*img.height());
993
// get minimum and maximum graylevel
997
if(img.format() != QImage::Format_ARGB32_Premultiplied){
999
mean = (qRed(*ptr) + qGreen(*ptr) + qBlue(*ptr)) / 3;
1000
min = qMin(min, mean);
1001
max = qMax(max, mean);
1008
pixel = BlitzPrivate::convertFromPremult(*ptr);
1009
mean = (qRed(pixel) + qGreen(pixel) + qBlue(pixel)) / 3;
1010
min = qMin(min, mean);
1011
max = qMax(max, mean);
1016
// conversion factors
1017
float sr = ((float) r2 - r1) / (max - min);
1018
float sg = ((float) g2 - g1) / (max - min);
1019
float sb = ((float) b2 - b1) / (max - min);
1021
if(img.format() != QImage::Format_ARGB32_Premultiplied){
1023
mean = (qRed(*data) + qGreen(*data) + qBlue(*data)) / 3;
1024
*data = qRgba((unsigned char)(sr * (mean - min) + r1 + 0.5),
1025
(unsigned char)(sg * (mean - min) + g1 + 0.5),
1026
(unsigned char)(sb * (mean - min) + b1 + 0.5),
1034
pixel = BlitzPrivate::convertFromPremult(*data);
1035
mean = (qRed(pixel) + qGreen(pixel) + qBlue(pixel)) / 3;
1038
convertToPremult(qRgba((unsigned char)(sr * (mean - min) + r1 + 0.5),
1039
(unsigned char)(sg * (mean - min) + g1 + 0.5),
1040
(unsigned char)(sb * (mean - min) + b1 + 0.5),
1046
if(img.format() == QImage::Format_Indexed8)
1047
img.setColorTable(cTable);