2
% Copyright (C) 2003 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
5
% This program is covered by multiple licenses, which are described in
6
% Copyright.txt. You should have received a copy of Copyright.txt with this
7
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12
% RRRR EEEEE SSSSS IIIII ZZZZZ EEEEE %
14
% RRRR EEE SSS I ZZZ EEE %
16
% R R EEEEE SSSSS IIIII ZZZZZ EEEEE %
18
% GraphicsMagick Image Resize Methods %
27
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
#include "magick/studio.h"
36
#include "magick/cache.h"
37
#include "magick/log.h"
38
#include "magick/monitor.h"
39
#include "magick/resize.h"
40
#include "magick/utility.h"
45
typedef struct _ContributionInfo
54
typedef struct _FilterInfo
57
(*function)(const double,const double),
61
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65
+ B e s s e l O r d e r O n e %
69
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71
% BesselOrderOne() computes the Bessel function of x of the first kind of
74
% Reduce x to |x| since j1(x)= -j1(-x), and for x in (0,8]
80
% j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
82
% where x1 = x-3*pi/4. Compute sin(x1) and cos(x1) as follow:
84
% cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
85
% = 1/sqrt(2) * (sin(x) - cos(x))
86
% sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
87
% = -1/sqrt(2) * (sin(x) + cos(x))
89
% The format of the BesselOrderOne method is:
91
% double BesselOrderOne(double x)
93
% A description of each parameter follows:
95
% o value: Method BesselOrderOne returns the Bessel function of x of the
96
% first kind of orders 1.
103
static double J1(double x)
115
0.581199354001606143928050809e+21,
116
-0.6672106568924916298020941484e+20,
117
0.2316433580634002297931815435e+19,
118
-0.3588817569910106050743641413e+17,
119
0.2908795263834775409737601689e+15,
120
-0.1322983480332126453125473247e+13,
121
0.3413234182301700539091292655e+10,
122
-0.4695753530642995859767162166e+7,
123
0.270112271089232341485679099e+4
127
0.11623987080032122878585294e+22,
128
0.1185770712190320999837113348e+20,
129
0.6092061398917521746105196863e+17,
130
0.2081661221307607351240184229e+15,
131
0.5243710262167649715406728642e+12,
132
0.1013863514358673989967045588e+10,
133
0.1501793594998585505921097578e+7,
134
0.1606931573481487801970916749e+4,
140
for (i=7; i >= 0; i--)
148
static double P1(double x)
160
0.352246649133679798341724373e+5,
161
0.62758845247161281269005675e+5,
162
0.313539631109159574238669888e+5,
163
0.49854832060594338434500455e+4,
164
0.2111529182853962382105718e+3,
165
0.12571716929145341558495e+1
169
0.352246649133679798068390431e+5,
170
0.626943469593560511888833731e+5,
171
0.312404063819041039923015703e+5,
172
0.4930396490181088979386097e+4,
173
0.2030775189134759322293574e+3,
179
for (i=4; i >= 0; i--)
181
p=p*(8.0/x)*(8.0/x)+Pone[i];
182
q=q*(8.0/x)*(8.0/x)+Qone[i];
187
static double Q1(double x)
199
0.3511751914303552822533318e+3,
200
0.7210391804904475039280863e+3,
201
0.4259873011654442389886993e+3,
202
0.831898957673850827325226e+2,
203
0.45681716295512267064405e+1,
204
0.3532840052740123642735e-1
208
0.74917374171809127714519505e+4,
209
0.154141773392650970499848051e+5,
210
0.91522317015169922705904727e+4,
211
0.18111867005523513506724158e+4,
212
0.1038187585462133728776636e+3,
218
for (i=4; i >= 0; i--)
220
p=p*(8.0/x)*(8.0/x)+Pone[i];
221
q=q*(8.0/x)*(8.0/x)+Qone[i];
226
static double BesselOrderOne(double x)
239
q=sqrt(2.0/(MagickPI*x))*(P1(x)*(1.0/sqrt(2.0)*(sin(x)-cos(x)))-8.0/x*Q1(x)*
240
(-1.0/sqrt(2.0)*(sin(x)+cos(x))));
247
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251
% M a g n i f y I m a g e %
255
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257
% MagnifyImage() is a convenience method that scales an image proportionally
260
% The format of the MagnifyImage method is:
262
% Image *MagnifyImage(const Image *image,ExceptionInfo *exception)
264
% A description of each parameter follows:
266
% o image: The image.
268
% o exception: Return any errors or warnings in this structure.
272
MagickExport Image *MagnifyImage(const Image *image,ExceptionInfo *exception)
274
#define MagnifyImageText " Magnify image... "
298
Initialize magnify image attributes.
300
assert(image != (Image *) NULL);
301
assert(image->signature == MagickSignature);
302
assert(exception != (ExceptionInfo *) NULL);
303
assert(exception->signature == MagickSignature);
304
magnify_image=CloneImage(image,2*image->columns,2*image->rows,True,exception);
305
if (magnify_image == (Image *) NULL)
306
return((Image *) NULL);
308
LogMagickEvent(TransformEvent,GetMagickModule(),
309
"Magnifying image of size %lux%lu to %lux%lu",
310
image->columns,image->rows,magnify_image->columns,magnify_image->rows);
312
magnify_image->storage_class=DirectClass;
314
Allocate image buffer and scanline buffer for 4 rows of the image.
316
scanline=MagickAllocateMemory(PixelPacket *,
317
magnify_image->columns*sizeof(PixelPacket));
318
if (scanline == (PixelPacket *) NULL)
320
DestroyImage(magnify_image);
321
ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
322
UnableToMagnifyImage)
325
Initialize magnify image pixels.
327
for (y=0; y < (long) image->rows; y++)
329
pixels=AcquireImagePixels(image,0,y,image->columns,1,exception);
330
q=SetImagePixels(magnify_image,0,y,magnify_image->columns,1);
331
if ((pixels == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
333
(void) memcpy(q,pixels,image->columns*sizeof(PixelPacket));
334
if (!SyncImagePixels(magnify_image))
340
for (y=0; y < (long) image->rows; y++)
342
p=GetImagePixels(magnify_image,0,(long) (image->rows-y-1),
343
magnify_image->columns,1);
344
if (p == (PixelPacket *) NULL)
346
(void) memcpy(scanline,p,magnify_image->columns*sizeof(PixelPacket));
347
q=GetImagePixels(magnify_image,0,(long) (2*(image->rows-y-1)),
348
magnify_image->columns,1);
349
if (q == (PixelPacket *) NULL)
351
p=scanline+image->columns-1;
352
q+=2*(image->columns-1);
355
for (x=1; x < (long) image->columns; x++)
360
(q+1)->red=(Quantum) (((double) p->red+(double) (p+1)->red)/2+0.5);
361
(q+1)->green=(Quantum) (((double) p->green+(double) (p+1)->green)/2+0.5);
362
(q+1)->blue=(Quantum) (((double) p->blue+(double) (p+1)->blue)/2+0.5);
363
(q+1)->opacity=(Quantum)
364
(((double) p->opacity+(double) (p+1)->opacity)/2+0.5);
366
if (!SyncImagePixels(magnify_image))
369
for (y=0; y < (long) image->rows; y++)
371
rows=(long) Min(image->rows-y,3);
372
p=GetImagePixels(magnify_image,0,2*y,magnify_image->columns,rows);
373
if (p == (PixelPacket *) NULL)
377
q=p+magnify_image->columns;
380
r=q+magnify_image->columns;
381
for (x=0; x < (long) (image->columns-1); x++)
383
q->red=(Quantum) (((double) p->red+(double) r->red)/2+0.5);
384
q->green=(Quantum) (((double) p->green+(double) r->green)/2+0.5);
385
q->blue=(Quantum) (((double) p->blue+(double) r->blue)/2+0.5);
386
q->opacity=(Quantum) (((double) p->opacity+(double) r->opacity)/2+0.5);
387
(q+1)->red=(Quantum) (((double) p->red+(double) (p+2)->red+
388
(double) r->red+(double) (r+2)->red)/4+0.5);
389
(q+1)->green=(Quantum) (((double) p->green+(double) (p+2)->green+
390
(double) r->green+(double) (r+2)->green)/4+0.5);
391
(q+1)->blue=(Quantum) (((double) p->blue+(double) (p+2)->blue+
392
(double) r->blue+(double) (r+2)->blue)/4+0.5);
393
(q+1)->opacity=(Quantum) (((double) p->opacity+(double) (p+2)->opacity+
394
(double) r->opacity+(double) (r+2)->opacity)/4+0.5);
399
q->red=(Quantum) (((double) p->red+(double) r->red)/2+0.5);
400
q->green=(Quantum) (((double) p->green+(double) r->green)/2+0.5);
401
q->blue=(Quantum) (((double) p->blue+(double) r->blue)/2+0.5);
402
q->opacity=(Quantum) (((double) p->opacity+(double) r->opacity)/2+0.5);
406
q->red=(Quantum) (((double) p->red+(double) r->red)/2+0.5);
407
q->green=(Quantum) (((double) p->green+(double) r->green)/2+0.5);
408
q->blue=(Quantum) (((double) p->blue+(double) r->blue)/2+0.5);
409
q->opacity=(Quantum) (((double) p->opacity+(double) r->opacity)/2+0.5);
410
if (!SyncImagePixels(magnify_image))
412
if (QuantumTick(y,image->rows))
413
if (!MagickMonitor(MagnifyImageText,y,image->rows,exception))
416
p=GetImagePixels(magnify_image,0,(long) (2*image->rows-2),
417
magnify_image->columns,1);
418
if (p != (PixelPacket *) NULL)
419
(void) memcpy(scanline,p,magnify_image->columns*sizeof(PixelPacket));
420
q=GetImagePixels(magnify_image,0,(long) (2*image->rows-1),
421
magnify_image->columns,1);
422
if (q != (PixelPacket *) NULL)
423
(void) memcpy(q,scanline,magnify_image->columns*sizeof(PixelPacket));
424
(void) SyncImagePixels(magnify_image);
425
MagickFreeMemory(scanline);
426
magnify_image->is_grayscale=image->is_grayscale;
427
return(magnify_image);
431
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435
% M i n i f y I m a g e %
439
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441
% MinifyImage() is a convenience method that scales an image proportionally
444
% The format of the MinifyImage method is:
446
% Image *MinifyImage(const Image *image,ExceptionInfo *exception)
448
% A description of each parameter follows:
450
% o image: The image.
452
% o exception: Return any errors or warnings in this structure.
456
MagickExport Image *MinifyImage(const Image *image,ExceptionInfo *exception)
458
#define Minify(weight) \
459
total.red+=(weight)*(r->red); \
460
total.green+=(weight)*(r->green); \
461
total.blue+=(weight)*(r->blue); \
462
total.opacity+=(weight)*(r->opacity); \
464
#define MinifyImageText " Minify image... "
476
register const PixelPacket
487
Initialize minified image.
489
assert(image != (Image *) NULL);
490
assert(image->signature == MagickSignature);
491
assert(exception != (ExceptionInfo *) NULL);
492
assert(exception->signature == MagickSignature);
494
minify_image=CloneImage(image,Max(image->columns/2,1),Max(image->rows/2,1),
496
if (minify_image == (Image *) NULL)
497
return((Image *) NULL);
499
LogMagickEvent(TransformEvent,GetMagickModule(),
500
"Minifying image of size %lux%lu to %lux%lu",
501
image->columns,image->rows,minify_image->columns,minify_image->rows);
503
minify_image->storage_class=DirectClass;
507
memset(&zero,0,sizeof(DoublePixelPacket));
508
for (y=0; y < (long) minify_image->rows; y++)
510
p=AcquireImagePixels(image,-2,2*(y-1),image->columns+4,4,exception);
511
q=SetImagePixels(minify_image,0,y,minify_image->columns,1);
512
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
514
for (x=0; x < (long) minify_image->columns; x++)
517
Compute weighted average of target pixel color components.
521
Minify(3.0); Minify(7.0); Minify(7.0); Minify(3.0);
522
r=p+(image->columns+4);
523
Minify(7.0); Minify(15.0); Minify(15.0); Minify(7.0);
524
r=p+2*(image->columns+4);
525
Minify(7.0); Minify(15.0); Minify(15.0); Minify(7.0);
526
r=p+3*(image->columns+4);
527
Minify(3.0); Minify(7.0); Minify(7.0); Minify(3.0);
528
q->red=(Quantum) (total.red/128.0+0.5);
529
q->green=(Quantum) (total.green/128.0+0.5);
530
q->blue=(Quantum) (total.blue/128.0+0.5);
531
q->opacity=(Quantum) (total.opacity/128.0+0.5);
535
if (!SyncImagePixels(minify_image))
537
if (QuantumTick(y,image->rows))
538
if (!MagickMonitor(MinifyImageText,y,minify_image->rows,exception))
541
minify_image->is_grayscale=image->is_grayscale;
542
return(minify_image);
546
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
550
% R e s i z e I m a g e %
554
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
556
% ResizeImage() scales an image to the desired dimensions with one of these
559
% Bessel Blackman Box
560
% Catrom Cubic Gaussian
561
% Hanning Hermite Lanczos
562
% Mitchell Point Quandratic
565
% Most of the filters are FIR (finite impulse response), however, Bessel,
566
% Gaussian, and Sinc are IIR (infinite impulse response). Bessel and Sinc
567
% are windowed (brought down to zero) with the Blackman filter.
569
% ResizeImage() was inspired by Paul Heckbert's zoom program.
571
% The format of the ResizeImage method is:
573
% Image *ResizeImage(Image *image,const unsigned long columns,
574
% const unsigned long rows,const FilterTypes filter,const double blur,
575
% ExceptionInfo *exception)
577
% A description of each parameter follows:
579
% o image: The image.
581
% o columns: The number of columns in the scaled image.
583
% o rows: The number of rows in the scaled image.
585
% o filter: Image filter to use.
587
% o blur: The blur factor where > 1 is blurry, < 1 is sharp.
589
% o exception: Return any errors or warnings in this structure.
594
static double Bessel(const double x,const double support)
597
return(MagickPI/4.0);
598
return(BesselOrderOne(MagickPI*x)/(2.0*x));
601
static double Sinc(const double x,const double support)
605
return(sin(MagickPI*x)/(MagickPI*x));
608
static double Blackman(const double x,const double support)
610
return(0.42+0.5*cos(MagickPI*x)+0.08*cos(2*MagickPI*x));
613
static double BlackmanBessel(const double x,const double support)
615
return(Blackman(x/support,support)*Bessel(x,support));
618
static double BlackmanSinc(const double x,const double support)
620
return(Blackman(x/support,support)*Sinc(x,support));
623
static double Box(const double x,const double support)
632
static double Catrom(const double x,const double support)
637
return(0.5*(4.0+x*(8.0+x*(5.0+x))));
639
return(0.5*(2.0+x*x*(-5.0-3.0*x)));
641
return(0.5*(2.0+x*x*(-5.0+3.0*x)));
643
return(0.5*(4.0+x*(-8.0+x*(5.0-x))));
647
static double Cubic(const double x,const double support)
652
return((2.0+x)*(2.0+x)*(2.0+x)/6.0);
654
return((4.0+x*x*(-6.0-3.0*x))/6.0);
656
return((4.0+x*x*(-6.0+3.0*x))/6.0);
658
return((2.0-x)*(2.0-x)*(2.0-x)/6.0);
662
static double Gaussian(const double x,const double support)
664
return(exp(-2.0*x*x)*sqrt(2.0/MagickPI));
667
static double Hanning(const double x,const double support)
669
return(0.5+0.5*cos(MagickPI*x));
672
static double Hamming(const double x,const double support)
674
return(0.54+0.46*cos(MagickPI*x));
677
static double Hermite(const double x,const double support)
682
return((2.0*(-x)-3.0)*(-x)*(-x)+1.0);
684
return((2.0*x-3.0)*x*x+1.0);
688
static double Lanczos(const double x,const double support)
693
return(Sinc(-x,support)*Sinc(-x/3.0,support));
695
return(Sinc(x,support)*Sinc(x/3.0,support));
699
static double Mitchell(const double x,const double support)
703
#define P0 (( 6.0- 2.0*B )/6.0)
704
#define P2 ((-18.0+12.0*B+ 6.0*C)/6.0)
705
#define P3 (( 12.0- 9.0*B- 6.0*C)/6.0)
706
#define Q0 (( 8.0*B+24.0*C)/6.0)
707
#define Q1 (( -12.0*B-48.0*C)/6.0)
708
#define Q2 (( 6.0*B+30.0*C)/6.0)
709
#define Q3 (( - 1.0*B- 6.0*C)/6.0)
714
return(Q0-x*(Q1-x*(Q2-x*Q3)));
716
return(P0+x*x*(P2-x*P3));
718
return(P0+x*x*(P2+x*P3));
720
return(Q0+x*(Q1+x*(Q2+x*Q3)));
724
static double Quadratic(const double x,const double support)
729
return(0.5*(x+1.5)*(x+1.5));
733
return(0.5*(x-1.5)*(x-1.5));
737
static double Triangle(const double x,const double support)
748
static unsigned int HorizontalFilter(const Image *source,Image *destination,
749
const double x_factor,const FilterInfo *filter_info,const double blur,
750
ContributionInfo *contribution,const size_t span,unsigned long *quantum,
751
ExceptionInfo *exception)
753
#define ResizeImageText " Resize image... "
772
register const PixelPacket
787
Apply filter to resize horizontally from source to destination.
789
scale=blur*Max(1.0/x_factor,1.0);
790
support=scale*filter_info->support;
791
destination->storage_class=source->storage_class;
793
destination->storage_class=DirectClass;
797
Reduce to point sampling.
799
support=0.5+MagickEpsilon;
803
memset(&zero,0,sizeof(DoublePixelPacket));
804
for (x=0; x < (long) destination->columns; x++)
806
center=(double) (x+0.5)/x_factor;
807
start=(long) Max(center-support+0.5,0);
808
stop=(long) Min(center+support+0.5,source->columns);
810
for (n=0; n < (stop-start); n++)
812
contribution[n].pixel=start+n;
813
contribution[n].weight=
814
filter_info->function(scale*(start+n-center+0.5),filter_info->support);
815
density+=contribution[n].weight;
817
if ((density != 0.0) && (density != 1.0))
823
for (i=0; i < n; i++)
824
contribution[i].weight*=density;
826
p=AcquireImagePixels(source,contribution[0].pixel,0,
827
contribution[n-1].pixel-contribution[0].pixel+1,source->rows,exception);
828
q=SetImagePixels(destination,x,0,1,destination->rows);
829
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
831
source_indexes=GetIndexes(source);
832
indexes=GetIndexes(destination);
833
for (y=0; y < (long) destination->rows; y++)
836
for (i=0; i < n; i++)
838
j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
839
(contribution[i].pixel-contribution[0].pixel);
840
pixel.red+=contribution[i].weight*(p+j)->red;
841
pixel.green+=contribution[i].weight*(p+j)->green;
842
pixel.blue+=contribution[i].weight*(p+j)->blue;
843
if ((source->matte) || (source->colorspace == CMYKColorspace))
844
pixel.opacity+=contribution[i].weight*(p+j)->opacity;
846
if ((indexes != (IndexPacket *) NULL) &&
847
(source_indexes != (IndexPacket *) NULL))
849
i=Min(Max((long) (center+0.5),start),stop-1);
850
j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
851
(contribution[i-start].pixel-contribution[0].pixel);
852
indexes[y]=source_indexes[j];
854
q->red=(Quantum) ((pixel.red < 0) ? 0 :
855
(pixel.red > MaxRGB) ? MaxRGB : pixel.red+0.5);
856
q->green=(Quantum) ((pixel.green < 0) ? 0 :
857
(pixel.green > MaxRGB) ? MaxRGB : pixel.green+0.5);
858
q->blue=(Quantum) ((pixel.blue < 0) ? 0 :
859
(pixel.blue > MaxRGB) ? MaxRGB : pixel.blue+0.5);
860
if ((destination->matte) || (destination->colorspace == CMYKColorspace))
861
q->opacity=(Quantum) ((pixel.opacity < 0) ? 0 :
862
(pixel.opacity > MaxRGB) ? MaxRGB : pixel.opacity+0.5);
865
if (!SyncImagePixels(destination))
867
if (QuantumTick(*quantum,span))
868
if (!MagickMonitor(ResizeImageText,*quantum,span,exception))
872
return(x == (long) destination->columns);
875
static unsigned int VerticalFilter(const Image *source,Image *destination,
876
const double y_factor,const FilterInfo *filter_info,const double blur,
877
ContributionInfo *contribution,const size_t span,unsigned long *quantum,
878
ExceptionInfo *exception)
897
register const PixelPacket
912
Apply filter to resize vertically from source to destination.
914
scale=blur*Max(1.0/y_factor,1.0);
915
support=scale*filter_info->support;
916
destination->storage_class=source->storage_class;
918
destination->storage_class=DirectClass;
922
Reduce to point sampling.
924
support=0.5+MagickEpsilon;
928
memset(&zero,0,sizeof(DoublePixelPacket));
929
for (y=0; y < (long) destination->rows; y++)
931
center=(double) (y+0.5)/y_factor;
932
start=(long) Max(center-support+0.5,0);
933
stop=(long) Min(center+support+0.5,source->rows);
935
for (n=0; n < (stop-start); n++)
937
contribution[n].pixel=start+n;
938
contribution[n].weight=
939
filter_info->function(scale*(start+n-center+0.5),filter_info->support);
940
density+=contribution[n].weight;
942
if ((density != 0.0) && (density != 1.0))
948
for (i=0; i < n; i++)
949
contribution[i].weight*=density;
951
p=AcquireImagePixels(source,0,contribution[0].pixel,source->columns,
952
contribution[n-1].pixel-contribution[0].pixel+1,exception);
953
q=SetImagePixels(destination,0,y,destination->columns,1);
954
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
956
source_indexes=GetIndexes(source);
957
indexes=GetIndexes(destination);
958
for (x=0; x < (long) destination->columns; x++)
961
for (i=0; i < n; i++)
963
j=(long) ((contribution[i].pixel-contribution[0].pixel)*
965
pixel.red+=contribution[i].weight*(p+j)->red;
966
pixel.green+=contribution[i].weight*(p+j)->green;
967
pixel.blue+=contribution[i].weight*(p+j)->blue;
968
if ((source->matte) || (source->colorspace == CMYKColorspace))
969
pixel.opacity+=contribution[i].weight*(p+j)->opacity;
971
if ((indexes != (IndexPacket *) NULL) &&
972
(source_indexes != (IndexPacket *) NULL))
974
i=Min(Max((long) (center+0.5),start),stop-1);
975
j=(long) ((contribution[i-start].pixel-contribution[0].pixel)*
977
indexes[x]=source_indexes[j];
979
q->red=(Quantum) ((pixel.red < 0) ? 0 :
980
(pixel.red > MaxRGB) ? MaxRGB : pixel.red+0.5);
981
q->green=(Quantum) ((pixel.green < 0) ? 0 :
982
(pixel.green > MaxRGB) ? MaxRGB : pixel.green+0.5);
983
q->blue=(Quantum) ((pixel.blue < 0) ? 0 :
984
(pixel.blue > MaxRGB) ? MaxRGB : pixel.blue+0.5);
985
if ((destination->matte) || (destination->colorspace == CMYKColorspace))
986
q->opacity=(Quantum) ((pixel.opacity < 0) ? 0 :
987
(pixel.opacity > MaxRGB) ? MaxRGB : pixel.opacity+0.5);
990
if (!SyncImagePixels(destination))
992
if (QuantumTick(*quantum,span))
993
if (!MagickMonitor(ResizeImageText,*quantum,span,exception))
997
return(y == (long) destination->rows);
1000
static const char *ResizeFilterToString(const FilterTypes filter)
1003
filter_string = "Unknown";
1007
case UndefinedFilter:
1008
filter_string="Undefined";
1011
filter_string="Point";
1014
filter_string="Box";
1016
case TriangleFilter:
1017
filter_string="Triangle";
1020
filter_string="Hermite";
1023
filter_string="Hanning";
1026
filter_string="Hamming";
1028
case BlackmanFilter:
1029
filter_string="Blackman";
1031
case GaussianFilter:
1032
filter_string="Gaussian";
1034
case QuadraticFilter:
1035
filter_string="Quadratic";
1038
filter_string="Cubi";
1041
filter_string="Catrom";
1043
case MitchellFilter:
1044
filter_string="Mitchell";
1047
filter_string="Lanczos";
1050
filter_string="Bessel";
1053
filter_string="Sinc";
1057
return filter_string;
1060
MagickExport Image *ResizeImage(const Image *image,const unsigned long columns,
1061
const unsigned long rows,const FilterTypes filter,const double blur,
1062
ExceptionInfo *exception)
1081
static const FilterInfo
1082
filters[SincFilter+1] =
1098
{ BlackmanBessel, 3.2383 },
1099
{ BlackmanSinc, 4.0 }
1112
Initialize resize image attributes.
1114
assert(image != (Image *) NULL);
1115
assert(image->signature == MagickSignature);
1116
assert(exception != (ExceptionInfo *) NULL);
1117
assert(exception->signature == MagickSignature);
1118
assert((filter >= 0) && (filter <= SincFilter));
1119
if ((columns == 0) || (rows == 0))
1120
ThrowImageException(ImageError,UnableToResizeImage,
1121
MagickMsg(CorruptImageError,NegativeOrZeroImageSize));
1122
if ((columns == image->columns) && (rows == image->rows) && (blur == 1.0))
1123
return(CloneImage(image,0,0,True,exception));
1124
resize_image=CloneImage(image,columns,rows,True,exception);
1125
if (resize_image == (Image *) NULL)
1126
return((Image *) NULL);
1128
Allocate filter contribution info.
1130
x_factor=(double) resize_image->columns/image->columns;
1131
y_factor=(double) resize_image->rows/image->rows;
1132
i=(long) DefaultResizeFilter;
1133
if (image->filter != UndefinedFilter)
1134
i=(long) image->filter;
1136
if ((image->storage_class == PseudoClass) || image->matte ||
1137
((x_factor*y_factor) > 1.0))
1138
i=(long) MitchellFilter;
1140
LogMagickEvent(TransformEvent,GetMagickModule(),
1141
"Resizing image of size %lux%lu to %lux%lu using %s filter",
1142
image->columns,image->rows,columns,rows,
1143
ResizeFilterToString((FilterTypes)i));
1145
x_support=blur*Max(1.0/x_factor,1.0)*filters[i].support;
1146
y_support=blur*Max(1.0/y_factor,1.0)*filters[i].support;
1147
support=Max(x_support,y_support);
1148
if (support < filters[i].support)
1149
support=filters[i].support;
1150
contribution=MagickAllocateMemory(ContributionInfo *,
1151
(size_t) (2.0*Max(support,0.5)+3)*sizeof(ContributionInfo));
1152
if (contribution == (ContributionInfo *) NULL)
1154
DestroyImage(resize_image);
1155
ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
1156
UnableToResizeImage)
1163
if (((double) columns*(image->rows+rows)) >
1164
((double) rows*(image->columns+columns)))
1166
source_image=CloneImage(resize_image,columns,image->rows,True,exception);
1167
if (source_image == (Image *) NULL)
1169
MagickFreeMemory(contribution);
1170
DestroyImage(resize_image);
1171
return((Image *) NULL);
1173
span=source_image->columns+resize_image->rows;
1174
status=HorizontalFilter(image,source_image,x_factor,&filters[i],blur,
1175
contribution,span,&quantum,exception);
1176
status|=VerticalFilter(source_image,resize_image,y_factor,&filters[i],
1177
blur,contribution,span,&quantum,exception);
1181
source_image=CloneImage(resize_image,image->columns,rows,True,exception);
1182
if (source_image == (Image *) NULL)
1184
MagickFreeMemory(contribution);
1185
DestroyImage(resize_image);
1186
return((Image *) NULL);
1188
span=resize_image->columns+source_image->rows;
1189
status=VerticalFilter(image,source_image,y_factor,&filters[i],blur,
1190
contribution,span,&quantum,exception);
1191
status|=HorizontalFilter(source_image,resize_image,x_factor,&filters[i],
1192
blur,contribution,span,&quantum,exception);
1195
Free allocated memory.
1197
MagickFreeMemory(contribution);
1198
DestroyImage(source_image);
1199
if (status == False)
1201
DestroyImage(resize_image);
1202
ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
1203
UnableToResizeImage)
1205
resize_image->is_grayscale=image->is_grayscale;
1206
return(resize_image);
1210
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1214
% S a m p l e I m a g e %
1218
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1220
% SampleImage() scales an image to the desired dimensions with pixel
1221
% sampling. Unlike other scaling methods, this method does not introduce
1222
% any additional color into the scaled image.
1224
% The format of the SampleImage method is:
1226
% Image *SampleImage(const Image *image,const unsigned long columns,
1227
% const unsigned long rows,ExceptionInfo *exception)
1229
% A description of each parameter follows:
1231
% o image: The image.
1233
% o columns: The number of columns in the sampled image.
1235
% o rows: The number of rows in the sampled image.
1237
% o exception: Return any errors or warnings in this structure.
1241
MagickExport Image *SampleImage(const Image *image,const unsigned long columns,
1242
const unsigned long rows,ExceptionInfo *exception)
1244
#define SampleImageText " Sample image... "
1260
register const PixelPacket
1263
register IndexPacket
1270
register PixelPacket
1274
Initialize sampled image attributes.
1276
assert(image != (const Image *) NULL);
1277
assert(image->signature == MagickSignature);
1278
assert(exception != (ExceptionInfo *) NULL);
1279
assert(exception->signature == MagickSignature);
1280
if ((columns == 0) || (rows == 0))
1281
ThrowImageException(ImageError,UnableToResizeImage,
1282
MagickMsg(CorruptImageError,NegativeOrZeroImageSize));
1283
if ((columns == image->columns) && (rows == image->rows))
1284
return(CloneImage(image,0,0,True,exception));
1285
sample_image=CloneImage(image,columns,rows,True,exception);
1286
if (sample_image == (Image *) NULL)
1287
return((Image *) NULL);
1289
LogMagickEvent(TransformEvent,GetMagickModule(),
1290
"Sampling image of size %lux%lu to %lux%lu",
1291
image->columns,image->rows,sample_image->columns,sample_image->rows);
1294
Allocate scan line buffer and column offset buffers.
1296
pixels=MagickAllocateMemory(PixelPacket *,image->columns*sizeof(PixelPacket));
1297
x_offset=MagickAllocateMemory(double *,sample_image->columns*sizeof(double));
1298
y_offset=MagickAllocateMemory(double *,sample_image->rows*sizeof(double));
1299
if ((pixels == (PixelPacket *) NULL) || (x_offset == (double *) NULL) ||
1300
(y_offset == (double *) NULL))
1302
DestroyImage(sample_image);
1303
ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
1304
UnableToSampleImage)
1307
Initialize pixel offsets.
1309
for (x=0; x < (long) sample_image->columns; x++)
1310
x_offset[x]=(double) x*image->columns/(double) sample_image->columns;
1311
for (y=0; y < (long) sample_image->rows; y++)
1312
y_offset[y]=(double) y*image->rows/(double) sample_image->rows;
1317
for (y=0; y < (long) sample_image->rows; y++)
1319
q=SetImagePixels(sample_image,0,y,sample_image->columns,1);
1320
if (q == (PixelPacket *) NULL)
1322
if (j != (long) y_offset[y])
1327
j=(long) y_offset[y];
1328
p=AcquireImagePixels(image,0,j,image->columns,1,exception);
1329
if (p == (const PixelPacket *) NULL)
1331
(void) memcpy(pixels,p,image->columns*sizeof(PixelPacket));
1336
for (x=0; x < (long) sample_image->columns; x++)
1337
*q++=pixels[(long) x_offset[x]];
1338
indexes=GetIndexes(image);
1339
sample_indexes=GetIndexes(sample_image);
1340
if ((indexes != (IndexPacket *) NULL) &&
1341
(sample_indexes != (IndexPacket *) NULL))
1342
for (x=0; x < (long) sample_image->columns; x++)
1343
sample_indexes[x]=indexes[(long) x_offset[x]];
1344
if (!SyncImagePixels(sample_image))
1346
if (QuantumTick(y,sample_image->rows))
1347
if (!MagickMonitor(SampleImageText,y,sample_image->rows,exception))
1350
MagickFreeMemory(y_offset);
1351
MagickFreeMemory(x_offset);
1352
MagickFreeMemory(pixels);
1354
Sampling does not change the image properties.
1356
sample_image->is_monochrome=image->is_monochrome;
1357
sample_image->is_grayscale=image->is_grayscale;
1358
return(sample_image);
1362
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366
% S c a l e I m a g e %
1370
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372
% ScaleImage() changes the size of an image to the given dimensions.
1374
% The format of the ScaleImage method is:
1376
% Image *ScaleImage(const Image *image,const unsigned long columns,
1377
% const unsigned long rows,ExceptionInfo *exception)
1379
% A description of each parameter follows:
1381
% o image: The image.
1383
% o columns: The number of columns in the scaled image.
1385
% o rows: The number of rows in the scaled image.
1387
% o exception: Return any errors or warnings in this structure.
1391
MagickExport Image *ScaleImage(const Image *image,const unsigned long columns,
1392
const unsigned long rows,ExceptionInfo *exception)
1394
#define ScaleImageText " Scale image... "
1417
register const PixelPacket
1424
register PixelPacket
1427
register DoublePixelPacket
1436
Initialize scaled image attributes.
1438
assert(image != (const Image *) NULL);
1439
assert(image->signature == MagickSignature);
1440
assert(exception != (ExceptionInfo *) NULL);
1441
assert(exception->signature == MagickSignature);
1442
if ((columns == 0) || (rows == 0))
1443
return((Image *) NULL);
1444
scale_image=CloneImage(image,columns,rows,True,exception);
1445
if (scale_image == (Image *) NULL)
1446
return((Image *) NULL);
1448
LogMagickEvent(TransformEvent,GetMagickModule(),
1449
"Scaling image of size %lux%lu to %lux%lu",
1450
image->columns,image->rows,scale_image->columns,scale_image->rows);
1452
scale_image->storage_class=DirectClass;
1456
x_vector=MagickAllocateMemory(DoublePixelPacket *,
1457
image->columns*sizeof(DoublePixelPacket));
1459
if (image->rows != scale_image->rows)
1460
scanline=MagickAllocateMemory(DoublePixelPacket *,
1461
image->columns*sizeof(DoublePixelPacket));
1462
scale_scanline=MagickAllocateMemory(DoublePixelPacket *,
1463
scale_image->columns*sizeof(DoublePixelPacket));
1464
y_vector=MagickAllocateMemory(DoublePixelPacket *,
1465
image->columns*sizeof(DoublePixelPacket));
1466
if ((scanline == (DoublePixelPacket *) NULL) ||
1467
(scale_scanline == (DoublePixelPacket *) NULL) ||
1468
(x_vector == (DoublePixelPacket *) NULL) ||
1469
(y_vector == (DoublePixelPacket *) NULL))
1471
DestroyImage(scale_image);
1472
ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
1481
y_scale=(double) scale_image->rows/image->rows;
1482
memset(y_vector,0,image->columns*sizeof(DoublePixelPacket));
1483
memset(&zero,0,sizeof(DoublePixelPacket));
1485
for (y=0; y < (long) scale_image->rows; y++)
1487
q=SetImagePixels(scale_image,0,y,scale_image->columns,1);
1488
if (q == (PixelPacket *) NULL)
1490
if (scale_image->rows == image->rows)
1493
Read a new scanline.
1495
p=AcquireImagePixels(image,0,i++,image->columns,1,exception);
1496
if (p == (const PixelPacket *) NULL)
1498
for (x=0; x < (long) image->columns; x++)
1500
x_vector[x].red=p->red;
1501
x_vector[x].green=p->green;
1502
x_vector[x].blue=p->blue;
1503
x_vector[x].opacity=p->opacity;
1512
while (y_scale < y_span)
1514
if (next_row && (number_rows < (long) image->rows))
1517
Read a new scanline.
1519
p=AcquireImagePixels(image,0,i++,image->columns,1,exception);
1520
if (p == (const PixelPacket *) NULL)
1522
for (x=0; x < (long) image->columns; x++)
1524
x_vector[x].red=p->red;
1525
x_vector[x].green=p->green;
1526
x_vector[x].blue=p->blue;
1527
x_vector[x].opacity=p->opacity;
1532
for (x=0; x < (long) image->columns; x++)
1534
y_vector[x].red+=y_scale*x_vector[x].red;
1535
y_vector[x].green+=y_scale*x_vector[x].green;
1536
y_vector[x].blue+=y_scale*x_vector[x].blue;
1537
y_vector[x].opacity+=y_scale*x_vector[x].opacity;
1540
y_scale=(double) scale_image->rows/image->rows;
1543
if (next_row && (number_rows < (long) image->rows))
1546
Read a new scanline.
1548
p=AcquireImagePixels(image,0,i++,image->columns,1,exception);
1549
if (p == (const PixelPacket *) NULL)
1551
for (x=0; x < (long) image->columns; x++)
1553
x_vector[x].red=p->red;
1554
x_vector[x].green=p->green;
1555
x_vector[x].blue=p->blue;
1556
x_vector[x].opacity=p->opacity;
1563
for (x=0; x < (long) image->columns; x++)
1565
pixel.red=y_vector[x].red+y_span*x_vector[x].red;
1566
pixel.green=y_vector[x].green+y_span*x_vector[x].green;
1567
pixel.blue=y_vector[x].blue+y_span*x_vector[x].blue;
1568
pixel.opacity=y_vector[x].opacity+y_span*x_vector[x].opacity;
1569
s->red=pixel.red > MaxRGB ? MaxRGB : pixel.red;
1570
s->green=pixel.green > MaxRGB ? MaxRGB : pixel.green;
1571
s->blue=pixel.blue > MaxRGB ? MaxRGB : pixel.blue;
1572
s->opacity=pixel.opacity > MaxRGB ? MaxRGB : pixel.opacity;
1575
y_vector[x].green=0;
1577
y_vector[x].opacity=0;
1582
y_scale=(double) scale_image->rows/image->rows;
1587
if (scale_image->columns == image->columns)
1590
Transfer scanline to scaled image.
1593
for (x=0; x < (long) scale_image->columns; x++)
1595
q->red=(Quantum) (s->red+0.5);
1596
q->green=(Quantum) (s->green+0.5);
1597
q->blue=(Quantum) (s->blue+0.5);
1598
q->opacity=(Quantum) (s->opacity+0.5);
1613
for (x=0; x < (long) image->columns; x++)
1615
x_scale=(double) scale_image->columns/image->columns;
1616
while (x_scale >= x_span)
1623
pixel.red+=x_span*s->red;
1624
pixel.green+=x_span*s->green;
1625
pixel.blue+=x_span*s->blue;
1626
pixel.opacity+=x_span*s->opacity;
1627
t->red=pixel.red > MaxRGB ? MaxRGB : pixel.red;
1628
t->green=pixel.green > MaxRGB ? MaxRGB : pixel.green;
1629
t->blue=pixel.blue > MaxRGB ? MaxRGB : pixel.blue;
1630
t->opacity=pixel.opacity > MaxRGB ? MaxRGB : pixel.opacity;
1643
pixel.red+=x_scale*s->red;
1644
pixel.green+=x_scale*s->green;
1645
pixel.blue+=x_scale*s->blue;
1646
pixel.opacity+=x_scale*s->opacity;
1654
pixel.red+=x_span*s->red;
1655
pixel.green+=x_span*s->green;
1656
pixel.blue+=x_span*s->blue;
1657
pixel.opacity+=x_span*s->opacity;
1659
if (!next_column && ((t-scale_scanline) < (long) scale_image->columns))
1661
t->red=pixel.red > MaxRGB ? MaxRGB : pixel.red;
1662
t->green=pixel.green > MaxRGB ? MaxRGB : pixel.green;
1663
t->blue=pixel.blue > MaxRGB ? MaxRGB : pixel.blue;
1664
t->opacity=pixel.opacity > MaxRGB ? MaxRGB : pixel.opacity;
1667
Transfer scanline to scaled image.
1670
for (x=0; x < (long) scale_image->columns; x++)
1672
q->red=(Quantum) (t->red+0.5);
1673
q->green=(Quantum) (t->green+0.5);
1674
q->blue=(Quantum) (t->blue+0.5);
1675
q->opacity=(Quantum) (t->opacity+0.5);
1680
if (!SyncImagePixels(scale_image))
1682
if (QuantumTick(y,scale_image->rows))
1683
if (!MagickMonitor(ScaleImageText,y,scale_image->rows,exception))
1687
Free allocated memory.
1689
MagickFreeMemory(y_vector);
1690
MagickFreeMemory(scale_scanline);
1691
if (scale_image->rows != image->rows)
1692
MagickFreeMemory(scanline);
1693
MagickFreeMemory(x_vector);
1694
scale_image->is_grayscale=image->is_grayscale;
1695
return(scale_image);
1699
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703
% T h u m b n a i l I m a g e %
1707
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1709
% ThumbnailImage() changes the size of an image to the given dimensions.
1710
% This method was designed by Bob Friesenhahn as a low cost thumbnail
1713
% The format of the ThumbnailImage method is:
1715
% Image *ThumbnailImage(const Image *image,const unsigned long columns,
1716
% const unsigned long rows,ExceptionInfo *exception)
1718
% A description of each parameter follows:
1720
% o image: The image.
1722
% o columns: The number of columns in the scaled image.
1724
% o rows: The number of rows in the scaled image.
1726
% o exception: Return any errors or warnings in this structure.
1730
MagickExport Image *ThumbnailImage(const Image *image,
1731
const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
1741
x_factor=(double) columns/image->columns;
1742
y_factor=(double) rows/image->rows;
1743
if ((x_factor*y_factor) > 0.1)
1744
return(ResizeImage(image,columns,rows,BoxFilter,image->blur,exception));
1745
sample_image=SampleImage(image,5*columns,5*rows,exception);
1746
if (sample_image == (Image *) NULL)
1747
return((Image *) NULL);
1748
thumbnail_image=ResizeImage(sample_image,columns,rows,BoxFilter,
1749
sample_image->blur,exception);
1750
DestroyImage(sample_image);
1751
return(thumbnail_image);
1755
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759
+ Z o o m I m a g e %
1763
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765
% ZoomImage() creates a new image that is a scaled size of an existing one.
1766
% It allocates the memory necessary for the new Image structure and returns a
1767
% pointer to the new image. The Point filter gives fast pixel replication,
1768
% Triangle is equivalent to bi-linear interpolation, and Mitchel giver slower,
1769
% very high-quality results. See Graphic Gems III for details on this
1772
% The filter member of the Image structure specifies which image filter to
1773
% use. Blur specifies the blur factor where > 1 is blurry, < 1 is sharp.
1775
% The format of the ZoomImage method is:
1777
% Image *ZoomImage(const Image *image,const unsigned long columns,
1778
% const unsigned long rows,ExceptionInfo *exception)
1780
% A description of each parameter follows:
1782
% o zoom_image: Method ZoomImage returns a pointer to the image after
1783
% scaling. A null image is returned if there is a memory shortage.
1785
% o image: The image.
1787
% o columns: An integer that specifies the number of columns in the zoom
1790
% o rows: An integer that specifies the number of rows in the scaled
1793
% o exception: Return any errors or warnings in this structure.
1797
MagickExport Image *ZoomImage(const Image *image,const unsigned long columns,
1798
const unsigned long rows,ExceptionInfo *exception)
1803
assert(image != (const Image *) NULL);
1804
assert(image->signature == MagickSignature);
1805
assert(exception != (ExceptionInfo *) NULL);
1806
assert(exception->signature == MagickSignature);
1807
zoom_image=ResizeImage(image,columns,rows,image->filter,image->blur,