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/quantum-private.h"
72#include "MagickCore/resample.h"
73#include "MagickCore/resample-private.h"
74#include "MagickCore/resize.h"
75#include "MagickCore/resize-private.h"
76#include "MagickCore/resource_.h"
77#include "MagickCore/string_.h"
78#include "MagickCore/string-private.h"
79#include "MagickCore/thread-private.h"
80#include "MagickCore/token.h"
81#include "MagickCore/utility.h"
82#include "MagickCore/utility-private.h"
83#include "MagickCore/version.h"
84#if defined(MAGICKCORE_LQR_DELEGATE)
102 ResizeWeightingFunctionType
115 BesselOrderOne(
double),
151static double Blackman(
const double x,
161 const double cosine = cos((
double) (MagickPI*x));
162 magick_unreferenced(resize_filter);
163 return(0.34+cosine*(0.5+cosine*0.16));
166static double Bohman(
const double x,
177 const double cosine = cos((
double) (MagickPI*x));
178 const double sine=sqrt(1.0-cosine*cosine);
179 magick_unreferenced(resize_filter);
180 return((1.0-x)*cosine+(1.0/MagickPI)*sine);
183static double Box(
const double magick_unused(x),
186 magick_unreferenced(x);
187 magick_unreferenced(resize_filter);
197static double Cosine(
const double x,
200 magick_unreferenced(resize_filter);
206 return(cos((
double) (MagickPI2*x)));
209static double CubicBC(
const double x,
const ResizeFilter *resize_filter)
241 return(resize_filter->coefficient[0]+x*(x*
242 (resize_filter->coefficient[1]+x*resize_filter->coefficient[2])));
244 return(resize_filter->coefficient[3]+x*(resize_filter->coefficient[4]+x*
245 (resize_filter->coefficient[5]+x*resize_filter->coefficient[6])));
249static double CubicSpline(
const double x,
const ResizeFilter *resize_filter)
251 if (resize_filter->support <= 2.0)
257 return(((x-9.0/5.0)*x-1.0/5.0)*x+1.0);
259 return(((-1.0/3.0*(x-1.0)+4.0/5.0)*(x-1.0)-7.0/15.0)*(x-1.0));
262 if (resize_filter->support <= 3.0)
268 return(((13.0/11.0*x-453.0/209.0)*x-3.0/209.0)*x+1.0);
270 return(((-6.0/11.0*(x-1.0)+270.0/209.0)*(x-1.0)-156.0/209.0)*(x-1.0));
272 return(((1.0/11.0*(x-2.0)-45.0/209.0)*(x-2.0)+26.0/209.0)*(x-2.0));
279 return(((49.0/41.0*x-6387.0/2911.0)*x-3.0/2911.0)*x+1.0);
281 return(((-24.0/41.0*(x-1.0)+4032.0/2911.0)*(x-1.0)-2328.0/2911.0)*(x-1.0));
283 return(((6.0/41.0*(x-2.0)-1008.0/2911.0)*(x-2.0)+582.0/2911.0)*(x-2.0));
285 return(((-1.0/41.0*(x-3.0)+168.0/2911.0)*(x-3.0)-97.0/2911.0)*(x-3.0));
289static double Gaussian(
const double x,
const ResizeFilter *resize_filter)
321 return(exp((
double)(-resize_filter->coefficient[1]*x*x)));
324static double Hann(
const double x,
331 const double cosine = cos((
double) (MagickPI*x));
332 magick_unreferenced(resize_filter);
333 return(0.5+0.5*cosine);
336static double Hamming(
const double x,
343 const double cosine = cos((
double) (MagickPI*x));
344 magick_unreferenced(resize_filter);
345 return(0.54+0.46*cosine);
348static double Jinc(
const double x,
351 magick_unreferenced(resize_filter);
362 return(0.5*MagickPI);
363 return(BesselOrderOne(MagickPI*x)/x);
366static double Kaiser(
const double x,
const ResizeFilter *resize_filter)
380 return(resize_filter->coefficient[1]*I0(resize_filter->coefficient[0]*
381 sqrt((
double) (1.0-x*x))));
384static double Lagrange(
const double x,
const ResizeFilter *resize_filter)
406 if (x > resize_filter->support)
408 order=(ssize_t) (2.0*resize_filter->window_support);
409 n=(ssize_t) (resize_filter->window_support+x);
411 for (i=0; i < order; i++)
413 value*=(n-i-x)/(n-i);
417static double Quadratic(
const double x,
420 magick_unreferenced(resize_filter);
428 return(0.5*(x-1.5)*(x-1.5));
432static double Sinc(
const double x,
435 magick_unreferenced(resize_filter);
443 const double alpha=(double) (MagickPI*x);
444 return(sin((
double) alpha)/alpha);
446 return((
double) 1.0);
449static double SincFast(
const double x,
452 magick_unreferenced(resize_filter);
480 const double alpha=(double) (MagickPI*x);
481 return(sin((
double) alpha)/alpha);
487 const double xx = x*x;
488#if MAGICKCORE_QUANTUM_DEPTH <= 8
492 const double c0 = 0.173610016489197553621906385078711564924e-2L;
493 const double c1 = -0.384186115075660162081071290162149315834e-3L;
494 const double c2 = 0.393684603287860108352720146121813443561e-4L;
495 const double c3 = -0.248947210682259168029030370205389323899e-5L;
496 const double c4 = 0.107791837839662283066379987646635416692e-6L;
497 const double c5 = -0.324874073895735800961260474028013982211e-8L;
498 const double c6 = 0.628155216606695311524920882748052490116e-10L;
499 const double c7 = -0.586110644039348333520104379959307242711e-12L;
501 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
502 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
503#elif MAGICKCORE_QUANTUM_DEPTH <= 16
507 const double c0 = 0.173611107357320220183368594093166520811e-2L;
508 const double c1 = -0.384240921114946632192116762889211361285e-3L;
509 const double c2 = 0.394201182359318128221229891724947048771e-4L;
510 const double c3 = -0.250963301609117217660068889165550534856e-5L;
511 const double c4 = 0.111902032818095784414237782071368805120e-6L;
512 const double c5 = -0.372895101408779549368465614321137048875e-8L;
513 const double c6 = 0.957694196677572570319816780188718518330e-10L;
514 const double c7 = -0.187208577776590710853865174371617338991e-11L;
515 const double c8 = 0.253524321426864752676094495396308636823e-13L;
516 const double c9 = -0.177084805010701112639035485248501049364e-15L;
518 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*(c7+xx*(c8+xx*c9))))))));
519 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
524 const double c0 = 0.173611111110910715186413700076827593074e-2L;
525 const double c1 = -0.289105544717893415815859968653611245425e-3L;
526 const double c2 = 0.206952161241815727624413291940849294025e-4L;
527 const double c3 = -0.834446180169727178193268528095341741698e-6L;
528 const double c4 = 0.207010104171026718629622453275917944941e-7L;
529 const double c5 = -0.319724784938507108101517564300855542655e-9L;
530 const double c6 = 0.288101675249103266147006509214934493930e-11L;
531 const double c7 = -0.118218971804934245819960233886876537953e-13L;
533 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
534 const double d0 = 1.0L;
535 const double d1 = 0.547981619622284827495856984100563583948e-1L;
536 const double d2 = 0.134226268835357312626304688047086921806e-2L;
537 const double d3 = 0.178994697503371051002463656833597608689e-4L;
538 const double d4 = 0.114633394140438168641246022557689759090e-6L;
539 const double q = d0+xx*(d1+xx*(d2+xx*(d3+xx*d4)));
540 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)/q*p);
545static double Triangle(
const double x,
548 magick_unreferenced(resize_filter);
560static double Welch(
const double x,
563 magick_unreferenced(resize_filter);
760 const FilterType filter,
const MagickBooleanType cylindrical,
796 }
const mapping[SentinelFilter] =
798 { UndefinedFilter, BoxFilter },
799 { PointFilter, BoxFilter },
800 { BoxFilter, BoxFilter },
801 { TriangleFilter, BoxFilter },
802 { HermiteFilter, BoxFilter },
803 { SincFastFilter, HannFilter },
804 { SincFastFilter, HammingFilter },
805 { SincFastFilter, BlackmanFilter },
806 { GaussianFilter, BoxFilter },
807 { QuadraticFilter, BoxFilter },
808 { CubicFilter, BoxFilter },
809 { CatromFilter, BoxFilter },
810 { MitchellFilter, BoxFilter },
811 { JincFilter, BoxFilter },
812 { SincFilter, BoxFilter },
813 { SincFastFilter, BoxFilter },
814 { SincFastFilter, KaiserFilter },
815 { LanczosFilter, WelchFilter },
816 { SincFastFilter, CubicFilter },
817 { SincFastFilter, BohmanFilter },
818 { SincFastFilter, TriangleFilter },
819 { LagrangeFilter, BoxFilter },
820 { LanczosFilter, LanczosFilter },
821 { LanczosSharpFilter, LanczosSharpFilter },
822 { Lanczos2Filter, Lanczos2Filter },
823 { Lanczos2SharpFilter, Lanczos2SharpFilter },
824 { RobidouxFilter, BoxFilter },
825 { RobidouxSharpFilter, BoxFilter },
826 { LanczosFilter, CosineFilter },
827 { SplineFilter, BoxFilter },
828 { LanczosRadiusFilter, LanczosFilter },
829 { CubicSplineFilter, BoxFilter },
850 ResizeWeightingFunctionType weightingFunctionType;
851 }
const filters[SentinelFilter] =
858 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
859 { Box, 0.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
860 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
861 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
862 { CubicBC, 1.0, 1.0, 0.0, 0.0, CubicBCWeightingFunction },
863 { Hann, 1.0, 1.0, 0.0, 0.0, HannWeightingFunction },
864 { Hamming, 1.0, 1.0, 0.0, 0.0, HammingWeightingFunction },
865 { Blackman, 1.0, 1.0, 0.0, 0.0, BlackmanWeightingFunction },
866 { Gaussian, 2.0, 1.5, 0.0, 0.0, GaussianWeightingFunction },
867 { Quadratic, 1.5, 1.5, 0.0, 0.0, QuadraticWeightingFunction },
868 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
869 { CubicBC, 2.0, 1.0, 0.0, 0.5, CubicBCWeightingFunction },
870 { CubicBC, 2.0, 8.0/7.0, 1./3., 1./3., CubicBCWeightingFunction },
871 { Jinc, 3.0, 1.2196698912665045, 0.0, 0.0, JincWeightingFunction },
872 { Sinc, 4.0, 1.0, 0.0, 0.0, SincWeightingFunction },
873 { SincFast, 4.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
874 { Kaiser, 1.0, 1.0, 0.0, 0.0, KaiserWeightingFunction },
875 { Welch, 1.0, 1.0, 0.0, 0.0, WelchWeightingFunction },
876 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
877 { Bohman, 1.0, 1.0, 0.0, 0.0, BohmanWeightingFunction },
878 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
879 { Lagrange, 2.0, 1.0, 0.0, 0.0, LagrangeWeightingFunction },
880 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
881 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
882 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
883 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
885 { CubicBC, 2.0, 1.1685777620836932,
886 0.37821575509399867, 0.31089212245300067, CubicBCWeightingFunction },
888 { CubicBC, 2.0, 1.105822933719019,
889 0.2620145123990142, 0.3689927438004929, CubicBCWeightingFunction },
890 { Cosine, 1.0, 1.0, 0.0, 0.0, CosineWeightingFunction },
891 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
892 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
893 { CubicSpline,2.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
930 assert(image != (
const Image *) NULL);
931 assert(image->signature == MagickCoreSignature);
932 assert(UndefinedFilter < filter && filter < SentinelFilter);
934 assert(exception->signature == MagickCoreSignature);
935 if (IsEventLogging() != MagickFalse)
936 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
938 resize_filter=(
ResizeFilter *) AcquireCriticalMemory(
sizeof(*resize_filter));
939 (void) memset(resize_filter,0,
sizeof(*resize_filter));
943 filter_type=mapping[filter].filter;
944 window_type=mapping[filter].window;
945 resize_filter->blur=1.0;
947 if ((cylindrical != MagickFalse) && (filter_type == SincFastFilter) &&
948 (filter != SincFastFilter))
949 filter_type=JincFilter;
952 artifact=GetImageArtifact(image,
"filter:filter");
953 if (IsStringTrue(artifact) != MagickFalse)
958 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
959 if ((UndefinedFilter < option) && (option < SentinelFilter))
961 filter_type=(FilterType) option;
962 window_type=BoxFilter;
965 artifact=GetImageArtifact(image,
"filter:window");
966 if (artifact != (
const char *) NULL)
968 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
969 if ((UndefinedFilter < option) && (option < SentinelFilter))
970 window_type=(FilterType) option;
976 artifact=GetImageArtifact(image,
"filter:window");
977 if (artifact != (
const char *) NULL)
982 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
983 if ((UndefinedFilter < option) && (option < SentinelFilter))
985 filter_type= cylindrical != MagickFalse ? JincFilter
987 window_type=(FilterType) option;
993 resize_filter->filter=filters[filter_type].function;
994 resize_filter->support=filters[filter_type].support;
995 resize_filter->filterWeightingType=filters[filter_type].weightingFunctionType;
996 resize_filter->window=filters[window_type].function;
997 resize_filter->windowWeightingType=filters[window_type].weightingFunctionType;
998 resize_filter->scale=filters[window_type].scale;
999 resize_filter->signature=MagickCoreSignature;
1002 if (cylindrical != MagickFalse)
1003 switch (filter_type)
1007 resize_filter->support=(double) MagickSQ1_2;
1010 case LanczosSharpFilter:
1011 case Lanczos2Filter:
1012 case Lanczos2SharpFilter:
1013 case LanczosRadiusFilter:
1014 resize_filter->filter=filters[JincFilter].function;
1015 resize_filter->window=filters[JincFilter].function;
1016 resize_filter->scale=filters[JincFilter].scale;
1023 switch (filter_type)
1025 case LanczosSharpFilter:
1026 resize_filter->blur *= 0.9812505644269356;
1028 case Lanczos2SharpFilter:
1029 resize_filter->blur *= 0.9549963639785485;
1041 if ((resize_filter->filter == Gaussian) ||
1042 (resize_filter->window == Gaussian) ) {
1044 artifact=GetImageArtifact(image,
"filter:sigma");
1045 if (artifact != (
const char *) NULL)
1046 value=StringToDouble(artifact,(
char **) NULL);
1048 resize_filter->coefficient[0]=value;
1049 resize_filter->coefficient[1]=PerceptibleReciprocal(2.0*value*value);
1050 resize_filter->coefficient[2]=PerceptibleReciprocal(Magick2PI*value*value);
1053 resize_filter->support *= 2*value;
1057 if ((resize_filter->filter == Kaiser) ||
1058 (resize_filter->window == Kaiser) ) {
1060 artifact=GetImageArtifact(image,
"filter:alpha");
1061 if (artifact != (
const char *) NULL)
1062 value=StringToDouble(artifact,(
char **) NULL);
1063 artifact=GetImageArtifact(image,
"filter:kaiser-beta");
1064 if (artifact != (
const char *) NULL)
1065 value=StringToDouble(artifact,(
char **) NULL);
1066 artifact=GetImageArtifact(image,
"filter:kaiser-alpha");
1067 if (artifact != (
const char *) NULL)
1068 value=StringToDouble(artifact,(
char **) NULL)*MagickPI;
1070 resize_filter->coefficient[0]=value;
1071 resize_filter->coefficient[1]=PerceptibleReciprocal(I0(value));
1076 artifact=GetImageArtifact(image,
"filter:lobes");
1077 if (artifact != (
const char *) NULL)
1082 lobes=(ssize_t) StringToLong(artifact);
1085 resize_filter->support=(double) lobes;
1087 if (resize_filter->filter == Jinc)
1092 if (resize_filter->support > 16)
1093 resize_filter->support=jinc_zeros[15];
1095 resize_filter->support=jinc_zeros[((long) resize_filter->support)-1];
1099 if (filter_type == LanczosRadiusFilter)
1100 resize_filter->blur*=floor(resize_filter->support)/
1101 resize_filter->support;
1106 artifact=GetImageArtifact(image,
"filter:blur");
1107 if (artifact != (
const char *) NULL)
1108 resize_filter->blur*=StringToDouble(artifact,(
char **) NULL);
1109 if (resize_filter->blur < MagickEpsilon)
1110 resize_filter->blur=(double) MagickEpsilon;
1114 artifact=GetImageArtifact(image,
"filter:support");
1115 if (artifact != (
const char *) NULL)
1116 resize_filter->support=fabs(StringToDouble(artifact,(
char **) NULL));
1121 resize_filter->window_support=resize_filter->support;
1122 artifact=GetImageArtifact(image,
"filter:win-support");
1123 if (artifact != (
const char *) NULL)
1124 resize_filter->window_support=fabs(StringToDouble(artifact,(
char **) NULL));
1129 resize_filter->scale*=PerceptibleReciprocal(resize_filter->window_support);
1135 if ((resize_filter->filter == CubicBC) ||
1136 (resize_filter->window == CubicBC) )
1138 B=filters[filter_type].B;
1139 C=filters[filter_type].C;
1140 if (filters[window_type].function == CubicBC)
1142 B=filters[window_type].B;
1143 C=filters[window_type].C;
1145 artifact=GetImageArtifact(image,
"filter:b");
1146 if (artifact != (
const char *) NULL)
1148 B=StringToDouble(artifact,(
char **) NULL);
1150 artifact=GetImageArtifact(image,
"filter:c");
1151 if (artifact != (
const char *) NULL)
1152 C=StringToDouble(artifact,(
char **) NULL);
1156 artifact=GetImageArtifact(image,
"filter:c");
1157 if (artifact != (
const char *) NULL)
1159 C=StringToDouble(artifact,(
char **) NULL);
1170 resize_filter->coefficient[0]=1.0-(1.0/3.0)*B;
1171 resize_filter->coefficient[1]=-3.0+twoB+C;
1172 resize_filter->coefficient[2]=2.0-1.5*B-C;
1173 resize_filter->coefficient[3]=(4.0/3.0)*B+4.0*C;
1174 resize_filter->coefficient[4]=-8.0*C-twoB;
1175 resize_filter->coefficient[5]=B+5.0*C;
1176 resize_filter->coefficient[6]=(-1.0/6.0)*B-C;
1183 if (IsStringTrue(GetImageArtifact(image,
"filter:verbose")) != MagickFalse)
1184#if defined(MAGICKCORE_OPENMP_SUPPORT)
1198 if (resize_filter->filter == Box) filter_type=BoxFilter;
1199 if (resize_filter->filter == Sinc) filter_type=SincFilter;
1200 if (resize_filter->filter == SincFast) filter_type=SincFastFilter;
1201 if (resize_filter->filter == Jinc) filter_type=JincFilter;
1202 if (resize_filter->filter == CubicBC) filter_type=CubicFilter;
1203 if (resize_filter->window == Box) window_type=BoxFilter;
1204 if (resize_filter->window == Sinc) window_type=SincFilter;
1205 if (resize_filter->window == SincFast) window_type=SincFastFilter;
1206 if (resize_filter->window == Jinc) window_type=JincFilter;
1207 if (resize_filter->window == CubicBC) window_type=CubicFilter;
1211 support=GetResizeFilterSupport(resize_filter);
1212 (void) FormatLocaleFile(stdout,
"# Resampling Filter (for graphing)\n#\n");
1213 (void) FormatLocaleFile(stdout,
"# filter = %s\n",
1214 CommandOptionToMnemonic(MagickFilterOptions,filter_type));
1215 (void) FormatLocaleFile(stdout,
"# window = %s\n",
1216 CommandOptionToMnemonic(MagickFilterOptions,window_type));
1217 (void) FormatLocaleFile(stdout,
"# support = %.*g\n",
1218 GetMagickPrecision(),(double) resize_filter->support);
1219 (void) FormatLocaleFile(stdout,
"# window-support = %.*g\n",
1220 GetMagickPrecision(),(double) resize_filter->window_support);
1221 (void) FormatLocaleFile(stdout,
"# scale-blur = %.*g\n",
1222 GetMagickPrecision(),(double) resize_filter->blur);
1223 if ((filter_type == GaussianFilter) || (window_type == GaussianFilter))
1224 (void) FormatLocaleFile(stdout,
"# gaussian-sigma = %.*g\n",
1225 GetMagickPrecision(),(double) resize_filter->coefficient[0]);
1226 if ((filter_type == KaiserFilter) || (window_type == KaiserFilter))
1227 (void) FormatLocaleFile(stdout,
"# kaiser-beta = %.*g\n",
1228 GetMagickPrecision(),(double) resize_filter->coefficient[0]);
1229 (void) FormatLocaleFile(stdout,
"# practical-support = %.*g\n",
1230 GetMagickPrecision(), (double) support);
1231 if ((filter_type == CubicFilter) || (window_type == CubicFilter))
1232 (void) FormatLocaleFile(stdout,
"# B,C = %.*g,%.*g\n",
1233 GetMagickPrecision(),(double) B,GetMagickPrecision(),(double) C);
1234 (void) FormatLocaleFile(stdout,
"\n");
1238 for (x=0.0; x <= support; x+=0.01)
1239 (
void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",x,GetMagickPrecision(),
1240 (
double) GetResizeFilterWeight(resize_filter,x));
1244 (void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",support,
1245 GetMagickPrecision(),0.0);
1247 (void) DeleteImageArtifact((
Image *) image,
"filter:verbose");
1249 return(resize_filter);
1286MagickExport
Image *AdaptiveResizeImage(
const Image *image,
1287 const size_t columns,
const size_t rows,
ExceptionInfo *exception)
1292 resize_image=InterpolativeResizeImage(image,columns,rows,MeshInterpolatePixel,
1294 return(resize_image);
1337static double I0(
double x)
1353 for (i=2; t > MagickEpsilon; i++)
1356 t*=y/((double) i*i);
1362static double J1(
double x)
1374 0.581199354001606143928050809e+21,
1375 -0.6672106568924916298020941484e+20,
1376 0.2316433580634002297931815435e+19,
1377 -0.3588817569910106050743641413e+17,
1378 0.2908795263834775409737601689e+15,
1379 -0.1322983480332126453125473247e+13,
1380 0.3413234182301700539091292655e+10,
1381 -0.4695753530642995859767162166e+7,
1382 0.270112271089232341485679099e+4
1386 0.11623987080032122878585294e+22,
1387 0.1185770712190320999837113348e+20,
1388 0.6092061398917521746105196863e+17,
1389 0.2081661221307607351240184229e+15,
1390 0.5243710262167649715406728642e+12,
1391 0.1013863514358673989967045588e+10,
1392 0.1501793594998585505921097578e+7,
1393 0.1606931573481487801970916749e+4,
1399 for (i=7; i >= 0; i--)
1408static double P1(
double x)
1420 0.352246649133679798341724373e+5,
1421 0.62758845247161281269005675e+5,
1422 0.313539631109159574238669888e+5,
1423 0.49854832060594338434500455e+4,
1424 0.2111529182853962382105718e+3,
1425 0.12571716929145341558495e+1
1429 0.352246649133679798068390431e+5,
1430 0.626943469593560511888833731e+5,
1431 0.312404063819041039923015703e+5,
1432 0.4930396490181088979386097e+4,
1433 0.2030775189134759322293574e+3,
1439 for (i=4; i >= 0; i--)
1441 p=p*(8.0/x)*(8.0/x)+Pone[i];
1442 q=q*(8.0/x)*(8.0/x)+Qone[i];
1448static double Q1(
double x)
1460 0.3511751914303552822533318e+3,
1461 0.7210391804904475039280863e+3,
1462 0.4259873011654442389886993e+3,
1463 0.831898957673850827325226e+2,
1464 0.45681716295512267064405e+1,
1465 0.3532840052740123642735e-1
1469 0.74917374171809127714519505e+4,
1470 0.154141773392650970499848051e+5,
1471 0.91522317015169922705904727e+4,
1472 0.18111867005523513506724158e+4,
1473 0.1038187585462133728776636e+3,
1479 for (i=4; i >= 0; i--)
1481 p=p*(8.0/x)*(8.0/x)+Pone[i];
1482 q=q*(8.0/x)*(8.0/x)+Qone[i];
1487static double BesselOrderOne(
double x)
1500 q=sqrt((
double) (2.0/(MagickPI*x)))*(P1(x)*(1.0/sqrt(2.0)*(sin(x)-
1501 cos(x)))-8.0/x*Q1(x)*(-1.0/sqrt(2.0)*(sin(x)+cos(x))));
1532 assert(resize_filter->signature == MagickCoreSignature);
1533 resize_filter->signature=(~MagickCoreSignature);
1534 resize_filter=(
ResizeFilter *) RelinquishMagickMemory(resize_filter);
1535 return(resize_filter);
1562MagickPrivate
double *GetResizeFilterCoefficient(
1566 assert(resize_filter->signature == MagickCoreSignature);
1567 return((
double *) resize_filter->coefficient);
1570MagickPrivate
double GetResizeFilterBlur(
const ResizeFilter *resize_filter)
1573 assert(resize_filter->signature == MagickCoreSignature);
1574 return(resize_filter->blur);
1577MagickPrivate
double GetResizeFilterScale(
const ResizeFilter *resize_filter)
1580 assert(resize_filter->signature == MagickCoreSignature);
1581 return(resize_filter->scale);
1584MagickPrivate
double GetResizeFilterWindowSupport(
1588 assert(resize_filter->signature == MagickCoreSignature);
1589 return(resize_filter->window_support);
1592MagickPrivate ResizeWeightingFunctionType GetResizeFilterWeightingType(
1596 assert(resize_filter->signature == MagickCoreSignature);
1597 return(resize_filter->filterWeightingType);
1600MagickPrivate ResizeWeightingFunctionType GetResizeFilterWindowWeightingType(
1604 assert(resize_filter->signature == MagickCoreSignature);
1605 return(resize_filter->windowWeightingType);
1608MagickPrivate
double GetResizeFilterSupport(
const ResizeFilter *resize_filter)
1611 assert(resize_filter->signature == MagickCoreSignature);
1612 return(resize_filter->support*resize_filter->blur);
1642MagickPrivate
double GetResizeFilterWeight(
const ResizeFilter *resize_filter,
1654 assert(resize_filter->signature == MagickCoreSignature);
1655 x_blur=fabs((
double) x)*PerceptibleReciprocal(resize_filter->blur);
1656 if ((resize_filter->window_support < MagickEpsilon) ||
1657 (resize_filter->window == Box))
1661 scale=resize_filter->scale;
1662 scale=resize_filter->window(x_blur*scale,resize_filter);
1664 weight=scale*resize_filter->filter(x_blur,resize_filter);
1701MagickExport
Image *InterpolativeResizeImage(
const Image *image,
1702 const size_t columns,
const size_t rows,
const PixelInterpolateMethod method,
1705#define InterpolativeResizeImageTag "Resize/Image"
1729 assert(image != (
const Image *) NULL);
1730 assert(image->signature == MagickCoreSignature);
1732 assert(exception->signature == MagickCoreSignature);
1733 if (IsEventLogging() != MagickFalse)
1734 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1735 if ((columns == 0) || (rows == 0))
1736 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1737 if ((columns == image->columns) && (rows == image->rows))
1738 return(CloneImage(image,0,0,MagickTrue,exception));
1739 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
1740 if (resize_image == (
Image *) NULL)
1741 return((
Image *) NULL);
1742 if (SetImageStorageClass(resize_image,DirectClass,exception) == MagickFalse)
1744 resize_image=DestroyImage(resize_image);
1745 return((
Image *) NULL);
1749 image_view=AcquireVirtualCacheView(image,exception);
1750 resize_view=AcquireAuthenticCacheView(resize_image,exception);
1751 scale.x=(double) image->columns/resize_image->columns;
1752 scale.y=(double) image->rows/resize_image->rows;
1753#if defined(MAGICKCORE_OPENMP_SUPPORT)
1754 #pragma omp parallel for schedule(static) shared(progress,status) \
1755 magick_number_threads(image,resize_image,resize_image->rows,1)
1757 for (y=0; y < (ssize_t) resize_image->rows; y++)
1768 if (status == MagickFalse)
1770 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
1772 if (q == (Quantum *) NULL)
1774 offset.y=((double) y+0.5)*scale.y-0.5;
1775 for (x=0; x < (ssize_t) resize_image->columns; x++)
1780 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1789 channel=GetPixelChannelChannel(image,i);
1790 traits=GetPixelChannelTraits(image,channel);
1791 resize_traits=GetPixelChannelTraits(resize_image,channel);
1792 if ((traits == UndefinedPixelTrait) ||
1793 (resize_traits == UndefinedPixelTrait))
1795 offset.x=((double) x+0.5)*scale.x-0.5;
1796 status=InterpolatePixelChannels(image,image_view,resize_image,method,
1797 offset.x,offset.y,q,exception);
1798 if (status == MagickFalse)
1801 q+=GetPixelChannels(resize_image);
1803 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
1805 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1810#if defined(MAGICKCORE_OPENMP_SUPPORT)
1814 proceed=SetImageProgress(image,InterpolativeResizeImageTag,progress,
1816 if (proceed == MagickFalse)
1820 resize_view=DestroyCacheView(resize_view);
1821 image_view=DestroyCacheView(image_view);
1822 if (status == MagickFalse)
1823 resize_image=DestroyImage(resize_image);
1824 return(resize_image);
1826#if defined(MAGICKCORE_LQR_DELEGATE)
1862MagickExport
Image *LiquidRescaleImage(
const Image *image,
const size_t columns,
1863 const size_t rows,
const double delta_x,
const double rigidity,
1866#define LiquidRescaleImageTag "Rescale/Image"
1904 assert(image != (
const Image *) NULL);
1905 assert(image->signature == MagickCoreSignature);
1907 assert(exception->signature == MagickCoreSignature);
1908 if (IsEventLogging() != MagickFalse)
1909 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1910 if ((columns == 0) || (rows == 0))
1911 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1912 if ((columns == image->columns) && (rows == image->rows))
1913 return(CloneImage(image,0,0,MagickTrue,exception));
1914 if ((columns <= 2) || (rows <= 2))
1915 return(ResizeImage(image,columns,rows,image->filter,exception));
1916 pixel_info=AcquireVirtualMemory(image->columns,image->rows*MaxPixelChannels*
1919 return((
Image *) NULL);
1920 pixels=(gfloat *) GetVirtualMemoryBlob(pixel_info);
1923 image_view=AcquireVirtualCacheView(image,exception);
1924 for (y=0; y < (ssize_t) image->rows; y++)
1932 if (status == MagickFalse)
1934 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1935 if (p == (
const Quantum *) NULL)
1940 for (x=0; x < (ssize_t) image->columns; x++)
1945 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1946 *q++=QuantumScale*(
double) p[i];
1947 p+=GetPixelChannels(image);
1950 image_view=DestroyCacheView(image_view);
1951 carver=lqr_carver_new_ext(pixels,(
int) image->columns,(
int) image->rows,
1952 (
int) GetPixelChannels(image),LQR_COLDEPTH_32F);
1953 if (carver == (LqrCarver *) NULL)
1955 pixel_info=RelinquishVirtualMemory(pixel_info);
1956 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
1958 lqr_carver_set_preserve_input_image(carver);
1959 lqr_status=lqr_carver_init(carver,(
int) delta_x,rigidity);
1960 lqr_status=lqr_carver_resize(carver,(
int) columns,(
int) rows);
1962 rescale_image=CloneImage(image,(
size_t) lqr_carver_get_width(carver),
1963 (
size_t) lqr_carver_get_height(carver),MagickTrue,exception);
1964 if (rescale_image == (
Image *) NULL)
1966 pixel_info=RelinquishVirtualMemory(pixel_info);
1967 return((
Image *) NULL);
1969 if (SetImageStorageClass(rescale_image,DirectClass,exception) == MagickFalse)
1971 pixel_info=RelinquishVirtualMemory(pixel_info);
1972 rescale_image=DestroyImage(rescale_image);
1973 return((
Image *) NULL);
1975 rescale_view=AcquireAuthenticCacheView(rescale_image,exception);
1976 (void) lqr_carver_scan_reset(carver);
1977 while (lqr_carver_scan_ext(carver,&x_offset,&y_offset,(
void **) &packet) != 0)
1985 p=QueueCacheViewAuthenticPixels(rescale_view,x_offset,y_offset,1,1,
1987 if (p == (Quantum *) NULL)
1989 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1998 channel=GetPixelChannelChannel(image,i);
1999 traits=GetPixelChannelTraits(image,channel);
2000 rescale_traits=GetPixelChannelTraits(rescale_image,channel);
2001 if ((traits == UndefinedPixelTrait) ||
2002 (rescale_traits == UndefinedPixelTrait))
2004 SetPixelChannel(rescale_image,channel,ClampToQuantum(QuantumRange*
2007 if (SyncCacheViewAuthenticPixels(rescale_view,exception) == MagickFalse)
2010 rescale_view=DestroyCacheView(rescale_view);
2011 pixel_info=RelinquishVirtualMemory(pixel_info);
2012 lqr_carver_destroy(carver);
2013 return(rescale_image);
2016MagickExport
Image *LiquidRescaleImage(
const Image *image,
2017 const size_t magick_unused(columns),
const size_t magick_unused(rows),
2018 const double magick_unused(delta_x),
const double magick_unused(rigidity),
2021 assert(image != (
const Image *) NULL);
2022 assert(image->signature == MagickCoreSignature);
2024 assert(exception->signature == MagickCoreSignature);
2025 magick_unreferenced(columns);
2026 magick_unreferenced(rows);
2027 magick_unreferenced(delta_x);
2028 magick_unreferenced(rigidity);
2029 if (IsEventLogging() != MagickFalse)
2030 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2031 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
2032 "DelegateLibrarySupportNotBuiltIn",
"'%s' (LQR)",image->filename);
2033 return((
Image *) NULL);
2063static inline void CopyPixels(
const Quantum *source,
const ssize_t source_offset,
2064 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2069 for (i=0; i < (ssize_t) channels; i++)
2070 destination[(ssize_t) channels*destination_offset+i]=
2071 source[source_offset*(ssize_t) channels+i];
2074static inline void MixPixels(
const Quantum *source,
const ssize_t *source_offset,
2075 const size_t source_size,Quantum *destination,
2076 const ssize_t destination_offset,
const size_t channels)
2081 for (i=0; i < (ssize_t) channels; i++)
2087 for (j=0; j < (ssize_t) source_size; j++)
2088 sum+=source[source_offset[j]*(ssize_t) channels+i];
2089 destination[(ssize_t) channels*destination_offset+i]=(Quantum) (sum/
2090 (ssize_t) source_size);
2094static inline void Mix2Pixels(
const Quantum *source,
2095 const ssize_t source_offset1,
const ssize_t source_offset2,
2096 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2099 offsets[2] = { source_offset1, source_offset2 };
2101 MixPixels(source,offsets,2,destination,destination_offset,channels);
2104static inline int PixelsEqual(
const Quantum *source1,ssize_t offset1,
2105 const Quantum *source2,ssize_t offset2,
const size_t channels)
2110 offset1*=(ssize_t) channels;
2111 offset2*=(ssize_t) channels;
2112 for (i=0; i < (ssize_t) channels; i++)
2113 if (source1[offset1+i] != source2[offset2+i])
2118static inline void Eagle2X(
const Image *source,
const Quantum *pixels,
2119 Quantum *result,
const size_t channels)
2125 for (i=0; i < 4; i++)
2126 CopyPixels(pixels,4,result,i,channels);
2127 if (PixelsEqual(pixels,0,pixels,1,channels) &&
2128 PixelsEqual(pixels,1,pixels,3,channels))
2129 CopyPixels(pixels,0,result,0,channels);
2130 if (PixelsEqual(pixels,1,pixels,2,channels) &&
2131 PixelsEqual(pixels,2,pixels,5,channels))
2132 CopyPixels(pixels,2,result,1,channels);
2133 if (PixelsEqual(pixels,3,pixels,6,channels) &&
2134 PixelsEqual(pixels,6,pixels,7,channels))
2135 CopyPixels(pixels,6,result,2,channels);
2136 if (PixelsEqual(pixels,5,pixels,8,channels) &&
2137 PixelsEqual(pixels,8,pixels,7,channels))
2138 CopyPixels(pixels,8,result,3,channels);
2141static void Hq2XHelper(
const unsigned int rule,
const Quantum *source,
2142 Quantum *destination,
const ssize_t destination_offset,
const size_t channels,
2143 const ssize_t e,
const ssize_t a,
const ssize_t b,
const ssize_t d,
2144 const ssize_t f,
const ssize_t h)
2146#define caseA(N,A,B,C,D) \
2150 offsets[4] = { A, B, C, D }; \
2152 MixPixels(source,offsets,4,destination,destination_offset,channels);\
2155#define caseB(N,A,B,C,D,E,F,G,H) \
2159 offsets[8] = { A, B, C, D, E, F, G, H }; \
2161 MixPixels(source,offsets,8,destination,destination_offset,channels);\
2169 CopyPixels(source,e,destination,destination_offset,channels);
2178 caseB(7,e,e,e,e,e,b,b,d)
2179 caseB(8,e,e,e,e,e,d,d,b)
2180 caseB(9,e,e,e,e,e,e,d,b)
2181 caseB(10,e,e,d,d,d,b,b,b)
2185 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2187 MixPixels(source,offsets,16,destination,destination_offset,channels);
2192 if (PixelsEqual(source,b,source,d,channels))
2195 offsets[4] = { e, e, d, b };
2197 MixPixels(source,offsets,4,destination,destination_offset,channels);
2200 CopyPixels(source,e,destination,destination_offset,channels);
2205 if (PixelsEqual(source,b,source,d,channels))
2208 offsets[8] = { e, e, d, d, d, b, b, b };
2210 MixPixels(source,offsets,8,destination,destination_offset,channels);
2213 CopyPixels(source,e,destination,destination_offset,channels);
2218 if (PixelsEqual(source,b,source,d,channels))
2221 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2223 MixPixels(source,offsets,16,destination,destination_offset,channels);
2226 CopyPixels(source,e,destination,destination_offset,channels);
2231 if (PixelsEqual(source,b,source,d,channels))
2234 offsets[4] = { e, e, d, b };
2236 MixPixels(source,offsets,4,destination,destination_offset,channels);
2241 offsets[4] = { e, e, e, a };
2243 MixPixels(source,offsets,4,destination,destination_offset,channels);
2249 if (PixelsEqual(source,b,source,d,channels))
2252 offsets[8] = { e, e, e, e, e, e, d, b };
2254 MixPixels(source,offsets,8,destination,destination_offset,channels);
2259 offsets[4] = { e, e, e, a };
2261 MixPixels(source,offsets,4,destination,destination_offset,channels);
2267 if (PixelsEqual(source,b,source,d,channels))
2270 offsets[8] = { e, e, d, d, d, b, b, b };
2272 MixPixels(source,offsets,8,destination,destination_offset,channels);
2277 offsets[4] = { e, e, e, a };
2279 MixPixels(source,offsets,4,destination,destination_offset,channels);
2285 if (PixelsEqual(source,b,source,f,channels))
2288 offsets[8] = { e, e, e, e, e, b, b, d };
2290 MixPixels(source,offsets,8,destination,destination_offset,channels);
2295 offsets[4] = { e, e, e, d };
2297 MixPixels(source,offsets,4,destination,destination_offset,channels);
2303 if (PixelsEqual(source,d,source,h,channels))
2306 offsets[8] = { e, e, e, e, e, d, d, b };
2308 MixPixels(source,offsets,8,destination,destination_offset,channels);
2313 offsets[4] = { e, e, e, b };
2315 MixPixels(source,offsets,4,destination,destination_offset,channels);
2324static inline unsigned int Hq2XPatternToNumber(
const int *pattern)
2335 for (i=7; i >= 0; i--)
2337 result+=order*(
unsigned int) pattern[i];
2343static inline void Hq2X(
const Image *source,
const Quantum *pixels,
2344 Quantum *result,
const size_t channels)
2346 static const unsigned int
2349 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2350 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
2351 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2352 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
2353 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
2354 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2355 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
2356 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
2357 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2358 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2359 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2360 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
2361 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
2362 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
2363 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
2364 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14
2370 !PixelsEqual(pixels,4,pixels,8,channels),
2371 !PixelsEqual(pixels,4,pixels,7,channels),
2372 !PixelsEqual(pixels,4,pixels,6,channels),
2373 !PixelsEqual(pixels,4,pixels,5,channels),
2374 !PixelsEqual(pixels,4,pixels,3,channels),
2375 !PixelsEqual(pixels,4,pixels,2,channels),
2376 !PixelsEqual(pixels,4,pixels,1,channels),
2377 !PixelsEqual(pixels,4,pixels,0,channels)
2380#define Rotated(p) p[2], p[4], p[7], p[1], p[6], p[0], p[3], p[5]
2381 const int pattern2[] = { Rotated(pattern1) };
2382 const int pattern3[] = { Rotated(pattern2) };
2383 const int pattern4[] = { Rotated(pattern3) };
2386 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern1)],pixels,result,0,
2387 channels,4,0,1,3,5,7);
2388 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern2)],pixels,result,1,
2389 channels,4,2,5,1,7,3);
2390 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern3)],pixels,result,3,
2391 channels,4,8,7,5,3,1);
2392 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern4)],pixels,result,2,
2393 channels,4,6,3,7,1,5);
2396static void Fish2X(
const Image *source,
const Quantum *pixels,Quantum *result,
2397 const size_t channels)
2399#define Corner(A,B,C,D) \
2401 if (intensities[B] > intensities[A]) \
2404 offsets[3] = { B, C, D }; \
2406 MixPixels(pixels,offsets,3,result,3,channels); \
2411 offsets[3] = { A, B, C }; \
2413 MixPixels(pixels,offsets,3,result,3,channels); \
2417#define Line(A,B,C,D) \
2419 if (intensities[C] > intensities[A]) \
2420 Mix2Pixels(pixels,C,D,result,3,channels); \
2422 Mix2Pixels(pixels,A,B,result,3,channels); \
2426 pixels_offsets[4] = { 0, 1, 3, 4 };
2442 for (i=0; i < 9; i++)
2443 intensities[i]=GetPixelIntensity(source,pixels+i*(ssize_t) channels);
2444 CopyPixels(pixels,0,result,0,channels);
2445 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[1] ? 0 : 1),result,
2447 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[3] ? 0 : 3),result,
2449 ae=PixelsEqual(pixels,0,pixels,4,channels);
2450 bd=PixelsEqual(pixels,1,pixels,3,channels);
2451 ab=PixelsEqual(pixels,0,pixels,1,channels);
2452 de=PixelsEqual(pixels,3,pixels,4,channels);
2453 ad=PixelsEqual(pixels,0,pixels,3,channels);
2454 be=PixelsEqual(pixels,1,pixels,4,channels);
2457 CopyPixels(pixels,0,result,3,channels);
2460 if (ad && de && !ab)
2465 if (be && de && !ab)
2470 if (ad && ab && !be)
2475 if (ab && be && !ad)
2480 if (ae && (!bd || intensities[1] > intensities[0]))
2482 Mix2Pixels(pixels,0,4,result,3,channels);
2485 if (bd && (!ae || intensities[0] > intensities[1]))
2487 Mix2Pixels(pixels,1,3,result,3,channels);
2510 MixPixels(pixels,pixels_offsets,4,result,3,channels);
2515static void Xbr2X(
const Image *magick_unused(source),
const Quantum *pixels,
2516 Quantum *result,
const size_t channels)
2518#define WeightVar(M,N) const int w_##M##_##N = \
2519 PixelsEqual(pixels,M,pixels,N,channels) ? 0 : 1;
2551 magick_unreferenced(source);
2554 w_12_16 + w_12_8 + w_6_10 + w_6_2 + (4 * w_11_7) <
2555 w_11_17 + w_11_5 + w_7_13 + w_7_1 + (4 * w_12_6)
2557 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_7 ? 11 : 7),12,result,0,
2560 CopyPixels(pixels,12,result,0,channels);
2562 w_12_18 + w_12_6 + w_8_14 + w_8_2 + (4 * w_7_13) <
2563 w_13_17 + w_13_9 + w_11_7 + w_7_3 + (4 * w_12_8)
2565 Mix2Pixels(pixels,(ssize_t) (w_12_7 <= w_12_13 ? 7 : 13),12,result,1,
2568 CopyPixels(pixels,12,result,1,channels);
2570 w_12_6 + w_12_18 + w_16_10 + w_16_22 + (4 * w_11_17) <
2571 w_11_7 + w_11_15 + w_13_17 + w_17_21 + (4 * w_12_16)
2573 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_17 ? 11 : 17),12,result,2,
2576 CopyPixels(pixels,12,result,2,channels);
2578 w_12_8 + w_12_16 + w_18_14 + w_18_22 + (4 * w_13_17) <
2579 w_11_17 + w_17_23 + w_17_19 + w_7_13 + (4 * w_12_18)
2581 Mix2Pixels(pixels,(ssize_t) (w_12_13 <= w_12_17 ? 13 : 17),12,result,3,
2584 CopyPixels(pixels,12,result,3,channels);
2587static void Scale2X(
const Image *magick_unused(source),
const Quantum *pixels,
2588 Quantum *result,
const size_t channels)
2590 magick_unreferenced(source);
2592 if (PixelsEqual(pixels,1,pixels,7,channels) ||
2593 PixelsEqual(pixels,3,pixels,5,channels))
2598 for (i=0; i < 4; i++)
2599 CopyPixels(pixels,4,result,i,channels);
2602 if (PixelsEqual(pixels,1,pixels,3,channels))
2603 CopyPixels(pixels,3,result,0,channels);
2605 CopyPixels(pixels,4,result,0,channels);
2606 if (PixelsEqual(pixels,1,pixels,5,channels))
2607 CopyPixels(pixels,5,result,1,channels);
2609 CopyPixels(pixels,4,result,1,channels);
2610 if (PixelsEqual(pixels,3,pixels,7,channels))
2611 CopyPixels(pixels,3,result,2,channels);
2613 CopyPixels(pixels,4,result,2,channels);
2614 if (PixelsEqual(pixels,5,pixels,7,channels))
2615 CopyPixels(pixels,5,result,3,channels);
2617 CopyPixels(pixels,4,result,3,channels);
2620static void Epbx2X(
const Image *magick_unused(source),
const Quantum *pixels,
2621 Quantum *result,
const size_t channels)
2623#define HelperCond(a,b,c,d,e,f,g) ( \
2624 PixelsEqual(pixels,a,pixels,b,channels) && ( \
2625 PixelsEqual(pixels,c,pixels,d,channels) || \
2626 PixelsEqual(pixels,c,pixels,e,channels) || \
2627 PixelsEqual(pixels,a,pixels,f,channels) || \
2628 PixelsEqual(pixels,b,pixels,g,channels) \
2635 magick_unreferenced(source);
2637 for (i=0; i < 4; i++)
2638 CopyPixels(pixels,4,result,i,channels);
2640 !PixelsEqual(pixels,3,pixels,5,channels) &&
2641 !PixelsEqual(pixels,1,pixels,7,channels) &&
2643 PixelsEqual(pixels,4,pixels,3,channels) ||
2644 PixelsEqual(pixels,4,pixels,7,channels) ||
2645 PixelsEqual(pixels,4,pixels,5,channels) ||
2646 PixelsEqual(pixels,4,pixels,1,channels) ||
2649 !PixelsEqual(pixels,0,pixels,8,channels) ||
2650 PixelsEqual(pixels,4,pixels,6,channels) ||
2651 PixelsEqual(pixels,3,pixels,2,channels)
2654 !PixelsEqual(pixels,6,pixels,2,channels) ||
2655 PixelsEqual(pixels,4,pixels,0,channels) ||
2656 PixelsEqual(pixels,4,pixels,8,channels)
2662 if (HelperCond(1,3,4,0,8,2,6))
2663 Mix2Pixels(pixels,1,3,result,0,channels);
2664 if (HelperCond(5,1,4,2,6,8,0))
2665 Mix2Pixels(pixels,5,1,result,1,channels);
2666 if (HelperCond(3,7,4,6,2,0,8))
2667 Mix2Pixels(pixels,3,7,result,2,channels);
2668 if (HelperCond(7,5,4,8,0,6,2))
2669 Mix2Pixels(pixels,7,5,result,3,channels);
2675static inline void Eagle3X(
const Image *magick_unused(source),
2676 const Quantum *pixels,Quantum *result,
const size_t channels)
2684 magick_unreferenced(source);
2686 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2687 PixelsEqual(pixels,0,pixels,3,channels);
2688 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2689 PixelsEqual(pixels,2,pixels,5,channels);
2690 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2691 PixelsEqual(pixels,6,pixels,7,channels);
2692 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2693 PixelsEqual(pixels,7,pixels,8,channels);
2694 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2695 if (corner_tl && corner_tr)
2696 Mix2Pixels(pixels,0,2,result,1,channels);
2698 CopyPixels(pixels,4,result,1,channels);
2699 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2700 if (corner_tl && corner_bl)
2701 Mix2Pixels(pixels,0,6,result,3,channels);
2703 CopyPixels(pixels,4,result,3,channels);
2704 CopyPixels(pixels,4,result,4,channels);
2705 if (corner_tr && corner_br)
2706 Mix2Pixels(pixels,2,8,result,5,channels);
2708 CopyPixels(pixels,4,result,5,channels);
2709 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2710 if (corner_bl && corner_br)
2711 Mix2Pixels(pixels,6,8,result,7,channels);
2713 CopyPixels(pixels,4,result,7,channels);
2714 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2717static inline void Eagle3XB(
const Image *magick_unused(source),
2718 const Quantum *pixels,Quantum *result,
const size_t channels)
2726 magick_unreferenced(source);
2728 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2729 PixelsEqual(pixels,0,pixels,3,channels);
2730 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2731 PixelsEqual(pixels,2,pixels,5,channels);
2732 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2733 PixelsEqual(pixels,6,pixels,7,channels);
2734 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2735 PixelsEqual(pixels,7,pixels,8,channels);
2736 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2737 CopyPixels(pixels,4,result,1,channels);
2738 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2739 CopyPixels(pixels,4,result,3,channels);
2740 CopyPixels(pixels,4,result,4,channels);
2741 CopyPixels(pixels,4,result,5,channels);
2742 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2743 CopyPixels(pixels,4,result,7,channels);
2744 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2747static inline void Scale3X(
const Image *magick_unused(source),
2748 const Quantum *pixels,Quantum *result,
const size_t channels)
2750 magick_unreferenced(source);
2752 if (!PixelsEqual(pixels,1,pixels,7,channels) &&
2753 !PixelsEqual(pixels,3,pixels,5,channels))
2755 if (PixelsEqual(pixels,3,pixels,1,channels))
2756 CopyPixels(pixels,3,result,0,channels);
2758 CopyPixels(pixels,4,result,0,channels);
2762 PixelsEqual(pixels,3,pixels,1,channels) &&
2763 !PixelsEqual(pixels,4,pixels,2,channels)
2766 PixelsEqual(pixels,5,pixels,1,channels) &&
2767 !PixelsEqual(pixels,4,pixels,0,channels)
2770 CopyPixels(pixels,1,result,1,channels);
2772 CopyPixels(pixels,4,result,1,channels);
2773 if (PixelsEqual(pixels,5,pixels,1,channels))
2774 CopyPixels(pixels,5,result,2,channels);
2776 CopyPixels(pixels,4,result,2,channels);
2779 PixelsEqual(pixels,3,pixels,1,channels) &&
2780 !PixelsEqual(pixels,4,pixels,6,channels)
2783 PixelsEqual(pixels,3,pixels,7,channels) &&
2784 !PixelsEqual(pixels,4,pixels,0,channels)
2787 CopyPixels(pixels,3,result,3,channels);
2789 CopyPixels(pixels,4,result,3,channels);
2790 CopyPixels(pixels,4,result,4,channels);
2793 PixelsEqual(pixels,5,pixels,1,channels) &&
2794 !PixelsEqual(pixels,4,pixels,8,channels)
2797 PixelsEqual(pixels,5,pixels,7,channels) &&
2798 !PixelsEqual(pixels,4,pixels,2,channels)
2801 CopyPixels(pixels,5,result,5,channels);
2803 CopyPixels(pixels,4,result,5,channels);
2804 if (PixelsEqual(pixels,3,pixels,7,channels))
2805 CopyPixels(pixels,3,result,6,channels);
2807 CopyPixels(pixels,4,result,6,channels);
2810 PixelsEqual(pixels,3,pixels,7,channels) &&
2811 !PixelsEqual(pixels,4,pixels,8,channels)
2814 PixelsEqual(pixels,5,pixels,7,channels) &&
2815 !PixelsEqual(pixels,4,pixels,6,channels)
2818 CopyPixels(pixels,7,result,7,channels);
2820 CopyPixels(pixels,4,result,7,channels);
2821 if (PixelsEqual(pixels,5,pixels,7,channels))
2822 CopyPixels(pixels,5,result,8,channels);
2824 CopyPixels(pixels,4,result,8,channels);
2831 for (i=0; i < 9; i++)
2832 CopyPixels(pixels,4,result,i,channels);
2838#define MagnifyImageTag "Magnify/Image"
2871 (*scaling_method)(
const Image *,
const Quantum *,Quantum *,size_t);
2876 assert(image != (
const Image *) NULL);
2877 assert(image->signature == MagickCoreSignature);
2879 assert(exception->signature == MagickCoreSignature);
2880 if (IsEventLogging() != MagickFalse)
2881 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2882 option=GetImageOption(image->image_info,
"magnify:method");
2883 if (option == (
char *) NULL)
2885 scaling_method=Scale2X;
2892 if (LocaleCompare(option,
"eagle2x") == 0)
2894 scaling_method=Eagle2X;
2899 if (LocaleCompare(option,
"eagle3x") == 0)
2901 scaling_method=Eagle3X;
2906 if (LocaleCompare(option,
"eagle3xb") == 0)
2908 scaling_method=Eagle3XB;
2913 if (LocaleCompare(option,
"epbx2x") == 0)
2915 scaling_method=Epbx2X;
2924 if (LocaleCompare(option,
"fish2x") == 0)
2926 scaling_method=Fish2X;
2935 if (LocaleCompare(option,
"hq2x") == 0)
2937 scaling_method=Hq2X;
2946 if (LocaleCompare(option,
"scale2x") == 0)
2948 scaling_method=Scale2X;
2953 if (LocaleCompare(option,
"scale3x") == 0)
2955 scaling_method=Scale3X;
2964 if (LocaleCompare(option,
"xbr2x") == 0)
2966 scaling_method=Xbr2X;
2978 source_image=CloneImage(image,image->columns,image->rows,MagickTrue,
2980 if (source_image == (
Image *) NULL)
2981 return((
Image *) NULL);
2986 rectangle.width=image->columns;
2987 rectangle.height=image->rows;
2988 (void) CopyImagePixels(source_image,image,&rectangle,&offset,exception);
2989 if (IssRGBCompatibleColorspace(source_image->colorspace) == MagickFalse)
2990 (
void) TransformImageColorspace(source_image,sRGBColorspace,exception);
2991 magnify_image=CloneImage(source_image,magnification*source_image->columns,
2992 magnification*source_image->rows,MagickTrue,exception);
2993 if (magnify_image == (
Image *) NULL)
2995 source_image=DestroyImage(source_image);
2996 return((
Image *) NULL);
3003 image_view=AcquireVirtualCacheView(source_image,exception);
3004 magnify_view=AcquireAuthenticCacheView(magnify_image,exception);
3005#if defined(MAGICKCORE_OPENMP_SUPPORT)
3006 #pragma omp parallel for schedule(static) shared(progress,status) \
3007 magick_number_threads(source_image,magnify_image,source_image->rows,1)
3009 for (y=0; y < (ssize_t) source_image->rows; y++)
3020 if (status == MagickFalse)
3022 q=QueueCacheViewAuthenticPixels(magnify_view,0,magnification*y,
3023 magnify_image->columns,magnification,exception);
3024 if (q == (Quantum *) NULL)
3032 for (x=0; x < (ssize_t) source_image->columns; x++)
3044 p=GetCacheViewVirtualPixels(image_view,x-width/2,y-width/2,width,width,
3046 if (p == (Quantum *) NULL)
3051 channels=GetPixelChannels(source_image);
3052 scaling_method(source_image,p,r,channels);
3056 for (j=0; j < (ssize_t) magnification; j++)
3057 for (i=0; i < (ssize_t) (channels*magnification); i++)
3058 q[j*(ssize_t) channels*(ssize_t) magnify_image->columns+i]=
3059 r[j*magnification*(ssize_t) channels+i];
3060 q+=magnification*GetPixelChannels(magnify_image);
3062 if (SyncCacheViewAuthenticPixels(magnify_view,exception) == MagickFalse)
3064 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3069#if defined(MAGICKCORE_OPENMP_SUPPORT)
3073 proceed=SetImageProgress(image,MagnifyImageTag,progress,image->rows);
3074 if (proceed == MagickFalse)
3078 magnify_view=DestroyCacheView(magnify_view);
3079 image_view=DestroyCacheView(image_view);
3080 source_image=DestroyImage(source_image);
3081 if (status == MagickFalse)
3082 magnify_image=DestroyImage(magnify_image);
3083 return(magnify_image);
3116 assert(image != (
Image *) NULL);
3117 assert(image->signature == MagickCoreSignature);
3119 assert(exception->signature == MagickCoreSignature);
3120 if (IsEventLogging() != MagickFalse)
3121 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3122 minify_image=ResizeImage(image,image->columns/2,image->rows/2,SplineFilter,
3124 return(minify_image);
3161MagickExport
Image *ResampleImage(
const Image *image,
const double x_resolution,
3162 const double y_resolution,
const FilterType filter,
ExceptionInfo *exception)
3164#define ResampleImageTag "Resample/Image"
3176 assert(image != (
const Image *) NULL);
3177 assert(image->signature == MagickCoreSignature);
3179 assert(exception->signature == MagickCoreSignature);
3180 if (IsEventLogging() != MagickFalse)
3181 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3182 width=(size_t) (x_resolution*image->columns/(image->resolution.x == 0.0 ?
3183 DefaultResolution : image->resolution.x)+0.5);
3184 height=(size_t) (y_resolution*image->rows/(image->resolution.y == 0.0 ?
3185 DefaultResolution : image->resolution.y)+0.5);
3186 resample_image=ResizeImage(image,width,height,filter,exception);
3187 if (resample_image != (
Image *) NULL)
3189 resample_image->resolution.x=x_resolution;
3190 resample_image->resolution.y=y_resolution;
3192 return(resample_image);
3250 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3255 return(contribution);
3269 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3271 sizeof(*contribution));
3274 (void) memset(contribution,0,number_threads*
sizeof(*contribution));
3275 for (i=0; i < (ssize_t) number_threads; i++)
3278 AcquireAlignedMemory(count,
sizeof(**contribution)));
3280 return(DestroyContributionTLS(contribution));
3282 return(contribution);
3285static MagickBooleanType HorizontalFilter(
3287 const Image *magick_restrict image,
Image *magick_restrict resize_image,
3288 const double x_factor,
const MagickSizeType span,
3289 MagickOffsetType *magick_restrict progress,
ExceptionInfo *exception)
3291#define ResizeImageTag "Resize/Image"
3301 **magick_restrict contributions;
3316 scale=MagickMax(1.0/x_factor+MagickEpsilon,1.0);
3317 support=scale*GetResizeFilterSupport(resize_filter);
3318 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3319 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3320 return(MagickFalse);
3326 support=(double) 0.5;
3329 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3332 (void) ThrowMagickException(exception,GetMagickModule(),
3333 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3334 return(MagickFalse);
3337 scale=PerceptibleReciprocal(scale);
3338 image_view=AcquireVirtualCacheView(image,exception);
3339 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3340#if defined(MAGICKCORE_OPENMP_SUPPORT)
3341 #pragma omp parallel for schedule(static) shared(progress,status) \
3342 magick_number_threads(image,resize_image,resize_image->columns,1)
3344 for (x=0; x < (ssize_t) resize_image->columns; x++)
3347 id = GetOpenMPThreadId();
3353 *magick_restrict contribution;
3368 if (status == MagickFalse)
3370 bisect=(double) (x+0.5)/x_factor+MagickEpsilon;
3371 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3372 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->columns);
3374 contribution=contributions[id];
3375 for (n=0; n < (stop-start); n++)
3377 contribution[n].pixel=start+n;
3378 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3379 ((
double) (start+n)-bisect+0.5));
3380 density+=contribution[n].weight;
3384 if ((density != 0.0) && (density != 1.0))
3392 density=PerceptibleReciprocal(density);
3393 for (i=0; i < n; i++)
3394 contribution[i].weight*=density;
3396 p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,(
size_t)
3397 (contribution[n-1].pixel-contribution[0].pixel+1),image->rows,exception);
3398 q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
3400 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3405 for (y=0; y < (ssize_t) resize_image->rows; y++)
3410 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3428 channel=GetPixelChannelChannel(image,i);
3429 traits=GetPixelChannelTraits(image,channel);
3430 resize_traits=GetPixelChannelTraits(resize_image,channel);
3431 if ((traits == UndefinedPixelTrait) ||
3432 (resize_traits == UndefinedPixelTrait))
3434 if (((resize_traits & CopyPixelTrait) != 0) ||
3435 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3437 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3439 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3440 (contribution[j-start].pixel-contribution[0].pixel);
3441 SetPixelChannel(resize_image,channel,
3442 p[k*(ssize_t) GetPixelChannels(image)+i],q);
3446 if ((resize_traits & BlendPixelTrait) == 0)
3451 for (j=0; j < n; j++)
3453 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3454 (contribution[j].pixel-contribution[0].pixel);
3455 alpha=contribution[j].weight;
3456 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3458 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3465 for (j=0; j < n; j++)
3467 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3468 (contribution[j].pixel-contribution[0].pixel);
3469 alpha=contribution[j].weight*QuantumScale*
3470 (double) GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3471 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3474 gamma=PerceptibleReciprocal(gamma);
3475 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3477 q+=GetPixelChannels(resize_image);
3479 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3481 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3486#if defined(MAGICKCORE_OPENMP_SUPPORT)
3490 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3491 if (proceed == MagickFalse)
3495 resize_view=DestroyCacheView(resize_view);
3496 image_view=DestroyCacheView(image_view);
3497 contributions=DestroyContributionTLS(contributions);
3501static MagickBooleanType VerticalFilter(
3503 const Image *magick_restrict image,
Image *magick_restrict resize_image,
3504 const double y_factor,
const MagickSizeType span,
3505 MagickOffsetType *magick_restrict progress,
ExceptionInfo *exception)
3515 **magick_restrict contributions;
3530 scale=MagickMax(1.0/y_factor+MagickEpsilon,1.0);
3531 support=scale*GetResizeFilterSupport(resize_filter);
3532 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3533 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3534 return(MagickFalse);
3540 support=(double) 0.5;
3543 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3546 (void) ThrowMagickException(exception,GetMagickModule(),
3547 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3548 return(MagickFalse);
3551 scale=PerceptibleReciprocal(scale);
3552 image_view=AcquireVirtualCacheView(image,exception);
3553 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3554#if defined(MAGICKCORE_OPENMP_SUPPORT)
3555 #pragma omp parallel for schedule(static) shared(progress,status) \
3556 magick_number_threads(image,resize_image,resize_image->rows,1)
3558 for (y=0; y < (ssize_t) resize_image->rows; y++)
3561 id = GetOpenMPThreadId();
3567 *magick_restrict contribution;
3582 if (status == MagickFalse)
3584 bisect=(double) (y+0.5)/y_factor+MagickEpsilon;
3585 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3586 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->rows);
3588 contribution=contributions[id];
3589 for (n=0; n < (stop-start); n++)
3591 contribution[n].pixel=start+n;
3592 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3593 ((
double) (start+n)-bisect+0.5));
3594 density+=contribution[n].weight;
3598 if ((density != 0.0) && (density != 1.0))
3606 density=PerceptibleReciprocal(density);
3607 for (i=0; i < n; i++)
3608 contribution[i].weight*=density;
3610 p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
3611 image->columns,(
size_t) (contribution[n-1].pixel-contribution[0].pixel+1),
3613 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
3615 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3620 for (x=0; x < (ssize_t) resize_image->columns; x++)
3625 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3643 channel=GetPixelChannelChannel(image,i);
3644 traits=GetPixelChannelTraits(image,channel);
3645 resize_traits=GetPixelChannelTraits(resize_image,channel);
3646 if ((traits == UndefinedPixelTrait) ||
3647 (resize_traits == UndefinedPixelTrait))
3649 if (((resize_traits & CopyPixelTrait) != 0) ||
3650 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3652 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3654 k=(ssize_t) ((contribution[j-start].pixel-contribution[0].pixel)*
3655 (ssize_t) image->columns+x);
3656 SetPixelChannel(resize_image,channel,p[k*(ssize_t)
3657 GetPixelChannels(image)+i],q);
3661 if ((resize_traits & BlendPixelTrait) == 0)
3666 for (j=0; j < n; j++)
3668 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3669 (ssize_t) image->columns+x);
3670 alpha=contribution[j].weight;
3671 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3673 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3677 for (j=0; j < n; j++)
3679 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3680 (ssize_t) image->columns+x);
3681 alpha=contribution[j].weight*QuantumScale*(double)
3682 GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3683 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3686 gamma=PerceptibleReciprocal(gamma);
3687 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3689 q+=GetPixelChannels(resize_image);
3691 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3693 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3698#if defined(MAGICKCORE_OPENMP_SUPPORT)
3702 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3703 if (proceed == MagickFalse)
3707 resize_view=DestroyCacheView(resize_view);
3708 image_view=DestroyCacheView(image_view);
3709 contributions=DestroyContributionTLS(contributions);
3713MagickExport
Image *ResizeImage(
const Image *image,
const size_t columns,
3714 const size_t rows,
const FilterType filter,
ExceptionInfo *exception)
3742 assert(image != (
Image *) NULL);
3743 assert(image->signature == MagickCoreSignature);
3745 assert(exception->signature == MagickCoreSignature);
3746 if (IsEventLogging() != MagickFalse)
3747 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3748 if ((columns == 0) || (rows == 0))
3749 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3750 if ((columns == image->columns) && (rows == image->rows) &&
3751 (filter == UndefinedFilter))
3752 return(CloneImage(image,0,0,MagickTrue,exception));
3756 x_factor=(double) (columns*PerceptibleReciprocal((
double) image->columns));
3757 y_factor=(double) (rows*PerceptibleReciprocal((
double) image->rows));
3758 filter_type=LanczosFilter;
3759 if (filter != UndefinedFilter)
3762 if ((x_factor == 1.0) && (y_factor == 1.0))
3763 filter_type=PointFilter;
3765 if ((image->storage_class == PseudoClass) ||
3766 (image->alpha_trait != UndefinedPixelTrait) ||
3767 ((x_factor*y_factor) > 1.0))
3768 filter_type=MitchellFilter;
3769 resize_filter=AcquireResizeFilter(image,filter_type,MagickFalse,exception);
3770#if defined(MAGICKCORE_OPENCL_SUPPORT)
3771 resize_image=AccelerateResizeImage(image,columns,rows,resize_filter,
3773 if (resize_image != (
Image *) NULL)
3775 resize_filter=DestroyResizeFilter(resize_filter);
3776 return(resize_image);
3779 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
3780 if (resize_image == (
Image *) NULL)
3782 resize_filter=DestroyResizeFilter(resize_filter);
3783 return(resize_image);
3785 if (x_factor > y_factor)
3786 filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
3788 filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
3789 if (filter_image == (
Image *) NULL)
3791 resize_filter=DestroyResizeFilter(resize_filter);
3792 return(DestroyImage(resize_image));
3798 if (x_factor > y_factor)
3800 span=(MagickSizeType) (filter_image->columns+rows);
3801 status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
3803 status&=(MagickStatusType) VerticalFilter(resize_filter,filter_image,
3804 resize_image,y_factor,span,&offset,exception);
3808 span=(MagickSizeType) (filter_image->rows+columns);
3809 status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
3811 status&=(MagickStatusType) HorizontalFilter(resize_filter,filter_image,
3812 resize_image,x_factor,span,&offset,exception);
3817 filter_image=DestroyImage(filter_image);
3818 resize_filter=DestroyResizeFilter(resize_filter);
3819 if (status == MagickFalse)
3821 resize_image=DestroyImage(resize_image);
3822 return((
Image *) NULL);
3824 resize_image->type=image->type;
3825 return(resize_image);
3859MagickExport
Image *SampleImage(
const Image *image,
const size_t columns,
3862#define SampleImageTag "Sample/Image"
3888 assert(image != (
const Image *) NULL);
3889 assert(image->signature == MagickCoreSignature);
3891 assert(exception->signature == MagickCoreSignature);
3892 if (IsEventLogging() != MagickFalse)
3893 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3894 if ((columns == 0) || (rows == 0))
3895 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3896 if ((columns == image->columns) && (rows == image->rows))
3897 return(CloneImage(image,0,0,MagickTrue,exception));
3898 sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
3899 if (sample_image == (
Image *) NULL)
3900 return((
Image *) NULL);
3904 sample_offset.x=0.5-MagickEpsilon;
3905 sample_offset.y=sample_offset.x;
3910 value=GetImageArtifact(image,
"sample:offset");
3911 if (value != (
char *) NULL)
3919 (void) ParseGeometry(value,&geometry_info);
3920 flags=ParseGeometry(value,&geometry_info);
3921 sample_offset.x=sample_offset.y=geometry_info.rho/100.0-MagickEpsilon;
3922 if ((flags & SigmaValue) != 0)
3923 sample_offset.y=geometry_info.sigma/100.0-MagickEpsilon;
3929 x_offset=(ssize_t *) AcquireQuantumMemory((
size_t) sample_image->columns,
3931 if (x_offset == (ssize_t *) NULL)
3933 sample_image=DestroyImage(sample_image);
3934 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3936 for (j=0; j < (ssize_t) sample_image->columns; j++)
3937 x_offset[j]=(ssize_t) ((((double) j+sample_offset.x)*image->columns)/
3938 sample_image->columns);
3944 image_view=AcquireVirtualCacheView(image,exception);
3945 sample_view=AcquireAuthenticCacheView(sample_image,exception);
3946#if defined(MAGICKCORE_OPENMP_SUPPORT)
3947 #pragma omp parallel for schedule(static) shared(status) \
3948 magick_number_threads(image,sample_image,sample_image->rows,2)
3950 for (y=0; y < (ssize_t) sample_image->rows; y++)
3962 if (status == MagickFalse)
3964 y_offset=(ssize_t) ((((
double) y+sample_offset.y)*image->rows)/
3965 sample_image->rows);
3966 p=GetCacheViewVirtualPixels(image_view,0,y_offset,image->columns,1,
3968 q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
3970 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3978 for (x=0; x < (ssize_t) sample_image->columns; x++)
3983 if (GetPixelWriteMask(sample_image,q) <= (QuantumRange/2))
3985 q+=GetPixelChannels(sample_image);
3988 for (i=0; i < (ssize_t) GetPixelChannels(sample_image); i++)
3997 channel=GetPixelChannelChannel(sample_image,i);
3998 traits=GetPixelChannelTraits(sample_image,channel);
3999 image_traits=GetPixelChannelTraits(image,channel);
4000 if ((traits == UndefinedPixelTrait) ||
4001 (image_traits == UndefinedPixelTrait))
4003 SetPixelChannel(sample_image,channel,p[x_offset[x]*(ssize_t)
4004 GetPixelChannels(image)+i],q);
4006 q+=GetPixelChannels(sample_image);
4008 if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
4010 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4015 proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
4016 if (proceed == MagickFalse)
4020 image_view=DestroyCacheView(image_view);
4021 sample_view=DestroyCacheView(sample_view);
4022 x_offset=(ssize_t *) RelinquishMagickMemory(x_offset);
4023 sample_image->type=image->type;
4024 if (status == MagickFalse)
4025 sample_image=DestroyImage(sample_image);
4026 return(sample_image);
4058MagickExport
Image *ScaleImage(
const Image *image,
const size_t columns,
4061#define ScaleImageTag "Scale/Image"
4069 pixel[CompositePixelChannel],
4100 assert(image != (
const Image *) NULL);
4101 assert(image->signature == MagickCoreSignature);
4103 assert(exception->signature == MagickCoreSignature);
4104 if (IsEventLogging() != MagickFalse)
4105 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4106 if ((columns == 0) || (rows == 0))
4107 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
4108 if ((columns == image->columns) && (rows == image->rows))
4109 return(CloneImage(image,0,0,MagickTrue,exception));
4110 scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
4111 if (scale_image == (
Image *) NULL)
4112 return((
Image *) NULL);
4113 if (SetImageStorageClass(scale_image,DirectClass,exception) == MagickFalse)
4115 scale_image=DestroyImage(scale_image);
4116 return((
Image *) NULL);
4121 x_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4122 MaxPixelChannels*
sizeof(*x_vector));
4124 if (image->rows != scale_image->rows)
4125 scanline=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4126 MaxPixelChannels*
sizeof(*scanline));
4127 scale_scanline=(
double *) AcquireQuantumMemory((
size_t) scale_image->columns,
4128 MaxPixelChannels*
sizeof(*scale_scanline));
4129 y_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4130 MaxPixelChannels*
sizeof(*y_vector));
4131 if ((scanline == (
double *) NULL) || (scale_scanline == (
double *) NULL) ||
4132 (x_vector == (
double *) NULL) || (y_vector == (
double *) NULL))
4134 if ((image->rows != scale_image->rows) && (scanline != (
double *) NULL))
4135 scanline=(
double *) RelinquishMagickMemory(scanline);
4136 if (scale_scanline != (
double *) NULL)
4137 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4138 if (x_vector != (
double *) NULL)
4139 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4140 if (y_vector != (
double *) NULL)
4141 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4142 scale_image=DestroyImage(scale_image);
4143 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4149 next_row=MagickTrue;
4151 scale.y=(double) scale_image->rows/(
double) image->rows;
4152 (void) memset(y_vector,0,(
size_t) MaxPixelChannels*image->columns*
4156 image_view=AcquireVirtualCacheView(image,exception);
4157 scale_view=AcquireAuthenticCacheView(scale_image,exception);
4158 for (y=0; y < (ssize_t) scale_image->rows; y++)
4169 if (status == MagickFalse)
4171 q=QueueCacheViewAuthenticPixels(scale_view,0,y,scale_image->columns,1,
4173 if (q == (Quantum *) NULL)
4179 if (scale_image->rows == image->rows)
4184 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4186 if (p == (
const Quantum *) NULL)
4191 for (x=0; x < (ssize_t) image->columns; x++)
4193 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4195 p+=GetPixelChannels(image);
4198 if (image->alpha_trait != UndefinedPixelTrait)
4199 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4200 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4202 PixelChannel channel = GetPixelChannelChannel(image,i);
4203 PixelTrait traits = GetPixelChannelTraits(image,channel);
4204 if ((traits & BlendPixelTrait) == 0)
4206 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=(double) p[i];
4209 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*(double) p[i];
4211 p+=GetPixelChannels(image);
4219 while (scale.y < span.y)
4221 if ((next_row != MagickFalse) &&
4222 (number_rows < (ssize_t) image->rows))
4227 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4229 if (p == (
const Quantum *) NULL)
4234 for (x=0; x < (ssize_t) image->columns; x++)
4236 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4238 p+=GetPixelChannels(image);
4241 if (image->alpha_trait != UndefinedPixelTrait)
4242 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4243 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4245 PixelChannel channel = GetPixelChannelChannel(image,i);
4246 PixelTrait traits = GetPixelChannelTraits(image,channel);
4247 if ((traits & BlendPixelTrait) == 0)
4249 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4253 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4256 p+=GetPixelChannels(image);
4260 for (x=0; x < (ssize_t) image->columns; x++)
4261 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4262 y_vector[x*(ssize_t) GetPixelChannels(image)+i]+=scale.y*
4263 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4265 scale.y=(double) scale_image->rows/(
double) image->rows;
4266 next_row=MagickTrue;
4268 if ((next_row != MagickFalse) && (number_rows < (ssize_t) image->rows))
4273 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4275 if (p == (
const Quantum *) NULL)
4280 for (x=0; x < (ssize_t) image->columns; x++)
4282 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4284 p+=GetPixelChannels(image);
4287 if (image->alpha_trait != UndefinedPixelTrait)
4288 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4289 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4291 PixelChannel channel = GetPixelChannelChannel(image,i);
4292 PixelTrait traits = GetPixelChannelTraits(image,channel);
4293 if ((traits & BlendPixelTrait) == 0)
4295 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4299 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4302 p+=GetPixelChannels(image);
4305 next_row=MagickFalse;
4307 for (x=0; x < (ssize_t) image->columns; x++)
4309 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4311 pixel[i]=y_vector[x*(ssize_t) GetPixelChannels(image)+i]+span.y*
4312 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4313 scanline[x*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4314 y_vector[x*(ssize_t) GetPixelChannels(image)+i]=0.0;
4320 scale.y=(double) scale_image->rows/(
double) image->rows;
4321 next_row=MagickTrue;
4325 if (scale_image->columns == image->columns)
4330 for (x=0; x < (ssize_t) scale_image->columns; x++)
4332 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4334 q+=GetPixelChannels(scale_image);
4337 if (image->alpha_trait != UndefinedPixelTrait)
4339 alpha=QuantumScale*scanline[x*(ssize_t) GetPixelChannels(image)+
4340 GetPixelChannelOffset(image,AlphaPixelChannel)];
4341 alpha=PerceptibleReciprocal(alpha);
4343 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4345 PixelChannel channel = GetPixelChannelChannel(image,i);
4346 PixelTrait traits = GetPixelChannelTraits(image,channel);
4347 scale_traits=GetPixelChannelTraits(scale_image,channel);
4348 if ((traits == UndefinedPixelTrait) ||
4349 (scale_traits == UndefinedPixelTrait))
4351 if ((traits & BlendPixelTrait) == 0)
4353 SetPixelChannel(scale_image,channel,ClampToQuantum(
4354 scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4357 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*scanline[
4358 x*(ssize_t) GetPixelChannels(image)+i]),q);
4360 q+=GetPixelChannels(scale_image);
4371 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4373 next_column=MagickFalse;
4376 for (x=0; x < (ssize_t) image->columns; x++)
4378 scale.x=(double) scale_image->columns/(
double) image->columns;
4379 while (scale.x >= span.x)
4381 if (next_column != MagickFalse)
4383 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4387 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4389 PixelChannel channel = GetPixelChannelChannel(image,i);
4390 PixelTrait traits = GetPixelChannelTraits(image,channel);
4391 if (traits == UndefinedPixelTrait)
4393 pixel[i]+=span.x*scanline[x*(ssize_t) GetPixelChannels(image)+i];
4394 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4398 next_column=MagickTrue;
4402 if (next_column != MagickFalse)
4404 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4406 next_column=MagickFalse;
4409 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4410 pixel[i]+=scale.x*scanline[x*(ssize_t)
4411 GetPixelChannels(image)+i];
4417 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4419 scanline[(x-1)*(ssize_t) GetPixelChannels(image)+i];
4421 if ((next_column == MagickFalse) && (t < (ssize_t) scale_image->columns))
4422 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4423 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4427 for (x=0; x < (ssize_t) scale_image->columns; x++)
4429 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4431 q+=GetPixelChannels(scale_image);
4434 if (image->alpha_trait != UndefinedPixelTrait)
4436 alpha=QuantumScale*scale_scanline[x*(ssize_t)
4437 GetPixelChannels(image)+
4438 GetPixelChannelOffset(image,AlphaPixelChannel)];
4439 alpha=PerceptibleReciprocal(alpha);
4441 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4443 PixelChannel channel = GetPixelChannelChannel(image,i);
4444 PixelTrait traits = GetPixelChannelTraits(image,channel);
4445 scale_traits=GetPixelChannelTraits(scale_image,channel);
4446 if ((traits == UndefinedPixelTrait) ||
4447 (scale_traits == UndefinedPixelTrait))
4449 if ((traits & BlendPixelTrait) == 0)
4451 SetPixelChannel(scale_image,channel,ClampToQuantum(
4452 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4455 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*
4456 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4458 q+=GetPixelChannels(scale_image);
4461 if (SyncCacheViewAuthenticPixels(scale_view,exception) == MagickFalse)
4466 proceed=SetImageProgress(image,ScaleImageTag,(MagickOffsetType) y,
4468 if (proceed == MagickFalse)
4474 scale_view=DestroyCacheView(scale_view);
4475 image_view=DestroyCacheView(image_view);
4479 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4480 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4481 if (scale_image->rows != image->rows)
4482 scanline=(
double *) RelinquishMagickMemory(scanline);
4483 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4484 scale_image->type=image->type;
4485 if (status == MagickFalse)
4486 scale_image=DestroyImage(scale_image);
4487 return(scale_image);
4521MagickExport
Image *ThumbnailImage(
const Image *image,
const size_t columns,
4524#define SampleFactor 5
4527 filename[MagickPathExtent],
4528 value[MagickPathExtent];
4539 assert(image != (
Image *) NULL);
4540 assert(image->signature == MagickCoreSignature);
4542 assert(exception->signature == MagickCoreSignature);
4543 if (IsEventLogging() != MagickFalse)
4544 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4545 thumbnail_image=CloneImage(image,0,0,MagickTrue,exception);
4546 if (thumbnail_image == (
Image *) NULL)
4547 return(thumbnail_image);
4548 if ((columns != image->columns) || (rows != image->rows))
4551 *clone_image = thumbnail_image;
4557 x_factor=(ssize_t) image->columns/(ssize_t) columns;
4558 y_factor=(ssize_t) image->rows/(ssize_t) rows;
4559 if ((x_factor > 4) && (y_factor > 4))
4561 thumbnail_image=SampleImage(clone_image,4*columns,4*rows,exception);
4562 if (thumbnail_image != (
Image *) NULL)
4564 clone_image=DestroyImage(clone_image);
4565 clone_image=thumbnail_image;
4568 if ((x_factor > 2) && (y_factor > 2))
4570 thumbnail_image=ResizeImage(clone_image,2*columns,2*rows,BoxFilter,
4572 if (thumbnail_image != (
Image *) NULL)
4574 clone_image=DestroyImage(clone_image);
4575 clone_image=thumbnail_image;
4578 thumbnail_image=ResizeImage(clone_image,columns,rows,image->filter ==
4579 UndefinedFilter ? LanczosSharpFilter : image->filter,exception);
4580 clone_image=DestroyImage(clone_image);
4581 if (thumbnail_image == (
Image *) NULL)
4582 return(thumbnail_image);
4584 (void) ParseAbsoluteGeometry(
"0x0+0+0",&thumbnail_image->page);
4585 thumbnail_image->depth=8;
4586 thumbnail_image->interlace=NoInterlace;
4590 ResetImageProfileIterator(thumbnail_image);
4591 for (name=GetNextImageProfile(thumbnail_image); name != (
const char *) NULL; )
4593 if ((LocaleCompare(name,
"icc") != 0) && (LocaleCompare(name,
"icm") != 0))
4595 (void) DeleteImageProfile(thumbnail_image,name);
4596 ResetImageProfileIterator(thumbnail_image);
4598 name=GetNextImageProfile(thumbnail_image);
4600 (void) DeleteImageProperty(thumbnail_image,
"comment");
4601 (void) CopyMagickString(value,image->magick_filename,MagickPathExtent);
4602 if (strstr(image->magick_filename,
"//") == (
char *) NULL)
4603 (void) FormatLocaleString(value,MagickPathExtent,
"file://%s",
4604 image->magick_filename);
4605 (void) SetImageProperty(thumbnail_image,
"Thumb::URI",value,exception);
4606 GetPathComponent(image->magick_filename,TailPath,filename);
4607 (void) CopyMagickString(value,filename,MagickPathExtent);
4608 if ( GetPathAttributes(image->filename,&attributes) != MagickFalse )
4609 (
void) FormatImageProperty(thumbnail_image,
"Thumb::MTime",
"%.20g",(
double)
4610 attributes.st_mtime);
4611 (void) FormatLocaleString(value,MagickPathExtent,
"%.20g",(
double)
4612 attributes.st_mtime);
4613 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,
"B",MagickPathExtent,
4615 (void) SetImageProperty(thumbnail_image,
"Thumb::Size",value,exception);
4616 (void) FormatLocaleString(value,MagickPathExtent,
"image/%s",image->magick);
4618 (void) SetImageProperty(thumbnail_image,
"Thumb::Mimetype",value,exception);
4619 (void) SetImageProperty(thumbnail_image,
"software",MagickAuthoritativeURL,
4621 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Width",
"%.20g",
4622 (
double) image->magick_columns);
4623 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Height",
"%.20g",
4624 (
double) image->magick_rows);
4625 (void) FormatImageProperty(thumbnail_image,
"Thumb::Document::Pages",
"%.20g",
4626 (
double) GetImageListLength(image));
4627 return(thumbnail_image);