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 if (IsEventLogging() != MagickFalse)
2026 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2027 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
2028 "DelegateLibrarySupportNotBuiltIn",
"'%s' (LQR)",image->filename);
2029 return((
Image *) NULL);
2059static inline void CopyPixels(
const Quantum *source,
const ssize_t source_offset,
2060 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2065 for (i=0; i < (ssize_t) channels; i++)
2066 destination[(ssize_t) channels*destination_offset+i]=
2067 source[source_offset*(ssize_t) channels+i];
2070static inline void MixPixels(
const Quantum *source,
const ssize_t *source_offset,
2071 const size_t source_size,Quantum *destination,
2072 const ssize_t destination_offset,
const size_t channels)
2077 for (i=0; i < (ssize_t) channels; i++)
2083 for (j=0; j < (ssize_t) source_size; j++)
2084 sum+=source[source_offset[j]*(ssize_t) channels+i];
2085 destination[(ssize_t) channels*destination_offset+i]=(Quantum) (sum/
2086 (ssize_t) source_size);
2090static inline void Mix2Pixels(
const Quantum *source,
2091 const ssize_t source_offset1,
const ssize_t source_offset2,
2092 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2095 offsets[2] = { source_offset1, source_offset2 };
2097 MixPixels(source,offsets,2,destination,destination_offset,channels);
2100static inline int PixelsEqual(
const Quantum *source1,ssize_t offset1,
2101 const Quantum *source2,ssize_t offset2,
const size_t channels)
2106 offset1*=(ssize_t) channels;
2107 offset2*=(ssize_t) channels;
2108 for (i=0; i < (ssize_t) channels; i++)
2109 if (source1[offset1+i] != source2[offset2+i])
2114static inline void Eagle2X(
const Image *source,
const Quantum *pixels,
2115 Quantum *result,
const size_t channels)
2121 for (i=0; i < 4; i++)
2122 CopyPixels(pixels,4,result,i,channels);
2123 if (PixelsEqual(pixels,0,pixels,1,channels) &&
2124 PixelsEqual(pixels,1,pixels,3,channels))
2125 CopyPixels(pixels,0,result,0,channels);
2126 if (PixelsEqual(pixels,1,pixels,2,channels) &&
2127 PixelsEqual(pixels,2,pixels,5,channels))
2128 CopyPixels(pixels,2,result,1,channels);
2129 if (PixelsEqual(pixels,3,pixels,6,channels) &&
2130 PixelsEqual(pixels,6,pixels,7,channels))
2131 CopyPixels(pixels,6,result,2,channels);
2132 if (PixelsEqual(pixels,5,pixels,8,channels) &&
2133 PixelsEqual(pixels,8,pixels,7,channels))
2134 CopyPixels(pixels,8,result,3,channels);
2137static void Hq2XHelper(
const unsigned int rule,
const Quantum *source,
2138 Quantum *destination,
const ssize_t destination_offset,
const size_t channels,
2139 const ssize_t e,
const ssize_t a,
const ssize_t b,
const ssize_t d,
2140 const ssize_t f,
const ssize_t h)
2142#define caseA(N,A,B,C,D) \
2146 offsets[4] = { A, B, C, D }; \
2148 MixPixels(source,offsets,4,destination,destination_offset,channels);\
2151#define caseB(N,A,B,C,D,E,F,G,H) \
2155 offsets[8] = { A, B, C, D, E, F, G, H }; \
2157 MixPixels(source,offsets,8,destination,destination_offset,channels);\
2165 CopyPixels(source,e,destination,destination_offset,channels);
2174 caseB(7,e,e,e,e,e,b,b,d)
2175 caseB(8,e,e,e,e,e,d,d,b)
2176 caseB(9,e,e,e,e,e,e,d,b)
2177 caseB(10,e,e,d,d,d,b,b,b)
2181 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2183 MixPixels(source,offsets,16,destination,destination_offset,channels);
2188 if (PixelsEqual(source,b,source,d,channels))
2191 offsets[4] = { e, e, d, b };
2193 MixPixels(source,offsets,4,destination,destination_offset,channels);
2196 CopyPixels(source,e,destination,destination_offset,channels);
2201 if (PixelsEqual(source,b,source,d,channels))
2204 offsets[8] = { e, e, d, d, d, b, b, b };
2206 MixPixels(source,offsets,8,destination,destination_offset,channels);
2209 CopyPixels(source,e,destination,destination_offset,channels);
2214 if (PixelsEqual(source,b,source,d,channels))
2217 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2219 MixPixels(source,offsets,16,destination,destination_offset,channels);
2222 CopyPixels(source,e,destination,destination_offset,channels);
2227 if (PixelsEqual(source,b,source,d,channels))
2230 offsets[4] = { e, e, d, b };
2232 MixPixels(source,offsets,4,destination,destination_offset,channels);
2237 offsets[4] = { e, e, e, a };
2239 MixPixels(source,offsets,4,destination,destination_offset,channels);
2245 if (PixelsEqual(source,b,source,d,channels))
2248 offsets[8] = { e, e, e, e, e, e, d, b };
2250 MixPixels(source,offsets,8,destination,destination_offset,channels);
2255 offsets[4] = { e, e, e, a };
2257 MixPixels(source,offsets,4,destination,destination_offset,channels);
2263 if (PixelsEqual(source,b,source,d,channels))
2266 offsets[8] = { e, e, d, d, d, b, b, b };
2268 MixPixels(source,offsets,8,destination,destination_offset,channels);
2273 offsets[4] = { e, e, e, a };
2275 MixPixels(source,offsets,4,destination,destination_offset,channels);
2281 if (PixelsEqual(source,b,source,f,channels))
2284 offsets[8] = { e, e, e, e, e, b, b, d };
2286 MixPixels(source,offsets,8,destination,destination_offset,channels);
2291 offsets[4] = { e, e, e, d };
2293 MixPixels(source,offsets,4,destination,destination_offset,channels);
2299 if (PixelsEqual(source,d,source,h,channels))
2302 offsets[8] = { e, e, e, e, e, d, d, b };
2304 MixPixels(source,offsets,8,destination,destination_offset,channels);
2309 offsets[4] = { e, e, e, b };
2311 MixPixels(source,offsets,4,destination,destination_offset,channels);
2320static inline unsigned int Hq2XPatternToNumber(
const int *pattern)
2331 for (i=7; i >= 0; i--)
2333 result+=order*(
unsigned int) pattern[i];
2339static inline void Hq2X(
const Image *source,
const Quantum *pixels,
2340 Quantum *result,
const size_t channels)
2342 static const unsigned int
2345 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2346 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
2347 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2348 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
2349 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
2350 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2351 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
2352 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
2353 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
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, 3, 17, 13, 5, 3, 16, 14,
2356 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
2357 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
2358 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
2359 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
2360 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14
2366 !PixelsEqual(pixels,4,pixels,8,channels),
2367 !PixelsEqual(pixels,4,pixels,7,channels),
2368 !PixelsEqual(pixels,4,pixels,6,channels),
2369 !PixelsEqual(pixels,4,pixels,5,channels),
2370 !PixelsEqual(pixels,4,pixels,3,channels),
2371 !PixelsEqual(pixels,4,pixels,2,channels),
2372 !PixelsEqual(pixels,4,pixels,1,channels),
2373 !PixelsEqual(pixels,4,pixels,0,channels)
2376#define Rotated(p) p[2], p[4], p[7], p[1], p[6], p[0], p[3], p[5]
2377 const int pattern2[] = { Rotated(pattern1) };
2378 const int pattern3[] = { Rotated(pattern2) };
2379 const int pattern4[] = { Rotated(pattern3) };
2382 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern1)],pixels,result,0,
2383 channels,4,0,1,3,5,7);
2384 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern2)],pixels,result,1,
2385 channels,4,2,5,1,7,3);
2386 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern3)],pixels,result,3,
2387 channels,4,8,7,5,3,1);
2388 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern4)],pixels,result,2,
2389 channels,4,6,3,7,1,5);
2392static void Fish2X(
const Image *source,
const Quantum *pixels,Quantum *result,
2393 const size_t channels)
2395#define Corner(A,B,C,D) \
2397 if (intensities[B] > intensities[A]) \
2400 offsets[3] = { B, C, D }; \
2402 MixPixels(pixels,offsets,3,result,3,channels); \
2407 offsets[3] = { A, B, C }; \
2409 MixPixels(pixels,offsets,3,result,3,channels); \
2413#define Line(A,B,C,D) \
2415 if (intensities[C] > intensities[A]) \
2416 Mix2Pixels(pixels,C,D,result,3,channels); \
2418 Mix2Pixels(pixels,A,B,result,3,channels); \
2422 pixels_offsets[4] = { 0, 1, 3, 4 };
2438 for (i=0; i < 9; i++)
2439 intensities[i]=GetPixelIntensity(source,pixels+i*(ssize_t) channels);
2440 CopyPixels(pixels,0,result,0,channels);
2441 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[1] ? 0 : 1),result,
2443 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[3] ? 0 : 3),result,
2445 ae=PixelsEqual(pixels,0,pixels,4,channels);
2446 bd=PixelsEqual(pixels,1,pixels,3,channels);
2447 ab=PixelsEqual(pixels,0,pixels,1,channels);
2448 de=PixelsEqual(pixels,3,pixels,4,channels);
2449 ad=PixelsEqual(pixels,0,pixels,3,channels);
2450 be=PixelsEqual(pixels,1,pixels,4,channels);
2453 CopyPixels(pixels,0,result,3,channels);
2456 if (ad && de && !ab)
2461 if (be && de && !ab)
2466 if (ad && ab && !be)
2471 if (ab && be && !ad)
2476 if (ae && (!bd || intensities[1] > intensities[0]))
2478 Mix2Pixels(pixels,0,4,result,3,channels);
2481 if (bd && (!ae || intensities[0] > intensities[1]))
2483 Mix2Pixels(pixels,1,3,result,3,channels);
2506 MixPixels(pixels,pixels_offsets,4,result,3,channels);
2511static void Xbr2X(
const Image *magick_unused(source),
const Quantum *pixels,
2512 Quantum *result,
const size_t channels)
2514#define WeightVar(M,N) const int w_##M##_##N = \
2515 PixelsEqual(pixels,M,pixels,N,channels) ? 0 : 1;
2547 magick_unreferenced(source);
2550 w_12_16 + w_12_8 + w_6_10 + w_6_2 + (4 * w_11_7) <
2551 w_11_17 + w_11_5 + w_7_13 + w_7_1 + (4 * w_12_6)
2553 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_7 ? 11 : 7),12,result,0,
2556 CopyPixels(pixels,12,result,0,channels);
2558 w_12_18 + w_12_6 + w_8_14 + w_8_2 + (4 * w_7_13) <
2559 w_13_17 + w_13_9 + w_11_7 + w_7_3 + (4 * w_12_8)
2561 Mix2Pixels(pixels,(ssize_t) (w_12_7 <= w_12_13 ? 7 : 13),12,result,1,
2564 CopyPixels(pixels,12,result,1,channels);
2566 w_12_6 + w_12_18 + w_16_10 + w_16_22 + (4 * w_11_17) <
2567 w_11_7 + w_11_15 + w_13_17 + w_17_21 + (4 * w_12_16)
2569 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_17 ? 11 : 17),12,result,2,
2572 CopyPixels(pixels,12,result,2,channels);
2574 w_12_8 + w_12_16 + w_18_14 + w_18_22 + (4 * w_13_17) <
2575 w_11_17 + w_17_23 + w_17_19 + w_7_13 + (4 * w_12_18)
2577 Mix2Pixels(pixels,(ssize_t) (w_12_13 <= w_12_17 ? 13 : 17),12,result,3,
2580 CopyPixels(pixels,12,result,3,channels);
2583static void Scale2X(
const Image *magick_unused(source),
const Quantum *pixels,
2584 Quantum *result,
const size_t channels)
2586 magick_unreferenced(source);
2588 if (PixelsEqual(pixels,1,pixels,7,channels) ||
2589 PixelsEqual(pixels,3,pixels,5,channels))
2594 for (i=0; i < 4; i++)
2595 CopyPixels(pixels,4,result,i,channels);
2598 if (PixelsEqual(pixels,1,pixels,3,channels))
2599 CopyPixels(pixels,3,result,0,channels);
2601 CopyPixels(pixels,4,result,0,channels);
2602 if (PixelsEqual(pixels,1,pixels,5,channels))
2603 CopyPixels(pixels,5,result,1,channels);
2605 CopyPixels(pixels,4,result,1,channels);
2606 if (PixelsEqual(pixels,3,pixels,7,channels))
2607 CopyPixels(pixels,3,result,2,channels);
2609 CopyPixels(pixels,4,result,2,channels);
2610 if (PixelsEqual(pixels,5,pixels,7,channels))
2611 CopyPixels(pixels,5,result,3,channels);
2613 CopyPixels(pixels,4,result,3,channels);
2616static void Epbx2X(
const Image *magick_unused(source),
const Quantum *pixels,
2617 Quantum *result,
const size_t channels)
2619#define HelperCond(a,b,c,d,e,f,g) ( \
2620 PixelsEqual(pixels,a,pixels,b,channels) && ( \
2621 PixelsEqual(pixels,c,pixels,d,channels) || \
2622 PixelsEqual(pixels,c,pixels,e,channels) || \
2623 PixelsEqual(pixels,a,pixels,f,channels) || \
2624 PixelsEqual(pixels,b,pixels,g,channels) \
2631 magick_unreferenced(source);
2633 for (i=0; i < 4; i++)
2634 CopyPixels(pixels,4,result,i,channels);
2636 !PixelsEqual(pixels,3,pixels,5,channels) &&
2637 !PixelsEqual(pixels,1,pixels,7,channels) &&
2639 PixelsEqual(pixels,4,pixels,3,channels) ||
2640 PixelsEqual(pixels,4,pixels,7,channels) ||
2641 PixelsEqual(pixels,4,pixels,5,channels) ||
2642 PixelsEqual(pixels,4,pixels,1,channels) ||
2645 !PixelsEqual(pixels,0,pixels,8,channels) ||
2646 PixelsEqual(pixels,4,pixels,6,channels) ||
2647 PixelsEqual(pixels,3,pixels,2,channels)
2650 !PixelsEqual(pixels,6,pixels,2,channels) ||
2651 PixelsEqual(pixels,4,pixels,0,channels) ||
2652 PixelsEqual(pixels,4,pixels,8,channels)
2658 if (HelperCond(1,3,4,0,8,2,6))
2659 Mix2Pixels(pixels,1,3,result,0,channels);
2660 if (HelperCond(5,1,4,2,6,8,0))
2661 Mix2Pixels(pixels,5,1,result,1,channels);
2662 if (HelperCond(3,7,4,6,2,0,8))
2663 Mix2Pixels(pixels,3,7,result,2,channels);
2664 if (HelperCond(7,5,4,8,0,6,2))
2665 Mix2Pixels(pixels,7,5,result,3,channels);
2671static inline void Eagle3X(
const Image *magick_unused(source),
2672 const Quantum *pixels,Quantum *result,
const size_t channels)
2680 magick_unreferenced(source);
2682 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2683 PixelsEqual(pixels,0,pixels,3,channels);
2684 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2685 PixelsEqual(pixels,2,pixels,5,channels);
2686 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2687 PixelsEqual(pixels,6,pixels,7,channels);
2688 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2689 PixelsEqual(pixels,7,pixels,8,channels);
2690 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2691 if (corner_tl && corner_tr)
2692 Mix2Pixels(pixels,0,2,result,1,channels);
2694 CopyPixels(pixels,4,result,1,channels);
2695 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2696 if (corner_tl && corner_bl)
2697 Mix2Pixels(pixels,0,6,result,3,channels);
2699 CopyPixels(pixels,4,result,3,channels);
2700 CopyPixels(pixels,4,result,4,channels);
2701 if (corner_tr && corner_br)
2702 Mix2Pixels(pixels,2,8,result,5,channels);
2704 CopyPixels(pixels,4,result,5,channels);
2705 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2706 if (corner_bl && corner_br)
2707 Mix2Pixels(pixels,6,8,result,7,channels);
2709 CopyPixels(pixels,4,result,7,channels);
2710 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2713static inline void Eagle3XB(
const Image *magick_unused(source),
2714 const Quantum *pixels,Quantum *result,
const size_t channels)
2722 magick_unreferenced(source);
2724 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2725 PixelsEqual(pixels,0,pixels,3,channels);
2726 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2727 PixelsEqual(pixels,2,pixels,5,channels);
2728 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2729 PixelsEqual(pixels,6,pixels,7,channels);
2730 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2731 PixelsEqual(pixels,7,pixels,8,channels);
2732 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2733 CopyPixels(pixels,4,result,1,channels);
2734 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2735 CopyPixels(pixels,4,result,3,channels);
2736 CopyPixels(pixels,4,result,4,channels);
2737 CopyPixels(pixels,4,result,5,channels);
2738 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2739 CopyPixels(pixels,4,result,7,channels);
2740 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2743static inline void Scale3X(
const Image *magick_unused(source),
2744 const Quantum *pixels,Quantum *result,
const size_t channels)
2746 magick_unreferenced(source);
2748 if (!PixelsEqual(pixels,1,pixels,7,channels) &&
2749 !PixelsEqual(pixels,3,pixels,5,channels))
2751 if (PixelsEqual(pixels,3,pixels,1,channels))
2752 CopyPixels(pixels,3,result,0,channels);
2754 CopyPixels(pixels,4,result,0,channels);
2758 PixelsEqual(pixels,3,pixels,1,channels) &&
2759 !PixelsEqual(pixels,4,pixels,2,channels)
2762 PixelsEqual(pixels,5,pixels,1,channels) &&
2763 !PixelsEqual(pixels,4,pixels,0,channels)
2766 CopyPixels(pixels,1,result,1,channels);
2768 CopyPixels(pixels,4,result,1,channels);
2769 if (PixelsEqual(pixels,5,pixels,1,channels))
2770 CopyPixels(pixels,5,result,2,channels);
2772 CopyPixels(pixels,4,result,2,channels);
2775 PixelsEqual(pixels,3,pixels,1,channels) &&
2776 !PixelsEqual(pixels,4,pixels,6,channels)
2779 PixelsEqual(pixels,3,pixels,7,channels) &&
2780 !PixelsEqual(pixels,4,pixels,0,channels)
2783 CopyPixels(pixels,3,result,3,channels);
2785 CopyPixels(pixels,4,result,3,channels);
2786 CopyPixels(pixels,4,result,4,channels);
2789 PixelsEqual(pixels,5,pixels,1,channels) &&
2790 !PixelsEqual(pixels,4,pixels,8,channels)
2793 PixelsEqual(pixels,5,pixels,7,channels) &&
2794 !PixelsEqual(pixels,4,pixels,2,channels)
2797 CopyPixels(pixels,5,result,5,channels);
2799 CopyPixels(pixels,4,result,5,channels);
2800 if (PixelsEqual(pixels,3,pixels,7,channels))
2801 CopyPixels(pixels,3,result,6,channels);
2803 CopyPixels(pixels,4,result,6,channels);
2806 PixelsEqual(pixels,3,pixels,7,channels) &&
2807 !PixelsEqual(pixels,4,pixels,8,channels)
2810 PixelsEqual(pixels,5,pixels,7,channels) &&
2811 !PixelsEqual(pixels,4,pixels,6,channels)
2814 CopyPixels(pixels,7,result,7,channels);
2816 CopyPixels(pixels,4,result,7,channels);
2817 if (PixelsEqual(pixels,5,pixels,7,channels))
2818 CopyPixels(pixels,5,result,8,channels);
2820 CopyPixels(pixels,4,result,8,channels);
2827 for (i=0; i < 9; i++)
2828 CopyPixels(pixels,4,result,i,channels);
2834#define MagnifyImageTag "Magnify/Image"
2867 (*scaling_method)(
const Image *,
const Quantum *,Quantum *,size_t);
2872 assert(image != (
const Image *) NULL);
2873 assert(image->signature == MagickCoreSignature);
2875 assert(exception->signature == MagickCoreSignature);
2876 if (IsEventLogging() != MagickFalse)
2877 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2878 option=GetImageOption(image->image_info,
"magnify:method");
2879 if (option == (
char *) NULL)
2881 scaling_method=Scale2X;
2888 if (LocaleCompare(option,
"eagle2x") == 0)
2890 scaling_method=Eagle2X;
2895 if (LocaleCompare(option,
"eagle3x") == 0)
2897 scaling_method=Eagle3X;
2902 if (LocaleCompare(option,
"eagle3xb") == 0)
2904 scaling_method=Eagle3XB;
2909 if (LocaleCompare(option,
"epbx2x") == 0)
2911 scaling_method=Epbx2X;
2920 if (LocaleCompare(option,
"fish2x") == 0)
2922 scaling_method=Fish2X;
2931 if (LocaleCompare(option,
"hq2x") == 0)
2933 scaling_method=Hq2X;
2942 if (LocaleCompare(option,
"scale2x") == 0)
2944 scaling_method=Scale2X;
2949 if (LocaleCompare(option,
"scale3x") == 0)
2951 scaling_method=Scale3X;
2960 if (LocaleCompare(option,
"xbr2x") == 0)
2962 scaling_method=Xbr2X;
2974 source_image=CloneImage(image,image->columns,image->rows,MagickTrue,
2976 if (source_image == (
Image *) NULL)
2977 return((
Image *) NULL);
2982 rectangle.width=image->columns;
2983 rectangle.height=image->rows;
2984 (void) CopyImagePixels(source_image,image,&rectangle,&offset,exception);
2985 if (IssRGBCompatibleColorspace(source_image->colorspace) == MagickFalse)
2986 (
void) TransformImageColorspace(source_image,sRGBColorspace,exception);
2987 magnify_image=CloneImage(source_image,magnification*source_image->columns,
2988 magnification*source_image->rows,MagickTrue,exception);
2989 if (magnify_image == (
Image *) NULL)
2991 source_image=DestroyImage(source_image);
2992 return((
Image *) NULL);
2999 image_view=AcquireVirtualCacheView(source_image,exception);
3000 magnify_view=AcquireAuthenticCacheView(magnify_image,exception);
3001#if defined(MAGICKCORE_OPENMP_SUPPORT)
3002 #pragma omp parallel for schedule(static) shared(progress,status) \
3003 magick_number_threads(source_image,magnify_image,source_image->rows,1)
3005 for (y=0; y < (ssize_t) source_image->rows; y++)
3016 if (status == MagickFalse)
3018 q=QueueCacheViewAuthenticPixels(magnify_view,0,magnification*y,
3019 magnify_image->columns,magnification,exception);
3020 if (q == (Quantum *) NULL)
3028 for (x=0; x < (ssize_t) source_image->columns; x++)
3040 p=GetCacheViewVirtualPixels(image_view,x-width/2,y-width/2,width,width,
3042 if (p == (Quantum *) NULL)
3047 channels=GetPixelChannels(source_image);
3048 scaling_method(source_image,p,r,channels);
3052 for (j=0; j < (ssize_t) magnification; j++)
3053 for (i=0; i < (ssize_t) (channels*magnification); i++)
3054 q[j*(ssize_t) channels*(ssize_t) magnify_image->columns+i]=
3055 r[j*magnification*(ssize_t) channels+i];
3056 q+=magnification*GetPixelChannels(magnify_image);
3058 if (SyncCacheViewAuthenticPixels(magnify_view,exception) == MagickFalse)
3060 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3065#if defined(MAGICKCORE_OPENMP_SUPPORT)
3069 proceed=SetImageProgress(image,MagnifyImageTag,progress,image->rows);
3070 if (proceed == MagickFalse)
3074 magnify_view=DestroyCacheView(magnify_view);
3075 image_view=DestroyCacheView(image_view);
3076 source_image=DestroyImage(source_image);
3077 if (status == MagickFalse)
3078 magnify_image=DestroyImage(magnify_image);
3079 return(magnify_image);
3112 assert(image != (
Image *) NULL);
3113 assert(image->signature == MagickCoreSignature);
3115 assert(exception->signature == MagickCoreSignature);
3116 if (IsEventLogging() != MagickFalse)
3117 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3118 minify_image=ResizeImage(image,image->columns/2,image->rows/2,SplineFilter,
3120 return(minify_image);
3157MagickExport
Image *ResampleImage(
const Image *image,
const double x_resolution,
3158 const double y_resolution,
const FilterType filter,
ExceptionInfo *exception)
3160#define ResampleImageTag "Resample/Image"
3172 assert(image != (
const Image *) NULL);
3173 assert(image->signature == MagickCoreSignature);
3175 assert(exception->signature == MagickCoreSignature);
3176 if (IsEventLogging() != MagickFalse)
3177 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3178 width=(size_t) (x_resolution*image->columns/(image->resolution.x == 0.0 ?
3179 DefaultResolution : image->resolution.x)+0.5);
3180 height=(size_t) (y_resolution*image->rows/(image->resolution.y == 0.0 ?
3181 DefaultResolution : image->resolution.y)+0.5);
3182 resample_image=ResizeImage(image,width,height,filter,exception);
3183 if (resample_image != (
Image *) NULL)
3185 resample_image->resolution.x=x_resolution;
3186 resample_image->resolution.y=y_resolution;
3188 return(resample_image);
3246 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3251 return(contribution);
3265 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3267 sizeof(*contribution));
3270 (void) memset(contribution,0,number_threads*
sizeof(*contribution));
3271 for (i=0; i < (ssize_t) number_threads; i++)
3274 AcquireAlignedMemory(count,
sizeof(**contribution)));
3276 return(DestroyContributionTLS(contribution));
3278 return(contribution);
3281static MagickBooleanType HorizontalFilter(
3283 const Image *magick_restrict image,
Image *magick_restrict resize_image,
3284 const double x_factor,
const MagickSizeType span,
3285 MagickOffsetType *magick_restrict progress,
ExceptionInfo *exception)
3287#define ResizeImageTag "Resize/Image"
3297 **magick_restrict contributions;
3312 scale=MagickMax(1.0/x_factor+MagickEpsilon,1.0);
3313 support=scale*GetResizeFilterSupport(resize_filter);
3314 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3315 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3316 return(MagickFalse);
3322 support=(double) 0.5;
3325 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3328 (void) ThrowMagickException(exception,GetMagickModule(),
3329 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3330 return(MagickFalse);
3333 scale=PerceptibleReciprocal(scale);
3334 image_view=AcquireVirtualCacheView(image,exception);
3335 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3336#if defined(MAGICKCORE_OPENMP_SUPPORT)
3337 #pragma omp parallel for schedule(static) shared(progress,status) \
3338 magick_number_threads(image,resize_image,resize_image->columns,1)
3340 for (x=0; x < (ssize_t) resize_image->columns; x++)
3343 id = GetOpenMPThreadId();
3349 *magick_restrict contribution;
3364 if (status == MagickFalse)
3366 bisect=(double) (x+0.5)/x_factor+MagickEpsilon;
3367 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3368 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->columns);
3370 contribution=contributions[id];
3371 for (n=0; n < (stop-start); n++)
3373 contribution[n].pixel=start+n;
3374 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3375 ((
double) (start+n)-bisect+0.5));
3376 density+=contribution[n].weight;
3380 if ((density != 0.0) && (density != 1.0))
3388 density=PerceptibleReciprocal(density);
3389 for (i=0; i < n; i++)
3390 contribution[i].weight*=density;
3392 p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,(
size_t)
3393 (contribution[n-1].pixel-contribution[0].pixel+1),image->rows,exception);
3394 q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
3396 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3401 for (y=0; y < (ssize_t) resize_image->rows; y++)
3406 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3424 channel=GetPixelChannelChannel(image,i);
3425 traits=GetPixelChannelTraits(image,channel);
3426 resize_traits=GetPixelChannelTraits(resize_image,channel);
3427 if ((traits == UndefinedPixelTrait) ||
3428 (resize_traits == UndefinedPixelTrait))
3430 if (((resize_traits & CopyPixelTrait) != 0) ||
3431 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3433 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3435 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3436 (contribution[j-start].pixel-contribution[0].pixel);
3437 SetPixelChannel(resize_image,channel,
3438 p[k*(ssize_t) GetPixelChannels(image)+i],q);
3442 if ((resize_traits & BlendPixelTrait) == 0)
3447 for (j=0; j < n; j++)
3449 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3450 (contribution[j].pixel-contribution[0].pixel);
3451 alpha=contribution[j].weight;
3452 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3454 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3461 for (j=0; j < n; j++)
3463 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3464 (contribution[j].pixel-contribution[0].pixel);
3465 alpha=contribution[j].weight*QuantumScale*
3466 (double) GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3467 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3470 gamma=PerceptibleReciprocal(gamma);
3471 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3473 q+=GetPixelChannels(resize_image);
3475 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3477 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3482#if defined(MAGICKCORE_OPENMP_SUPPORT)
3486 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3487 if (proceed == MagickFalse)
3491 resize_view=DestroyCacheView(resize_view);
3492 image_view=DestroyCacheView(image_view);
3493 contributions=DestroyContributionTLS(contributions);
3497static MagickBooleanType VerticalFilter(
3499 const Image *magick_restrict image,
Image *magick_restrict resize_image,
3500 const double y_factor,
const MagickSizeType span,
3501 MagickOffsetType *magick_restrict progress,
ExceptionInfo *exception)
3511 **magick_restrict contributions;
3526 scale=MagickMax(1.0/y_factor+MagickEpsilon,1.0);
3527 support=scale*GetResizeFilterSupport(resize_filter);
3528 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3529 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3530 return(MagickFalse);
3536 support=(double) 0.5;
3539 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3542 (void) ThrowMagickException(exception,GetMagickModule(),
3543 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3544 return(MagickFalse);
3547 scale=PerceptibleReciprocal(scale);
3548 image_view=AcquireVirtualCacheView(image,exception);
3549 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3550#if defined(MAGICKCORE_OPENMP_SUPPORT)
3551 #pragma omp parallel for schedule(static) shared(progress,status) \
3552 magick_number_threads(image,resize_image,resize_image->rows,1)
3554 for (y=0; y < (ssize_t) resize_image->rows; y++)
3557 id = GetOpenMPThreadId();
3563 *magick_restrict contribution;
3578 if (status == MagickFalse)
3580 bisect=(double) (y+0.5)/y_factor+MagickEpsilon;
3581 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3582 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->rows);
3584 contribution=contributions[id];
3585 for (n=0; n < (stop-start); n++)
3587 contribution[n].pixel=start+n;
3588 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3589 ((
double) (start+n)-bisect+0.5));
3590 density+=contribution[n].weight;
3594 if ((density != 0.0) && (density != 1.0))
3602 density=PerceptibleReciprocal(density);
3603 for (i=0; i < n; i++)
3604 contribution[i].weight*=density;
3606 p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
3607 image->columns,(
size_t) (contribution[n-1].pixel-contribution[0].pixel+1),
3609 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
3611 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3616 for (x=0; x < (ssize_t) resize_image->columns; x++)
3621 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3639 channel=GetPixelChannelChannel(image,i);
3640 traits=GetPixelChannelTraits(image,channel);
3641 resize_traits=GetPixelChannelTraits(resize_image,channel);
3642 if ((traits == UndefinedPixelTrait) ||
3643 (resize_traits == UndefinedPixelTrait))
3645 if (((resize_traits & CopyPixelTrait) != 0) ||
3646 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3648 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3650 k=(ssize_t) ((contribution[j-start].pixel-contribution[0].pixel)*
3651 (ssize_t) image->columns+x);
3652 SetPixelChannel(resize_image,channel,p[k*(ssize_t)
3653 GetPixelChannels(image)+i],q);
3657 if ((resize_traits & BlendPixelTrait) == 0)
3662 for (j=0; j < n; j++)
3664 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3665 (ssize_t) image->columns+x);
3666 alpha=contribution[j].weight;
3667 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3669 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3673 for (j=0; j < n; j++)
3675 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3676 (ssize_t) image->columns+x);
3677 alpha=contribution[j].weight*QuantumScale*(double)
3678 GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3679 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3682 gamma=PerceptibleReciprocal(gamma);
3683 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3685 q+=GetPixelChannels(resize_image);
3687 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3689 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3694#if defined(MAGICKCORE_OPENMP_SUPPORT)
3698 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3699 if (proceed == MagickFalse)
3703 resize_view=DestroyCacheView(resize_view);
3704 image_view=DestroyCacheView(image_view);
3705 contributions=DestroyContributionTLS(contributions);
3709MagickExport
Image *ResizeImage(
const Image *image,
const size_t columns,
3710 const size_t rows,
const FilterType filter,
ExceptionInfo *exception)
3738 assert(image != (
Image *) NULL);
3739 assert(image->signature == MagickCoreSignature);
3741 assert(exception->signature == MagickCoreSignature);
3742 if (IsEventLogging() != MagickFalse)
3743 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3744 if ((columns == 0) || (rows == 0))
3745 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3746 if ((columns == image->columns) && (rows == image->rows) &&
3747 (filter == UndefinedFilter))
3748 return(CloneImage(image,0,0,MagickTrue,exception));
3752 x_factor=(double) (columns*PerceptibleReciprocal((
double) image->columns));
3753 y_factor=(double) (rows*PerceptibleReciprocal((
double) image->rows));
3754 filter_type=LanczosFilter;
3755 if (filter != UndefinedFilter)
3758 if ((x_factor == 1.0) && (y_factor == 1.0))
3759 filter_type=PointFilter;
3761 if ((image->storage_class == PseudoClass) ||
3762 (image->alpha_trait != UndefinedPixelTrait) ||
3763 ((x_factor*y_factor) > 1.0))
3764 filter_type=MitchellFilter;
3765 resize_filter=AcquireResizeFilter(image,filter_type,MagickFalse,exception);
3766#if defined(MAGICKCORE_OPENCL_SUPPORT)
3767 resize_image=AccelerateResizeImage(image,columns,rows,resize_filter,
3769 if (resize_image != (
Image *) NULL)
3771 resize_filter=DestroyResizeFilter(resize_filter);
3772 return(resize_image);
3775 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
3776 if (resize_image == (
Image *) NULL)
3778 resize_filter=DestroyResizeFilter(resize_filter);
3779 return(resize_image);
3781 if (x_factor > y_factor)
3782 filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
3784 filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
3785 if (filter_image == (
Image *) NULL)
3787 resize_filter=DestroyResizeFilter(resize_filter);
3788 return(DestroyImage(resize_image));
3794 if (x_factor > y_factor)
3796 span=(MagickSizeType) (filter_image->columns+rows);
3797 status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
3799 status&=(MagickStatusType) VerticalFilter(resize_filter,filter_image,
3800 resize_image,y_factor,span,&offset,exception);
3804 span=(MagickSizeType) (filter_image->rows+columns);
3805 status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
3807 status&=(MagickStatusType) HorizontalFilter(resize_filter,filter_image,
3808 resize_image,x_factor,span,&offset,exception);
3813 filter_image=DestroyImage(filter_image);
3814 resize_filter=DestroyResizeFilter(resize_filter);
3815 if (status == MagickFalse)
3817 resize_image=DestroyImage(resize_image);
3818 return((
Image *) NULL);
3820 resize_image->type=image->type;
3821 return(resize_image);
3855MagickExport
Image *SampleImage(
const Image *image,
const size_t columns,
3858#define SampleImageTag "Sample/Image"
3884 assert(image != (
const Image *) NULL);
3885 assert(image->signature == MagickCoreSignature);
3887 assert(exception->signature == MagickCoreSignature);
3888 if (IsEventLogging() != MagickFalse)
3889 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3890 if ((columns == 0) || (rows == 0))
3891 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3892 if ((columns == image->columns) && (rows == image->rows))
3893 return(CloneImage(image,0,0,MagickTrue,exception));
3894 sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
3895 if (sample_image == (
Image *) NULL)
3896 return((
Image *) NULL);
3900 sample_offset.x=0.5-MagickEpsilon;
3901 sample_offset.y=sample_offset.x;
3906 value=GetImageArtifact(image,
"sample:offset");
3907 if (value != (
char *) NULL)
3915 (void) ParseGeometry(value,&geometry_info);
3916 flags=ParseGeometry(value,&geometry_info);
3917 sample_offset.x=sample_offset.y=geometry_info.rho/100.0-MagickEpsilon;
3918 if ((flags & SigmaValue) != 0)
3919 sample_offset.y=geometry_info.sigma/100.0-MagickEpsilon;
3925 x_offset=(ssize_t *) AcquireQuantumMemory((
size_t) sample_image->columns,
3927 if (x_offset == (ssize_t *) NULL)
3929 sample_image=DestroyImage(sample_image);
3930 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3932 for (j=0; j < (ssize_t) sample_image->columns; j++)
3933 x_offset[j]=(ssize_t) ((((double) j+sample_offset.x)*image->columns)/
3934 sample_image->columns);
3940 image_view=AcquireVirtualCacheView(image,exception);
3941 sample_view=AcquireAuthenticCacheView(sample_image,exception);
3942#if defined(MAGICKCORE_OPENMP_SUPPORT)
3943 #pragma omp parallel for schedule(static) shared(status) \
3944 magick_number_threads(image,sample_image,sample_image->rows,2)
3946 for (y=0; y < (ssize_t) sample_image->rows; y++)
3958 if (status == MagickFalse)
3960 y_offset=(ssize_t) ((((
double) y+sample_offset.y)*image->rows)/
3961 sample_image->rows);
3962 p=GetCacheViewVirtualPixels(image_view,0,y_offset,image->columns,1,
3964 q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
3966 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3974 for (x=0; x < (ssize_t) sample_image->columns; x++)
3979 if (GetPixelWriteMask(sample_image,q) <= (QuantumRange/2))
3981 q+=GetPixelChannels(sample_image);
3984 for (i=0; i < (ssize_t) GetPixelChannels(sample_image); i++)
3993 channel=GetPixelChannelChannel(sample_image,i);
3994 traits=GetPixelChannelTraits(sample_image,channel);
3995 image_traits=GetPixelChannelTraits(image,channel);
3996 if ((traits == UndefinedPixelTrait) ||
3997 (image_traits == UndefinedPixelTrait))
3999 SetPixelChannel(sample_image,channel,p[x_offset[x]*(ssize_t)
4000 GetPixelChannels(image)+i],q);
4002 q+=GetPixelChannels(sample_image);
4004 if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
4006 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4011 proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
4012 if (proceed == MagickFalse)
4016 image_view=DestroyCacheView(image_view);
4017 sample_view=DestroyCacheView(sample_view);
4018 x_offset=(ssize_t *) RelinquishMagickMemory(x_offset);
4019 sample_image->type=image->type;
4020 if (status == MagickFalse)
4021 sample_image=DestroyImage(sample_image);
4022 return(sample_image);
4054MagickExport
Image *ScaleImage(
const Image *image,
const size_t columns,
4057#define ScaleImageTag "Scale/Image"
4065 pixel[CompositePixelChannel],
4096 assert(image != (
const Image *) NULL);
4097 assert(image->signature == MagickCoreSignature);
4099 assert(exception->signature == MagickCoreSignature);
4100 if (IsEventLogging() != MagickFalse)
4101 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4102 if ((columns == 0) || (rows == 0))
4103 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
4104 if ((columns == image->columns) && (rows == image->rows))
4105 return(CloneImage(image,0,0,MagickTrue,exception));
4106 scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
4107 if (scale_image == (
Image *) NULL)
4108 return((
Image *) NULL);
4109 if (SetImageStorageClass(scale_image,DirectClass,exception) == MagickFalse)
4111 scale_image=DestroyImage(scale_image);
4112 return((
Image *) NULL);
4117 x_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4118 MaxPixelChannels*
sizeof(*x_vector));
4120 if (image->rows != scale_image->rows)
4121 scanline=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4122 MaxPixelChannels*
sizeof(*scanline));
4123 scale_scanline=(
double *) AcquireQuantumMemory((
size_t) scale_image->columns,
4124 MaxPixelChannels*
sizeof(*scale_scanline));
4125 y_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4126 MaxPixelChannels*
sizeof(*y_vector));
4127 if ((scanline == (
double *) NULL) || (scale_scanline == (
double *) NULL) ||
4128 (x_vector == (
double *) NULL) || (y_vector == (
double *) NULL))
4130 if ((image->rows != scale_image->rows) && (scanline != (
double *) NULL))
4131 scanline=(
double *) RelinquishMagickMemory(scanline);
4132 if (scale_scanline != (
double *) NULL)
4133 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4134 if (x_vector != (
double *) NULL)
4135 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4136 if (y_vector != (
double *) NULL)
4137 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4138 scale_image=DestroyImage(scale_image);
4139 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4145 next_row=MagickTrue;
4147 scale.y=(double) scale_image->rows/(
double) image->rows;
4148 (void) memset(y_vector,0,(
size_t) MaxPixelChannels*image->columns*
4152 image_view=AcquireVirtualCacheView(image,exception);
4153 scale_view=AcquireAuthenticCacheView(scale_image,exception);
4154 for (y=0; y < (ssize_t) scale_image->rows; y++)
4165 if (status == MagickFalse)
4167 q=QueueCacheViewAuthenticPixels(scale_view,0,y,scale_image->columns,1,
4169 if (q == (Quantum *) NULL)
4175 if (scale_image->rows == image->rows)
4180 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4182 if (p == (
const Quantum *) NULL)
4187 for (x=0; x < (ssize_t) image->columns; x++)
4189 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4191 p+=GetPixelChannels(image);
4194 if (image->alpha_trait != UndefinedPixelTrait)
4195 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4196 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4198 PixelChannel channel = GetPixelChannelChannel(image,i);
4199 PixelTrait traits = GetPixelChannelTraits(image,channel);
4200 if ((traits & BlendPixelTrait) == 0)
4202 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=(double) p[i];
4205 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*(double) p[i];
4207 p+=GetPixelChannels(image);
4215 while (scale.y < span.y)
4217 if ((next_row != MagickFalse) &&
4218 (number_rows < (ssize_t) image->rows))
4223 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4225 if (p == (
const Quantum *) NULL)
4230 for (x=0; x < (ssize_t) image->columns; x++)
4232 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4234 p+=GetPixelChannels(image);
4237 if (image->alpha_trait != UndefinedPixelTrait)
4238 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4239 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4241 PixelChannel channel = GetPixelChannelChannel(image,i);
4242 PixelTrait traits = GetPixelChannelTraits(image,channel);
4243 if ((traits & BlendPixelTrait) == 0)
4245 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4249 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4252 p+=GetPixelChannels(image);
4256 for (x=0; x < (ssize_t) image->columns; x++)
4257 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4258 y_vector[x*(ssize_t) GetPixelChannels(image)+i]+=scale.y*
4259 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4261 scale.y=(double) scale_image->rows/(
double) image->rows;
4262 next_row=MagickTrue;
4264 if ((next_row != MagickFalse) && (number_rows < (ssize_t) image->rows))
4269 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4271 if (p == (
const Quantum *) NULL)
4276 for (x=0; x < (ssize_t) image->columns; x++)
4278 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4280 p+=GetPixelChannels(image);
4283 if (image->alpha_trait != UndefinedPixelTrait)
4284 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4285 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4287 PixelChannel channel = GetPixelChannelChannel(image,i);
4288 PixelTrait traits = GetPixelChannelTraits(image,channel);
4289 if ((traits & BlendPixelTrait) == 0)
4291 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4295 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4298 p+=GetPixelChannels(image);
4301 next_row=MagickFalse;
4303 for (x=0; x < (ssize_t) image->columns; x++)
4305 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4307 pixel[i]=y_vector[x*(ssize_t) GetPixelChannels(image)+i]+span.y*
4308 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4309 scanline[x*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4310 y_vector[x*(ssize_t) GetPixelChannels(image)+i]=0.0;
4316 scale.y=(double) scale_image->rows/(
double) image->rows;
4317 next_row=MagickTrue;
4321 if (scale_image->columns == image->columns)
4326 for (x=0; x < (ssize_t) scale_image->columns; x++)
4328 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4330 q+=GetPixelChannels(scale_image);
4333 if (image->alpha_trait != UndefinedPixelTrait)
4335 alpha=QuantumScale*scanline[x*(ssize_t) GetPixelChannels(image)+
4336 GetPixelChannelOffset(image,AlphaPixelChannel)];
4337 alpha=PerceptibleReciprocal(alpha);
4339 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4341 PixelChannel channel = GetPixelChannelChannel(image,i);
4342 PixelTrait traits = GetPixelChannelTraits(image,channel);
4343 scale_traits=GetPixelChannelTraits(scale_image,channel);
4344 if ((traits == UndefinedPixelTrait) ||
4345 (scale_traits == UndefinedPixelTrait))
4347 if ((traits & BlendPixelTrait) == 0)
4349 SetPixelChannel(scale_image,channel,ClampToQuantum(
4350 scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4353 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*scanline[
4354 x*(ssize_t) GetPixelChannels(image)+i]),q);
4356 q+=GetPixelChannels(scale_image);
4367 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4369 next_column=MagickFalse;
4372 for (x=0; x < (ssize_t) image->columns; x++)
4374 scale.x=(double) scale_image->columns/(
double) image->columns;
4375 while (scale.x >= span.x)
4377 if (next_column != MagickFalse)
4379 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4383 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4385 PixelChannel channel = GetPixelChannelChannel(image,i);
4386 PixelTrait traits = GetPixelChannelTraits(image,channel);
4387 if (traits == UndefinedPixelTrait)
4389 pixel[i]+=span.x*scanline[x*(ssize_t) GetPixelChannels(image)+i];
4390 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4394 next_column=MagickTrue;
4398 if (next_column != MagickFalse)
4400 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4402 next_column=MagickFalse;
4405 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4406 pixel[i]+=scale.x*scanline[x*(ssize_t)
4407 GetPixelChannels(image)+i];
4413 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4415 scanline[(x-1)*(ssize_t) GetPixelChannels(image)+i];
4417 if ((next_column == MagickFalse) && (t < (ssize_t) scale_image->columns))
4418 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4419 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4423 for (x=0; x < (ssize_t) scale_image->columns; x++)
4425 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4427 q+=GetPixelChannels(scale_image);
4430 if (image->alpha_trait != UndefinedPixelTrait)
4432 alpha=QuantumScale*scale_scanline[x*(ssize_t)
4433 GetPixelChannels(image)+
4434 GetPixelChannelOffset(image,AlphaPixelChannel)];
4435 alpha=PerceptibleReciprocal(alpha);
4437 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4439 PixelChannel channel = GetPixelChannelChannel(image,i);
4440 PixelTrait traits = GetPixelChannelTraits(image,channel);
4441 scale_traits=GetPixelChannelTraits(scale_image,channel);
4442 if ((traits == UndefinedPixelTrait) ||
4443 (scale_traits == UndefinedPixelTrait))
4445 if ((traits & BlendPixelTrait) == 0)
4447 SetPixelChannel(scale_image,channel,ClampToQuantum(
4448 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4451 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*
4452 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4454 q+=GetPixelChannels(scale_image);
4457 if (SyncCacheViewAuthenticPixels(scale_view,exception) == MagickFalse)
4462 proceed=SetImageProgress(image,ScaleImageTag,(MagickOffsetType) y,
4464 if (proceed == MagickFalse)
4470 scale_view=DestroyCacheView(scale_view);
4471 image_view=DestroyCacheView(image_view);
4475 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4476 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4477 if (scale_image->rows != image->rows)
4478 scanline=(
double *) RelinquishMagickMemory(scanline);
4479 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4480 scale_image->type=image->type;
4481 if (status == MagickFalse)
4482 scale_image=DestroyImage(scale_image);
4483 return(scale_image);
4517MagickExport
Image *ThumbnailImage(
const Image *image,
const size_t columns,
4520#define SampleFactor 5
4523 filename[MagickPathExtent],
4524 value[MagickPathExtent];
4535 assert(image != (
Image *) NULL);
4536 assert(image->signature == MagickCoreSignature);
4538 assert(exception->signature == MagickCoreSignature);
4539 if (IsEventLogging() != MagickFalse)
4540 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4541 thumbnail_image=CloneImage(image,0,0,MagickTrue,exception);
4542 if (thumbnail_image == (
Image *) NULL)
4543 return(thumbnail_image);
4544 if ((columns != image->columns) || (rows != image->rows))
4547 *clone_image = thumbnail_image;
4553 x_factor=(ssize_t) image->columns/(ssize_t) columns;
4554 y_factor=(ssize_t) image->rows/(ssize_t) rows;
4555 if ((x_factor > 4) && (y_factor > 4))
4557 thumbnail_image=SampleImage(clone_image,4*columns,4*rows,exception);
4558 if (thumbnail_image != (
Image *) NULL)
4560 clone_image=DestroyImage(clone_image);
4561 clone_image=thumbnail_image;
4564 if ((x_factor > 2) && (y_factor > 2))
4566 thumbnail_image=ResizeImage(clone_image,2*columns,2*rows,BoxFilter,
4568 if (thumbnail_image != (
Image *) NULL)
4570 clone_image=DestroyImage(clone_image);
4571 clone_image=thumbnail_image;
4574 thumbnail_image=ResizeImage(clone_image,columns,rows,image->filter ==
4575 UndefinedFilter ? LanczosSharpFilter : image->filter,exception);
4576 clone_image=DestroyImage(clone_image);
4577 if (thumbnail_image == (
Image *) NULL)
4578 return(thumbnail_image);
4580 (void) ParseAbsoluteGeometry(
"0x0+0+0",&thumbnail_image->page);
4581 thumbnail_image->depth=8;
4582 thumbnail_image->interlace=NoInterlace;
4586 ResetImageProfileIterator(thumbnail_image);
4587 for (name=GetNextImageProfile(thumbnail_image); name != (
const char *) NULL; )
4589 if ((LocaleCompare(name,
"icc") != 0) && (LocaleCompare(name,
"icm") != 0))
4591 (void) DeleteImageProfile(thumbnail_image,name);
4592 ResetImageProfileIterator(thumbnail_image);
4594 name=GetNextImageProfile(thumbnail_image);
4596 (void) DeleteImageProperty(thumbnail_image,
"comment");
4597 (void) CopyMagickString(value,image->magick_filename,MagickPathExtent);
4598 if (strstr(image->magick_filename,
"//") == (
char *) NULL)
4599 (void) FormatLocaleString(value,MagickPathExtent,
"file://%s",
4600 image->magick_filename);
4601 (void) SetImageProperty(thumbnail_image,
"Thumb::URI",value,exception);
4602 GetPathComponent(image->magick_filename,TailPath,filename);
4603 (void) CopyMagickString(value,filename,MagickPathExtent);
4604 if ( GetPathAttributes(image->filename,&attributes) != MagickFalse )
4605 (
void) FormatImageProperty(thumbnail_image,
"Thumb::MTime",
"%.20g",(
double)
4606 attributes.st_mtime);
4607 (void) FormatLocaleString(value,MagickPathExtent,
"%.20g",(
double)
4608 attributes.st_mtime);
4609 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,
"B",MagickPathExtent,
4611 (void) SetImageProperty(thumbnail_image,
"Thumb::Size",value,exception);
4612 (void) FormatLocaleString(value,MagickPathExtent,
"image/%s",image->magick);
4614 (void) SetImageProperty(thumbnail_image,
"Thumb::Mimetype",value,exception);
4615 (void) SetImageProperty(thumbnail_image,
"software",MagickAuthoritativeURL,
4617 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Width",
"%.20g",
4618 (
double) image->magick_columns);
4619 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Height",
"%.20g",
4620 (
double) image->magick_rows);
4621 (void) FormatImageProperty(thumbnail_image,
"Thumb::Document::Pages",
"%.20g",
4622 (
double) GetImageListLength(image));
4623 return(thumbnail_image);