42#include "MagickCore/studio.h"
43#include "MagickCore/accelerate-private.h"
44#include "MagickCore/artifact.h"
45#include "MagickCore/blob.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-view.h"
48#include "MagickCore/channel.h"
49#include "MagickCore/color.h"
50#include "MagickCore/color-private.h"
51#include "MagickCore/colorspace.h"
52#include "MagickCore/colorspace-private.h"
53#include "MagickCore/distort.h"
54#include "MagickCore/draw.h"
55#include "MagickCore/exception.h"
56#include "MagickCore/exception-private.h"
57#include "MagickCore/gem.h"
58#include "MagickCore/image.h"
59#include "MagickCore/image-private.h"
60#include "MagickCore/list.h"
61#include "MagickCore/memory_.h"
62#include "MagickCore/memory-private.h"
63#include "MagickCore/magick.h"
64#include "MagickCore/pixel-accessor.h"
65#include "MagickCore/property.h"
66#include "MagickCore/monitor.h"
67#include "MagickCore/monitor-private.h"
68#include "MagickCore/nt-base-private.h"
69#include "MagickCore/option.h"
70#include "MagickCore/pixel.h"
71#include "MagickCore/profile-private.h"
72#include "MagickCore/quantum-private.h"
73#include "MagickCore/resample.h"
74#include "MagickCore/resample-private.h"
75#include "MagickCore/resize.h"
76#include "MagickCore/resize-private.h"
77#include "MagickCore/resource_.h"
78#include "MagickCore/string_.h"
79#include "MagickCore/string-private.h"
80#include "MagickCore/thread-private.h"
81#include "MagickCore/token.h"
82#include "MagickCore/utility.h"
83#include "MagickCore/utility-private.h"
84#include "MagickCore/version.h"
85#if defined(MAGICKCORE_LQR_DELEGATE)
95 (*filter)(
const double,
const ResizeFilter *),
96 (*window)(
const double,
const ResizeFilter *),
103 ResizeWeightingFunctionType
116 BesselOrderOne(
double),
117 Sinc(
const double,
const ResizeFilter *),
118 SincFast(
const double,
const ResizeFilter *);
152static double Blackman(
const double x,
153 const ResizeFilter *magick_unused(resize_filter))
162 const double cosine = cos((
double) (MagickPI*x));
163 magick_unreferenced(resize_filter);
164 return(0.34+cosine*(0.5+cosine*0.16));
167static double Bohman(
const double x,
168 const ResizeFilter *magick_unused(resize_filter))
178 const double cosine = cos((
double) (MagickPI*x));
179 const double sine=sqrt(1.0-cosine*cosine);
180 magick_unreferenced(resize_filter);
181 return((1.0-x)*cosine+(1.0/MagickPI)*sine);
184static double Box(
const double magick_unused(x),
185 const ResizeFilter *magick_unused(resize_filter))
187 magick_unreferenced(x);
188 magick_unreferenced(resize_filter);
198static double Cosine(
const double x,
199 const ResizeFilter *magick_unused(resize_filter))
201 magick_unreferenced(resize_filter);
207 return(cos((
double) (MagickPI2*x)));
210static double CubicBC(
const double x,
const ResizeFilter *resize_filter)
242 return(resize_filter->coefficient[0]+x*(x*
243 (resize_filter->coefficient[1]+x*resize_filter->coefficient[2])));
245 return(resize_filter->coefficient[3]+x*(resize_filter->coefficient[4]+x*
246 (resize_filter->coefficient[5]+x*resize_filter->coefficient[6])));
250static double CubicSpline(
const double x,
const ResizeFilter *resize_filter)
252 if (resize_filter->support <= 2.0)
258 return(((x-9.0/5.0)*x-1.0/5.0)*x+1.0);
260 return(((-1.0/3.0*(x-1.0)+4.0/5.0)*(x-1.0)-7.0/15.0)*(x-1.0));
263 if (resize_filter->support <= 3.0)
269 return(((13.0/11.0*x-453.0/209.0)*x-3.0/209.0)*x+1.0);
271 return(((-6.0/11.0*(x-1.0)+270.0/209.0)*(x-1.0)-156.0/209.0)*(x-1.0));
273 return(((1.0/11.0*(x-2.0)-45.0/209.0)*(x-2.0)+26.0/209.0)*(x-2.0));
280 return(((49.0/41.0*x-6387.0/2911.0)*x-3.0/2911.0)*x+1.0);
282 return(((-24.0/41.0*(x-1.0)+4032.0/2911.0)*(x-1.0)-2328.0/2911.0)*(x-1.0));
284 return(((6.0/41.0*(x-2.0)-1008.0/2911.0)*(x-2.0)+582.0/2911.0)*(x-2.0));
286 return(((-1.0/41.0*(x-3.0)+168.0/2911.0)*(x-3.0)-97.0/2911.0)*(x-3.0));
290static double Gaussian(
const double x,
const ResizeFilter *resize_filter)
322 return(exp((
double)(-resize_filter->coefficient[1]*x*x)));
325static double Hann(
const double x,
326 const ResizeFilter *magick_unused(resize_filter))
332 const double cosine = cos((
double) (MagickPI*x));
333 magick_unreferenced(resize_filter);
334 return(0.5+0.5*cosine);
337static double Hamming(
const double x,
338 const ResizeFilter *magick_unused(resize_filter))
344 const double cosine = cos((
double) (MagickPI*x));
345 magick_unreferenced(resize_filter);
346 return(0.54+0.46*cosine);
349static double Jinc(
const double x,
350 const ResizeFilter *magick_unused(resize_filter))
352 magick_unreferenced(resize_filter);
363 return(0.5*MagickPI);
364 return(BesselOrderOne(MagickPI*x)/x);
367static double Kaiser(
const double x,
const ResizeFilter *resize_filter)
381 return(resize_filter->coefficient[1]*I0(resize_filter->coefficient[0]*
382 sqrt((
double) (1.0-x*x))));
385static double Lagrange(
const double x,
const ResizeFilter *resize_filter)
407 if (x > resize_filter->support)
409 order=(ssize_t) (2.0*resize_filter->window_support);
410 n=(ssize_t) (resize_filter->window_support+x);
412 for (i=0; i < order; i++)
414 value*=(n-i-x)/(n-i);
418static double MagicKernelSharp2013(
const double x,
419 const ResizeFilter *magick_unused(resize_filter))
421 magick_unreferenced(resize_filter);
430 return(0.625+1.75*(0.5-x)*(0.5+x));
432 return((1.0-x)*(1.75-x));
434 return(-0.125*(2.5-x)*(2.5-x));
438static double MagicKernelSharp2021(
const double x,
439 const ResizeFilter *magick_unused(resize_filter))
441 magick_unreferenced(resize_filter);
450 return(577.0/576.0-239.0/144.0*x*x);
452 return(35.0/36.0*(x-1.0)*(x-239.0/140.0));
454 return(1.0/6.0*(x-2.0)*(65.0/24.0-x));
456 return(1.0/36.0*(x-3.0)*(x-3.75));
458 return(-1.0/288.0*(x-4.5)*(x-4.5));
462static double Quadratic(
const double x,
463 const ResizeFilter *magick_unused(resize_filter))
465 magick_unreferenced(resize_filter);
473 return(0.5*(x-1.5)*(x-1.5));
477static double Sinc(
const double x,
478 const ResizeFilter *magick_unused(resize_filter))
480 magick_unreferenced(resize_filter);
488 const double alpha=(double) (MagickPI*x);
489 return(sin((
double) alpha)/alpha);
491 return((
double) 1.0);
494static double SincFast(
const double x,
495 const ResizeFilter *magick_unused(resize_filter))
497 magick_unreferenced(resize_filter);
525 const double alpha=(double) (MagickPI*x);
526 return(sin((
double) alpha)/alpha);
532 const double xx = x*x;
533#if MAGICKCORE_QUANTUM_DEPTH <= 8
537 const double c0 = 0.173610016489197553621906385078711564924e-2L;
538 const double c1 = -0.384186115075660162081071290162149315834e-3L;
539 const double c2 = 0.393684603287860108352720146121813443561e-4L;
540 const double c3 = -0.248947210682259168029030370205389323899e-5L;
541 const double c4 = 0.107791837839662283066379987646635416692e-6L;
542 const double c5 = -0.324874073895735800961260474028013982211e-8L;
543 const double c6 = 0.628155216606695311524920882748052490116e-10L;
544 const double c7 = -0.586110644039348333520104379959307242711e-12L;
546 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
547 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
548#elif MAGICKCORE_QUANTUM_DEPTH <= 16
552 const double c0 = 0.173611107357320220183368594093166520811e-2L;
553 const double c1 = -0.384240921114946632192116762889211361285e-3L;
554 const double c2 = 0.394201182359318128221229891724947048771e-4L;
555 const double c3 = -0.250963301609117217660068889165550534856e-5L;
556 const double c4 = 0.111902032818095784414237782071368805120e-6L;
557 const double c5 = -0.372895101408779549368465614321137048875e-8L;
558 const double c6 = 0.957694196677572570319816780188718518330e-10L;
559 const double c7 = -0.187208577776590710853865174371617338991e-11L;
560 const double c8 = 0.253524321426864752676094495396308636823e-13L;
561 const double c9 = -0.177084805010701112639035485248501049364e-15L;
563 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*(c7+xx*(c8+xx*c9))))))));
564 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
569 const double c0 = 0.173611111110910715186413700076827593074e-2L;
570 const double c1 = -0.289105544717893415815859968653611245425e-3L;
571 const double c2 = 0.206952161241815727624413291940849294025e-4L;
572 const double c3 = -0.834446180169727178193268528095341741698e-6L;
573 const double c4 = 0.207010104171026718629622453275917944941e-7L;
574 const double c5 = -0.319724784938507108101517564300855542655e-9L;
575 const double c6 = 0.288101675249103266147006509214934493930e-11L;
576 const double c7 = -0.118218971804934245819960233886876537953e-13L;
578 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
579 const double d0 = 1.0L;
580 const double d1 = 0.547981619622284827495856984100563583948e-1L;
581 const double d2 = 0.134226268835357312626304688047086921806e-2L;
582 const double d3 = 0.178994697503371051002463656833597608689e-4L;
583 const double d4 = 0.114633394140438168641246022557689759090e-6L;
584 const double q = d0+xx*(d1+xx*(d2+xx*(d3+xx*d4)));
585 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)/q*p);
590static double Triangle(
const double x,
591 const ResizeFilter *magick_unused(resize_filter))
593 magick_unreferenced(resize_filter);
605static double Welch(
const double x,
606 const ResizeFilter *magick_unused(resize_filter))
608 magick_unreferenced(resize_filter);
804MagickPrivate ResizeFilter *AcquireResizeFilter(
const Image *image,
805 const FilterType filter,
const MagickBooleanType cylindrical,
806 ExceptionInfo *exception)
841 }
const mapping[SentinelFilter] =
843 { UndefinedFilter, BoxFilter },
844 { PointFilter, BoxFilter },
845 { BoxFilter, BoxFilter },
846 { TriangleFilter, BoxFilter },
847 { HermiteFilter, BoxFilter },
848 { SincFastFilter, HannFilter },
849 { SincFastFilter, HammingFilter },
850 { SincFastFilter, BlackmanFilter },
851 { GaussianFilter, BoxFilter },
852 { QuadraticFilter, BoxFilter },
853 { CubicFilter, BoxFilter },
854 { CatromFilter, BoxFilter },
855 { MitchellFilter, BoxFilter },
856 { JincFilter, BoxFilter },
857 { SincFilter, BoxFilter },
858 { SincFastFilter, BoxFilter },
859 { SincFastFilter, KaiserFilter },
860 { LanczosFilter, WelchFilter },
861 { SincFastFilter, CubicFilter },
862 { SincFastFilter, BohmanFilter },
863 { SincFastFilter, TriangleFilter },
864 { LagrangeFilter, BoxFilter },
865 { LanczosFilter, LanczosFilter },
866 { LanczosSharpFilter, LanczosSharpFilter },
867 { Lanczos2Filter, Lanczos2Filter },
868 { Lanczos2SharpFilter, Lanczos2SharpFilter },
869 { RobidouxFilter, BoxFilter },
870 { RobidouxSharpFilter, BoxFilter },
871 { LanczosFilter, CosineFilter },
872 { SplineFilter, BoxFilter },
873 { LanczosRadiusFilter, LanczosFilter },
874 { CubicSplineFilter, BoxFilter },
875 { MagicKernelSharp2013Filter, BoxFilter },
876 { MagicKernelSharp2021Filter, BoxFilter },
892 (*function)(
const double,
const ResizeFilter*),
897 ResizeWeightingFunctionType weightingFunctionType;
898 }
const filters[SentinelFilter] =
905 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
906 { Box, 0.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
907 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
908 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
909 { CubicBC, 1.0, 1.0, 0.0, 0.0, CubicBCWeightingFunction },
910 { Hann, 1.0, 1.0, 0.0, 0.0, HannWeightingFunction },
911 { Hamming, 1.0, 1.0, 0.0, 0.0, HammingWeightingFunction },
912 { Blackman, 1.0, 1.0, 0.0, 0.0, BlackmanWeightingFunction },
913 { Gaussian, 2.0, 1.5, 0.0, 0.0, GaussianWeightingFunction },
914 { Quadratic, 1.5, 1.5, 0.0, 0.0, QuadraticWeightingFunction },
915 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
916 { CubicBC, 2.0, 1.0, 0.0, 0.5, CubicBCWeightingFunction },
917 { CubicBC, 2.0, 8.0/7.0, 1./3., 1./3., CubicBCWeightingFunction },
918 { Jinc, 3.0, 1.2196698912665045, 0.0, 0.0, JincWeightingFunction },
919 { Sinc, 4.0, 1.0, 0.0, 0.0, SincWeightingFunction },
920 { SincFast, 4.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
921 { Kaiser, 1.0, 1.0, 0.0, 0.0, KaiserWeightingFunction },
922 { Welch, 1.0, 1.0, 0.0, 0.0, WelchWeightingFunction },
923 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
924 { Bohman, 1.0, 1.0, 0.0, 0.0, BohmanWeightingFunction },
925 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
926 { Lagrange, 2.0, 1.0, 0.0, 0.0, LagrangeWeightingFunction },
927 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
928 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
929 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
930 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
932 { CubicBC, 2.0, 1.1685777620836932,
933 0.37821575509399867, 0.31089212245300067, CubicBCWeightingFunction },
935 { CubicBC, 2.0, 1.105822933719019,
936 0.2620145123990142, 0.3689927438004929, CubicBCWeightingFunction },
937 { Cosine, 1.0, 1.0, 0.0, 0.0, CosineWeightingFunction },
938 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
939 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
940 { CubicSpline,2.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
941 { MagicKernelSharp2013, 2.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
942 { MagicKernelSharp2021, 4.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
979 assert(image != (
const Image *) NULL);
980 assert(image->signature == MagickCoreSignature);
981 assert(UndefinedFilter < filter && filter < SentinelFilter);
982 assert(exception != (ExceptionInfo *) NULL);
983 assert(exception->signature == MagickCoreSignature);
984 if (IsEventLogging() != MagickFalse)
985 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
987 resize_filter=(ResizeFilter *) AcquireCriticalMemory(
sizeof(*resize_filter));
988 (void) memset(resize_filter,0,
sizeof(*resize_filter));
992 filter_type=mapping[filter].filter;
993 window_type=mapping[filter].window;
994 resize_filter->blur=1.0;
996 if ((cylindrical != MagickFalse) && (filter_type == SincFastFilter) &&
997 (filter != SincFastFilter))
998 filter_type=JincFilter;
1001 artifact=GetImageArtifact(image,
"filter:filter");
1002 if (IsStringTrue(artifact) != MagickFalse)
1007 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1008 if ((UndefinedFilter < option) && (option < SentinelFilter))
1010 filter_type=(FilterType) option;
1011 window_type=BoxFilter;
1014 artifact=GetImageArtifact(image,
"filter:window");
1015 if (artifact != (
const char *) NULL)
1017 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1018 if ((UndefinedFilter < option) && (option < SentinelFilter))
1019 window_type=(FilterType) option;
1025 artifact=GetImageArtifact(image,
"filter:window");
1026 if (artifact != (
const char *) NULL)
1031 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1032 if ((UndefinedFilter < option) && (option < SentinelFilter))
1034 filter_type= cylindrical != MagickFalse ? JincFilter
1036 window_type=(FilterType) option;
1042 resize_filter->filter=filters[filter_type].function;
1043 resize_filter->support=filters[filter_type].support;
1044 resize_filter->filterWeightingType=filters[filter_type].weightingFunctionType;
1045 resize_filter->window=filters[window_type].function;
1046 resize_filter->windowWeightingType=filters[window_type].weightingFunctionType;
1047 resize_filter->scale=filters[window_type].scale;
1048 resize_filter->signature=MagickCoreSignature;
1051 if (cylindrical != MagickFalse)
1052 switch (filter_type)
1056 resize_filter->support=(double) MagickSQ1_2;
1059 case LanczosSharpFilter:
1060 case Lanczos2Filter:
1061 case Lanczos2SharpFilter:
1062 case LanczosRadiusFilter:
1063 resize_filter->filter=filters[JincFilter].function;
1064 resize_filter->window=filters[JincFilter].function;
1065 resize_filter->scale=filters[JincFilter].scale;
1072 switch (filter_type)
1074 case LanczosSharpFilter:
1075 resize_filter->blur *= 0.9812505644269356;
1077 case Lanczos2SharpFilter:
1078 resize_filter->blur *= 0.9549963639785485;
1090 if ((resize_filter->filter == Gaussian) ||
1091 (resize_filter->window == Gaussian) ) {
1093 artifact=GetImageArtifact(image,
"filter:sigma");
1094 if (artifact != (
const char *) NULL)
1095 value=StringToDouble(artifact,(
char **) NULL);
1097 resize_filter->coefficient[0]=value;
1098 resize_filter->coefficient[1]=MagickSafeReciprocal(2.0*value*value);
1099 resize_filter->coefficient[2]=MagickSafeReciprocal(Magick2PI*value*value);
1102 resize_filter->support *= 2*value;
1106 if ((resize_filter->filter == Kaiser) ||
1107 (resize_filter->window == Kaiser) ) {
1109 artifact=GetImageArtifact(image,
"filter:alpha");
1110 if (artifact != (
const char *) NULL)
1111 value=StringToDouble(artifact,(
char **) NULL);
1112 artifact=GetImageArtifact(image,
"filter:kaiser-beta");
1113 if (artifact != (
const char *) NULL)
1114 value=StringToDouble(artifact,(
char **) NULL);
1115 artifact=GetImageArtifact(image,
"filter:kaiser-alpha");
1116 if (artifact != (
const char *) NULL)
1117 value=StringToDouble(artifact,(
char **) NULL)*MagickPI;
1119 resize_filter->coefficient[0]=value;
1120 resize_filter->coefficient[1]=MagickSafeReciprocal(I0(value));
1125 artifact=GetImageArtifact(image,
"filter:lobes");
1126 if (artifact != (
const char *) NULL)
1131 lobes=(ssize_t) StringToLong(artifact);
1134 resize_filter->support=(double) lobes;
1136 if (resize_filter->filter == Jinc)
1141 if (resize_filter->support > 16)
1142 resize_filter->support=jinc_zeros[15];
1144 resize_filter->support=jinc_zeros[((long) resize_filter->support)-1];
1148 if (filter_type == LanczosRadiusFilter)
1149 resize_filter->blur*=floor(resize_filter->support)/
1150 resize_filter->support;
1155 artifact=GetImageArtifact(image,
"filter:blur");
1156 if (artifact != (
const char *) NULL)
1157 resize_filter->blur*=StringToDouble(artifact,(
char **) NULL);
1158 if (resize_filter->blur < MagickEpsilon)
1159 resize_filter->blur=(double) MagickEpsilon;
1163 artifact=GetImageArtifact(image,
"filter:support");
1164 if (artifact != (
const char *) NULL)
1165 resize_filter->support=fabs(StringToDouble(artifact,(
char **) NULL));
1170 resize_filter->window_support=resize_filter->support;
1171 artifact=GetImageArtifact(image,
"filter:win-support");
1172 if (artifact != (
const char *) NULL)
1173 resize_filter->window_support=fabs(StringToDouble(artifact,(
char **) NULL));
1178 resize_filter->scale*=MagickSafeReciprocal(resize_filter->window_support);
1184 if ((resize_filter->filter == CubicBC) ||
1185 (resize_filter->window == CubicBC) )
1187 B=filters[filter_type].B;
1188 C=filters[filter_type].C;
1189 if (filters[window_type].function == CubicBC)
1191 B=filters[window_type].B;
1192 C=filters[window_type].C;
1194 artifact=GetImageArtifact(image,
"filter:b");
1195 if (artifact != (
const char *) NULL)
1197 B=StringToDouble(artifact,(
char **) NULL);
1199 artifact=GetImageArtifact(image,
"filter:c");
1200 if (artifact != (
const char *) NULL)
1201 C=StringToDouble(artifact,(
char **) NULL);
1205 artifact=GetImageArtifact(image,
"filter:c");
1206 if (artifact != (
const char *) NULL)
1208 C=StringToDouble(artifact,(
char **) NULL);
1219 resize_filter->coefficient[0]=1.0-(1.0/3.0)*B;
1220 resize_filter->coefficient[1]=-3.0+twoB+C;
1221 resize_filter->coefficient[2]=2.0-1.5*B-C;
1222 resize_filter->coefficient[3]=(4.0/3.0)*B+4.0*C;
1223 resize_filter->coefficient[4]=-8.0*C-twoB;
1224 resize_filter->coefficient[5]=B+5.0*C;
1225 resize_filter->coefficient[6]=(-1.0/6.0)*B-C;
1232 if (IsStringTrue(GetImageArtifact(image,
"filter:verbose")) != MagickFalse)
1233#if defined(MAGICKCORE_OPENMP_SUPPORT)
1247 if (resize_filter->filter == Box) filter_type=BoxFilter;
1248 if (resize_filter->filter == Sinc) filter_type=SincFilter;
1249 if (resize_filter->filter == SincFast) filter_type=SincFastFilter;
1250 if (resize_filter->filter == Jinc) filter_type=JincFilter;
1251 if (resize_filter->filter == CubicBC) filter_type=CubicFilter;
1252 if (resize_filter->window == Box) window_type=BoxFilter;
1253 if (resize_filter->window == Sinc) window_type=SincFilter;
1254 if (resize_filter->window == SincFast) window_type=SincFastFilter;
1255 if (resize_filter->window == Jinc) window_type=JincFilter;
1256 if (resize_filter->window == CubicBC) window_type=CubicFilter;
1260 support=GetResizeFilterSupport(resize_filter);
1261 (void) FormatLocaleFile(stdout,
"# Resampling Filter (for graphing)\n#\n");
1262 (void) FormatLocaleFile(stdout,
"# filter = %s\n",
1263 CommandOptionToMnemonic(MagickFilterOptions,filter_type));
1264 (void) FormatLocaleFile(stdout,
"# window = %s\n",
1265 CommandOptionToMnemonic(MagickFilterOptions,window_type));
1266 (void) FormatLocaleFile(stdout,
"# support = %.*g\n",
1267 GetMagickPrecision(),(
double) resize_filter->support);
1268 (void) FormatLocaleFile(stdout,
"# window-support = %.*g\n",
1269 GetMagickPrecision(),(
double) resize_filter->window_support);
1270 (void) FormatLocaleFile(stdout,
"# scale-blur = %.*g\n",
1271 GetMagickPrecision(),(
double) resize_filter->blur);
1272 if ((filter_type == GaussianFilter) || (window_type == GaussianFilter))
1273 (void) FormatLocaleFile(stdout,
"# gaussian-sigma = %.*g\n",
1274 GetMagickPrecision(),(
double) resize_filter->coefficient[0]);
1275 if ((filter_type == KaiserFilter) || (window_type == KaiserFilter))
1276 (void) FormatLocaleFile(stdout,
"# kaiser-beta = %.*g\n",
1277 GetMagickPrecision(),(
double) resize_filter->coefficient[0]);
1278 (void) FormatLocaleFile(stdout,
"# practical-support = %.*g\n",
1279 GetMagickPrecision(), (
double) support);
1280 if ((filter_type == CubicFilter) || (window_type == CubicFilter))
1281 (void) FormatLocaleFile(stdout,
"# B,C = %.*g,%.*g\n",
1282 GetMagickPrecision(),(
double) B,GetMagickPrecision(),(
double) C);
1283 (void) FormatLocaleFile(stdout,
"\n");
1287 for (x=0.0; x <= support; x+=0.01)
1288 (
void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",x,GetMagickPrecision(),
1289 (
double) GetResizeFilterWeight(resize_filter,x));
1293 (void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",support,
1294 GetMagickPrecision(),0.0);
1296 (void) DeleteImageArtifact((Image *) image,
"filter:verbose");
1298 return(resize_filter);
1335MagickExport Image *AdaptiveResizeImage(
const Image *image,
1336 const size_t columns,
const size_t rows,ExceptionInfo *exception)
1341 resize_image=InterpolativeResizeImage(image,columns,rows,MeshInterpolatePixel,
1343 return(resize_image);
1386static double I0(
double x)
1402 for (i=2; t > MagickEpsilon; i++)
1405 t*=y/((double) i*i);
1411static double J1(
double x)
1423 0.581199354001606143928050809e+21,
1424 -0.6672106568924916298020941484e+20,
1425 0.2316433580634002297931815435e+19,
1426 -0.3588817569910106050743641413e+17,
1427 0.2908795263834775409737601689e+15,
1428 -0.1322983480332126453125473247e+13,
1429 0.3413234182301700539091292655e+10,
1430 -0.4695753530642995859767162166e+7,
1431 0.270112271089232341485679099e+4
1435 0.11623987080032122878585294e+22,
1436 0.1185770712190320999837113348e+20,
1437 0.6092061398917521746105196863e+17,
1438 0.2081661221307607351240184229e+15,
1439 0.5243710262167649715406728642e+12,
1440 0.1013863514358673989967045588e+10,
1441 0.1501793594998585505921097578e+7,
1442 0.1606931573481487801970916749e+4,
1448 for (i=7; i >= 0; i--)
1457static double P1(
double x)
1469 0.352246649133679798341724373e+5,
1470 0.62758845247161281269005675e+5,
1471 0.313539631109159574238669888e+5,
1472 0.49854832060594338434500455e+4,
1473 0.2111529182853962382105718e+3,
1474 0.12571716929145341558495e+1
1478 0.352246649133679798068390431e+5,
1479 0.626943469593560511888833731e+5,
1480 0.312404063819041039923015703e+5,
1481 0.4930396490181088979386097e+4,
1482 0.2030775189134759322293574e+3,
1488 for (i=4; i >= 0; i--)
1490 p=p*(8.0/x)*(8.0/x)+Pone[i];
1491 q=q*(8.0/x)*(8.0/x)+Qone[i];
1497static double Q1(
double x)
1509 0.3511751914303552822533318e+3,
1510 0.7210391804904475039280863e+3,
1511 0.4259873011654442389886993e+3,
1512 0.831898957673850827325226e+2,
1513 0.45681716295512267064405e+1,
1514 0.3532840052740123642735e-1
1518 0.74917374171809127714519505e+4,
1519 0.154141773392650970499848051e+5,
1520 0.91522317015169922705904727e+4,
1521 0.18111867005523513506724158e+4,
1522 0.1038187585462133728776636e+3,
1528 for (i=4; i >= 0; i--)
1530 p=p*(8.0/x)*(8.0/x)+Pone[i];
1531 q=q*(8.0/x)*(8.0/x)+Qone[i];
1536static double BesselOrderOne(
double x)
1549 q=sqrt((
double) (2.0/(MagickPI*x)))*(P1(x)*(1.0/sqrt(2.0)*(sin(x)-
1550 cos(x)))-8.0/x*Q1(x)*(-1.0/sqrt(2.0)*(sin(x)+cos(x))));
1578MagickPrivate ResizeFilter *DestroyResizeFilter(ResizeFilter *resize_filter)
1580 assert(resize_filter != (ResizeFilter *) NULL);
1581 assert(resize_filter->signature == MagickCoreSignature);
1582 resize_filter->signature=(~MagickCoreSignature);
1583 resize_filter=(ResizeFilter *) RelinquishMagickMemory(resize_filter);
1584 return(resize_filter);
1611MagickPrivate
double *GetResizeFilterCoefficient(
1612 const ResizeFilter *resize_filter)
1614 assert(resize_filter != (ResizeFilter *) NULL);
1615 assert(resize_filter->signature == MagickCoreSignature);
1616 return((
double *) resize_filter->coefficient);
1619MagickPrivate
double GetResizeFilterBlur(
const ResizeFilter *resize_filter)
1621 assert(resize_filter != (ResizeFilter *) NULL);
1622 assert(resize_filter->signature == MagickCoreSignature);
1623 return(resize_filter->blur);
1626MagickPrivate
double GetResizeFilterScale(
const ResizeFilter *resize_filter)
1628 assert(resize_filter != (ResizeFilter *) NULL);
1629 assert(resize_filter->signature == MagickCoreSignature);
1630 return(resize_filter->scale);
1633MagickPrivate
double GetResizeFilterWindowSupport(
1634 const ResizeFilter *resize_filter)
1636 assert(resize_filter != (ResizeFilter *) NULL);
1637 assert(resize_filter->signature == MagickCoreSignature);
1638 return(resize_filter->window_support);
1641MagickPrivate ResizeWeightingFunctionType GetResizeFilterWeightingType(
1642 const ResizeFilter *resize_filter)
1644 assert(resize_filter != (ResizeFilter *) NULL);
1645 assert(resize_filter->signature == MagickCoreSignature);
1646 return(resize_filter->filterWeightingType);
1649MagickPrivate ResizeWeightingFunctionType GetResizeFilterWindowWeightingType(
1650 const ResizeFilter *resize_filter)
1652 assert(resize_filter != (ResizeFilter *) NULL);
1653 assert(resize_filter->signature == MagickCoreSignature);
1654 return(resize_filter->windowWeightingType);
1657MagickPrivate
double GetResizeFilterSupport(
const ResizeFilter *resize_filter)
1659 assert(resize_filter != (ResizeFilter *) NULL);
1660 assert(resize_filter->signature == MagickCoreSignature);
1661 return(resize_filter->support*resize_filter->blur);
1691MagickPrivate
double GetResizeFilterWeight(
const ResizeFilter *resize_filter,
1702 assert(resize_filter != (ResizeFilter *) NULL);
1703 assert(resize_filter->signature == MagickCoreSignature);
1704 x_blur=fabs((
double) x)*MagickSafeReciprocal(resize_filter->blur);
1705 if ((resize_filter->window_support < MagickEpsilon) ||
1706 (resize_filter->window == Box))
1710 scale=resize_filter->scale;
1711 scale=resize_filter->window(x_blur*scale,resize_filter);
1713 weight=scale*resize_filter->filter(x_blur,resize_filter);
1750MagickExport Image *InterpolativeResizeImage(
const Image *image,
1751 const size_t columns,
const size_t rows,
const PixelInterpolateMethod method,
1752 ExceptionInfo *exception)
1754#define InterpolativeResizeImageTag "Resize/Image"
1778 assert(image != (
const Image *) NULL);
1779 assert(image->signature == MagickCoreSignature);
1780 assert(exception != (ExceptionInfo *) NULL);
1781 assert(exception->signature == MagickCoreSignature);
1782 if (IsEventLogging() != MagickFalse)
1783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1784 if ((columns == 0) || (rows == 0))
1785 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1786 if ((columns == image->columns) && (rows == image->rows))
1787 return(CloneImage(image,0,0,MagickTrue,exception));
1788 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
1789 if (resize_image == (Image *) NULL)
1790 return((Image *) NULL);
1791 if (SetImageStorageClass(resize_image,DirectClass,exception) == MagickFalse)
1793 resize_image=DestroyImage(resize_image);
1794 return((Image *) NULL);
1798 image_view=AcquireVirtualCacheView(image,exception);
1799 resize_view=AcquireAuthenticCacheView(resize_image,exception);
1800 scale.x=(double) image->columns/resize_image->columns;
1801 scale.y=(double) image->rows/resize_image->rows;
1802#if defined(MAGICKCORE_OPENMP_SUPPORT)
1803 #pragma omp parallel for schedule(static) shared(progress,status) \
1804 magick_number_threads(image,resize_image,resize_image->rows,1)
1806 for (y=0; y < (ssize_t) resize_image->rows; y++)
1817 if (status == MagickFalse)
1819 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
1821 if (q == (Quantum *) NULL)
1823 offset.y=((double) y+0.5)*scale.y-0.5;
1824 for (x=0; x < (ssize_t) resize_image->columns; x++)
1829 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1838 channel=GetPixelChannelChannel(image,i);
1839 traits=GetPixelChannelTraits(image,channel);
1840 resize_traits=GetPixelChannelTraits(resize_image,channel);
1841 if ((traits == UndefinedPixelTrait) ||
1842 (resize_traits == UndefinedPixelTrait))
1844 offset.x=((double) x+0.5)*scale.x-0.5;
1845 status=InterpolatePixelChannels(image,image_view,resize_image,method,
1846 offset.x,offset.y,q,exception);
1847 if (status == MagickFalse)
1850 q+=(ptrdiff_t) GetPixelChannels(resize_image);
1852 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
1854 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1859#if defined(MAGICKCORE_OPENMP_SUPPORT)
1863 proceed=SetImageProgress(image,InterpolativeResizeImageTag,progress,
1865 if (proceed == MagickFalse)
1869 resize_view=DestroyCacheView(resize_view);
1870 image_view=DestroyCacheView(image_view);
1871 if (status == MagickFalse)
1872 resize_image=DestroyImage(resize_image);
1873 return(resize_image);
1875#if defined(MAGICKCORE_LQR_DELEGATE)
1911MagickExport Image *LiquidRescaleImage(
const Image *image,
const size_t columns,
1912 const size_t rows,
const double delta_x,
const double rigidity,
1913 ExceptionInfo *exception)
1915#define LiquidRescaleImageTag "Rescale/Image"
1953 assert(image != (
const Image *) NULL);
1954 assert(image->signature == MagickCoreSignature);
1955 assert(exception != (ExceptionInfo *) NULL);
1956 assert(exception->signature == MagickCoreSignature);
1957 if (IsEventLogging() != MagickFalse)
1958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1959 if ((columns == 0) || (rows == 0))
1960 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1961 if ((columns == image->columns) && (rows == image->rows))
1962 return(CloneImage(image,0,0,MagickTrue,exception));
1963 if ((columns <= 2) || (rows <= 2))
1964 return(ResizeImage(image,columns,rows,image->filter,exception));
1965 pixel_info=AcquireVirtualMemory(image->columns,image->rows*MaxPixelChannels*
1967 if (pixel_info == (MemoryInfo *) NULL)
1968 return((Image *) NULL);
1969 pixels=(gfloat *) GetVirtualMemoryBlob(pixel_info);
1972 image_view=AcquireVirtualCacheView(image,exception);
1973 for (y=0; y < (ssize_t) image->rows; y++)
1981 if (status == MagickFalse)
1983 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1984 if (p == (
const Quantum *) NULL)
1989 for (x=0; x < (ssize_t) image->columns; x++)
1994 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1995 *q++=(gfloat) (QuantumScale*(double) p[i]);
1996 p+=(ptrdiff_t) GetPixelChannels(image);
1999 image_view=DestroyCacheView(image_view);
2000 carver=lqr_carver_new_ext(pixels,(
int) image->columns,(
int) image->rows,
2001 (
int) GetPixelChannels(image),LQR_COLDEPTH_32F);
2002 if (carver == (LqrCarver *) NULL)
2004 pixel_info=RelinquishVirtualMemory(pixel_info);
2005 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2007 lqr_carver_set_preserve_input_image(carver);
2008 lqr_status=lqr_carver_init(carver,(gint) delta_x,(gfloat) rigidity);
2009 lqr_status=lqr_carver_resize(carver,(gint) columns,(gint) rows);
2011 rescale_image=CloneImage(image,(
size_t) lqr_carver_get_width(carver),
2012 (
size_t) lqr_carver_get_height(carver),MagickTrue,exception);
2013 if (rescale_image == (Image *) NULL)
2015 pixel_info=RelinquishVirtualMemory(pixel_info);
2016 return((Image *) NULL);
2018 if (SetImageStorageClass(rescale_image,DirectClass,exception) == MagickFalse)
2020 pixel_info=RelinquishVirtualMemory(pixel_info);
2021 rescale_image=DestroyImage(rescale_image);
2022 return((Image *) NULL);
2024 rescale_view=AcquireAuthenticCacheView(rescale_image,exception);
2025 (void) lqr_carver_scan_reset(carver);
2026 while (lqr_carver_scan_ext(carver,&x_offset,&y_offset,(
void **) &packet) != 0)
2034 p=QueueCacheViewAuthenticPixels(rescale_view,x_offset,y_offset,1,1,
2036 if (p == (Quantum *) NULL)
2038 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2047 channel=GetPixelChannelChannel(image,i);
2048 traits=GetPixelChannelTraits(image,channel);
2049 rescale_traits=GetPixelChannelTraits(rescale_image,channel);
2050 if ((traits == UndefinedPixelTrait) ||
2051 (rescale_traits == UndefinedPixelTrait))
2053 SetPixelChannel(rescale_image,channel,ClampToQuantum(QuantumRange*
2056 if (SyncCacheViewAuthenticPixels(rescale_view,exception) == MagickFalse)
2059 rescale_view=DestroyCacheView(rescale_view);
2060 pixel_info=RelinquishVirtualMemory(pixel_info);
2061 lqr_carver_destroy(carver);
2062 return(rescale_image);
2065MagickExport Image *LiquidRescaleImage(
const Image *image,
2066 const size_t magick_unused(columns),
const size_t magick_unused(rows),
2067 const double magick_unused(delta_x),
const double magick_unused(rigidity),
2068 ExceptionInfo *exception)
2070 assert(image != (
const Image *) NULL);
2071 assert(image->signature == MagickCoreSignature);
2072 assert(exception != (ExceptionInfo *) NULL);
2073 assert(exception->signature == MagickCoreSignature);
2074 magick_unreferenced(columns);
2075 magick_unreferenced(rows);
2076 magick_unreferenced(delta_x);
2077 magick_unreferenced(rigidity);
2078 if (IsEventLogging() != MagickFalse)
2079 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2080 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
2081 "DelegateLibrarySupportNotBuiltIn",
"'%s' (LQR)",image->filename);
2082 return((Image *) NULL);
2112static inline void CopyPixels(
const Quantum *source,
const ssize_t source_offset,
2113 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2118 for (i=0; i < (ssize_t) channels; i++)
2119 destination[(ssize_t) channels*destination_offset+i]=
2120 source[source_offset*(ssize_t) channels+i];
2123static inline void MixPixels(
const Quantum *source,
const ssize_t *source_offset,
2124 const size_t source_size,Quantum *destination,
2125 const ssize_t destination_offset,
const size_t channels)
2130 for (i=0; i < (ssize_t) channels; i++)
2136 for (j=0; j < (ssize_t) source_size; j++)
2137 sum+=(ssize_t) source[source_offset[j]*(ssize_t) channels+i];
2138 destination[(ssize_t) channels*destination_offset+i]=(Quantum) (sum/
2139 (ssize_t) source_size);
2143static inline void Mix2Pixels(
const Quantum *source,
2144 const ssize_t source_offset1,
const ssize_t source_offset2,
2145 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2148 offsets[2] = { source_offset1, source_offset2 };
2150 MixPixels(source,offsets,2,destination,destination_offset,channels);
2153static inline int PixelsEqual(
const Quantum *source1,ssize_t offset1,
2154 const Quantum *source2,ssize_t offset2,
const size_t channels)
2159 offset1*=(ssize_t) channels;
2160 offset2*=(ssize_t) channels;
2161 for (i=0; i < (ssize_t) channels; i++)
2162 if (source1[offset1+i] != source2[offset2+i])
2167static inline void Eagle2X(
const Image *source,
const Quantum *pixels,
2168 Quantum *result,
const size_t channels)
2174 for (i=0; i < 4; i++)
2175 CopyPixels(pixels,4,result,i,channels);
2176 if (PixelsEqual(pixels,0,pixels,1,channels) &&
2177 PixelsEqual(pixels,1,pixels,3,channels))
2178 CopyPixels(pixels,0,result,0,channels);
2179 if (PixelsEqual(pixels,1,pixels,2,channels) &&
2180 PixelsEqual(pixels,2,pixels,5,channels))
2181 CopyPixels(pixels,2,result,1,channels);
2182 if (PixelsEqual(pixels,3,pixels,6,channels) &&
2183 PixelsEqual(pixels,6,pixels,7,channels))
2184 CopyPixels(pixels,6,result,2,channels);
2185 if (PixelsEqual(pixels,5,pixels,8,channels) &&
2186 PixelsEqual(pixels,8,pixels,7,channels))
2187 CopyPixels(pixels,8,result,3,channels);
2190static void Hq2XHelper(
const unsigned int rule,
const Quantum *source,
2191 Quantum *destination,
const ssize_t destination_offset,
const size_t channels,
2192 const ssize_t e,
const ssize_t a,
const ssize_t b,
const ssize_t d,
2193 const ssize_t f,
const ssize_t h)
2195#define caseA(N,A,B,C,D) \
2199 offsets[4] = { A, B, C, D }; \
2201 MixPixels(source,offsets,4,destination,destination_offset,channels);\
2204#define caseB(N,A,B,C,D,E,F,G,H) \
2208 offsets[8] = { A, B, C, D, E, F, G, H }; \
2210 MixPixels(source,offsets,8,destination,destination_offset,channels);\
2218 CopyPixels(source,e,destination,destination_offset,channels);
2227 caseB(7,e,e,e,e,e,b,b,d)
2228 caseB(8,e,e,e,e,e,d,d,b)
2229 caseB(9,e,e,e,e,e,e,d,b)
2230 caseB(10,e,e,d,d,d,b,b,b)
2234 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2236 MixPixels(source,offsets,16,destination,destination_offset,channels);
2241 if (PixelsEqual(source,b,source,d,channels))
2244 offsets[4] = { e, e, d, b };
2246 MixPixels(source,offsets,4,destination,destination_offset,channels);
2249 CopyPixels(source,e,destination,destination_offset,channels);
2254 if (PixelsEqual(source,b,source,d,channels))
2257 offsets[8] = { e, e, d, d, d, b, b, b };
2259 MixPixels(source,offsets,8,destination,destination_offset,channels);
2262 CopyPixels(source,e,destination,destination_offset,channels);
2267 if (PixelsEqual(source,b,source,d,channels))
2270 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2272 MixPixels(source,offsets,16,destination,destination_offset,channels);
2275 CopyPixels(source,e,destination,destination_offset,channels);
2280 if (PixelsEqual(source,b,source,d,channels))
2283 offsets[4] = { e, e, d, b };
2285 MixPixels(source,offsets,4,destination,destination_offset,channels);
2290 offsets[4] = { e, e, e, a };
2292 MixPixels(source,offsets,4,destination,destination_offset,channels);
2298 if (PixelsEqual(source,b,source,d,channels))
2301 offsets[8] = { e, e, e, e, e, e, d, b };
2303 MixPixels(source,offsets,8,destination,destination_offset,channels);
2308 offsets[4] = { e, e, e, a };
2310 MixPixels(source,offsets,4,destination,destination_offset,channels);
2316 if (PixelsEqual(source,b,source,d,channels))
2319 offsets[8] = { e, e, d, d, d, b, b, b };
2321 MixPixels(source,offsets,8,destination,destination_offset,channels);
2326 offsets[4] = { e, e, e, a };
2328 MixPixels(source,offsets,4,destination,destination_offset,channels);
2334 if (PixelsEqual(source,b,source,f,channels))
2337 offsets[8] = { e, e, e, e, e, b, b, d };
2339 MixPixels(source,offsets,8,destination,destination_offset,channels);
2344 offsets[4] = { e, e, e, d };
2346 MixPixels(source,offsets,4,destination,destination_offset,channels);
2352 if (PixelsEqual(source,d,source,h,channels))
2355 offsets[8] = { e, e, e, e, e, d, d, b };
2357 MixPixels(source,offsets,8,destination,destination_offset,channels);
2362 offsets[4] = { e, e, e, b };
2364 MixPixels(source,offsets,4,destination,destination_offset,channels);
2373static inline unsigned int Hq2XPatternToNumber(
const int *pattern)
2384 for (i=7; i >= 0; i--)
2386 result+=order*(
unsigned int) pattern[i];
2392static inline void Hq2X(
const Image *source,
const Quantum *pixels,
2393 Quantum *result,
const size_t channels)
2395 static const unsigned int
2398 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2399 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
2400 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2401 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
2402 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
2403 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2404 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
2405 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
2406 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2407 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2408 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2409 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
2410 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
2411 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
2412 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
2413 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14
2419 !PixelsEqual(pixels,4,pixels,8,channels),
2420 !PixelsEqual(pixels,4,pixels,7,channels),
2421 !PixelsEqual(pixels,4,pixels,6,channels),
2422 !PixelsEqual(pixels,4,pixels,5,channels),
2423 !PixelsEqual(pixels,4,pixels,3,channels),
2424 !PixelsEqual(pixels,4,pixels,2,channels),
2425 !PixelsEqual(pixels,4,pixels,1,channels),
2426 !PixelsEqual(pixels,4,pixels,0,channels)
2429#define Rotated(p) p[2], p[4], p[7], p[1], p[6], p[0], p[3], p[5]
2430 const int pattern2[] = { Rotated(pattern1) };
2431 const int pattern3[] = { Rotated(pattern2) };
2432 const int pattern4[] = { Rotated(pattern3) };
2435 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern1)],pixels,result,0,
2436 channels,4,0,1,3,5,7);
2437 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern2)],pixels,result,1,
2438 channels,4,2,5,1,7,3);
2439 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern3)],pixels,result,3,
2440 channels,4,8,7,5,3,1);
2441 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern4)],pixels,result,2,
2442 channels,4,6,3,7,1,5);
2445static void Fish2X(
const Image *source,
const Quantum *pixels,Quantum *result,
2446 const size_t channels)
2448#define Corner(A,B,C,D) \
2450 if (intensities[B] > intensities[A]) \
2453 offsets[3] = { B, C, D }; \
2455 MixPixels(pixels,offsets,3,result,3,channels); \
2460 offsets[3] = { A, B, C }; \
2462 MixPixels(pixels,offsets,3,result,3,channels); \
2466#define Line(A,B,C,D) \
2468 if (intensities[C] > intensities[A]) \
2469 Mix2Pixels(pixels,C,D,result,3,channels); \
2471 Mix2Pixels(pixels,A,B,result,3,channels); \
2475 pixels_offsets[4] = { 0, 1, 3, 4 };
2491 for (i=0; i < 9; i++)
2492 intensities[i]=(MagickFloatType) GetPixelIntensity(source,pixels+
2493 i*(ssize_t) channels);
2494 CopyPixels(pixels,0,result,0,channels);
2495 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[1] ? 0 : 1),result,
2497 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[3] ? 0 : 3),result,
2499 ae=PixelsEqual(pixels,0,pixels,4,channels);
2500 bd=PixelsEqual(pixels,1,pixels,3,channels);
2501 ab=PixelsEqual(pixels,0,pixels,1,channels);
2502 de=PixelsEqual(pixels,3,pixels,4,channels);
2503 ad=PixelsEqual(pixels,0,pixels,3,channels);
2504 be=PixelsEqual(pixels,1,pixels,4,channels);
2507 CopyPixels(pixels,0,result,3,channels);
2510 if (ad && de && !ab)
2515 if (be && de && !ab)
2520 if (ad && ab && !be)
2525 if (ab && be && !ad)
2530 if (ae && (!bd || intensities[1] > intensities[0]))
2532 Mix2Pixels(pixels,0,4,result,3,channels);
2535 if (bd && (!ae || intensities[0] > intensities[1]))
2537 Mix2Pixels(pixels,1,3,result,3,channels);
2560 MixPixels(pixels,pixels_offsets,4,result,3,channels);
2565static void Xbr2X(
const Image *magick_unused(source),
const Quantum *pixels,
2566 Quantum *result,
const size_t channels)
2568#define WeightVar(M,N) const int w_##M##_##N = \
2569 PixelsEqual(pixels,M,pixels,N,channels) ? 0 : 1;
2601 magick_unreferenced(source);
2604 w_12_16 + w_12_8 + w_6_10 + w_6_2 + (4 * w_11_7) <
2605 w_11_17 + w_11_5 + w_7_13 + w_7_1 + (4 * w_12_6)
2607 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_7 ? 11 : 7),12,result,0,
2610 CopyPixels(pixels,12,result,0,channels);
2612 w_12_18 + w_12_6 + w_8_14 + w_8_2 + (4 * w_7_13) <
2613 w_13_17 + w_13_9 + w_11_7 + w_7_3 + (4 * w_12_8)
2615 Mix2Pixels(pixels,(ssize_t) (w_12_7 <= w_12_13 ? 7 : 13),12,result,1,
2618 CopyPixels(pixels,12,result,1,channels);
2620 w_12_6 + w_12_18 + w_16_10 + w_16_22 + (4 * w_11_17) <
2621 w_11_7 + w_11_15 + w_13_17 + w_17_21 + (4 * w_12_16)
2623 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_17 ? 11 : 17),12,result,2,
2626 CopyPixels(pixels,12,result,2,channels);
2628 w_12_8 + w_12_16 + w_18_14 + w_18_22 + (4 * w_13_17) <
2629 w_11_17 + w_17_23 + w_17_19 + w_7_13 + (4 * w_12_18)
2631 Mix2Pixels(pixels,(ssize_t) (w_12_13 <= w_12_17 ? 13 : 17),12,result,3,
2634 CopyPixels(pixels,12,result,3,channels);
2637static void Scale2X(
const Image *magick_unused(source),
const Quantum *pixels,
2638 Quantum *result,
const size_t channels)
2640 magick_unreferenced(source);
2642 if (PixelsEqual(pixels,1,pixels,7,channels) ||
2643 PixelsEqual(pixels,3,pixels,5,channels))
2648 for (i=0; i < 4; i++)
2649 CopyPixels(pixels,4,result,i,channels);
2652 if (PixelsEqual(pixels,1,pixels,3,channels))
2653 CopyPixels(pixels,3,result,0,channels);
2655 CopyPixels(pixels,4,result,0,channels);
2656 if (PixelsEqual(pixels,1,pixels,5,channels))
2657 CopyPixels(pixels,5,result,1,channels);
2659 CopyPixels(pixels,4,result,1,channels);
2660 if (PixelsEqual(pixels,3,pixels,7,channels))
2661 CopyPixels(pixels,3,result,2,channels);
2663 CopyPixels(pixels,4,result,2,channels);
2664 if (PixelsEqual(pixels,5,pixels,7,channels))
2665 CopyPixels(pixels,5,result,3,channels);
2667 CopyPixels(pixels,4,result,3,channels);
2670static void Epbx2X(
const Image *magick_unused(source),
const Quantum *pixels,
2671 Quantum *result,
const size_t channels)
2673#define HelperCond(a,b,c,d,e,f,g) ( \
2674 PixelsEqual(pixels,a,pixels,b,channels) && ( \
2675 PixelsEqual(pixels,c,pixels,d,channels) || \
2676 PixelsEqual(pixels,c,pixels,e,channels) || \
2677 PixelsEqual(pixels,a,pixels,f,channels) || \
2678 PixelsEqual(pixels,b,pixels,g,channels) \
2685 magick_unreferenced(source);
2687 for (i=0; i < 4; i++)
2688 CopyPixels(pixels,4,result,i,channels);
2690 !PixelsEqual(pixels,3,pixels,5,channels) &&
2691 !PixelsEqual(pixels,1,pixels,7,channels) &&
2693 PixelsEqual(pixels,4,pixels,3,channels) ||
2694 PixelsEqual(pixels,4,pixels,7,channels) ||
2695 PixelsEqual(pixels,4,pixels,5,channels) ||
2696 PixelsEqual(pixels,4,pixels,1,channels) ||
2699 !PixelsEqual(pixels,0,pixels,8,channels) ||
2700 PixelsEqual(pixels,4,pixels,6,channels) ||
2701 PixelsEqual(pixels,3,pixels,2,channels)
2704 !PixelsEqual(pixels,6,pixels,2,channels) ||
2705 PixelsEqual(pixels,4,pixels,0,channels) ||
2706 PixelsEqual(pixels,4,pixels,8,channels)
2712 if (HelperCond(1,3,4,0,8,2,6))
2713 Mix2Pixels(pixels,1,3,result,0,channels);
2714 if (HelperCond(5,1,4,2,6,8,0))
2715 Mix2Pixels(pixels,5,1,result,1,channels);
2716 if (HelperCond(3,7,4,6,2,0,8))
2717 Mix2Pixels(pixels,3,7,result,2,channels);
2718 if (HelperCond(7,5,4,8,0,6,2))
2719 Mix2Pixels(pixels,7,5,result,3,channels);
2725static inline void Eagle3X(
const Image *magick_unused(source),
2726 const Quantum *pixels,Quantum *result,
const size_t channels)
2734 magick_unreferenced(source);
2736 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2737 PixelsEqual(pixels,0,pixels,3,channels);
2738 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2739 PixelsEqual(pixels,2,pixels,5,channels);
2740 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2741 PixelsEqual(pixels,6,pixels,7,channels);
2742 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2743 PixelsEqual(pixels,7,pixels,8,channels);
2744 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2745 if (corner_tl && corner_tr)
2746 Mix2Pixels(pixels,0,2,result,1,channels);
2748 CopyPixels(pixels,4,result,1,channels);
2749 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2750 if (corner_tl && corner_bl)
2751 Mix2Pixels(pixels,0,6,result,3,channels);
2753 CopyPixels(pixels,4,result,3,channels);
2754 CopyPixels(pixels,4,result,4,channels);
2755 if (corner_tr && corner_br)
2756 Mix2Pixels(pixels,2,8,result,5,channels);
2758 CopyPixels(pixels,4,result,5,channels);
2759 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2760 if (corner_bl && corner_br)
2761 Mix2Pixels(pixels,6,8,result,7,channels);
2763 CopyPixels(pixels,4,result,7,channels);
2764 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2767static inline void Eagle3XB(
const Image *magick_unused(source),
2768 const Quantum *pixels,Quantum *result,
const size_t channels)
2776 magick_unreferenced(source);
2778 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2779 PixelsEqual(pixels,0,pixels,3,channels);
2780 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2781 PixelsEqual(pixels,2,pixels,5,channels);
2782 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2783 PixelsEqual(pixels,6,pixels,7,channels);
2784 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2785 PixelsEqual(pixels,7,pixels,8,channels);
2786 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2787 CopyPixels(pixels,4,result,1,channels);
2788 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2789 CopyPixels(pixels,4,result,3,channels);
2790 CopyPixels(pixels,4,result,4,channels);
2791 CopyPixels(pixels,4,result,5,channels);
2792 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2793 CopyPixels(pixels,4,result,7,channels);
2794 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2797static inline void Scale3X(
const Image *magick_unused(source),
2798 const Quantum *pixels,Quantum *result,
const size_t channels)
2800 magick_unreferenced(source);
2802 if (!PixelsEqual(pixels,1,pixels,7,channels) &&
2803 !PixelsEqual(pixels,3,pixels,5,channels))
2805 if (PixelsEqual(pixels,3,pixels,1,channels))
2806 CopyPixels(pixels,3,result,0,channels);
2808 CopyPixels(pixels,4,result,0,channels);
2812 PixelsEqual(pixels,3,pixels,1,channels) &&
2813 !PixelsEqual(pixels,4,pixels,2,channels)
2816 PixelsEqual(pixels,5,pixels,1,channels) &&
2817 !PixelsEqual(pixels,4,pixels,0,channels)
2820 CopyPixels(pixels,1,result,1,channels);
2822 CopyPixels(pixels,4,result,1,channels);
2823 if (PixelsEqual(pixels,5,pixels,1,channels))
2824 CopyPixels(pixels,5,result,2,channels);
2826 CopyPixels(pixels,4,result,2,channels);
2829 PixelsEqual(pixels,3,pixels,1,channels) &&
2830 !PixelsEqual(pixels,4,pixels,6,channels)
2833 PixelsEqual(pixels,3,pixels,7,channels) &&
2834 !PixelsEqual(pixels,4,pixels,0,channels)
2837 CopyPixels(pixels,3,result,3,channels);
2839 CopyPixels(pixels,4,result,3,channels);
2840 CopyPixels(pixels,4,result,4,channels);
2843 PixelsEqual(pixels,5,pixels,1,channels) &&
2844 !PixelsEqual(pixels,4,pixels,8,channels)
2847 PixelsEqual(pixels,5,pixels,7,channels) &&
2848 !PixelsEqual(pixels,4,pixels,2,channels)
2851 CopyPixels(pixels,5,result,5,channels);
2853 CopyPixels(pixels,4,result,5,channels);
2854 if (PixelsEqual(pixels,3,pixels,7,channels))
2855 CopyPixels(pixels,3,result,6,channels);
2857 CopyPixels(pixels,4,result,6,channels);
2860 PixelsEqual(pixels,3,pixels,7,channels) &&
2861 !PixelsEqual(pixels,4,pixels,8,channels)
2864 PixelsEqual(pixels,5,pixels,7,channels) &&
2865 !PixelsEqual(pixels,4,pixels,6,channels)
2868 CopyPixels(pixels,7,result,7,channels);
2870 CopyPixels(pixels,4,result,7,channels);
2871 if (PixelsEqual(pixels,5,pixels,7,channels))
2872 CopyPixels(pixels,5,result,8,channels);
2874 CopyPixels(pixels,4,result,8,channels);
2881 for (i=0; i < 9; i++)
2882 CopyPixels(pixels,4,result,i,channels);
2886MagickExport Image *MagnifyImage(
const Image *image,ExceptionInfo *exception)
2888#define MagnifyImageTag "Magnify/Image"
2889#define MaxMagnification 9
2922 (*scaling_method)(
const Image *,
const Quantum *,Quantum *,size_t);
2927 assert(image != (
const Image *) NULL);
2928 assert(image->signature == MagickCoreSignature);
2929 assert(exception != (ExceptionInfo *) NULL);
2930 assert(exception->signature == MagickCoreSignature);
2931 if (IsEventLogging() != MagickFalse)
2932 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2933 option=GetImageOption(image->image_info,
"magnify:method");
2934 if (option == (
char *) NULL)
2936 scaling_method=Scale2X;
2943 if (LocaleCompare(option,
"eagle2x") == 0)
2945 scaling_method=Eagle2X;
2950 if (LocaleCompare(option,
"eagle3x") == 0)
2952 scaling_method=Eagle3X;
2957 if (LocaleCompare(option,
"eagle3xb") == 0)
2959 scaling_method=Eagle3XB;
2964 if (LocaleCompare(option,
"epbx2x") == 0)
2966 scaling_method=Epbx2X;
2975 if (LocaleCompare(option,
"fish2x") == 0)
2977 scaling_method=Fish2X;
2986 if (LocaleCompare(option,
"hq2x") == 0)
2988 scaling_method=Hq2X;
2997 if (LocaleCompare(option,
"scale2x") == 0)
2999 scaling_method=Scale2X;
3004 if (LocaleCompare(option,
"scale3x") == 0)
3006 scaling_method=Scale3X;
3015 if (LocaleCompare(option,
"xbr2x") == 0)
3017 scaling_method=Xbr2X;
3026 assert((magnification*magnification) <= MaxMagnification);
3030 source_image=CloneImage(image,image->columns,image->rows,MagickTrue,
3032 if (source_image == (Image *) NULL)
3033 return((Image *) NULL);
3038 rectangle.width=image->columns;
3039 rectangle.height=image->rows;
3040 (void) CopyImagePixels(source_image,image,&rectangle,&offset,exception);
3041 if (IssRGBCompatibleColorspace(source_image->colorspace) == MagickFalse)
3042 (void) TransformImageColorspace(source_image,sRGBColorspace,exception);
3043 magnify_image=CloneImage(source_image,magnification*source_image->columns,
3044 magnification*source_image->rows,MagickTrue,exception);
3045 if (magnify_image == (Image *) NULL)
3047 source_image=DestroyImage(source_image);
3048 return((Image *) NULL);
3055 image_view=AcquireVirtualCacheView(source_image,exception);
3056 magnify_view=AcquireAuthenticCacheView(magnify_image,exception);
3057#if defined(MAGICKCORE_OPENMP_SUPPORT)
3058 #pragma omp parallel for schedule(static) shared(progress,status) \
3059 magick_number_threads(source_image,magnify_image,source_image->rows,1)
3061 for (y=0; y < (ssize_t) source_image->rows; y++)
3064 r[MaxMagnification*MaxPixelChannels];
3072 if (status == MagickFalse)
3074 q=QueueCacheViewAuthenticPixels(magnify_view,0,magnification*y,
3075 magnify_image->columns,magnification,exception);
3076 if (q == (Quantum *) NULL)
3084 for (x=0; x < (ssize_t) source_image->columns; x++)
3096 p=GetCacheViewVirtualPixels(image_view,x-width/2,y-width/2,width,width,
3098 if (p == (Quantum *) NULL)
3103 channels=GetPixelChannels(source_image);
3104 scaling_method(source_image,p,r,channels);
3108 for (j=0; j < (ssize_t) magnification; j++)
3109 for (i=0; i < (ssize_t) (channels*magnification); i++)
3110 q[j*(ssize_t) channels*(ssize_t) magnify_image->columns+i]=
3111 r[j*magnification*(ssize_t) channels+i];
3112 q+=(ptrdiff_t) magnification*GetPixelChannels(magnify_image);
3114 if (SyncCacheViewAuthenticPixels(magnify_view,exception) == MagickFalse)
3116 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3121#if defined(MAGICKCORE_OPENMP_SUPPORT)
3125 proceed=SetImageProgress(image,MagnifyImageTag,progress,image->rows);
3126 if (proceed == MagickFalse)
3130 magnify_view=DestroyCacheView(magnify_view);
3131 image_view=DestroyCacheView(image_view);
3132 source_image=DestroyImage(source_image);
3133 if (status == MagickFalse)
3134 magnify_image=DestroyImage(magnify_image);
3135 return(magnify_image);
3163MagickExport Image *MinifyImage(
const Image *image,ExceptionInfo *exception)
3168 assert(image != (Image *) NULL);
3169 assert(image->signature == MagickCoreSignature);
3170 assert(exception != (ExceptionInfo *) NULL);
3171 assert(exception->signature == MagickCoreSignature);
3172 if (IsEventLogging() != MagickFalse)
3173 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3174 minify_image=ResizeImage(image,image->columns/2,image->rows/2,SplineFilter,
3176 return(minify_image);
3213MagickExport Image *ResampleImage(
const Image *image,
const double x_resolution,
3214 const double y_resolution,
const FilterType filter,ExceptionInfo *exception)
3216#define ResampleImageTag "Resample/Image"
3228 assert(image != (
const Image *) NULL);
3229 assert(image->signature == MagickCoreSignature);
3230 assert(exception != (ExceptionInfo *) NULL);
3231 assert(exception->signature == MagickCoreSignature);
3232 if (IsEventLogging() != MagickFalse)
3233 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3234 width=(size_t) (x_resolution*image->columns/(image->resolution.x == 0.0 ?
3235 DefaultResolution : image->resolution.x)+0.5);
3236 height=(size_t) (y_resolution*image->rows/(image->resolution.y == 0.0 ?
3237 DefaultResolution : image->resolution.y)+0.5);
3238 resample_image=ResizeImage(image,width,height,filter,exception);
3239 if (resample_image != (Image *) NULL)
3241 resample_image->resolution.x=x_resolution;
3242 resample_image->resolution.y=y_resolution;
3244 return(resample_image);
3295static ContributionInfo **DestroyContributionTLS(
3296 ContributionInfo **contribution)
3301 assert(contribution != (ContributionInfo **) NULL);
3302 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3303 if (contribution[i] != (ContributionInfo *) NULL)
3304 contribution[i]=(ContributionInfo *) RelinquishAlignedMemory(
3306 contribution=(ContributionInfo **) RelinquishMagickMemory(contribution);
3307 return(contribution);
3310static ContributionInfo **AcquireContributionTLS(
const size_t count)
3321 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3322 contribution=(ContributionInfo **) AcquireQuantumMemory(number_threads,
3323 sizeof(*contribution));
3324 if (contribution == (ContributionInfo **) NULL)
3325 return((ContributionInfo **) NULL);
3326 (void) memset(contribution,0,number_threads*
sizeof(*contribution));
3327 for (i=0; i < (ssize_t) number_threads; i++)
3329 contribution[i]=(ContributionInfo *) MagickAssumeAligned(
3330 AcquireAlignedMemory(count,
sizeof(**contribution)));
3331 if (contribution[i] == (ContributionInfo *) NULL)
3332 return(DestroyContributionTLS(contribution));
3334 return(contribution);
3337static MagickBooleanType HorizontalFilter(
3338 const ResizeFilter *magick_restrict resize_filter,
3339 const Image *magick_restrict image,Image *magick_restrict resize_image,
3340 const double x_factor,
const MagickSizeType span,
3341 MagickOffsetType *magick_restrict progress,ExceptionInfo *exception)
3343#define ResizeImageTag "Resize/Image"
3353 **magick_restrict contributions;
3368 scale=MagickMax(1.0/x_factor+MagickEpsilon,1.0);
3369 support=scale*GetResizeFilterSupport(resize_filter);
3370 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3371 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3372 return(MagickFalse);
3378 support=(double) 0.5;
3381 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3382 if (contributions == (ContributionInfo **) NULL)
3384 (void) ThrowMagickException(exception,GetMagickModule(),
3385 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3386 return(MagickFalse);
3389 scale=MagickSafeReciprocal(scale);
3390 image_view=AcquireVirtualCacheView(image,exception);
3391 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3392#if defined(MAGICKCORE_OPENMP_SUPPORT)
3393 #pragma omp parallel for schedule(static) shared(progress,status) \
3394 magick_number_threads(image,resize_image,resize_image->columns,1)
3396 for (x=0; x < (ssize_t) resize_image->columns; x++)
3399 id = GetOpenMPThreadId();
3405 *magick_restrict contribution;
3420 if (status == MagickFalse)
3422 bisect=(double) (x+0.5)/x_factor+MagickEpsilon;
3423 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3424 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->columns);
3426 contribution=contributions[id];
3427 for (n=0; n < (stop-start); n++)
3429 contribution[n].pixel=start+n;
3430 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3431 ((
double) (start+n)-bisect+0.5));
3432 density+=contribution[n].weight;
3436 if ((density != 0.0) && (density != 1.0))
3444 density=MagickSafeReciprocal(density);
3445 for (i=0; i < n; i++)
3446 contribution[i].weight*=density;
3448 p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,(
size_t)
3449 (contribution[n-1].pixel-contribution[0].pixel+1),image->rows,exception);
3450 q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
3452 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3457 for (y=0; y < (ssize_t) resize_image->rows; y++)
3462 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3480 channel=GetPixelChannelChannel(image,i);
3481 traits=GetPixelChannelTraits(image,channel);
3482 resize_traits=GetPixelChannelTraits(resize_image,channel);
3483 if ((traits == UndefinedPixelTrait) ||
3484 (resize_traits == UndefinedPixelTrait))
3486 if (((resize_traits & CopyPixelTrait) != 0) ||
3487 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3489 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3491 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3492 (contribution[j-start].pixel-contribution[0].pixel);
3493 SetPixelChannel(resize_image,channel,
3494 p[k*(ssize_t) GetPixelChannels(image)+i],q);
3498 if ((resize_traits & BlendPixelTrait) == 0)
3503 for (j=0; j < n; j++)
3505 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3506 (contribution[j].pixel-contribution[0].pixel);
3507 alpha=contribution[j].weight;
3508 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3510 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3517 for (j=0; j < n; j++)
3519 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3520 (contribution[j].pixel-contribution[0].pixel);
3521 alpha=contribution[j].weight*QuantumScale*
3522 (double) GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3523 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3526 gamma=MagickSafeReciprocal(gamma);
3527 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3529 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3531 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3533 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3538#if defined(MAGICKCORE_OPENMP_SUPPORT)
3542 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3543 if (proceed == MagickFalse)
3547 resize_view=DestroyCacheView(resize_view);
3548 image_view=DestroyCacheView(image_view);
3549 contributions=DestroyContributionTLS(contributions);
3553static MagickBooleanType VerticalFilter(
3554 const ResizeFilter *magick_restrict resize_filter,
3555 const Image *magick_restrict image,Image *magick_restrict resize_image,
3556 const double y_factor,
const MagickSizeType span,
3557 MagickOffsetType *magick_restrict progress,ExceptionInfo *exception)
3567 **magick_restrict contributions;
3582 scale=MagickMax(1.0/y_factor+MagickEpsilon,1.0);
3583 support=scale*GetResizeFilterSupport(resize_filter);
3584 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3585 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3586 return(MagickFalse);
3592 support=(double) 0.5;
3595 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3596 if (contributions == (ContributionInfo **) NULL)
3598 (void) ThrowMagickException(exception,GetMagickModule(),
3599 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3600 return(MagickFalse);
3603 scale=MagickSafeReciprocal(scale);
3604 image_view=AcquireVirtualCacheView(image,exception);
3605 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3606#if defined(MAGICKCORE_OPENMP_SUPPORT)
3607 #pragma omp parallel for schedule(static) shared(progress,status) \
3608 magick_number_threads(image,resize_image,resize_image->rows,1)
3610 for (y=0; y < (ssize_t) resize_image->rows; y++)
3613 id = GetOpenMPThreadId();
3619 *magick_restrict contribution;
3634 if (status == MagickFalse)
3636 bisect=(double) (y+0.5)/y_factor+MagickEpsilon;
3637 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3638 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->rows);
3640 contribution=contributions[id];
3641 for (n=0; n < (stop-start); n++)
3643 contribution[n].pixel=start+n;
3644 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3645 ((
double) (start+n)-bisect+0.5));
3646 density+=contribution[n].weight;
3650 if ((density != 0.0) && (density != 1.0))
3658 density=MagickSafeReciprocal(density);
3659 for (i=0; i < n; i++)
3660 contribution[i].weight*=density;
3662 p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
3663 image->columns,(
size_t) (contribution[n-1].pixel-contribution[0].pixel+1),
3665 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
3667 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3672 for (x=0; x < (ssize_t) resize_image->columns; x++)
3677 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3695 channel=GetPixelChannelChannel(image,i);
3696 traits=GetPixelChannelTraits(image,channel);
3697 resize_traits=GetPixelChannelTraits(resize_image,channel);
3698 if ((traits == UndefinedPixelTrait) ||
3699 (resize_traits == UndefinedPixelTrait))
3701 if (((resize_traits & CopyPixelTrait) != 0) ||
3702 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3704 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3706 k=(ssize_t) ((contribution[j-start].pixel-contribution[0].pixel)*
3707 (ssize_t) image->columns+x);
3708 SetPixelChannel(resize_image,channel,p[k*(ssize_t)
3709 GetPixelChannels(image)+i],q);
3713 if ((resize_traits & BlendPixelTrait) == 0)
3718 for (j=0; j < n; j++)
3720 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3721 (ssize_t) image->columns+x);
3722 alpha=contribution[j].weight;
3723 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3725 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3729 for (j=0; j < n; j++)
3731 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3732 (ssize_t) image->columns+x);
3733 alpha=contribution[j].weight*QuantumScale*(double)
3734 GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3735 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3738 gamma=MagickSafeReciprocal(gamma);
3739 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3741 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3743 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3745 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3750#if defined(MAGICKCORE_OPENMP_SUPPORT)
3754 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3755 if (proceed == MagickFalse)
3759 resize_view=DestroyCacheView(resize_view);
3760 image_view=DestroyCacheView(image_view);
3761 contributions=DestroyContributionTLS(contributions);
3765MagickExport Image *ResizeImage(
const Image *image,
const size_t columns,
3766 const size_t rows,
const FilterType filter,ExceptionInfo *exception)
3794 assert(image != (Image *) NULL);
3795 assert(image->signature == MagickCoreSignature);
3796 assert(exception != (ExceptionInfo *) NULL);
3797 assert(exception->signature == MagickCoreSignature);
3798 if (IsEventLogging() != MagickFalse)
3799 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3800 if ((columns == 0) || (rows == 0))
3801 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3802 if ((columns == image->columns) && (rows == image->rows) &&
3803 (filter == UndefinedFilter))
3804 return(CloneImage(image,0,0,MagickTrue,exception));
3808 x_factor=(double) (columns*MagickSafeReciprocal((
double) image->columns));
3809 y_factor=(double) (rows*MagickSafeReciprocal((
double) image->rows));
3810 filter_type=LanczosFilter;
3811 if (filter != UndefinedFilter)
3814 if ((x_factor == 1.0) && (y_factor == 1.0))
3815 filter_type=PointFilter;
3817 if ((image->storage_class == PseudoClass) ||
3818 (image->alpha_trait != UndefinedPixelTrait) ||
3819 ((x_factor*y_factor) > 1.0))
3820 filter_type=MitchellFilter;
3821 resize_filter=AcquireResizeFilter(image,filter_type,MagickFalse,exception);
3822#if defined(MAGICKCORE_OPENCL_SUPPORT)
3823 resize_image=AccelerateResizeImage(image,columns,rows,resize_filter,
3825 if (resize_image != (Image *) NULL)
3827 resize_filter=DestroyResizeFilter(resize_filter);
3828 return(resize_image);
3831 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
3832 if (resize_image == (Image *) NULL)
3834 resize_filter=DestroyResizeFilter(resize_filter);
3835 return(resize_image);
3837 if (x_factor > y_factor)
3838 filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
3840 filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
3841 if (filter_image == (Image *) NULL)
3843 resize_filter=DestroyResizeFilter(resize_filter);
3844 return(DestroyImage(resize_image));
3850 if (x_factor > y_factor)
3852 span=(MagickSizeType) (filter_image->columns+rows);
3853 status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
3855 status&=(MagickStatusType) VerticalFilter(resize_filter,filter_image,
3856 resize_image,y_factor,span,&offset,exception);
3860 span=(MagickSizeType) (filter_image->rows+columns);
3861 status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
3863 status&=(MagickStatusType) HorizontalFilter(resize_filter,filter_image,
3864 resize_image,x_factor,span,&offset,exception);
3869 filter_image=DestroyImage(filter_image);
3870 resize_filter=DestroyResizeFilter(resize_filter);
3871 if (status == MagickFalse)
3873 resize_image=DestroyImage(resize_image);
3874 return((Image *) NULL);
3876 resize_image->type=image->type;
3879 transform[MagickPathExtent];
3881 (void) FormatLocaleString(transform,MagickPathExtent,
3882 "resize %.20gx%.20g %.20gx%.20g",(
double) image->columns,
3883 (
double) image->rows,(
double) resize_image->columns,
3884 (
double) resize_image->rows);
3885 AppendImageProfileProperty(resize_image,
"hdrgm",
"hdrgm:Transform",
3886 transform,exception);
3888 return(resize_image);
3922MagickExport Image *SampleImage(
const Image *image,
const size_t columns,
3923 const size_t rows,ExceptionInfo *exception)
3925#define SampleImageTag "Sample/Image"
3949 assert(image != (
const Image *) NULL);
3950 assert(image->signature == MagickCoreSignature);
3951 assert(exception != (ExceptionInfo *) NULL);
3952 assert(exception->signature == MagickCoreSignature);
3953 if (IsEventLogging() != MagickFalse)
3954 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3955 if ((columns == 0) || (rows == 0))
3956 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3957 if ((columns == image->columns) && (rows == image->rows))
3958 return(CloneImage(image,0,0,MagickTrue,exception));
3959 sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
3960 if (sample_image == (Image *) NULL)
3961 return((Image *) NULL);
3965 sample_offset.x=0.5-MagickEpsilon;
3966 sample_offset.y=sample_offset.x;
3971 value=GetImageArtifact(image,
"sample:offset");
3972 if (value != (
char *) NULL)
3980 (void) ParseGeometry(value,&geometry_info);
3981 flags=ParseGeometry(value,&geometry_info);
3982 sample_offset.x=sample_offset.y=geometry_info.rho/100.0-MagickEpsilon;
3983 if ((flags & SigmaValue) != 0)
3984 sample_offset.y=geometry_info.sigma/100.0-MagickEpsilon;
3992 image_view=AcquireVirtualCacheView(image,exception);
3993 sample_view=AcquireAuthenticCacheView(sample_image,exception);
3994#if defined(MAGICKCORE_OPENMP_SUPPORT)
3995 #pragma omp parallel for schedule(static) shared(status) \
3996 magick_number_threads(image,sample_image,sample_image->rows,2)
3998 for (y=0; y < (ssize_t) sample_image->rows; y++)
4006 if (status == MagickFalse)
4008 q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
4010 if (q == (Quantum *) NULL)
4018 for (x=0; x < (ssize_t) sample_image->columns; x++)
4028 if (GetPixelWriteMask(sample_image,q) <= (QuantumRange/2))
4030 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4033 x_offset=(ssize_t) ((((
double) x+sample_offset.x)*image->columns)/
4034 sample_image->columns);
4035 y_offset=(ssize_t) ((((
double) y+sample_offset.y)*image->rows)/
4036 sample_image->rows);
4037 p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
4038 if (p == (
const Quantum *) NULL)
4043 for (i=0; i < (ssize_t) GetPixelChannels(sample_image); i++)
4052 channel=GetPixelChannelChannel(sample_image,i);
4053 traits=GetPixelChannelTraits(sample_image,channel);
4054 image_traits=GetPixelChannelTraits(image,channel);
4055 if ((traits == UndefinedPixelTrait) ||
4056 (image_traits == UndefinedPixelTrait))
4058 SetPixelChannel(sample_image,channel,p[i],q);
4060 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4062 if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
4064 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4069 proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
4070 if (proceed == MagickFalse)
4074 image_view=DestroyCacheView(image_view);
4075 sample_view=DestroyCacheView(sample_view);
4076 sample_image->type=image->type;
4077 if (status == MagickFalse)
4078 sample_image=DestroyImage(sample_image);
4079 return(sample_image);
4111MagickExport Image *ScaleImage(
const Image *image,
const size_t columns,
4112 const size_t rows,ExceptionInfo *exception)
4114#define ScaleImageTag "Scale/Image"
4122 pixel[CompositePixelChannel],
4153 assert(image != (
const Image *) NULL);
4154 assert(image->signature == MagickCoreSignature);
4155 assert(exception != (ExceptionInfo *) NULL);
4156 assert(exception->signature == MagickCoreSignature);
4157 if (IsEventLogging() != MagickFalse)
4158 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4159 if ((columns == 0) || (rows == 0))
4160 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
4161 if ((columns == image->columns) && (rows == image->rows))
4162 return(CloneImage(image,0,0,MagickTrue,exception));
4163 scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
4164 if (scale_image == (Image *) NULL)
4165 return((Image *) NULL);
4166 if (SetImageStorageClass(scale_image,DirectClass,exception) == MagickFalse)
4168 scale_image=DestroyImage(scale_image);
4169 return((Image *) NULL);
4174 x_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4175 MaxPixelChannels*
sizeof(*x_vector));
4177 if (image->rows != scale_image->rows)
4178 scanline=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4179 MaxPixelChannels*
sizeof(*scanline));
4180 scale_scanline=(
double *) AcquireQuantumMemory((
size_t) scale_image->columns,
4181 MaxPixelChannels*
sizeof(*scale_scanline));
4182 y_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4183 MaxPixelChannels*
sizeof(*y_vector));
4184 if ((scanline == (
double *) NULL) || (scale_scanline == (
double *) NULL) ||
4185 (x_vector == (
double *) NULL) || (y_vector == (
double *) NULL))
4187 if ((image->rows != scale_image->rows) && (scanline != (
double *) NULL))
4188 scanline=(
double *) RelinquishMagickMemory(scanline);
4189 if (scale_scanline != (
double *) NULL)
4190 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4191 if (x_vector != (
double *) NULL)
4192 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4193 if (y_vector != (
double *) NULL)
4194 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4195 scale_image=DestroyImage(scale_image);
4196 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4202 next_row=MagickTrue;
4204 scale.y=(double) scale_image->rows/(
double) image->rows;
4205 (void) memset(y_vector,0,(
size_t) MaxPixelChannels*image->columns*
4209 image_view=AcquireVirtualCacheView(image,exception);
4210 scale_view=AcquireAuthenticCacheView(scale_image,exception);
4211 for (y=0; y < (ssize_t) scale_image->rows; y++)
4222 if (status == MagickFalse)
4224 q=QueueCacheViewAuthenticPixels(scale_view,0,y,scale_image->columns,1,
4226 if (q == (Quantum *) NULL)
4232 if (scale_image->rows == image->rows)
4237 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4239 if (p == (
const Quantum *) NULL)
4244 for (x=0; x < (ssize_t) image->columns; x++)
4246 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4248 p+=(ptrdiff_t) GetPixelChannels(image);
4251 if (image->alpha_trait != UndefinedPixelTrait)
4252 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4253 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4255 PixelChannel channel = GetPixelChannelChannel(image,i);
4256 PixelTrait traits = GetPixelChannelTraits(image,channel);
4257 if ((traits & BlendPixelTrait) == 0)
4259 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=(double) p[i];
4262 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*(double) p[i];
4264 p+=(ptrdiff_t) GetPixelChannels(image);
4272 while (scale.y < span.y)
4274 if ((next_row != MagickFalse) &&
4275 (number_rows < (ssize_t) image->rows))
4280 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4282 if (p == (
const Quantum *) NULL)
4287 for (x=0; x < (ssize_t) image->columns; x++)
4289 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4291 p+=(ptrdiff_t) GetPixelChannels(image);
4294 if (image->alpha_trait != UndefinedPixelTrait)
4295 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4296 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4298 PixelChannel channel = GetPixelChannelChannel(image,i);
4299 PixelTrait traits = GetPixelChannelTraits(image,channel);
4300 if ((traits & BlendPixelTrait) == 0)
4302 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4306 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4309 p+=(ptrdiff_t) GetPixelChannels(image);
4313 for (x=0; x < (ssize_t) image->columns; x++)
4314 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4315 y_vector[x*(ssize_t) GetPixelChannels(image)+i]+=scale.y*
4316 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4318 scale.y=(double) scale_image->rows/(
double) image->rows;
4319 next_row=MagickTrue;
4321 if ((next_row != MagickFalse) && (number_rows < (ssize_t) image->rows))
4326 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4328 if (p == (
const Quantum *) NULL)
4333 for (x=0; x < (ssize_t) image->columns; x++)
4335 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4337 p+=(ptrdiff_t) GetPixelChannels(image);
4340 if (image->alpha_trait != UndefinedPixelTrait)
4341 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4342 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4344 PixelChannel channel = GetPixelChannelChannel(image,i);
4345 PixelTrait traits = GetPixelChannelTraits(image,channel);
4346 if ((traits & BlendPixelTrait) == 0)
4348 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4352 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4355 p+=(ptrdiff_t) GetPixelChannels(image);
4358 next_row=MagickFalse;
4360 for (x=0; x < (ssize_t) image->columns; x++)
4362 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4364 pixel[i]=y_vector[x*(ssize_t) GetPixelChannels(image)+i]+span.y*
4365 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4366 scanline[x*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4367 y_vector[x*(ssize_t) GetPixelChannels(image)+i]=0.0;
4373 scale.y=(double) scale_image->rows/(
double) image->rows;
4374 next_row=MagickTrue;
4378 if (scale_image->columns == image->columns)
4383 for (x=0; x < (ssize_t) scale_image->columns; x++)
4385 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4387 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4390 if (image->alpha_trait != UndefinedPixelTrait)
4392 alpha=QuantumScale*scanline[x*(ssize_t) GetPixelChannels(image)+
4393 GetPixelChannelOffset(image,AlphaPixelChannel)];
4394 alpha=MagickSafeReciprocal(alpha);
4396 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4398 PixelChannel channel = GetPixelChannelChannel(image,i);
4399 PixelTrait traits = GetPixelChannelTraits(image,channel);
4400 scale_traits=GetPixelChannelTraits(scale_image,channel);
4401 if ((traits == UndefinedPixelTrait) ||
4402 (scale_traits == UndefinedPixelTrait))
4404 if ((traits & BlendPixelTrait) == 0)
4406 SetPixelChannel(scale_image,channel,ClampToQuantum(
4407 scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4410 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*scanline[
4411 x*(ssize_t) GetPixelChannels(image)+i]),q);
4413 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4424 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4426 next_column=MagickFalse;
4429 for (x=0; x < (ssize_t) image->columns; x++)
4431 scale.x=(double) scale_image->columns/(
double) image->columns;
4432 while (scale.x >= span.x)
4434 if (next_column != MagickFalse)
4436 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4440 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4442 PixelChannel channel = GetPixelChannelChannel(image,i);
4443 PixelTrait traits = GetPixelChannelTraits(image,channel);
4444 if (traits == UndefinedPixelTrait)
4446 pixel[i]+=span.x*scanline[x*(ssize_t) GetPixelChannels(image)+i];
4447 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4451 next_column=MagickTrue;
4455 if (next_column != MagickFalse)
4457 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4459 next_column=MagickFalse;
4462 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4463 pixel[i]+=scale.x*scanline[x*(ssize_t)
4464 GetPixelChannels(image)+i];
4470 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4472 scanline[(x-1)*(ssize_t) GetPixelChannels(image)+i];
4474 if ((next_column == MagickFalse) && (t < (ssize_t) scale_image->columns))
4475 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4476 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4480 for (x=0; x < (ssize_t) scale_image->columns; x++)
4482 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4484 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4487 if (image->alpha_trait != UndefinedPixelTrait)
4489 alpha=QuantumScale*scale_scanline[x*(ssize_t)
4490 GetPixelChannels(image)+
4491 GetPixelChannelOffset(image,AlphaPixelChannel)];
4492 alpha=MagickSafeReciprocal(alpha);
4494 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4496 PixelChannel channel = GetPixelChannelChannel(image,i);
4497 PixelTrait traits = GetPixelChannelTraits(image,channel);
4498 scale_traits=GetPixelChannelTraits(scale_image,channel);
4499 if ((traits == UndefinedPixelTrait) ||
4500 (scale_traits == UndefinedPixelTrait))
4502 if ((traits & BlendPixelTrait) == 0)
4504 SetPixelChannel(scale_image,channel,ClampToQuantum(
4505 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4508 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*
4509 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4511 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4514 if (SyncCacheViewAuthenticPixels(scale_view,exception) == MagickFalse)
4519 proceed=SetImageProgress(image,ScaleImageTag,(MagickOffsetType) y,
4521 if (proceed == MagickFalse)
4527 scale_view=DestroyCacheView(scale_view);
4528 image_view=DestroyCacheView(image_view);
4532 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4533 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4534 if (scale_image->rows != image->rows)
4535 scanline=(
double *) RelinquishMagickMemory(scanline);
4536 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4537 scale_image->type=image->type;
4538 if (status == MagickFalse)
4539 scale_image=DestroyImage(scale_image);
4540 return(scale_image);
4575static void url_encode(
const char *uri,
char *encode_uri)
4581 *hex =
"0123456789ABCDEF";
4583 for (p=encode_uri; *uri !=
'\0'; uri++)
4584 if (((
'a' <= *uri) && (*uri <=
'z')) || ((
'A' <= *uri) && (*uri <=
'Z')) ||
4585 ((
'0' <= *uri) && (*uri <=
'9')) || (strchr(
"/-_.~",*uri) != 0))
4590 *p++=hex[(*uri >> 4) & 0xF];
4591 *p++=hex[*uri & 0xF];
4596MagickExport Image *ThumbnailImage(
const Image *image,
const size_t columns,
4597 const size_t rows,ExceptionInfo *exception)
4599#define SampleFactor 5
4602 encode_uri[3*MagickPathExtent+1] =
"/0";
4614 assert(image != (Image *) NULL);
4615 assert(image->signature == MagickCoreSignature);
4616 assert(exception != (ExceptionInfo *) NULL);
4617 assert(exception->signature == MagickCoreSignature);
4618 if (IsEventLogging() != MagickFalse)
4619 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4620 thumbnail_image=CloneImage(image,0,0,MagickTrue,exception);
4621 if (thumbnail_image == (Image *) NULL)
4622 return(thumbnail_image);
4623 if ((columns != image->columns) || (rows != image->rows))
4626 *clone_image = thumbnail_image;
4632 x_factor=(ssize_t) (image->columns*MagickSafeReciprocal((
double)
4634 y_factor=(ssize_t) (image->rows*MagickSafeReciprocal((
double) rows));
4635 if ((x_factor > 4) && (y_factor > 4))
4637 thumbnail_image=SampleImage(clone_image,4*columns,4*rows,exception);
4638 if (thumbnail_image != (Image *) NULL)
4640 clone_image=DestroyImage(clone_image);
4641 clone_image=thumbnail_image;
4644 if ((x_factor > 2) && (y_factor > 2))
4646 thumbnail_image=ResizeImage(clone_image,2*columns,2*rows,BoxFilter,
4648 if (thumbnail_image != (Image *) NULL)
4650 clone_image=DestroyImage(clone_image);
4651 clone_image=thumbnail_image;
4654 thumbnail_image=ResizeImage(clone_image,columns,rows,image->filter ==
4655 UndefinedFilter ? LanczosSharpFilter : image->filter,exception);
4656 clone_image=DestroyImage(clone_image);
4657 if (thumbnail_image == (Image *) NULL)
4658 return(thumbnail_image);
4660 (void) ParseAbsoluteGeometry(
"0x0+0+0",&thumbnail_image->page);
4661 thumbnail_image->depth=8;
4662 thumbnail_image->interlace=NoInterlace;
4666 ResetImageProfileIterator(thumbnail_image);
4667 for (name=GetNextImageProfile(thumbnail_image); name != (
const char *) NULL; )
4669 if ((LocaleCompare(name,
"icc") != 0) && (LocaleCompare(name,
"icm") != 0))
4671 (void) DeleteImageProfile(thumbnail_image,name);
4672 ResetImageProfileIterator(thumbnail_image);
4674 name=GetNextImageProfile(thumbnail_image);
4676 (void) DeleteImageProperty(thumbnail_image,
"comment");
4677 url_encode(image->filename,encode_uri);
4678 if (*image->filename !=
'/')
4679 (void) FormatImageProperty(thumbnail_image,
"Thumb::URI",
"./%s",encode_uri);
4681 (
void) FormatImageProperty(thumbnail_image,
"Thumb::URI",
"file://%s",
4683 if (GetPathAttributes(image->filename,&attributes) != MagickFalse )
4684 (void) FormatImageProperty(thumbnail_image,
"Thumb::MTime",
"%.20g",(
double)
4685 attributes.st_mtime);
4686 (void) FormatImageProperty(thumbnail_image,
"Thumb::Size",
"%.20g",
4687 (
double) GetBlobSize(image));
4688 mime_type=GetImageProperty(image,
"mime:type",exception);
4689 if (mime_type != (
const char *) NULL)
4690 (void) SetImageProperty(thumbnail_image,
"Thumb::Mimetype",mime_type,
4692 (void) SetImageProperty(thumbnail_image,
"software",MagickAuthoritativeURL,
4694 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Width",
"%.20g",
4695 (
double) image->magick_columns);
4696 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Height",
"%.20g",
4697 (
double) image->magick_rows);
4698 (void) FormatImageProperty(thumbnail_image,
"Thumb::Document::Pages",
"%.20g",
4699 (
double) GetImageListLength(image));
4700 return(thumbnail_image);