1
// This file includes code for scaling images, in two versions.
2
// One ported from ImageMagick (slower, but can achieve better quality),
3
// and from Imlib2 ported by Mosfet (very fast).
6
// ImageMagick code begin
7
// ----------------------
9
// This code is ImageMagick's resize code, adapted for QImage, with
10
// fastfloat class added as an optimization.
11
// The original license text follows.
14
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17
% RRRR EEEEE SSSSS IIIII ZZZZZ EEEEE %
19
% RRRR EEE SSS I ZZZ EEE %
21
% R R EEEEE SSSSS IIIII ZZZZZ EEEEE %
23
% ImageMagick Image Resize Methods %
31
% Copyright (C) 2003 ImageMagick Studio, a non-profit organization dedicated %
32
% to making software imaging solutions freely available. %
34
% Permission is hereby granted, free of charge, to any person obtaining a %
35
% copy of this software and associated documentation files ("ImageMagick"), %
36
% to deal in ImageMagick without restriction, including without limitation %
37
% the rights to use, copy, modify, merge, publish, distribute, sublicense, %
38
% and/or sell copies of ImageMagick, and to permit persons to whom the %
39
% ImageMagick is furnished to do so, subject to the following conditions: %
41
% The above copyright notice and this permission notice shall be included in %
42
% all copies or substantial portions of ImageMagick. %
44
% The software is provided "as is", without warranty of any kind, express or %
45
% implied, including but not limited to the warranties of merchantability, %
46
% fitness for a particular purpose and noninfringement. In no event shall %
47
% ImageMagick Studio be liable for any claim, damages or other liability, %
48
% whether in an action of contract, tort or otherwise, arising from, out of %
49
% or in connection with ImageMagick or the use or other dealings in %
52
% Except as contained in this notice, the name of the ImageMagick Studio %
53
% shall not be used in advertising or otherwise to promote the sale, use or %
54
% other dealings in ImageMagick without prior written authorization from the %
55
% ImageMagick Studio. %
57
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66
#include <kdeversion.h>
67
#if KDE_IS_VERSION(3, 2, 0)
70
#include <libgvcompat/kcpuinfo.h>
77
#include "gvimageutils.h"
79
// everything in namespace
80
namespace GVImageUtils {
86
// mustn't be less than used precision (i.e. 1/fastfloat::RATIO)
87
#define MagickEpsilon 0.0002
90
// this class stores floating point numbers as integers, with BITS shift,
91
// i.e. value XYZ is stored as XYZ * RATIO
95
enum { BITS = 12, RATIO = 4096 };
98
fastfloat( long v ) : value( v << BITS ) {}
99
fastfloat( int v ) : value( v << BITS ) {}
100
fastfloat( double v ) : value( static_cast< long >( v * RATIO + 0.5 )) {}
101
double toDouble() const { return static_cast< double >( value ) / RATIO; }
102
long toLong() const { return value >> BITS; }
103
fastfloat& operator += ( fastfloat r ) { value += r.value; return *this; }
104
fastfloat& operator -= ( fastfloat r ) { value -= r.value; return *this; }
105
fastfloat& operator *= ( fastfloat r ) { value = static_cast< long long >( value ) * r.value >> BITS; return *this; }
106
fastfloat& operator /= ( fastfloat r ) { value = ( static_cast< long long >( value ) << BITS ) / r.value; return *this; }
107
bool operator< ( fastfloat r ) const { return value < r.value; }
108
bool operator<= ( fastfloat r ) const { return value <= r.value; }
109
bool operator> ( fastfloat r ) const { return value > r.value; }
110
bool operator>= ( fastfloat r ) const { return value >= r.value; }
111
bool operator== ( fastfloat r ) const { return value == r.value; }
112
bool operator!= ( fastfloat r ) const { return value != r.value; }
113
fastfloat operator-() const { return fastfloat( -value, false ); }
115
fastfloat( long v, bool ) : value( v ) {} // for operator-()
119
inline fastfloat operator+ ( fastfloat l, fastfloat r ) { return fastfloat( l ) += r; }
120
inline fastfloat operator- ( fastfloat l, fastfloat r ) { return fastfloat( l ) -= r; }
121
inline fastfloat operator* ( fastfloat l, fastfloat r ) { return fastfloat( l ) *= r; }
122
inline fastfloat operator/ ( fastfloat l, fastfloat r ) { return fastfloat( l ) /= r; }
124
inline bool operator< ( fastfloat l, double r ) { return l < fastfloat( r ); }
125
inline bool operator<= ( fastfloat l, double r ) { return l <= fastfloat( r ); }
126
inline bool operator> ( fastfloat l, double r ) { return l > fastfloat( r ); }
127
inline bool operator>= ( fastfloat l, double r ) { return l >= fastfloat( r ); }
128
inline bool operator== ( fastfloat l, double r ) { return l == fastfloat( r ); }
129
inline bool operator!= ( fastfloat l, double r ) { return l != fastfloat( r ); }
131
inline bool operator< ( double l, fastfloat r ) { return fastfloat( l ) < r ; }
132
inline bool operator<= ( double l, fastfloat r ) { return fastfloat( l ) <= r ; }
133
inline bool operator> ( double l, fastfloat r ) { return fastfloat( l ) > r ; }
134
inline bool operator>= ( double l, fastfloat r ) { return fastfloat( l ) >= r ; }
135
inline bool operator== ( double l, fastfloat r ) { return fastfloat( l ) == r ; }
136
inline bool operator!= ( double l, fastfloat r ) { return fastfloat( l ) != r ; }
138
inline double fasttodouble( fastfloat v ) { return v.toDouble(); }
139
inline long fasttolong( fastfloat v ) { return v.toLong(); }
141
#if 1 // change to 0 to turn fastfloat usage off
143
#define fastfloat double
144
#define fasttodouble( v ) double( v )
145
#define fasttolong( v ) long( v )
151
typedef fastfloat (*Filter)(const fastfloat, const fastfloat);
153
typedef struct _ContributionInfo
164
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168
% R e s i z e I m a g e %
172
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
174
% ResizeImage() scales an image to the desired dimensions with one of these
177
% Bessel Blackman Box
178
% Catrom Cubic Gaussian
179
% Hanning Hermite Lanczos
180
% Mitchell Point Quandratic
183
% Most of the filters are FIR (finite impulse response), however, Bessel,
184
% Gaussian, and Sinc are IIR (infinite impulse response). Bessel and Sinc
185
% are windowed (brought down to zero) with the Blackman filter.
187
% ResizeImage() was inspired by Paul Heckbert's zoom program.
189
% The format of the ResizeImage method is:
191
% Image *ResizeImage(Image *image,const unsigned long columns,
192
% const unsigned long rows,const FilterTypes filter,const double blur,
193
% ExceptionInfo *exception)
195
% A description of each parameter follows:
197
% o image: The image.
199
% o columns: The number of columns in the scaled image.
201
% o rows: The number of rows in the scaled image.
203
% o filter: Image filter to use.
205
% o blur: The blur factor where > 1 is blurry, < 1 is sharp.
207
% o exception: Return any errors or warnings in this structure.
213
static fastfloat Bessel(const fastfloat x,const fastfloat)
216
return(MagickPI/4.0);
217
return(BesselOrderOne(MagickPI*x)/(2.0*x));
220
static fastfloat Sinc(const fastfloat x,const fastfloat)
224
return(sin(MagickPI*x)/(MagickPI*x));
227
static fastfloat Blackman(const fastfloat x,const fastfloat)
229
return(0.42+0.5*cos(MagickPI*x)+0.08*cos(2*MagickPI*x));
232
static fastfloat BlackmanBessel(const fastfloat x,const fastfloat)
234
return(Blackman(x/support,support)*Bessel(x,support));
237
static fastfloat BlackmanSinc(const fastfloat x,const fastfloat)
239
return(Blackman(x/support,support)*Sinc(x,support));
243
static fastfloat Box(const fastfloat x,const fastfloat)
253
static fastfloat Catrom(const fastfloat x,const fastfloat)
258
return(0.5*(4.0+x*(8.0+x*(5.0+x))));
260
return(0.5*(2.0+x*x*(-5.0-3.0*x)));
262
return(0.5*(2.0+x*x*(-5.0+3.0*x)));
264
return(0.5*(4.0+x*(-8.0+x*(5.0-x))));
268
static fastfloat Cubic(const fastfloat x,const fastfloat)
273
return((2.0+x)*(2.0+x)*(2.0+x)/6.0);
275
return((4.0+x*x*(-6.0-3.0*x))/6.0);
277
return((4.0+x*x*(-6.0+3.0*x))/6.0);
279
return((2.0-x)*(2.0-x)*(2.0-x)/6.0);
283
static fastfloat Gaussian(const fastfloat x,const fastfloat)
285
return(exp(-2.0*x*x)*sqrt(2.0/MagickPI));
288
static fastfloat Hanning(const fastfloat x,const fastfloat)
290
return(0.5+0.5*cos(MagickPI*x));
293
static fastfloat Hamming(const fastfloat x,const fastfloat)
295
return(0.54+0.46*cos(MagickPI*x));
298
static fastfloat Hermite(const fastfloat x,const fastfloat)
303
return((2.0*(-x)-3.0)*(-x)*(-x)+1.0);
305
return((2.0*x-3.0)*x*x+1.0);
309
static fastfloat Lanczos(const fastfloat x,const fastfloat support)
314
return(Sinc(-x,support)*Sinc(-x/3.0,support));
316
return(Sinc(x,support)*Sinc(x/3.0,support));
321
static fastfloat Mitchell(const fastfloat x,const fastfloat)
325
#define P0 (( 6.0- 2.0*B )/6.0)
326
#define P2 ((-18.0+12.0*B+ 6.0*C)/6.0)
327
#define P3 (( 12.0- 9.0*B- 6.0*C)/6.0)
328
#define Q0 (( 8.0*B+24.0*C)/6.0)
329
#define Q1 (( -12.0*B-48.0*C)/6.0)
330
#define Q2 (( 6.0*B+30.0*C)/6.0)
331
#define Q3 (( - 1.0*B- 6.0*C)/6.0)
336
return(Q0-x*(Q1-x*(Q2-x*Q3)));
338
return(P0+x*x*(P2-x*P3));
340
return(P0+x*x*(P2+x*P3));
342
return(Q0+x*(Q1+x*(Q2+x*Q3)));
347
static fastfloat Quadratic(const fastfloat x,const fastfloat)
352
return(0.5*(x+1.5)*(x+1.5));
356
return(0.5*(x-1.5)*(x-1.5));
361
static fastfloat Triangle(const fastfloat x,const fastfloat)
372
static void HorizontalFilter(const QImage& source,QImage& destination,
373
const fastfloat x_factor,const fastfloat blur,
374
ContributionInfo *contribution, Filter filter, fastfloat filtersupport)
393
Apply filter to resize horizontally from source to destination.
395
scale=blur*Max(1.0/x_factor,1.0);
396
support=scale* filtersupport;
400
Reduce to point sampling.
402
support=0.5+MagickEpsilon;
406
for (x=0; x < (long) destination.width(); x++)
408
center=(fastfloat) (x+0.5)/x_factor;
409
start= fasttolong(Max(center-support+0.5,0));
410
stop= fasttolong(Min(center+support+0.5,source.width()));
412
for (n=0; n < (stop-start); n++)
414
contribution[n].pixel=start+n;
415
contribution[n].weight=
416
filter (scale*(start+n-center+0.5), filtersupport );
417
density+=contribution[n].weight;
419
if ((density != 0.0) && (density != 1.0))
425
for (i=0; i < n; i++)
426
contribution[i].weight*=density;
428
// p=AcquireImagePixels(source,contribution[0].pixel,0,contribution[n-1].pixel-
429
// contribution[0].pixel+1,source->rows,exception);
430
// q=SetImagePixels(destination,x,0,1,destination->rows);
431
for (y=0; y < (long) destination.height(); y++)
437
for (i=0; i < n; i++)
439
int px = contribution[i].pixel;
441
QRgb p = reinterpret_cast< QRgb* >( source.jumpTable()[ py ])[ px ];
442
red+=contribution[i].weight*qRed(p);
443
green+=contribution[i].weight*qGreen(p);
444
blue+=contribution[i].weight*qBlue(p);
445
alpha+=contribution[i].weight*qAlpha(p);
448
fasttolong( red < 0 ? 0 : red > 255 ? 255 : red + 0.5 ),
449
fasttolong( green < 0 ? 0 : green > 255 ? 255 : green + 0.5 ),
450
fasttolong( blue < 0 ? 0 : blue > 255 ? 255 : blue + 0.5 ),
451
fasttolong( alpha < 0 ? 0 : alpha > 255 ? 255 : alpha + 0.5 ));
452
reinterpret_cast< QRgb* >( destination.jumpTable()[ y ])[ x ] = pix;
457
static void VerticalFilter(const QImage& source,QImage& destination,
458
const fastfloat y_factor,const fastfloat blur,
459
ContributionInfo *contribution, Filter filter, fastfloat filtersupport )
478
Apply filter to resize vertically from source to destination.
480
scale=blur*Max(1.0/y_factor,1.0);
481
support=scale* filtersupport;
485
Reduce to point sampling.
487
support=0.5+MagickEpsilon;
491
for (y=0; y < (long) destination.height(); y++)
493
center=(fastfloat) (y+0.5)/y_factor;
494
start= fasttolong(Max(center-support+0.5,0));
495
stop= fasttolong(Min(center+support+0.5,source.height()));
497
for (n=0; n < (stop-start); n++)
499
contribution[n].pixel=start+n;
500
contribution[n].weight=
501
filter (scale*(start+n-center+0.5), filtersupport);
502
density+=contribution[n].weight;
504
if ((density != 0.0) && (density != 1.0))
510
for (i=0; i < n; i++)
511
contribution[i].weight*=density;
513
// p=AcquireImagePixels(source,0,contribution[0].pixel,source->columns,
514
// contribution[n-1].pixel-contribution[0].pixel+1,exception);
515
// q=SetImagePixels(destination,0,y,destination->columns,1);
516
for (x=0; x < (long) destination.width(); x++)
522
for (i=0; i < n; i++)
525
int py = contribution[i].pixel;
526
QRgb p = reinterpret_cast< QRgb* >( source.jumpTable()[ py ])[ px ];
527
red+=contribution[i].weight*qRed(p);
528
green+=contribution[i].weight*qGreen(p);
529
blue+=contribution[i].weight*qBlue(p);
530
alpha+=contribution[i].weight*qAlpha(p);
533
fasttolong( red < 0 ? 0 : red > 255 ? 255 : red + 0.5 ),
534
fasttolong( green < 0 ? 0 : green > 255 ? 255 : green + 0.5 ),
535
fasttolong( blue < 0 ? 0 : blue > 255 ? 255 : blue + 0.5 ),
536
fasttolong( alpha < 0 ? 0 : alpha > 255 ? 255 : alpha + 0.5 ));
537
reinterpret_cast< QRgb* >( destination.jumpTable()[ y ])[ x ] = pix;
542
static QImage ResizeImage(const QImage& image,const int columns,
543
const int rows, Filter filter, fastfloat filtersupport, double blur)
556
Initialize resize image attributes.
558
if ((columns == image.width()) && (rows == image.height()) && (blur == 1.0))
560
QImage resize_image( columns, rows, 32 );
561
resize_image.setAlphaBuffer( image.hasAlphaBuffer());
563
Allocate filter contribution info.
565
x_factor=(fastfloat) resize_image.width()/image.width();
566
y_factor=(fastfloat) resize_image.height()/image.height();
567
// i=(long) LanczosFilter;
568
// if (image->filter != UndefinedFilter)
569
// i=(long) image->filter;
571
// if ((image->storage_class == PseudoClass) || image->matte ||
572
// ((x_factor*y_factor) > 1.0))
573
// i=(long) MitchellFilter;
574
x_support=blur*Max(1.0/x_factor,1.0)*filtersupport;
575
y_support=blur*Max(1.0/y_factor,1.0)*filtersupport;
576
support=Max(x_support,y_support);
577
if (support < filtersupport)
578
support=filtersupport;
579
contribution=new ContributionInfo[ fasttolong( 2.0*Max(support,0.5)+3 ) ];
580
Q_CHECK_PTR( contribution );
584
if (((fastfloat) columns*(image.height()+rows)) >
585
((fastfloat) rows*(image.width()+columns)))
587
QImage source_image( columns, image.height(), 32 );
588
source_image.setAlphaBuffer( image.hasAlphaBuffer());
589
HorizontalFilter(image,source_image,x_factor,blur,
590
contribution,filter,filtersupport);
591
VerticalFilter(source_image,resize_image,y_factor,
592
blur,contribution,filter,filtersupport);
596
QImage source_image( image.width(), rows, 32 );
597
source_image.setAlphaBuffer( image.hasAlphaBuffer());
598
VerticalFilter(image,source_image,y_factor,blur,
599
contribution,filter,filtersupport);
600
HorizontalFilter(source_image,resize_image,x_factor,
601
blur,contribution,filter,filtersupport);
604
Free allocated memory.
606
delete[] contribution;
607
return(resize_image);
616
// filters and their matching support values
618
static const FilterInfo
619
filters[SincFilter+1] =
635
{ BlackmanBessel, 3.2383 },
636
{ BlackmanSinc, 4.0 }
642
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
646
% S a m p l e I m a g e %
650
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
652
% SampleImage() scales an image to the desired dimensions with pixel
653
% sampling. Unlike other scaling methods, this method does not introduce
654
% any additional color into the scaled image.
656
% The format of the SampleImage method is:
658
% Image *SampleImage(const Image *image,const unsigned long columns,
659
% const unsigned long rows,ExceptionInfo *exception)
661
% A description of each parameter follows:
663
% o image: The image.
665
% o columns: The number of columns in the sampled image.
667
% o rows: The number of rows in the sampled image.
669
% o exception: Return any errors or warnings in this structure.
673
QImage SampleImage(const QImage& image,const int columns,
697
Initialize sampled image attributes.
699
if ((columns == image.width()) && (rows == image.height()))
701
// This function is modified to handle any image depth, not only
702
// 32bit like the ImageMagick original. This avoids the relatively
703
// expensive conversion.
704
const int d = image.depth() / 8;
705
QImage sample_image( columns, rows, image.depth());
706
sample_image.setAlphaBuffer( image.hasAlphaBuffer());
708
Allocate scan line buffer and column offset buffers.
710
pixels= new uchar[ image.width() * d ];
711
x_offset= new int[ sample_image.width() ];
712
y_offset= new int[ sample_image.height() ];
714
Initialize pixel offsets.
716
// In the following several code 0.5 needs to be added, otherwise the image
717
// would be moved by half a pixel to bottom-right, just like
718
// with Qt's QImage::scale()
719
for (x=0; x < (long) sample_image.width(); x++)
721
x_offset[x]=int((x+0.5)*image.width()/sample_image.width());
723
for (y=0; y < (long) sample_image.height(); y++)
725
y_offset[y]=int((y+0.5)*image.height()/sample_image.height());
731
for (y=0; y < (long) sample_image.height(); y++)
733
q= sample_image.scanLine( y );
734
if (j != y_offset[y] )
740
p= image.scanLine( j );
741
(void) memcpy(pixels,p,image.width()*d);
749
for (x=0; x < (long) sample_image.width(); x++)
751
*q++=pixels[ x_offset[x] ];
755
for (x=0; x < (long) sample_image.width(); x++)
757
*(QRgb*)q=((QRgb*)pixels)[ x_offset[x] ];
762
for (x=0; x < (long) sample_image.width(); x++)
764
memcpy( q, pixels + x_offset[x] * d, d );
770
if( d != 4 ) // != 32bit
772
sample_image.setNumColors( image.numColors());
773
for( int i = 0; i < image.numColors(); ++i )
774
sample_image.setColor( i, image.color( i ));
783
// ImageMagick code end
786
// Imlib2/Mosfet code begin
787
// ------------------------
789
// This code is Imlib2 code, additionally modified by Mosfet, and with few small
790
// modifications for Gwenview. The MMX scaling code also belongs to it.
792
// The original license texts follow.
795
* This is the normal smoothscale method, based on Imlib2's smoothscale.
797
* Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow
798
* optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's
799
* C algorithm and it ran at about the same speed as my MMX optimized one...
800
* Finally I ported Imlib's MMX version and it ran in less than half the
801
* time as my MMX algorithm, (taking only a quarter of the time Qt does).
803
* Changes include formatting, namespaces and other C++'ings, removal of old
804
* #ifdef'ed code, and removal of unneeded border calculation code.
806
* Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code
807
* is by Willem Monsuwe <willem@stack.nl>. All other modifications are
808
* (C) Daniel M. Duley.
812
Copyright (C) 2004 Daniel M. Duley <dan.duley@verizon.net>
814
Redistribution and use in source and binary forms, with or without
815
modification, are permitted provided that the following conditions
818
1. Redistributions of source code must retain the above copyright
819
notice, this list of conditions and the following disclaimer.
820
2. Redistributions in binary form must reproduce the above copyright
821
notice, this list of conditions and the following disclaimer in the
822
documentation and/or other materials provided with the distribution.
824
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
825
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
826
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
827
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
828
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
829
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
830
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
831
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
832
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
833
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
838
Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS)
840
Permission is hereby granted, free of charge, to any person obtaining a copy
841
of this software and associated documentation files (the "Software"), to
842
deal in the Software without restriction, including without limitation the
843
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
844
sell copies of the Software, and to permit persons to whom the Software is
845
furnished to do so, subject to the following conditions:
847
The above copyright notice and this permission notice shall be included in
848
all copies of the Software and its Copyright notices. In addition publicly
849
documented acknowledgment must be given that this software has been used if no
850
source code of this software is made available publicly. This includes
851
acknowledgments in either Copyright notices, Manuals, Publicity and Marketing
852
documents or any documentation provided with any product containing this
853
software. This License does not apply to any software that links to the
854
libraries provided by this software (statically or dynamically), but only to
855
the software provided.
857
Please see the COPYING.PLAIN for a plain-english explanation of this notice
860
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
861
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
862
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
863
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
864
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
865
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
868
namespace MImageScale{
869
typedef struct __mimage_scale_info
872
unsigned int **ypoints;
873
int *xapoints, *yapoints;
877
unsigned int** mimageCalcYPoints(unsigned int *src, int sw, int sh,
879
int* mimageCalcXPoints(int sw, int dw);
880
int* mimageCalcApoints(int s, int d, int up);
881
MImageScaleInfo* mimageFreeScaleInfo(MImageScaleInfo *isi);
882
MImageScaleInfo *mimageCalcScaleInfo(QImage &img, int sw, int sh,
883
int dw, int dh, char aa);
884
void mimageSampleRGBA(MImageScaleInfo *isi, unsigned int *dest, int dxx,
885
int dyy, int dx, int dy, int dw, int dh, int dow);
886
void mimageScaleAARGBA(MImageScaleInfo *isi, unsigned int *dest, int dxx,
887
int dyy, int dx, int dy, int dw, int dh, int dow,
889
void mimageScaleAARGB(MImageScaleInfo *isi, unsigned int *dest, int dxx,
890
int dyy, int dx, int dy, int dw, int dh, int dow, int
892
QImage smoothScale(const QImage& img, int dw, int dh);
897
void __mimageScale_mmx_AARGBA(MImageScale::MImageScaleInfo *isi,
898
unsigned int *dest, int dxx, int dyy,
899
int dx, int dy, int dw, int dh,
904
using namespace MImageScale;
906
QImage MImageScale::smoothScale(const QImage& image, int dw, int dh)
908
QImage img = image.depth() < 32 ? image.convertDepth( 32 ) : image;
910
int h = img.height();
912
MImageScaleInfo *scaleinfo =
913
mimageCalcScaleInfo(img, w, h, dw, dh, true);
917
QImage buffer(dw, dh, 32);
918
buffer.setAlphaBuffer(img.hasAlphaBuffer());
921
//#warning Using MMX Smoothscale
922
bool haveMMX = KCPUInfo::haveExtension( KCPUInfo::IntelMMX );
924
__mimageScale_mmx_AARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0),
925
0, 0, 0, 0, dw, dh, dw, w);
930
if(img.hasAlphaBuffer())
931
mimageScaleAARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0,
932
0, 0, dw, dh, dw, w);
934
mimageScaleAARGB(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0,
935
0, 0, dw, dh, dw, w);
937
mimageFreeScaleInfo(scaleinfo);
942
// Code ported from Imlib...
945
// FIXME: replace with mRed, etc... These work on pointers to pixels, not
947
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
948
#define A_VAL(p) ((unsigned char *)(p))[0]
949
#define R_VAL(p) ((unsigned char *)(p))[1]
950
#define G_VAL(p) ((unsigned char *)(p))[2]
951
#define B_VAL(p) ((unsigned char *)(p))[3]
952
#elif Q_BYTE_ORDER == Q_LITTLE_ENDIAN
953
#define A_VAL(p) ((unsigned char *)(p))[3]
954
#define R_VAL(p) ((unsigned char *)(p))[2]
955
#define G_VAL(p) ((unsigned char *)(p))[1]
956
#define B_VAL(p) ((unsigned char *)(p))[0]
959
#define INV_XAP (256 - xapoints[x])
960
#define XAP (xapoints[x])
961
#define INV_YAP (256 - yapoints[dyy + y])
962
#define YAP (yapoints[dyy + y])
964
unsigned int** MImageScale::mimageCalcYPoints(unsigned int *src,
965
int sw, int sh, int dh)
969
int val, inc, rv = 0;
975
p = new unsigned int* [dh+1];
978
inc = (sh << 16) / dh;
979
for(i = 0; i < dh; i++){
980
p[j++] = src + ((val >> 16) * sw);
984
for(i = dh / 2; --i >= 0; ){
985
unsigned int *tmp = p[i];
986
p[i] = p[dh - i - 1];
993
int* MImageScale::mimageCalcXPoints(int sw, int dw)
996
int val, inc, rv = 0;
1005
inc = (sw << 16) / dw;
1006
for(i = 0; i < dw; i++){
1007
p[j++] = (val >> 16);
1012
for(i = dw / 2; --i >= 0; ){
1014
p[i] = p[dw - i - 1];
1015
p[dw - i - 1] = tmp;
1021
int* MImageScale::mimageCalcApoints(int s, int d, int up)
1023
int *p, i, j = 0, rv = 0;
1036
inc = (s << 16) / d;
1037
for(i = 0; i < d; i++){
1038
p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00);
1039
if((val >> 16) >= (s - 1))
1046
int val, inc, ap, Cp;
1048
inc = (s << 16) / d;
1049
Cp = ((d << 14) / s) + 1;
1050
for(i = 0; i < d; i++){
1051
ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8;
1052
p[j] = ap | (Cp << 16);
1059
for(i = d / 2; --i >= 0; ){
1061
p[i] = p[d - i - 1];
1068
MImageScaleInfo* MImageScale::mimageFreeScaleInfo(MImageScaleInfo *isi)
1071
delete[] isi->xpoints;
1072
delete[] isi->ypoints;
1073
delete[] isi->xapoints;
1074
delete[] isi->yapoints;
1080
MImageScaleInfo* MImageScale::mimageCalcScaleInfo(QImage &img, int sw, int sh,
1081
int dw, int dh, char aa)
1083
MImageScaleInfo *isi;
1086
scw = dw * img.width() / sw;
1087
sch = dh * img.height() / sh;
1089
isi = new MImageScaleInfo;
1092
memset(isi, 0, sizeof(MImageScaleInfo));
1094
isi->xup_yup = (abs(dw) >= sw) + ((abs(dh) >= sh) << 1);
1096
isi->xpoints = mimageCalcXPoints(img.width(), scw);
1098
return(mimageFreeScaleInfo(isi));
1099
isi->ypoints = mimageCalcYPoints((unsigned int *)img.scanLine(0),
1100
img.width(), img.height(), sch);
1102
return(mimageFreeScaleInfo(isi));
1104
isi->xapoints = mimageCalcApoints(img.width(), scw, isi->xup_yup & 1);
1106
return(mimageFreeScaleInfo(isi));
1107
isi->yapoints = mimageCalcApoints(img.height(), sch, isi->xup_yup & 2);
1109
return(mimageFreeScaleInfo(isi));
1114
/* scale by pixel sampling only */
1115
void MImageScale::mimageSampleRGBA(MImageScaleInfo *isi, unsigned int *dest,
1116
int dxx, int dyy, int dx, int dy, int dw,
1119
unsigned int *sptr, *dptr;
1121
unsigned int **ypoints = isi->ypoints;
1122
int *xpoints = isi->xpoints;
1124
/* whats the last pixel ont he line so we stop there */
1126
/* go through every scanline in the output buffer */
1127
for(y = 0; y < dh; y++){
1128
/* get the pointer to the start of the destination scanline */
1129
dptr = dest + dx + ((y + dy) * dow);
1130
/* calculate the source line we'll scan from */
1131
sptr = ypoints[dyy + y];
1132
/* go thru the scanline and copy across */
1133
for(x = dxx; x < end; x++)
1134
*dptr++ = sptr[xpoints[x]];
1138
/* FIXME: NEED to optimise ScaleAARGBA - currently its "ok" but needs work*/
1140
/* scale by area sampling */
1141
void MImageScale::mimageScaleAARGBA(MImageScaleInfo *isi, unsigned int *dest,
1142
int dxx, int dyy, int dx, int dy, int dw,
1143
int dh, int dow, int sow)
1145
unsigned int *sptr, *dptr;
1147
unsigned int **ypoints = isi->ypoints;
1148
int *xpoints = isi->xpoints;
1149
int *xapoints = isi->xapoints;
1150
int *yapoints = isi->yapoints;
1153
/* scaling up both ways */
1154
if(isi->xup_yup == 3){
1155
/* go through every scanline in the output buffer */
1156
for(y = 0; y < dh; y++){
1157
/* calculate the source line we'll scan from */
1158
dptr = dest + dx + ((y + dy) * dow);
1159
sptr = ypoints[dyy + y];
1161
for(x = dxx; x < end; x++){
1167
pix = ypoints[dyy + y] + xpoints[x];
1168
r = R_VAL(pix) * INV_XAP;
1169
g = G_VAL(pix) * INV_XAP;
1170
b = B_VAL(pix) * INV_XAP;
1171
a = A_VAL(pix) * INV_XAP;
1173
r += R_VAL(pix) * XAP;
1174
g += G_VAL(pix) * XAP;
1175
b += B_VAL(pix) * XAP;
1176
a += A_VAL(pix) * XAP;
1178
rr = R_VAL(pix) * XAP;
1179
gg = G_VAL(pix) * XAP;
1180
bb = B_VAL(pix) * XAP;
1181
aa = A_VAL(pix) * XAP;
1183
rr += R_VAL(pix) * INV_XAP;
1184
gg += G_VAL(pix) * INV_XAP;
1185
bb += B_VAL(pix) * INV_XAP;
1186
aa += A_VAL(pix) * INV_XAP;
1187
r = ((rr * YAP) + (r * INV_YAP)) >> 16;
1188
g = ((gg * YAP) + (g * INV_YAP)) >> 16;
1189
b = ((bb * YAP) + (b * INV_YAP)) >> 16;
1190
a = ((aa * YAP) + (a * INV_YAP)) >> 16;
1191
*dptr++ = qRgba(r, g, b, a);
1194
pix = ypoints[dyy + y] + xpoints[x];
1195
r = R_VAL(pix) * INV_YAP;
1196
g = G_VAL(pix) * INV_YAP;
1197
b = B_VAL(pix) * INV_YAP;
1198
a = A_VAL(pix) * INV_YAP;
1200
r += R_VAL(pix) * YAP;
1201
g += G_VAL(pix) * YAP;
1202
b += B_VAL(pix) * YAP;
1203
a += A_VAL(pix) * YAP;
1208
*dptr++ = qRgba(r, g, b, a);
1213
for(x = dxx; x < end; x++){
1218
pix = ypoints[dyy + y] + xpoints[x];
1219
r = R_VAL(pix) * INV_XAP;
1220
g = G_VAL(pix) * INV_XAP;
1221
b = B_VAL(pix) * INV_XAP;
1222
a = A_VAL(pix) * INV_XAP;
1224
r += R_VAL(pix) * XAP;
1225
g += G_VAL(pix) * XAP;
1226
b += B_VAL(pix) * XAP;
1227
a += A_VAL(pix) * XAP;
1232
*dptr++ = qRgba(r, g, b, a);
1235
*dptr++ = sptr[xpoints[x] ];
1240
/* if we're scaling down vertically */
1241
else if(isi->xup_yup == 1){
1242
/*\ 'Correct' version, with math units prepared for MMXification \*/
1245
int r, g, b, a, rr, gg, bb, aa;
1248
/* go through every scanline in the output buffer */
1249
for(y = 0; y < dh; y++){
1253
dptr = dest + dx + ((y + dy) * dow);
1254
for(x = dxx; x < end; x++){
1255
pix = ypoints[dyy + y] + xpoints[x];
1256
r = (R_VAL(pix) * yap) >> 10;
1257
g = (G_VAL(pix) * yap) >> 10;
1258
b = (B_VAL(pix) * yap) >> 10;
1259
a = (A_VAL(pix) * yap) >> 10;
1260
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
1262
r += (R_VAL(pix) * Cy) >> 10;
1263
g += (G_VAL(pix) * Cy) >> 10;
1264
b += (B_VAL(pix) * Cy) >> 10;
1265
a += (A_VAL(pix) * Cy) >> 10;
1269
r += (R_VAL(pix) * j) >> 10;
1270
g += (G_VAL(pix) * j) >> 10;
1271
b += (B_VAL(pix) * j) >> 10;
1272
a += (A_VAL(pix) * j) >> 10;
1275
pix = ypoints[dyy + y] + xpoints[x] + 1;
1276
rr = (R_VAL(pix) * yap) >> 10;
1277
gg = (G_VAL(pix) * yap) >> 10;
1278
bb = (B_VAL(pix) * yap) >> 10;
1279
aa = (A_VAL(pix) * yap) >> 10;
1280
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
1282
rr += (R_VAL(pix) * Cy) >> 10;
1283
gg += (G_VAL(pix) * Cy) >> 10;
1284
bb += (B_VAL(pix) * Cy) >> 10;
1285
aa += (A_VAL(pix) * Cy) >> 10;
1289
rr += (R_VAL(pix) * j) >> 10;
1290
gg += (G_VAL(pix) * j) >> 10;
1291
bb += (B_VAL(pix) * j) >> 10;
1292
aa += (A_VAL(pix) * j) >> 10;
1298
r = (r + ((rr * XAP))) >> 12;
1299
g = (g + ((gg * XAP))) >> 12;
1300
b = (b + ((bb * XAP))) >> 12;
1301
a = (a + ((aa * XAP))) >> 12;
1309
*dptr = qRgba(r, g, b, a);
1314
/* if we're scaling down horizontally */
1315
else if(isi->xup_yup == 2){
1316
/*\ 'Correct' version, with math units prepared for MMXification \*/
1319
int r, g, b, a, rr, gg, bb, aa;
1322
/* go through every scanline in the output buffer */
1323
for(y = 0; y < dh; y++){
1324
dptr = dest + dx + ((y + dy) * dow);
1325
for(x = dxx; x < end; x++){
1329
pix = ypoints[dyy + y] + xpoints[x];
1330
r = (R_VAL(pix) * xap) >> 10;
1331
g = (G_VAL(pix) * xap) >> 10;
1332
b = (B_VAL(pix) * xap) >> 10;
1333
a = (A_VAL(pix) * xap) >> 10;
1334
for(j = (1 << 14) - xap; j > Cx; j -= Cx){
1336
r += (R_VAL(pix) * Cx) >> 10;
1337
g += (G_VAL(pix) * Cx) >> 10;
1338
b += (B_VAL(pix) * Cx) >> 10;
1339
a += (A_VAL(pix) * Cx) >> 10;
1343
r += (R_VAL(pix) * j) >> 10;
1344
g += (G_VAL(pix) * j) >> 10;
1345
b += (B_VAL(pix) * j) >> 10;
1346
a += (A_VAL(pix) * j) >> 10;
1349
pix = ypoints[dyy + y] + xpoints[x] + sow;
1350
rr = (R_VAL(pix) * xap) >> 10;
1351
gg = (G_VAL(pix) * xap) >> 10;
1352
bb = (B_VAL(pix) * xap) >> 10;
1353
aa = (A_VAL(pix) * xap) >> 10;
1354
for(j = (1 << 14) - xap; j > Cx; j -= Cx){
1356
rr += (R_VAL(pix) * Cx) >> 10;
1357
gg += (G_VAL(pix) * Cx) >> 10;
1358
bb += (B_VAL(pix) * Cx) >> 10;
1359
aa += (A_VAL(pix) * Cx) >> 10;
1363
rr += (R_VAL(pix) * j) >> 10;
1364
gg += (G_VAL(pix) * j) >> 10;
1365
bb += (B_VAL(pix) * j) >> 10;
1366
aa += (A_VAL(pix) * j) >> 10;
1372
r = (r + ((rr * YAP))) >> 12;
1373
g = (g + ((gg * YAP))) >> 12;
1374
b = (b + ((bb * YAP))) >> 12;
1375
a = (a + ((aa * YAP))) >> 12;
1383
*dptr = qRgba(r, g, b, a);
1388
/* if we're scaling down horizontally & vertically */
1390
/*\ 'Correct' version, with math units prepared for MMXification:
1391
|*| The operation 'b = (b * c) >> 16' translates to pmulhw,
1392
|*| so the operation 'b = (b * c) >> d' would translate to
1393
|*| psllw (16 - d), %mmb; pmulh %mmc, %mmb
1397
int a, r, g, b, ax, rx, gx, bx;
1400
for(y = 0; y < dh; y++){
1404
dptr = dest + dx + ((y + dy) * dow);
1405
for(x = dxx; x < end; x++){
1409
sptr = ypoints[dyy + y] + xpoints[x];
1412
rx = (R_VAL(pix) * xap) >> 9;
1413
gx = (G_VAL(pix) * xap) >> 9;
1414
bx = (B_VAL(pix) * xap) >> 9;
1415
ax = (A_VAL(pix) * xap) >> 9;
1417
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
1418
rx += (R_VAL(pix) * Cx) >> 9;
1419
gx += (G_VAL(pix) * Cx) >> 9;
1420
bx += (B_VAL(pix) * Cx) >> 9;
1421
ax += (A_VAL(pix) * Cx) >> 9;
1425
rx += (R_VAL(pix) * i) >> 9;
1426
gx += (G_VAL(pix) * i) >> 9;
1427
bx += (B_VAL(pix) * i) >> 9;
1428
ax += (A_VAL(pix) * i) >> 9;
1431
r = (rx * yap) >> 14;
1432
g = (gx * yap) >> 14;
1433
b = (bx * yap) >> 14;
1434
a = (ax * yap) >> 14;
1436
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
1439
rx = (R_VAL(pix) * xap) >> 9;
1440
gx = (G_VAL(pix) * xap) >> 9;
1441
bx = (B_VAL(pix) * xap) >> 9;
1442
ax = (A_VAL(pix) * xap) >> 9;
1444
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
1445
rx += (R_VAL(pix) * Cx) >> 9;
1446
gx += (G_VAL(pix) * Cx) >> 9;
1447
bx += (B_VAL(pix) * Cx) >> 9;
1448
ax += (A_VAL(pix) * Cx) >> 9;
1452
rx += (R_VAL(pix) * i) >> 9;
1453
gx += (G_VAL(pix) * i) >> 9;
1454
bx += (B_VAL(pix) * i) >> 9;
1455
ax += (A_VAL(pix) * i) >> 9;
1458
r += (rx * Cy) >> 14;
1459
g += (gx * Cy) >> 14;
1460
b += (bx * Cy) >> 14;
1461
a += (ax * Cy) >> 14;
1466
rx = (R_VAL(pix) * xap) >> 9;
1467
gx = (G_VAL(pix) * xap) >> 9;
1468
bx = (B_VAL(pix) * xap) >> 9;
1469
ax = (A_VAL(pix) * xap) >> 9;
1471
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
1472
rx += (R_VAL(pix) * Cx) >> 9;
1473
gx += (G_VAL(pix) * Cx) >> 9;
1474
bx += (B_VAL(pix) * Cx) >> 9;
1475
ax += (A_VAL(pix) * Cx) >> 9;
1479
rx += (R_VAL(pix) * i) >> 9;
1480
gx += (G_VAL(pix) * i) >> 9;
1481
bx += (B_VAL(pix) * i) >> 9;
1482
ax += (A_VAL(pix) * i) >> 9;
1485
r += (rx * j) >> 14;
1486
g += (gx * j) >> 14;
1487
b += (bx * j) >> 14;
1488
a += (ax * j) >> 14;
1491
R_VAL(dptr) = r >> 5;
1492
G_VAL(dptr) = g >> 5;
1493
B_VAL(dptr) = b >> 5;
1494
A_VAL(dptr) = a >> 5;
1501
/* scale by area sampling - IGNORE the ALPHA byte*/
1502
void MImageScale::mimageScaleAARGB(MImageScaleInfo *isi, unsigned int *dest,
1503
int dxx, int dyy, int dx, int dy, int dw,
1504
int dh, int dow, int sow)
1506
unsigned int *sptr, *dptr;
1508
unsigned int **ypoints = isi->ypoints;
1509
int *xpoints = isi->xpoints;
1510
int *xapoints = isi->xapoints;
1511
int *yapoints = isi->yapoints;
1514
/* scaling up both ways */
1515
if(isi->xup_yup == 3){
1516
/* go through every scanline in the output buffer */
1517
for(y = 0; y < dh; y++){
1518
/* calculate the source line we'll scan from */
1519
dptr = dest + dx + ((y + dy) * dow);
1520
sptr = ypoints[dyy + y];
1522
for(x = dxx; x < end; x++){
1523
int r = 0, g = 0, b = 0;
1524
int rr = 0, gg = 0, bb = 0;
1528
pix = ypoints[dyy + y] + xpoints[x];
1529
r = R_VAL(pix) * INV_XAP;
1530
g = G_VAL(pix) * INV_XAP;
1531
b = B_VAL(pix) * INV_XAP;
1533
r += R_VAL(pix) * XAP;
1534
g += G_VAL(pix) * XAP;
1535
b += B_VAL(pix) * XAP;
1537
rr = R_VAL(pix) * XAP;
1538
gg = G_VAL(pix) * XAP;
1539
bb = B_VAL(pix) * XAP;
1541
rr += R_VAL(pix) * INV_XAP;
1542
gg += G_VAL(pix) * INV_XAP;
1543
bb += B_VAL(pix) * INV_XAP;
1544
r = ((rr * YAP) + (r * INV_YAP)) >> 16;
1545
g = ((gg * YAP) + (g * INV_YAP)) >> 16;
1546
b = ((bb * YAP) + (b * INV_YAP)) >> 16;
1547
*dptr++ = qRgba(r, g, b, 0xff);
1550
pix = ypoints[dyy + y] + xpoints[x];
1551
r = R_VAL(pix) * INV_YAP;
1552
g = G_VAL(pix) * INV_YAP;
1553
b = B_VAL(pix) * INV_YAP;
1555
r += R_VAL(pix) * YAP;
1556
g += G_VAL(pix) * YAP;
1557
b += B_VAL(pix) * YAP;
1561
*dptr++ = qRgba(r, g, b, 0xff);
1566
for(x = dxx; x < end; x++){
1567
int r = 0, g = 0, b = 0;
1571
pix = ypoints[dyy + y] + xpoints[x];
1572
r = R_VAL(pix) * INV_XAP;
1573
g = G_VAL(pix) * INV_XAP;
1574
b = B_VAL(pix) * INV_XAP;
1576
r += R_VAL(pix) * XAP;
1577
g += G_VAL(pix) * XAP;
1578
b += B_VAL(pix) * XAP;
1582
*dptr++ = qRgba(r, g, b, 0xff);
1585
*dptr++ = sptr[xpoints[x] ];
1590
/* if we're scaling down vertically */
1591
else if(isi->xup_yup == 1){
1592
/*\ 'Correct' version, with math units prepared for MMXification \*/
1595
int r, g, b, rr, gg, bb;
1598
/* go through every scanline in the output buffer */
1599
for(y = 0; y < dh; y++){
1603
dptr = dest + dx + ((y + dy) * dow);
1604
for(x = dxx; x < end; x++){
1605
pix = ypoints[dyy + y] + xpoints[x];
1606
r = (R_VAL(pix) * yap) >> 10;
1607
g = (G_VAL(pix) * yap) >> 10;
1608
b = (B_VAL(pix) * yap) >> 10;
1610
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
1611
r += (R_VAL(pix) * Cy) >> 10;
1612
g += (G_VAL(pix) * Cy) >> 10;
1613
b += (B_VAL(pix) * Cy) >> 10;
1617
r += (R_VAL(pix) * j) >> 10;
1618
g += (G_VAL(pix) * j) >> 10;
1619
b += (B_VAL(pix) * j) >> 10;
1622
pix = ypoints[dyy + y] + xpoints[x] + 1;
1623
rr = (R_VAL(pix) * yap) >> 10;
1624
gg = (G_VAL(pix) * yap) >> 10;
1625
bb = (B_VAL(pix) * yap) >> 10;
1627
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
1628
rr += (R_VAL(pix) * Cy) >> 10;
1629
gg += (G_VAL(pix) * Cy) >> 10;
1630
bb += (B_VAL(pix) * Cy) >> 10;
1634
rr += (R_VAL(pix) * j) >> 10;
1635
gg += (G_VAL(pix) * j) >> 10;
1636
bb += (B_VAL(pix) * j) >> 10;
1641
r = (r + ((rr * XAP))) >> 12;
1642
g = (g + ((gg * XAP))) >> 12;
1643
b = (b + ((bb * XAP))) >> 12;
1650
*dptr = qRgba(r, g, b, 0xff);
1655
/* if we're scaling down horizontally */
1656
else if(isi->xup_yup == 2){
1657
/*\ 'Correct' version, with math units prepared for MMXification \*/
1660
int r, g, b, rr, gg, bb;
1663
/* go through every scanline in the output buffer */
1664
for(y = 0; y < dh; y++){
1665
dptr = dest + dx + ((y + dy) * dow);
1666
for(x = dxx; x < end; x++){
1670
pix = ypoints[dyy + y] + xpoints[x];
1671
r = (R_VAL(pix) * xap) >> 10;
1672
g = (G_VAL(pix) * xap) >> 10;
1673
b = (B_VAL(pix) * xap) >> 10;
1675
for(j = (1 << 14) - xap; j > Cx; j -= Cx){
1676
r += (R_VAL(pix) * Cx) >> 10;
1677
g += (G_VAL(pix) * Cx) >> 10;
1678
b += (B_VAL(pix) * Cx) >> 10;
1682
r += (R_VAL(pix) * j) >> 10;
1683
g += (G_VAL(pix) * j) >> 10;
1684
b += (B_VAL(pix) * j) >> 10;
1687
pix = ypoints[dyy + y] + xpoints[x] + sow;
1688
rr = (R_VAL(pix) * xap) >> 10;
1689
gg = (G_VAL(pix) * xap) >> 10;
1690
bb = (B_VAL(pix) * xap) >> 10;
1692
for(j = (1 << 14) - xap; j > Cx; j -= Cx){
1693
rr += (R_VAL(pix) * Cx) >> 10;
1694
gg += (G_VAL(pix) * Cx) >> 10;
1695
bb += (B_VAL(pix) * Cx) >> 10;
1699
rr += (R_VAL(pix) * j) >> 10;
1700
gg += (G_VAL(pix) * j) >> 10;
1701
bb += (B_VAL(pix) * j) >> 10;
1706
r = (r + ((rr * YAP))) >> 12;
1707
g = (g + ((gg * YAP))) >> 12;
1708
b = (b + ((bb * YAP))) >> 12;
1715
*dptr = qRgba(r, g, b, 0xff);
1720
/* fully optimized (i think) - onyl change of algorithm can help */
1721
/* if we're scaling down horizontally & vertically */
1723
/*\ 'Correct' version, with math units prepared for MMXification \*/
1726
int r, g, b, rx, gx, bx;
1729
for(y = 0; y < dh; y++){
1733
dptr = dest + dx + ((y + dy) * dow);
1734
for(x = dxx; x < end; x++){
1738
sptr = ypoints[dyy + y] + xpoints[x];
1741
rx = (R_VAL(pix) * xap) >> 9;
1742
gx = (G_VAL(pix) * xap) >> 9;
1743
bx = (B_VAL(pix) * xap) >> 9;
1745
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
1746
rx += (R_VAL(pix) * Cx) >> 9;
1747
gx += (G_VAL(pix) * Cx) >> 9;
1748
bx += (B_VAL(pix) * Cx) >> 9;
1752
rx += (R_VAL(pix) * i) >> 9;
1753
gx += (G_VAL(pix) * i) >> 9;
1754
bx += (B_VAL(pix) * i) >> 9;
1757
r = (rx * yap) >> 14;
1758
g = (gx * yap) >> 14;
1759
b = (bx * yap) >> 14;
1761
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
1764
rx = (R_VAL(pix) * xap) >> 9;
1765
gx = (G_VAL(pix) * xap) >> 9;
1766
bx = (B_VAL(pix) * xap) >> 9;
1768
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
1769
rx += (R_VAL(pix) * Cx) >> 9;
1770
gx += (G_VAL(pix) * Cx) >> 9;
1771
bx += (B_VAL(pix) * Cx) >> 9;
1775
rx += (R_VAL(pix) * i) >> 9;
1776
gx += (G_VAL(pix) * i) >> 9;
1777
bx += (B_VAL(pix) * i) >> 9;
1780
r += (rx * Cy) >> 14;
1781
g += (gx * Cy) >> 14;
1782
b += (bx * Cy) >> 14;
1787
rx = (R_VAL(pix) * xap) >> 9;
1788
gx = (G_VAL(pix) * xap) >> 9;
1789
bx = (B_VAL(pix) * xap) >> 9;
1791
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
1792
rx += (R_VAL(pix) * Cx) >> 9;
1793
gx += (G_VAL(pix) * Cx) >> 9;
1794
bx += (B_VAL(pix) * Cx) >> 9;
1798
rx += (R_VAL(pix) * i) >> 9;
1799
gx += (G_VAL(pix) * i) >> 9;
1800
bx += (B_VAL(pix) * i) >> 9;
1803
r += (rx * j) >> 14;
1804
g += (gx * j) >> 14;
1805
b += (bx * j) >> 14;
1808
R_VAL(dptr) = r >> 5;
1809
G_VAL(dptr) = g >> 5;
1810
B_VAL(dptr) = b >> 5;
1817
// Imlib2/Mosfet code end
1820
// public functions :
1821
// ------------------
1823
// This function returns how many pixels around the zoomed area should be
1824
// included in the image. This is used when doing incremental painting, because
1825
// some smoothing algorithms use surrounding pixels and not including them
1826
// could sometimes make the edges between incremental steps visible.
1827
int extraScalePixels( SmoothAlgorithm alg, double zoom, double blur )
1829
double filtersupport = 0;
1830
Filter filter = NULL;
1834
filtersupport = 0.0;
1838
filtersupport = 0.5;
1842
filtersupport = 1.0;
1846
filtersupport = 2.0;
1849
if( zoom == 1.0 || filtersupport == 0.0 ) return 0;
1850
// Imlib2/Mosfet scale - I have really no idea how many pixels it needs
1851
if( filter == Box && blur == 1.0 ) return int( 3 / zoom + 1 );
1852
// This is support size for ImageMagick's scaling.
1853
double scale=blur*QMAX(1.0/zoom,1.0);
1854
double support=scale* filtersupport;
1855
if (support <= 0.5) support=0.5+0.000001;
1856
return int( support + 1 );
1859
QImage scale(const QImage& image, int width, int height,
1860
SmoothAlgorithm alg, QImage::ScaleMode mode, double blur )
1862
if( image.isNull()) return image.copy();
1864
QSize newSize( image.size() );
1865
newSize.scale( QSize( width, height ), (QSize::ScaleMode)mode ); // ### remove cast in Qt 4.0
1866
newSize = newSize.expandedTo( QSize( 1, 1 )); // make sure it doesn't become null
1868
if ( newSize == image.size() ) return image.copy();
1870
width = newSize.width();
1871
height = newSize.height();
1872
Filter filter = NULL;
1873
fastfloat filtersupport;
1878
filtersupport = 0.0;
1882
filtersupport = 0.5;
1886
filtersupport = 1.0;
1890
filtersupport = 2.0;
1894
if( filter == Box && blur == 1.0 )
1895
return MImageScale::smoothScale( image, width, height );
1897
if( filter == Box && width > image.width() && height > image.height() && blur == 1.0 ) {
1898
filter = NULL; // Box doesn't really smooth when enlarging
1901
if( filter == NULL ) {
1902
return SampleImage( image, width, height ); // doesn't need 32bit
1905
return ResizeImage( image.convertDepth( 32 ), width, height, filter, filtersupport, blur );
1906
// unlike Qt's smoothScale() this function introduces new colors to grayscale images ... oh well