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)
87#include "MagickCore/statistic-private.h"
103 ResizeWeightingFunctionType
116 BesselOrderOne(
double),
152static double Blackman(
const double x,
162 const double cosine = cos((
double) (MagickPI*x));
163 magick_unreferenced(resize_filter);
164 return(0.34+cosine*(0.5+cosine*0.16));
167static double Bohman(
const double x,
178 const double cosine = cos((
double) (MagickPI*x));
179 const double sine=sqrt(1.0-cosine*cosine);
180 magick_unreferenced(resize_filter);
181 return((1.0-x)*cosine+(1.0/MagickPI)*sine);
184static double Box(
const double magick_unused(x),
187 magick_unreferenced(x);
188 magick_unreferenced(resize_filter);
198static double Cosine(
const double x,
201 magick_unreferenced(resize_filter);
207 return(cos((
double) (MagickPI2*x)));
210static double CubicBC(
const double x,
const ResizeFilter *resize_filter)
242 return(resize_filter->coefficient[0]+x*(x*
243 (resize_filter->coefficient[1]+x*resize_filter->coefficient[2])));
245 return(resize_filter->coefficient[3]+x*(resize_filter->coefficient[4]+x*
246 (resize_filter->coefficient[5]+x*resize_filter->coefficient[6])));
250static double CubicSpline(
const double x,
const ResizeFilter *resize_filter)
252 if (resize_filter->support <= 2.0)
258 return(((x-9.0/5.0)*x-1.0/5.0)*x+1.0);
260 return(((-1.0/3.0*(x-1.0)+4.0/5.0)*(x-1.0)-7.0/15.0)*(x-1.0));
263 if (resize_filter->support <= 3.0)
269 return(((13.0/11.0*x-453.0/209.0)*x-3.0/209.0)*x+1.0);
271 return(((-6.0/11.0*(x-1.0)+270.0/209.0)*(x-1.0)-156.0/209.0)*(x-1.0));
273 return(((1.0/11.0*(x-2.0)-45.0/209.0)*(x-2.0)+26.0/209.0)*(x-2.0));
280 return(((49.0/41.0*x-6387.0/2911.0)*x-3.0/2911.0)*x+1.0);
282 return(((-24.0/41.0*(x-1.0)+4032.0/2911.0)*(x-1.0)-2328.0/2911.0)*(x-1.0));
284 return(((6.0/41.0*(x-2.0)-1008.0/2911.0)*(x-2.0)+582.0/2911.0)*(x-2.0));
286 return(((-1.0/41.0*(x-3.0)+168.0/2911.0)*(x-3.0)-97.0/2911.0)*(x-3.0));
290static double Gaussian(
const double x,
const ResizeFilter *resize_filter)
322 return(exp((
double)(-resize_filter->coefficient[1]*x*x)));
325static double Hann(
const double x,
332 const double cosine = cos((
double) (MagickPI*x));
333 magick_unreferenced(resize_filter);
334 return(0.5+0.5*cosine);
337static double Hamming(
const double x,
344 const double cosine = cos((
double) (MagickPI*x));
345 magick_unreferenced(resize_filter);
346 return(0.54+0.46*cosine);
349static double Jinc(
const double x,
352 magick_unreferenced(resize_filter);
363 return(0.5*MagickPI);
364 return(BesselOrderOne(MagickPI*x)/x);
367static double Kaiser(
const double x,
const ResizeFilter *resize_filter)
381 return(resize_filter->coefficient[1]*I0(resize_filter->coefficient[0]*
382 sqrt((
double) (1.0-x*x))));
385static double Lagrange(
const double x,
const ResizeFilter *resize_filter)
407 if (x > resize_filter->support)
409 order=(ssize_t) (2.0*resize_filter->window_support);
410 n=(ssize_t) (resize_filter->window_support+x);
412 for (i=0; i < order; i++)
414 value*=(n-i-x)/(n-i);
418static double MagicKernelSharp2013(
const double x,
421 magick_unreferenced(resize_filter);
430 return(0.625+1.75*(0.5-x)*(0.5+x));
432 return((1.0-x)*(1.75-x));
434 return(-0.125*(2.5-x)*(2.5-x));
438static double MagicKernelSharp2021(
const double x,
441 magick_unreferenced(resize_filter);
450 return(577.0/576.0-239.0/144.0*x*x);
452 return(35.0/36.0*(x-1.0)*(x-239.0/140.0));
454 return(1.0/6.0*(x-2.0)*(65.0/24.0-x));
456 return(1.0/36.0*(x-3.0)*(x-3.75));
458 return(-1.0/288.0*(x-4.5)*(x-4.5));
462static double Quadratic(
const double x,
465 magick_unreferenced(resize_filter);
473 return(0.5*(x-1.5)*(x-1.5));
477static double Sinc(
const double x,
480 magick_unreferenced(resize_filter);
488 const double alpha=(double) (MagickPI*x);
489 return(sin((
double) alpha)/alpha);
491 return((
double) 1.0);
494static double SincFast(
const double x,
497 magick_unreferenced(resize_filter);
525 const double alpha=(double) (MagickPI*x);
526 return(sin((
double) alpha)/alpha);
532 const double xx = x*x;
533#if MAGICKCORE_QUANTUM_DEPTH <= 8
537 const double c0 = 0.173610016489197553621906385078711564924e-2L;
538 const double c1 = -0.384186115075660162081071290162149315834e-3L;
539 const double c2 = 0.393684603287860108352720146121813443561e-4L;
540 const double c3 = -0.248947210682259168029030370205389323899e-5L;
541 const double c4 = 0.107791837839662283066379987646635416692e-6L;
542 const double c5 = -0.324874073895735800961260474028013982211e-8L;
543 const double c6 = 0.628155216606695311524920882748052490116e-10L;
544 const double c7 = -0.586110644039348333520104379959307242711e-12L;
546 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
547 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
548#elif MAGICKCORE_QUANTUM_DEPTH <= 16
552 const double c0 = 0.173611107357320220183368594093166520811e-2L;
553 const double c1 = -0.384240921114946632192116762889211361285e-3L;
554 const double c2 = 0.394201182359318128221229891724947048771e-4L;
555 const double c3 = -0.250963301609117217660068889165550534856e-5L;
556 const double c4 = 0.111902032818095784414237782071368805120e-6L;
557 const double c5 = -0.372895101408779549368465614321137048875e-8L;
558 const double c6 = 0.957694196677572570319816780188718518330e-10L;
559 const double c7 = -0.187208577776590710853865174371617338991e-11L;
560 const double c8 = 0.253524321426864752676094495396308636823e-13L;
561 const double c9 = -0.177084805010701112639035485248501049364e-15L;
563 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*(c7+xx*(c8+xx*c9))))))));
564 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
569 const double c0 = 0.173611111110910715186413700076827593074e-2L;
570 const double c1 = -0.289105544717893415815859968653611245425e-3L;
571 const double c2 = 0.206952161241815727624413291940849294025e-4L;
572 const double c3 = -0.834446180169727178193268528095341741698e-6L;
573 const double c4 = 0.207010104171026718629622453275917944941e-7L;
574 const double c5 = -0.319724784938507108101517564300855542655e-9L;
575 const double c6 = 0.288101675249103266147006509214934493930e-11L;
576 const double c7 = -0.118218971804934245819960233886876537953e-13L;
578 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
579 const double d0 = 1.0L;
580 const double d1 = 0.547981619622284827495856984100563583948e-1L;
581 const double d2 = 0.134226268835357312626304688047086921806e-2L;
582 const double d3 = 0.178994697503371051002463656833597608689e-4L;
583 const double d4 = 0.114633394140438168641246022557689759090e-6L;
584 const double q = d0+xx*(d1+xx*(d2+xx*(d3+xx*d4)));
585 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)/q*p);
590static double Triangle(
const double x,
593 magick_unreferenced(resize_filter);
605static double Welch(
const double x,
608 magick_unreferenced(resize_filter);
805 const FilterType filter,
const MagickBooleanType cylindrical,
841 }
const mapping[SentinelFilter] =
843 { UndefinedFilter, BoxFilter },
844 { PointFilter, BoxFilter },
845 { BoxFilter, BoxFilter },
846 { TriangleFilter, BoxFilter },
847 { HermiteFilter, BoxFilter },
848 { SincFastFilter, HannFilter },
849 { SincFastFilter, HammingFilter },
850 { SincFastFilter, BlackmanFilter },
851 { GaussianFilter, BoxFilter },
852 { QuadraticFilter, BoxFilter },
853 { CubicFilter, BoxFilter },
854 { CatromFilter, BoxFilter },
855 { MitchellFilter, BoxFilter },
856 { JincFilter, BoxFilter },
857 { SincFilter, BoxFilter },
858 { SincFastFilter, BoxFilter },
859 { SincFastFilter, KaiserFilter },
860 { LanczosFilter, WelchFilter },
861 { SincFastFilter, CubicFilter },
862 { SincFastFilter, BohmanFilter },
863 { SincFastFilter, TriangleFilter },
864 { LagrangeFilter, BoxFilter },
865 { LanczosFilter, LanczosFilter },
866 { LanczosSharpFilter, LanczosSharpFilter },
867 { Lanczos2Filter, Lanczos2Filter },
868 { Lanczos2SharpFilter, Lanczos2SharpFilter },
869 { RobidouxFilter, BoxFilter },
870 { RobidouxSharpFilter, BoxFilter },
871 { LanczosFilter, CosineFilter },
872 { SplineFilter, BoxFilter },
873 { LanczosRadiusFilter, LanczosFilter },
874 { CubicSplineFilter, BoxFilter },
875 { MagicKernelSharp2013Filter, BoxFilter },
876 { MagicKernelSharp2021Filter, BoxFilter },
897 ResizeWeightingFunctionType weightingFunctionType;
898 }
const filters[SentinelFilter] =
905 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
906 { Box, 0.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
907 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
908 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
909 { CubicBC, 1.0, 1.0, 0.0, 0.0, CubicBCWeightingFunction },
910 { Hann, 1.0, 1.0, 0.0, 0.0, HannWeightingFunction },
911 { Hamming, 1.0, 1.0, 0.0, 0.0, HammingWeightingFunction },
912 { Blackman, 1.0, 1.0, 0.0, 0.0, BlackmanWeightingFunction },
913 { Gaussian, 2.0, 1.5, 0.0, 0.0, GaussianWeightingFunction },
914 { Quadratic, 1.5, 1.5, 0.0, 0.0, QuadraticWeightingFunction },
915 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
916 { CubicBC, 2.0, 1.0, 0.0, 0.5, CubicBCWeightingFunction },
917 { CubicBC, 2.0, 8.0/7.0, 1./3., 1./3., CubicBCWeightingFunction },
918 { Jinc, 3.0, 1.2196698912665045, 0.0, 0.0, JincWeightingFunction },
919 { Sinc, 4.0, 1.0, 0.0, 0.0, SincWeightingFunction },
920 { SincFast, 4.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
921 { Kaiser, 1.0, 1.0, 0.0, 0.0, KaiserWeightingFunction },
922 { Welch, 1.0, 1.0, 0.0, 0.0, WelchWeightingFunction },
923 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
924 { Bohman, 1.0, 1.0, 0.0, 0.0, BohmanWeightingFunction },
925 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
926 { Lagrange, 2.0, 1.0, 0.0, 0.0, LagrangeWeightingFunction },
927 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
928 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
929 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
930 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
932 { CubicBC, 2.0, 1.1685777620836932,
933 0.37821575509399867, 0.31089212245300067, CubicBCWeightingFunction },
935 { CubicBC, 2.0, 1.105822933719019,
936 0.2620145123990142, 0.3689927438004929, CubicBCWeightingFunction },
937 { Cosine, 1.0, 1.0, 0.0, 0.0, CosineWeightingFunction },
938 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
939 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
940 { CubicSpline,2.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
941 { MagicKernelSharp2013, 2.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
942 { MagicKernelSharp2021, 4.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
979 assert(image != (
const Image *) NULL);
980 assert(image->signature == MagickCoreSignature);
981 assert(UndefinedFilter < filter && filter < SentinelFilter);
983 assert(exception->signature == MagickCoreSignature);
984 if (IsEventLogging() != MagickFalse)
985 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
987 resize_filter=(
ResizeFilter *) AcquireCriticalMemory(
sizeof(*resize_filter));
988 (void) memset(resize_filter,0,
sizeof(*resize_filter));
992 filter_type=mapping[filter].filter;
993 window_type=mapping[filter].window;
994 resize_filter->blur=1.0;
996 if ((cylindrical != MagickFalse) && (filter_type == SincFastFilter) &&
997 (filter != SincFastFilter))
998 filter_type=JincFilter;
1001 artifact=GetImageArtifact(image,
"filter:filter");
1002 if (IsStringTrue(artifact) != MagickFalse)
1007 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1008 if ((UndefinedFilter < option) && (option < SentinelFilter))
1010 filter_type=(FilterType) option;
1011 window_type=BoxFilter;
1014 artifact=GetImageArtifact(image,
"filter:window");
1015 if (artifact != (
const char *) NULL)
1017 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1018 if ((UndefinedFilter < option) && (option < SentinelFilter))
1019 window_type=(FilterType) option;
1025 artifact=GetImageArtifact(image,
"filter:window");
1026 if (artifact != (
const char *) NULL)
1031 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1032 if ((UndefinedFilter < option) && (option < SentinelFilter))
1034 filter_type= cylindrical != MagickFalse ? JincFilter
1036 window_type=(FilterType) option;
1042 resize_filter->filter=filters[filter_type].function;
1043 resize_filter->support=filters[filter_type].support;
1044 resize_filter->filterWeightingType=filters[filter_type].weightingFunctionType;
1045 resize_filter->window=filters[window_type].function;
1046 resize_filter->windowWeightingType=filters[window_type].weightingFunctionType;
1047 resize_filter->scale=filters[window_type].scale;
1048 resize_filter->signature=MagickCoreSignature;
1051 if (cylindrical != MagickFalse)
1052 switch (filter_type)
1056 resize_filter->support=(double) MagickSQ1_2;
1059 case LanczosSharpFilter:
1060 case Lanczos2Filter:
1061 case Lanczos2SharpFilter:
1062 case LanczosRadiusFilter:
1063 resize_filter->filter=filters[JincFilter].function;
1064 resize_filter->window=filters[JincFilter].function;
1065 resize_filter->scale=filters[JincFilter].scale;
1072 switch (filter_type)
1074 case LanczosSharpFilter:
1075 resize_filter->blur *= 0.9812505644269356;
1077 case Lanczos2SharpFilter:
1078 resize_filter->blur *= 0.9549963639785485;
1090 if ((resize_filter->filter == Gaussian) ||
1091 (resize_filter->window == Gaussian) ) {
1093 artifact=GetImageArtifact(image,
"filter:sigma");
1094 if (artifact != (
const char *) NULL)
1095 value=StringToDouble(artifact,(
char **) NULL);
1097 resize_filter->coefficient[0]=value;
1098 resize_filter->coefficient[1]=PerceptibleReciprocal(2.0*value*value);
1099 resize_filter->coefficient[2]=PerceptibleReciprocal(Magick2PI*value*value);
1102 resize_filter->support *= 2*value;
1106 if ((resize_filter->filter == Kaiser) ||
1107 (resize_filter->window == Kaiser) ) {
1109 artifact=GetImageArtifact(image,
"filter:alpha");
1110 if (artifact != (
const char *) NULL)
1111 value=StringToDouble(artifact,(
char **) NULL);
1112 artifact=GetImageArtifact(image,
"filter:kaiser-beta");
1113 if (artifact != (
const char *) NULL)
1114 value=StringToDouble(artifact,(
char **) NULL);
1115 artifact=GetImageArtifact(image,
"filter:kaiser-alpha");
1116 if (artifact != (
const char *) NULL)
1117 value=StringToDouble(artifact,(
char **) NULL)*MagickPI;
1119 resize_filter->coefficient[0]=value;
1120 resize_filter->coefficient[1]=PerceptibleReciprocal(I0(value));
1125 artifact=GetImageArtifact(image,
"filter:lobes");
1126 if (artifact != (
const char *) NULL)
1131 lobes=(ssize_t) StringToLong(artifact);
1134 resize_filter->support=(double) lobes;
1136 if (resize_filter->filter == Jinc)
1141 if (resize_filter->support > 16)
1142 resize_filter->support=jinc_zeros[15];
1144 resize_filter->support=jinc_zeros[((long) resize_filter->support)-1];
1148 if (filter_type == LanczosRadiusFilter)
1149 resize_filter->blur*=floor(resize_filter->support)/
1150 resize_filter->support;
1155 artifact=GetImageArtifact(image,
"filter:blur");
1156 if (artifact != (
const char *) NULL)
1157 resize_filter->blur*=StringToDouble(artifact,(
char **) NULL);
1158 if (resize_filter->blur < MagickEpsilon)
1159 resize_filter->blur=(double) MagickEpsilon;
1163 artifact=GetImageArtifact(image,
"filter:support");
1164 if (artifact != (
const char *) NULL)
1165 resize_filter->support=fabs(StringToDouble(artifact,(
char **) NULL));
1170 resize_filter->window_support=resize_filter->support;
1171 artifact=GetImageArtifact(image,
"filter:win-support");
1172 if (artifact != (
const char *) NULL)
1173 resize_filter->window_support=fabs(StringToDouble(artifact,(
char **) NULL));
1178 resize_filter->scale*=PerceptibleReciprocal(resize_filter->window_support);
1184 if ((resize_filter->filter == CubicBC) ||
1185 (resize_filter->window == CubicBC) )
1187 B=filters[filter_type].B;
1188 C=filters[filter_type].C;
1189 if (filters[window_type].function == CubicBC)
1191 B=filters[window_type].B;
1192 C=filters[window_type].C;
1194 artifact=GetImageArtifact(image,
"filter:b");
1195 if (artifact != (
const char *) NULL)
1197 B=StringToDouble(artifact,(
char **) NULL);
1199 artifact=GetImageArtifact(image,
"filter:c");
1200 if (artifact != (
const char *) NULL)
1201 C=StringToDouble(artifact,(
char **) NULL);
1205 artifact=GetImageArtifact(image,
"filter:c");
1206 if (artifact != (
const char *) NULL)
1208 C=StringToDouble(artifact,(
char **) NULL);
1219 resize_filter->coefficient[0]=1.0-(1.0/3.0)*B;
1220 resize_filter->coefficient[1]=-3.0+twoB+C;
1221 resize_filter->coefficient[2]=2.0-1.5*B-C;
1222 resize_filter->coefficient[3]=(4.0/3.0)*B+4.0*C;
1223 resize_filter->coefficient[4]=-8.0*C-twoB;
1224 resize_filter->coefficient[5]=B+5.0*C;
1225 resize_filter->coefficient[6]=(-1.0/6.0)*B-C;
1232 if (IsStringTrue(GetImageArtifact(image,
"filter:verbose")) != MagickFalse)
1233#if defined(MAGICKCORE_OPENMP_SUPPORT)
1247 if (resize_filter->filter == Box) filter_type=BoxFilter;
1248 if (resize_filter->filter == Sinc) filter_type=SincFilter;
1249 if (resize_filter->filter == SincFast) filter_type=SincFastFilter;
1250 if (resize_filter->filter == Jinc) filter_type=JincFilter;
1251 if (resize_filter->filter == CubicBC) filter_type=CubicFilter;
1252 if (resize_filter->window == Box) window_type=BoxFilter;
1253 if (resize_filter->window == Sinc) window_type=SincFilter;
1254 if (resize_filter->window == SincFast) window_type=SincFastFilter;
1255 if (resize_filter->window == Jinc) window_type=JincFilter;
1256 if (resize_filter->window == CubicBC) window_type=CubicFilter;
1260 support=GetResizeFilterSupport(resize_filter);
1261 (void) FormatLocaleFile(stdout,
"# Resampling Filter (for graphing)\n#\n");
1262 (void) FormatLocaleFile(stdout,
"# filter = %s\n",
1263 CommandOptionToMnemonic(MagickFilterOptions,filter_type));
1264 (void) FormatLocaleFile(stdout,
"# window = %s\n",
1265 CommandOptionToMnemonic(MagickFilterOptions,window_type));
1266 (void) FormatLocaleFile(stdout,
"# support = %.*g\n",
1267 GetMagickPrecision(),(double) resize_filter->support);
1268 (void) FormatLocaleFile(stdout,
"# window-support = %.*g\n",
1269 GetMagickPrecision(),(double) resize_filter->window_support);
1270 (void) FormatLocaleFile(stdout,
"# scale-blur = %.*g\n",
1271 GetMagickPrecision(),(double) resize_filter->blur);
1272 if ((filter_type == GaussianFilter) || (window_type == GaussianFilter))
1273 (void) FormatLocaleFile(stdout,
"# gaussian-sigma = %.*g\n",
1274 GetMagickPrecision(),(double) resize_filter->coefficient[0]);
1275 if ((filter_type == KaiserFilter) || (window_type == KaiserFilter))
1276 (void) FormatLocaleFile(stdout,
"# kaiser-beta = %.*g\n",
1277 GetMagickPrecision(),(double) resize_filter->coefficient[0]);
1278 (void) FormatLocaleFile(stdout,
"# practical-support = %.*g\n",
1279 GetMagickPrecision(), (double) support);
1280 if ((filter_type == CubicFilter) || (window_type == CubicFilter))
1281 (void) FormatLocaleFile(stdout,
"# B,C = %.*g,%.*g\n",
1282 GetMagickPrecision(),(double) B,GetMagickPrecision(),(double) C);
1283 (void) FormatLocaleFile(stdout,
"\n");
1287 for (x=0.0; x <= support; x+=0.01)
1288 (
void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",x,GetMagickPrecision(),
1289 (
double) GetResizeFilterWeight(resize_filter,x));
1293 (void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",support,
1294 GetMagickPrecision(),0.0);
1296 (void) DeleteImageArtifact((
Image *) image,
"filter:verbose");
1298 return(resize_filter);
1335MagickExport
Image *AdaptiveResizeImage(
const Image *image,
1336 const size_t columns,
const size_t rows,
ExceptionInfo *exception)
1341 resize_image=InterpolativeResizeImage(image,columns,rows,MeshInterpolatePixel,
1343 return(resize_image);
1386static double I0(
double x)
1402 for (i=2; t > MagickEpsilon; i++)
1405 t*=y/((double) i*i);
1411static double J1(
double x)
1423 0.581199354001606143928050809e+21,
1424 -0.6672106568924916298020941484e+20,
1425 0.2316433580634002297931815435e+19,
1426 -0.3588817569910106050743641413e+17,
1427 0.2908795263834775409737601689e+15,
1428 -0.1322983480332126453125473247e+13,
1429 0.3413234182301700539091292655e+10,
1430 -0.4695753530642995859767162166e+7,
1431 0.270112271089232341485679099e+4
1435 0.11623987080032122878585294e+22,
1436 0.1185770712190320999837113348e+20,
1437 0.6092061398917521746105196863e+17,
1438 0.2081661221307607351240184229e+15,
1439 0.5243710262167649715406728642e+12,
1440 0.1013863514358673989967045588e+10,
1441 0.1501793594998585505921097578e+7,
1442 0.1606931573481487801970916749e+4,
1448 for (i=7; i >= 0; i--)
1457static double P1(
double x)
1469 0.352246649133679798341724373e+5,
1470 0.62758845247161281269005675e+5,
1471 0.313539631109159574238669888e+5,
1472 0.49854832060594338434500455e+4,
1473 0.2111529182853962382105718e+3,
1474 0.12571716929145341558495e+1
1478 0.352246649133679798068390431e+5,
1479 0.626943469593560511888833731e+5,
1480 0.312404063819041039923015703e+5,
1481 0.4930396490181088979386097e+4,
1482 0.2030775189134759322293574e+3,
1488 for (i=4; i >= 0; i--)
1490 p=p*(8.0/x)*(8.0/x)+Pone[i];
1491 q=q*(8.0/x)*(8.0/x)+Qone[i];
1497static double Q1(
double x)
1509 0.3511751914303552822533318e+3,
1510 0.7210391804904475039280863e+3,
1511 0.4259873011654442389886993e+3,
1512 0.831898957673850827325226e+2,
1513 0.45681716295512267064405e+1,
1514 0.3532840052740123642735e-1
1518 0.74917374171809127714519505e+4,
1519 0.154141773392650970499848051e+5,
1520 0.91522317015169922705904727e+4,
1521 0.18111867005523513506724158e+4,
1522 0.1038187585462133728776636e+3,
1528 for (i=4; i >= 0; i--)
1530 p=p*(8.0/x)*(8.0/x)+Pone[i];
1531 q=q*(8.0/x)*(8.0/x)+Qone[i];
1536static double BesselOrderOne(
double x)
1549 q=sqrt((
double) (2.0/(MagickPI*x)))*(P1(x)*(1.0/sqrt(2.0)*(sin(x)-
1550 cos(x)))-8.0/x*Q1(x)*(-1.0/sqrt(2.0)*(sin(x)+cos(x))));
1581 assert(resize_filter->signature == MagickCoreSignature);
1582 resize_filter->signature=(~MagickCoreSignature);
1583 resize_filter=(
ResizeFilter *) RelinquishMagickMemory(resize_filter);
1584 return(resize_filter);
1611MagickPrivate
double *GetResizeFilterCoefficient(
1615 assert(resize_filter->signature == MagickCoreSignature);
1616 return((
double *) resize_filter->coefficient);
1619MagickPrivate
double GetResizeFilterBlur(
const ResizeFilter *resize_filter)
1622 assert(resize_filter->signature == MagickCoreSignature);
1623 return(resize_filter->blur);
1626MagickPrivate
double GetResizeFilterScale(
const ResizeFilter *resize_filter)
1629 assert(resize_filter->signature == MagickCoreSignature);
1630 return(resize_filter->scale);
1633MagickPrivate
double GetResizeFilterWindowSupport(
1637 assert(resize_filter->signature == MagickCoreSignature);
1638 return(resize_filter->window_support);
1641MagickPrivate ResizeWeightingFunctionType GetResizeFilterWeightingType(
1645 assert(resize_filter->signature == MagickCoreSignature);
1646 return(resize_filter->filterWeightingType);
1649MagickPrivate ResizeWeightingFunctionType GetResizeFilterWindowWeightingType(
1653 assert(resize_filter->signature == MagickCoreSignature);
1654 return(resize_filter->windowWeightingType);
1657MagickPrivate
double GetResizeFilterSupport(
const ResizeFilter *resize_filter)
1660 assert(resize_filter->signature == MagickCoreSignature);
1661 return(resize_filter->support*resize_filter->blur);
1691MagickPrivate
double GetResizeFilterWeight(
const ResizeFilter *resize_filter,
1703 assert(resize_filter->signature == MagickCoreSignature);
1704 x_blur=fabs((
double) x)*PerceptibleReciprocal(resize_filter->blur);
1705 if ((resize_filter->window_support < MagickEpsilon) ||
1706 (resize_filter->window == Box))
1710 scale=resize_filter->scale;
1711 scale=resize_filter->window(x_blur*scale,resize_filter);
1713 weight=scale*resize_filter->filter(x_blur,resize_filter);
1750MagickExport
Image *InterpolativeResizeImage(
const Image *image,
1751 const size_t columns,
const size_t rows,
const PixelInterpolateMethod method,
1754#define InterpolativeResizeImageTag "Resize/Image"
1778 assert(image != (
const Image *) NULL);
1779 assert(image->signature == MagickCoreSignature);
1781 assert(exception->signature == MagickCoreSignature);
1782 if (IsEventLogging() != MagickFalse)
1783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1784 if ((columns == 0) || (rows == 0))
1785 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1786 if ((columns == image->columns) && (rows == image->rows))
1787 return(CloneImage(image,0,0,MagickTrue,exception));
1788 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
1789 if (resize_image == (
Image *) NULL)
1790 return((
Image *) NULL);
1791 if (SetImageStorageClass(resize_image,DirectClass,exception) == MagickFalse)
1793 resize_image=DestroyImage(resize_image);
1794 return((
Image *) NULL);
1798 image_view=AcquireVirtualCacheView(image,exception);
1799 resize_view=AcquireAuthenticCacheView(resize_image,exception);
1800 scale.x=(double) image->columns/resize_image->columns;
1801 scale.y=(double) image->rows/resize_image->rows;
1802#if defined(MAGICKCORE_OPENMP_SUPPORT)
1803 #pragma omp parallel for schedule(static) shared(progress,status) \
1804 magick_number_threads(image,resize_image,resize_image->rows,1)
1806 for (y=0; y < (ssize_t) resize_image->rows; y++)
1817 if (status == MagickFalse)
1819 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
1821 if (q == (Quantum *) NULL)
1823 offset.y=((double) y+0.5)*scale.y-0.5;
1824 for (x=0; x < (ssize_t) resize_image->columns; x++)
1829 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1838 channel=GetPixelChannelChannel(image,i);
1839 traits=GetPixelChannelTraits(image,channel);
1840 resize_traits=GetPixelChannelTraits(resize_image,channel);
1841 if ((traits == UndefinedPixelTrait) ||
1842 (resize_traits == UndefinedPixelTrait))
1844 offset.x=((double) x+0.5)*scale.x-0.5;
1845 status=InterpolatePixelChannels(image,image_view,resize_image,method,
1846 offset.x,offset.y,q,exception);
1847 if (status == MagickFalse)
1850 q+=(ptrdiff_t) GetPixelChannels(resize_image);
1852 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
1854 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1859#if defined(MAGICKCORE_OPENMP_SUPPORT)
1863 proceed=SetImageProgress(image,InterpolativeResizeImageTag,progress,
1865 if (proceed == MagickFalse)
1869 resize_view=DestroyCacheView(resize_view);
1870 image_view=DestroyCacheView(image_view);
1871 if (status == MagickFalse)
1872 resize_image=DestroyImage(resize_image);
1873 return(resize_image);
1875#if defined(MAGICKCORE_LQR_DELEGATE)
1911MagickExport
Image *LiquidRescaleImage(
const Image *image,
const size_t columns,
1912 const size_t rows,
const double delta_x,
const double rigidity,
1915#define LiquidRescaleImageTag "Rescale/Image"
1953 assert(image != (
const Image *) NULL);
1954 assert(image->signature == MagickCoreSignature);
1956 assert(exception->signature == MagickCoreSignature);
1957 if (IsEventLogging() != MagickFalse)
1958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1959 if ((columns == 0) || (rows == 0))
1960 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1961 if ((columns == image->columns) && (rows == image->rows))
1962 return(CloneImage(image,0,0,MagickTrue,exception));
1963 if ((columns <= 2) || (rows <= 2))
1964 return(ResizeImage(image,columns,rows,image->filter,exception));
1965 pixel_info=AcquireVirtualMemory(image->columns,image->rows*MaxPixelChannels*
1968 return((
Image *) NULL);
1969 pixels=(gfloat *) GetVirtualMemoryBlob(pixel_info);
1972 image_view=AcquireVirtualCacheView(image,exception);
1973 for (y=0; y < (ssize_t) image->rows; y++)
1981 if (status == MagickFalse)
1983 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1984 if (p == (
const Quantum *) NULL)
1989 for (x=0; x < (ssize_t) image->columns; x++)
1994 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1995 *q++=QuantumScale*(
double) p[i];
1996 p+=(ptrdiff_t) GetPixelChannels(image);
1999 image_view=DestroyCacheView(image_view);
2000 carver=lqr_carver_new_ext(pixels,(
int) image->columns,(
int) image->rows,
2001 (
int) GetPixelChannels(image),LQR_COLDEPTH_32F);
2002 if (carver == (LqrCarver *) NULL)
2004 pixel_info=RelinquishVirtualMemory(pixel_info);
2005 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2007 lqr_carver_set_preserve_input_image(carver);
2008 lqr_status=lqr_carver_init(carver,(
int) delta_x,rigidity);
2009 lqr_status=lqr_carver_resize(carver,(
int) columns,(
int) rows);
2011 rescale_image=CloneImage(image,(
size_t) lqr_carver_get_width(carver),
2012 (
size_t) lqr_carver_get_height(carver),MagickTrue,exception);
2013 if (rescale_image == (
Image *) NULL)
2015 pixel_info=RelinquishVirtualMemory(pixel_info);
2016 return((
Image *) NULL);
2018 if (SetImageStorageClass(rescale_image,DirectClass,exception) == MagickFalse)
2020 pixel_info=RelinquishVirtualMemory(pixel_info);
2021 rescale_image=DestroyImage(rescale_image);
2022 return((
Image *) NULL);
2024 rescale_view=AcquireAuthenticCacheView(rescale_image,exception);
2025 (void) lqr_carver_scan_reset(carver);
2026 while (lqr_carver_scan_ext(carver,&x_offset,&y_offset,(
void **) &packet) != 0)
2034 p=QueueCacheViewAuthenticPixels(rescale_view,x_offset,y_offset,1,1,
2036 if (p == (Quantum *) NULL)
2038 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2047 channel=GetPixelChannelChannel(image,i);
2048 traits=GetPixelChannelTraits(image,channel);
2049 rescale_traits=GetPixelChannelTraits(rescale_image,channel);
2050 if ((traits == UndefinedPixelTrait) ||
2051 (rescale_traits == UndefinedPixelTrait))
2053 SetPixelChannel(rescale_image,channel,ClampToQuantum(QuantumRange*
2056 if (SyncCacheViewAuthenticPixels(rescale_view,exception) == MagickFalse)
2059 rescale_view=DestroyCacheView(rescale_view);
2060 pixel_info=RelinquishVirtualMemory(pixel_info);
2061 lqr_carver_destroy(carver);
2062 return(rescale_image);
2065MagickExport
Image *LiquidRescaleImage(
const Image *image,
2066 const size_t magick_unused(columns),
const size_t magick_unused(rows),
2067 const double magick_unused(delta_x),
const double magick_unused(rigidity),
2070 assert(image != (
const Image *) NULL);
2071 assert(image->signature == MagickCoreSignature);
2073 assert(exception->signature == MagickCoreSignature);
2074 magick_unreferenced(columns);
2075 magick_unreferenced(rows);
2076 magick_unreferenced(delta_x);
2077 magick_unreferenced(rigidity);
2078 if (IsEventLogging() != MagickFalse)
2079 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2080 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
2081 "DelegateLibrarySupportNotBuiltIn",
"'%s' (LQR)",image->filename);
2082 return((
Image *) NULL);
2112static inline void CopyPixels(
const Quantum *source,
const ssize_t source_offset,
2113 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2118 for (i=0; i < (ssize_t) channels; i++)
2119 destination[(ssize_t) channels*destination_offset+i]=
2120 source[source_offset*(ssize_t) channels+i];
2123static inline void MixPixels(
const Quantum *source,
const ssize_t *source_offset,
2124 const size_t source_size,Quantum *destination,
2125 const ssize_t destination_offset,
const size_t channels)
2130 for (i=0; i < (ssize_t) channels; i++)
2136 for (j=0; j < (ssize_t) source_size; j++)
2137 sum+=source[source_offset[j]*(ssize_t) channels+i];
2138 destination[(ssize_t) channels*destination_offset+i]=(Quantum) (sum/
2139 (ssize_t) source_size);
2143static inline void Mix2Pixels(
const Quantum *source,
2144 const ssize_t source_offset1,
const ssize_t source_offset2,
2145 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2148 offsets[2] = { source_offset1, source_offset2 };
2150 MixPixels(source,offsets,2,destination,destination_offset,channels);
2153static inline int PixelsEqual(
const Quantum *source1,ssize_t offset1,
2154 const Quantum *source2,ssize_t offset2,
const size_t channels)
2159 offset1*=(ssize_t) channels;
2160 offset2*=(ssize_t) channels;
2161 for (i=0; i < (ssize_t) channels; i++)
2162 if (source1[offset1+i] != source2[offset2+i])
2167static inline void Eagle2X(
const Image *source,
const Quantum *pixels,
2168 Quantum *result,
const size_t channels)
2174 for (i=0; i < 4; i++)
2175 CopyPixels(pixels,4,result,i,channels);
2176 if (PixelsEqual(pixels,0,pixels,1,channels) &&
2177 PixelsEqual(pixels,1,pixels,3,channels))
2178 CopyPixels(pixels,0,result,0,channels);
2179 if (PixelsEqual(pixels,1,pixels,2,channels) &&
2180 PixelsEqual(pixels,2,pixels,5,channels))
2181 CopyPixels(pixels,2,result,1,channels);
2182 if (PixelsEqual(pixels,3,pixels,6,channels) &&
2183 PixelsEqual(pixels,6,pixels,7,channels))
2184 CopyPixels(pixels,6,result,2,channels);
2185 if (PixelsEqual(pixels,5,pixels,8,channels) &&
2186 PixelsEqual(pixels,8,pixels,7,channels))
2187 CopyPixels(pixels,8,result,3,channels);
2190static void Hq2XHelper(
const unsigned int rule,
const Quantum *source,
2191 Quantum *destination,
const ssize_t destination_offset,
const size_t channels,
2192 const ssize_t e,
const ssize_t a,
const ssize_t b,
const ssize_t d,
2193 const ssize_t f,
const ssize_t h)
2195#define caseA(N,A,B,C,D) \
2199 offsets[4] = { A, B, C, D }; \
2201 MixPixels(source,offsets,4,destination,destination_offset,channels);\
2204#define caseB(N,A,B,C,D,E,F,G,H) \
2208 offsets[8] = { A, B, C, D, E, F, G, H }; \
2210 MixPixels(source,offsets,8,destination,destination_offset,channels);\
2218 CopyPixels(source,e,destination,destination_offset,channels);
2227 caseB(7,e,e,e,e,e,b,b,d)
2228 caseB(8,e,e,e,e,e,d,d,b)
2229 caseB(9,e,e,e,e,e,e,d,b)
2230 caseB(10,e,e,d,d,d,b,b,b)
2234 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2236 MixPixels(source,offsets,16,destination,destination_offset,channels);
2241 if (PixelsEqual(source,b,source,d,channels))
2244 offsets[4] = { e, e, d, b };
2246 MixPixels(source,offsets,4,destination,destination_offset,channels);
2249 CopyPixels(source,e,destination,destination_offset,channels);
2254 if (PixelsEqual(source,b,source,d,channels))
2257 offsets[8] = { e, e, d, d, d, b, b, b };
2259 MixPixels(source,offsets,8,destination,destination_offset,channels);
2262 CopyPixels(source,e,destination,destination_offset,channels);
2267 if (PixelsEqual(source,b,source,d,channels))
2270 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2272 MixPixels(source,offsets,16,destination,destination_offset,channels);
2275 CopyPixels(source,e,destination,destination_offset,channels);
2280 if (PixelsEqual(source,b,source,d,channels))
2283 offsets[4] = { e, e, d, b };
2285 MixPixels(source,offsets,4,destination,destination_offset,channels);
2290 offsets[4] = { e, e, e, a };
2292 MixPixels(source,offsets,4,destination,destination_offset,channels);
2298 if (PixelsEqual(source,b,source,d,channels))
2301 offsets[8] = { e, e, e, e, e, e, d, b };
2303 MixPixels(source,offsets,8,destination,destination_offset,channels);
2308 offsets[4] = { e, e, e, a };
2310 MixPixels(source,offsets,4,destination,destination_offset,channels);
2316 if (PixelsEqual(source,b,source,d,channels))
2319 offsets[8] = { e, e, d, d, d, b, b, b };
2321 MixPixels(source,offsets,8,destination,destination_offset,channels);
2326 offsets[4] = { e, e, e, a };
2328 MixPixels(source,offsets,4,destination,destination_offset,channels);
2334 if (PixelsEqual(source,b,source,f,channels))
2337 offsets[8] = { e, e, e, e, e, b, b, d };
2339 MixPixels(source,offsets,8,destination,destination_offset,channels);
2344 offsets[4] = { e, e, e, d };
2346 MixPixels(source,offsets,4,destination,destination_offset,channels);
2352 if (PixelsEqual(source,d,source,h,channels))
2355 offsets[8] = { e, e, e, e, e, d, d, b };
2357 MixPixels(source,offsets,8,destination,destination_offset,channels);
2362 offsets[4] = { e, e, e, b };
2364 MixPixels(source,offsets,4,destination,destination_offset,channels);
2373static inline unsigned int Hq2XPatternToNumber(
const int *pattern)
2384 for (i=7; i >= 0; i--)
2386 result+=order*(
unsigned int) pattern[i];
2392static inline void Hq2X(
const Image *source,
const Quantum *pixels,
2393 Quantum *result,
const size_t channels)
2395 static const unsigned int
2398 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2399 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
2400 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2401 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
2402 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
2403 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2404 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
2405 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
2406 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2407 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2408 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2409 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
2410 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
2411 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
2412 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
2413 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14
2419 !PixelsEqual(pixels,4,pixels,8,channels),
2420 !PixelsEqual(pixels,4,pixels,7,channels),
2421 !PixelsEqual(pixels,4,pixels,6,channels),
2422 !PixelsEqual(pixels,4,pixels,5,channels),
2423 !PixelsEqual(pixels,4,pixels,3,channels),
2424 !PixelsEqual(pixels,4,pixels,2,channels),
2425 !PixelsEqual(pixels,4,pixels,1,channels),
2426 !PixelsEqual(pixels,4,pixels,0,channels)
2429#define Rotated(p) p[2], p[4], p[7], p[1], p[6], p[0], p[3], p[5]
2430 const int pattern2[] = { Rotated(pattern1) };
2431 const int pattern3[] = { Rotated(pattern2) };
2432 const int pattern4[] = { Rotated(pattern3) };
2435 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern1)],pixels,result,0,
2436 channels,4,0,1,3,5,7);
2437 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern2)],pixels,result,1,
2438 channels,4,2,5,1,7,3);
2439 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern3)],pixels,result,3,
2440 channels,4,8,7,5,3,1);
2441 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern4)],pixels,result,2,
2442 channels,4,6,3,7,1,5);
2445static void Fish2X(
const Image *source,
const Quantum *pixels,Quantum *result,
2446 const size_t channels)
2448#define Corner(A,B,C,D) \
2450 if (intensities[B] > intensities[A]) \
2453 offsets[3] = { B, C, D }; \
2455 MixPixels(pixels,offsets,3,result,3,channels); \
2460 offsets[3] = { A, B, C }; \
2462 MixPixels(pixels,offsets,3,result,3,channels); \
2466#define Line(A,B,C,D) \
2468 if (intensities[C] > intensities[A]) \
2469 Mix2Pixels(pixels,C,D,result,3,channels); \
2471 Mix2Pixels(pixels,A,B,result,3,channels); \
2475 pixels_offsets[4] = { 0, 1, 3, 4 };
2491 for (i=0; i < 9; i++)
2492 intensities[i]=GetPixelIntensity(source,pixels+i*(ssize_t) channels);
2493 CopyPixels(pixels,0,result,0,channels);
2494 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[1] ? 0 : 1),result,
2496 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[3] ? 0 : 3),result,
2498 ae=PixelsEqual(pixels,0,pixels,4,channels);
2499 bd=PixelsEqual(pixels,1,pixels,3,channels);
2500 ab=PixelsEqual(pixels,0,pixels,1,channels);
2501 de=PixelsEqual(pixels,3,pixels,4,channels);
2502 ad=PixelsEqual(pixels,0,pixels,3,channels);
2503 be=PixelsEqual(pixels,1,pixels,4,channels);
2506 CopyPixels(pixels,0,result,3,channels);
2509 if (ad && de && !ab)
2514 if (be && de && !ab)
2519 if (ad && ab && !be)
2524 if (ab && be && !ad)
2529 if (ae && (!bd || intensities[1] > intensities[0]))
2531 Mix2Pixels(pixels,0,4,result,3,channels);
2534 if (bd && (!ae || intensities[0] > intensities[1]))
2536 Mix2Pixels(pixels,1,3,result,3,channels);
2559 MixPixels(pixels,pixels_offsets,4,result,3,channels);
2564static void Xbr2X(
const Image *magick_unused(source),
const Quantum *pixels,
2565 Quantum *result,
const size_t channels)
2567#define WeightVar(M,N) const int w_##M##_##N = \
2568 PixelsEqual(pixels,M,pixels,N,channels) ? 0 : 1;
2600 magick_unreferenced(source);
2603 w_12_16 + w_12_8 + w_6_10 + w_6_2 + (4 * w_11_7) <
2604 w_11_17 + w_11_5 + w_7_13 + w_7_1 + (4 * w_12_6)
2606 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_7 ? 11 : 7),12,result,0,
2609 CopyPixels(pixels,12,result,0,channels);
2611 w_12_18 + w_12_6 + w_8_14 + w_8_2 + (4 * w_7_13) <
2612 w_13_17 + w_13_9 + w_11_7 + w_7_3 + (4 * w_12_8)
2614 Mix2Pixels(pixels,(ssize_t) (w_12_7 <= w_12_13 ? 7 : 13),12,result,1,
2617 CopyPixels(pixels,12,result,1,channels);
2619 w_12_6 + w_12_18 + w_16_10 + w_16_22 + (4 * w_11_17) <
2620 w_11_7 + w_11_15 + w_13_17 + w_17_21 + (4 * w_12_16)
2622 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_17 ? 11 : 17),12,result,2,
2625 CopyPixels(pixels,12,result,2,channels);
2627 w_12_8 + w_12_16 + w_18_14 + w_18_22 + (4 * w_13_17) <
2628 w_11_17 + w_17_23 + w_17_19 + w_7_13 + (4 * w_12_18)
2630 Mix2Pixels(pixels,(ssize_t) (w_12_13 <= w_12_17 ? 13 : 17),12,result,3,
2633 CopyPixels(pixels,12,result,3,channels);
2636static void Scale2X(
const Image *magick_unused(source),
const Quantum *pixels,
2637 Quantum *result,
const size_t channels)
2639 magick_unreferenced(source);
2641 if (PixelsEqual(pixels,1,pixels,7,channels) ||
2642 PixelsEqual(pixels,3,pixels,5,channels))
2647 for (i=0; i < 4; i++)
2648 CopyPixels(pixels,4,result,i,channels);
2651 if (PixelsEqual(pixels,1,pixels,3,channels))
2652 CopyPixels(pixels,3,result,0,channels);
2654 CopyPixels(pixels,4,result,0,channels);
2655 if (PixelsEqual(pixels,1,pixels,5,channels))
2656 CopyPixels(pixels,5,result,1,channels);
2658 CopyPixels(pixels,4,result,1,channels);
2659 if (PixelsEqual(pixels,3,pixels,7,channels))
2660 CopyPixels(pixels,3,result,2,channels);
2662 CopyPixels(pixels,4,result,2,channels);
2663 if (PixelsEqual(pixels,5,pixels,7,channels))
2664 CopyPixels(pixels,5,result,3,channels);
2666 CopyPixels(pixels,4,result,3,channels);
2669static void Epbx2X(
const Image *magick_unused(source),
const Quantum *pixels,
2670 Quantum *result,
const size_t channels)
2672#define HelperCond(a,b,c,d,e,f,g) ( \
2673 PixelsEqual(pixels,a,pixels,b,channels) && ( \
2674 PixelsEqual(pixels,c,pixels,d,channels) || \
2675 PixelsEqual(pixels,c,pixels,e,channels) || \
2676 PixelsEqual(pixels,a,pixels,f,channels) || \
2677 PixelsEqual(pixels,b,pixels,g,channels) \
2684 magick_unreferenced(source);
2686 for (i=0; i < 4; i++)
2687 CopyPixels(pixels,4,result,i,channels);
2689 !PixelsEqual(pixels,3,pixels,5,channels) &&
2690 !PixelsEqual(pixels,1,pixels,7,channels) &&
2692 PixelsEqual(pixels,4,pixels,3,channels) ||
2693 PixelsEqual(pixels,4,pixels,7,channels) ||
2694 PixelsEqual(pixels,4,pixels,5,channels) ||
2695 PixelsEqual(pixels,4,pixels,1,channels) ||
2698 !PixelsEqual(pixels,0,pixels,8,channels) ||
2699 PixelsEqual(pixels,4,pixels,6,channels) ||
2700 PixelsEqual(pixels,3,pixels,2,channels)
2703 !PixelsEqual(pixels,6,pixels,2,channels) ||
2704 PixelsEqual(pixels,4,pixels,0,channels) ||
2705 PixelsEqual(pixels,4,pixels,8,channels)
2711 if (HelperCond(1,3,4,0,8,2,6))
2712 Mix2Pixels(pixels,1,3,result,0,channels);
2713 if (HelperCond(5,1,4,2,6,8,0))
2714 Mix2Pixels(pixels,5,1,result,1,channels);
2715 if (HelperCond(3,7,4,6,2,0,8))
2716 Mix2Pixels(pixels,3,7,result,2,channels);
2717 if (HelperCond(7,5,4,8,0,6,2))
2718 Mix2Pixels(pixels,7,5,result,3,channels);
2724static inline void Eagle3X(
const Image *magick_unused(source),
2725 const Quantum *pixels,Quantum *result,
const size_t channels)
2733 magick_unreferenced(source);
2735 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2736 PixelsEqual(pixels,0,pixels,3,channels);
2737 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2738 PixelsEqual(pixels,2,pixels,5,channels);
2739 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2740 PixelsEqual(pixels,6,pixels,7,channels);
2741 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2742 PixelsEqual(pixels,7,pixels,8,channels);
2743 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2744 if (corner_tl && corner_tr)
2745 Mix2Pixels(pixels,0,2,result,1,channels);
2747 CopyPixels(pixels,4,result,1,channels);
2748 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2749 if (corner_tl && corner_bl)
2750 Mix2Pixels(pixels,0,6,result,3,channels);
2752 CopyPixels(pixels,4,result,3,channels);
2753 CopyPixels(pixels,4,result,4,channels);
2754 if (corner_tr && corner_br)
2755 Mix2Pixels(pixels,2,8,result,5,channels);
2757 CopyPixels(pixels,4,result,5,channels);
2758 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2759 if (corner_bl && corner_br)
2760 Mix2Pixels(pixels,6,8,result,7,channels);
2762 CopyPixels(pixels,4,result,7,channels);
2763 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2766static inline void Eagle3XB(
const Image *magick_unused(source),
2767 const Quantum *pixels,Quantum *result,
const size_t channels)
2775 magick_unreferenced(source);
2777 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2778 PixelsEqual(pixels,0,pixels,3,channels);
2779 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2780 PixelsEqual(pixels,2,pixels,5,channels);
2781 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2782 PixelsEqual(pixels,6,pixels,7,channels);
2783 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2784 PixelsEqual(pixels,7,pixels,8,channels);
2785 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2786 CopyPixels(pixels,4,result,1,channels);
2787 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2788 CopyPixels(pixels,4,result,3,channels);
2789 CopyPixels(pixels,4,result,4,channels);
2790 CopyPixels(pixels,4,result,5,channels);
2791 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2792 CopyPixels(pixels,4,result,7,channels);
2793 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2796static inline void Scale3X(
const Image *magick_unused(source),
2797 const Quantum *pixels,Quantum *result,
const size_t channels)
2799 magick_unreferenced(source);
2801 if (!PixelsEqual(pixels,1,pixels,7,channels) &&
2802 !PixelsEqual(pixels,3,pixels,5,channels))
2804 if (PixelsEqual(pixels,3,pixels,1,channels))
2805 CopyPixels(pixels,3,result,0,channels);
2807 CopyPixels(pixels,4,result,0,channels);
2811 PixelsEqual(pixels,3,pixels,1,channels) &&
2812 !PixelsEqual(pixels,4,pixels,2,channels)
2815 PixelsEqual(pixels,5,pixels,1,channels) &&
2816 !PixelsEqual(pixels,4,pixels,0,channels)
2819 CopyPixels(pixels,1,result,1,channels);
2821 CopyPixels(pixels,4,result,1,channels);
2822 if (PixelsEqual(pixels,5,pixels,1,channels))
2823 CopyPixels(pixels,5,result,2,channels);
2825 CopyPixels(pixels,4,result,2,channels);
2828 PixelsEqual(pixels,3,pixels,1,channels) &&
2829 !PixelsEqual(pixels,4,pixels,6,channels)
2832 PixelsEqual(pixels,3,pixels,7,channels) &&
2833 !PixelsEqual(pixels,4,pixels,0,channels)
2836 CopyPixels(pixels,3,result,3,channels);
2838 CopyPixels(pixels,4,result,3,channels);
2839 CopyPixels(pixels,4,result,4,channels);
2842 PixelsEqual(pixels,5,pixels,1,channels) &&
2843 !PixelsEqual(pixels,4,pixels,8,channels)
2846 PixelsEqual(pixels,5,pixels,7,channels) &&
2847 !PixelsEqual(pixels,4,pixels,2,channels)
2850 CopyPixels(pixels,5,result,5,channels);
2852 CopyPixels(pixels,4,result,5,channels);
2853 if (PixelsEqual(pixels,3,pixels,7,channels))
2854 CopyPixels(pixels,3,result,6,channels);
2856 CopyPixels(pixels,4,result,6,channels);
2859 PixelsEqual(pixels,3,pixels,7,channels) &&
2860 !PixelsEqual(pixels,4,pixels,8,channels)
2863 PixelsEqual(pixels,5,pixels,7,channels) &&
2864 !PixelsEqual(pixels,4,pixels,6,channels)
2867 CopyPixels(pixels,7,result,7,channels);
2869 CopyPixels(pixels,4,result,7,channels);
2870 if (PixelsEqual(pixels,5,pixels,7,channels))
2871 CopyPixels(pixels,5,result,8,channels);
2873 CopyPixels(pixels,4,result,8,channels);
2880 for (i=0; i < 9; i++)
2881 CopyPixels(pixels,4,result,i,channels);
2887#define MagnifyImageTag "Magnify/Image"
2920 (*scaling_method)(
const Image *,
const Quantum *,Quantum *,size_t);
2925 assert(image != (
const Image *) NULL);
2926 assert(image->signature == MagickCoreSignature);
2928 assert(exception->signature == MagickCoreSignature);
2929 if (IsEventLogging() != MagickFalse)
2930 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2931 option=GetImageOption(image->image_info,
"magnify:method");
2932 if (option == (
char *) NULL)
2934 scaling_method=Scale2X;
2941 if (LocaleCompare(option,
"eagle2x") == 0)
2943 scaling_method=Eagle2X;
2948 if (LocaleCompare(option,
"eagle3x") == 0)
2950 scaling_method=Eagle3X;
2955 if (LocaleCompare(option,
"eagle3xb") == 0)
2957 scaling_method=Eagle3XB;
2962 if (LocaleCompare(option,
"epbx2x") == 0)
2964 scaling_method=Epbx2X;
2973 if (LocaleCompare(option,
"fish2x") == 0)
2975 scaling_method=Fish2X;
2984 if (LocaleCompare(option,
"hq2x") == 0)
2986 scaling_method=Hq2X;
2995 if (LocaleCompare(option,
"scale2x") == 0)
2997 scaling_method=Scale2X;
3002 if (LocaleCompare(option,
"scale3x") == 0)
3004 scaling_method=Scale3X;
3013 if (LocaleCompare(option,
"xbr2x") == 0)
3015 scaling_method=Xbr2X;
3027 source_image=CloneImage(image,image->columns,image->rows,MagickTrue,
3029 if (source_image == (
Image *) NULL)
3030 return((
Image *) NULL);
3035 rectangle.width=image->columns;
3036 rectangle.height=image->rows;
3037 (void) CopyImagePixels(source_image,image,&rectangle,&offset,exception);
3038 if (IssRGBCompatibleColorspace(source_image->colorspace) == MagickFalse)
3039 (
void) TransformImageColorspace(source_image,sRGBColorspace,exception);
3040 magnify_image=CloneImage(source_image,magnification*source_image->columns,
3041 magnification*source_image->rows,MagickTrue,exception);
3042 if (magnify_image == (
Image *) NULL)
3044 source_image=DestroyImage(source_image);
3045 return((
Image *) NULL);
3052 image_view=AcquireVirtualCacheView(source_image,exception);
3053 magnify_view=AcquireAuthenticCacheView(magnify_image,exception);
3054#if defined(MAGICKCORE_OPENMP_SUPPORT)
3055 #pragma omp parallel for schedule(static) shared(progress,status) \
3056 magick_number_threads(source_image,magnify_image,source_image->rows,1)
3058 for (y=0; y < (ssize_t) source_image->rows; y++)
3061 r[magnification*magnification*MaxPixelChannels];
3069 if (status == MagickFalse)
3071 q=QueueCacheViewAuthenticPixels(magnify_view,0,magnification*y,
3072 magnify_image->columns,magnification,exception);
3073 if (q == (Quantum *) NULL)
3081 for (x=0; x < (ssize_t) source_image->columns; x++)
3093 p=GetCacheViewVirtualPixels(image_view,x-width/2,y-width/2,width,width,
3095 if (p == (Quantum *) NULL)
3100 channels=GetPixelChannels(source_image);
3101 scaling_method(source_image,p,r,channels);
3105 for (j=0; j < (ssize_t) magnification; j++)
3106 for (i=0; i < (ssize_t) (channels*magnification); i++)
3107 q[j*(ssize_t) channels*(ssize_t) magnify_image->columns+i]=
3108 r[j*magnification*(ssize_t) channels+i];
3109 q+=(ptrdiff_t) magnification*GetPixelChannels(magnify_image);
3111 if (SyncCacheViewAuthenticPixels(magnify_view,exception) == MagickFalse)
3113 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3118#if defined(MAGICKCORE_OPENMP_SUPPORT)
3122 proceed=SetImageProgress(image,MagnifyImageTag,progress,image->rows);
3123 if (proceed == MagickFalse)
3127 magnify_view=DestroyCacheView(magnify_view);
3128 image_view=DestroyCacheView(image_view);
3129 source_image=DestroyImage(source_image);
3130 if (status == MagickFalse)
3131 magnify_image=DestroyImage(magnify_image);
3132 return(magnify_image);
3165 assert(image != (
Image *) NULL);
3166 assert(image->signature == MagickCoreSignature);
3168 assert(exception->signature == MagickCoreSignature);
3169 if (IsEventLogging() != MagickFalse)
3170 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3171 minify_image=ResizeImage(image,image->columns/2,image->rows/2,SplineFilter,
3173 return(minify_image);
3210MagickExport
Image *ResampleImage(
const Image *image,
const double x_resolution,
3211 const double y_resolution,
const FilterType filter,
ExceptionInfo *exception)
3213#define ResampleImageTag "Resample/Image"
3225 assert(image != (
const Image *) NULL);
3226 assert(image->signature == MagickCoreSignature);
3228 assert(exception->signature == MagickCoreSignature);
3229 if (IsEventLogging() != MagickFalse)
3230 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3231 width=(size_t) (x_resolution*image->columns/(image->resolution.x == 0.0 ?
3232 DefaultResolution : image->resolution.x)+0.5);
3233 height=(size_t) (y_resolution*image->rows/(image->resolution.y == 0.0 ?
3234 DefaultResolution : image->resolution.y)+0.5);
3235 resample_image=ResizeImage(image,width,height,filter,exception);
3236 if (resample_image != (
Image *) NULL)
3238 resample_image->resolution.x=x_resolution;
3239 resample_image->resolution.y=y_resolution;
3241 return(resample_image);
3299 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3304 return(contribution);
3318 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3320 sizeof(*contribution));
3323 (void) memset(contribution,0,number_threads*
sizeof(*contribution));
3324 for (i=0; i < (ssize_t) number_threads; i++)
3327 AcquireAlignedMemory(count,
sizeof(**contribution)));
3329 return(DestroyContributionTLS(contribution));
3331 return(contribution);
3334static MagickBooleanType HorizontalFilter(
3336 const Image *magick_restrict image,
Image *magick_restrict resize_image,
3337 const double x_factor,
const MagickSizeType span,
3338 MagickOffsetType *magick_restrict progress,
ExceptionInfo *exception)
3340#define ResizeImageTag "Resize/Image"
3350 **magick_restrict contributions;
3365 scale=MagickMax(1.0/x_factor+MagickEpsilon,1.0);
3366 support=scale*GetResizeFilterSupport(resize_filter);
3367 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3368 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3369 return(MagickFalse);
3375 support=(double) 0.5;
3378 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3381 (void) ThrowMagickException(exception,GetMagickModule(),
3382 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3383 return(MagickFalse);
3386 scale=PerceptibleReciprocal(scale);
3387 image_view=AcquireVirtualCacheView(image,exception);
3388 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3389#if defined(MAGICKCORE_OPENMP_SUPPORT)
3390 #pragma omp parallel for schedule(static) shared(progress,status) \
3391 magick_number_threads(image,resize_image,resize_image->columns,1)
3393 for (x=0; x < (ssize_t) resize_image->columns; x++)
3396 id = GetOpenMPThreadId();
3402 *magick_restrict contribution;
3417 if (status == MagickFalse)
3419 bisect=(double) (x+0.5)/x_factor+MagickEpsilon;
3420 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3421 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->columns);
3423 contribution=contributions[id];
3424 for (n=0; n < (stop-start); n++)
3426 contribution[n].pixel=start+n;
3427 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3428 ((
double) (start+n)-bisect+0.5));
3429 density+=contribution[n].weight;
3433 if ((density != 0.0) && (density != 1.0))
3441 density=PerceptibleReciprocal(density);
3442 for (i=0; i < n; i++)
3443 contribution[i].weight*=density;
3445 p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,(
size_t)
3446 (contribution[n-1].pixel-contribution[0].pixel+1),image->rows,exception);
3447 q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
3449 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3454 for (y=0; y < (ssize_t) resize_image->rows; y++)
3459 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3477 channel=GetPixelChannelChannel(image,i);
3478 traits=GetPixelChannelTraits(image,channel);
3479 resize_traits=GetPixelChannelTraits(resize_image,channel);
3480 if ((traits == UndefinedPixelTrait) ||
3481 (resize_traits == UndefinedPixelTrait))
3483 if (((resize_traits & CopyPixelTrait) != 0) ||
3484 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3486 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3488 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3489 (contribution[j-start].pixel-contribution[0].pixel);
3490 SetPixelChannel(resize_image,channel,
3491 p[k*(ssize_t) GetPixelChannels(image)+i],q);
3495 if ((resize_traits & BlendPixelTrait) == 0)
3500 for (j=0; j < n; j++)
3502 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3503 (contribution[j].pixel-contribution[0].pixel);
3504 alpha=contribution[j].weight;
3505 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3507 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3514 for (j=0; j < n; j++)
3516 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3517 (contribution[j].pixel-contribution[0].pixel);
3518 alpha=contribution[j].weight*QuantumScale*
3519 (double) GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3520 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3523 gamma=PerceptibleReciprocal(gamma);
3524 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3526 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3528 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3530 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3535#if defined(MAGICKCORE_OPENMP_SUPPORT)
3539 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3540 if (proceed == MagickFalse)
3544 resize_view=DestroyCacheView(resize_view);
3545 image_view=DestroyCacheView(image_view);
3546 contributions=DestroyContributionTLS(contributions);
3550static MagickBooleanType VerticalFilter(
3552 const Image *magick_restrict image,
Image *magick_restrict resize_image,
3553 const double y_factor,
const MagickSizeType span,
3554 MagickOffsetType *magick_restrict progress,
ExceptionInfo *exception)
3564 **magick_restrict contributions;
3579 scale=MagickMax(1.0/y_factor+MagickEpsilon,1.0);
3580 support=scale*GetResizeFilterSupport(resize_filter);
3581 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3582 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3583 return(MagickFalse);
3589 support=(double) 0.5;
3592 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3595 (void) ThrowMagickException(exception,GetMagickModule(),
3596 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3597 return(MagickFalse);
3600 scale=PerceptibleReciprocal(scale);
3601 image_view=AcquireVirtualCacheView(image,exception);
3602 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3603#if defined(MAGICKCORE_OPENMP_SUPPORT)
3604 #pragma omp parallel for schedule(static) shared(progress,status) \
3605 magick_number_threads(image,resize_image,resize_image->rows,1)
3607 for (y=0; y < (ssize_t) resize_image->rows; y++)
3610 id = GetOpenMPThreadId();
3616 *magick_restrict contribution;
3631 if (status == MagickFalse)
3633 bisect=(double) (y+0.5)/y_factor+MagickEpsilon;
3634 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3635 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->rows);
3637 contribution=contributions[id];
3638 for (n=0; n < (stop-start); n++)
3640 contribution[n].pixel=start+n;
3641 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3642 ((
double) (start+n)-bisect+0.5));
3643 density+=contribution[n].weight;
3647 if ((density != 0.0) && (density != 1.0))
3655 density=PerceptibleReciprocal(density);
3656 for (i=0; i < n; i++)
3657 contribution[i].weight*=density;
3659 p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
3660 image->columns,(
size_t) (contribution[n-1].pixel-contribution[0].pixel+1),
3662 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
3664 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3669 for (x=0; x < (ssize_t) resize_image->columns; x++)
3674 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3692 channel=GetPixelChannelChannel(image,i);
3693 traits=GetPixelChannelTraits(image,channel);
3694 resize_traits=GetPixelChannelTraits(resize_image,channel);
3695 if ((traits == UndefinedPixelTrait) ||
3696 (resize_traits == UndefinedPixelTrait))
3698 if (((resize_traits & CopyPixelTrait) != 0) ||
3699 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3701 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3703 k=(ssize_t) ((contribution[j-start].pixel-contribution[0].pixel)*
3704 (ssize_t) image->columns+x);
3705 SetPixelChannel(resize_image,channel,p[k*(ssize_t)
3706 GetPixelChannels(image)+i],q);
3710 if ((resize_traits & BlendPixelTrait) == 0)
3715 for (j=0; j < n; j++)
3717 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3718 (ssize_t) image->columns+x);
3719 alpha=contribution[j].weight;
3720 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3722 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3726 for (j=0; j < n; j++)
3728 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3729 (ssize_t) image->columns+x);
3730 alpha=contribution[j].weight*QuantumScale*(double)
3731 GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3732 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3735 gamma=PerceptibleReciprocal(gamma);
3736 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3738 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3740 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3742 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3747#if defined(MAGICKCORE_OPENMP_SUPPORT)
3751 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3752 if (proceed == MagickFalse)
3756 resize_view=DestroyCacheView(resize_view);
3757 image_view=DestroyCacheView(image_view);
3758 contributions=DestroyContributionTLS(contributions);
3762MagickExport
Image *ResizeImage(
const Image *image,
const size_t columns,
3763 const size_t rows,
const FilterType filter,
ExceptionInfo *exception)
3791 assert(image != (
Image *) NULL);
3792 assert(image->signature == MagickCoreSignature);
3794 assert(exception->signature == MagickCoreSignature);
3795 if (IsEventLogging() != MagickFalse)
3796 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3797 if ((columns == 0) || (rows == 0))
3798 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3799 if ((columns == image->columns) && (rows == image->rows) &&
3800 (filter == UndefinedFilter))
3801 return(CloneImage(image,0,0,MagickTrue,exception));
3805 x_factor=(double) (columns*PerceptibleReciprocal((
double) image->columns));
3806 y_factor=(double) (rows*PerceptibleReciprocal((
double) image->rows));
3807 filter_type=LanczosFilter;
3808 if (filter != UndefinedFilter)
3811 if ((x_factor == 1.0) && (y_factor == 1.0))
3812 filter_type=PointFilter;
3814 if ((image->storage_class == PseudoClass) ||
3815 (image->alpha_trait != UndefinedPixelTrait) ||
3816 ((x_factor*y_factor) > 1.0))
3817 filter_type=MitchellFilter;
3818 resize_filter=AcquireResizeFilter(image,filter_type,MagickFalse,exception);
3819#if defined(MAGICKCORE_OPENCL_SUPPORT)
3820 resize_image=AccelerateResizeImage(image,columns,rows,resize_filter,
3822 if (resize_image != (
Image *) NULL)
3824 resize_filter=DestroyResizeFilter(resize_filter);
3825 return(resize_image);
3828 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
3829 if (resize_image == (
Image *) NULL)
3831 resize_filter=DestroyResizeFilter(resize_filter);
3832 return(resize_image);
3834 if (x_factor > y_factor)
3835 filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
3837 filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
3838 if (filter_image == (
Image *) NULL)
3840 resize_filter=DestroyResizeFilter(resize_filter);
3841 return(DestroyImage(resize_image));
3847 if (x_factor > y_factor)
3849 span=(MagickSizeType) (filter_image->columns+rows);
3850 status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
3852 status&=(MagickStatusType) VerticalFilter(resize_filter,filter_image,
3853 resize_image,y_factor,span,&offset,exception);
3857 span=(MagickSizeType) (filter_image->rows+columns);
3858 status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
3860 status&=(MagickStatusType) HorizontalFilter(resize_filter,filter_image,
3861 resize_image,x_factor,span,&offset,exception);
3866 filter_image=DestroyImage(filter_image);
3867 resize_filter=DestroyResizeFilter(resize_filter);
3868 if (status == MagickFalse)
3870 resize_image=DestroyImage(resize_image);
3871 return((
Image *) NULL);
3873 resize_image->type=image->type;
3874 return(resize_image);
3908MagickExport
Image *SampleImage(
const Image *image,
const size_t columns,
3911#define SampleImageTag "Sample/Image"
3937 assert(image != (
const Image *) NULL);
3938 assert(image->signature == MagickCoreSignature);
3940 assert(exception->signature == MagickCoreSignature);
3941 if (IsEventLogging() != MagickFalse)
3942 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3943 if ((columns == 0) || (rows == 0))
3944 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3945 if ((columns == image->columns) && (rows == image->rows))
3946 return(CloneImage(image,0,0,MagickTrue,exception));
3947 sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
3948 if (sample_image == (
Image *) NULL)
3949 return((
Image *) NULL);
3953 sample_offset.x=0.5-MagickEpsilon;
3954 sample_offset.y=sample_offset.x;
3959 value=GetImageArtifact(image,
"sample:offset");
3960 if (value != (
char *) NULL)
3968 (void) ParseGeometry(value,&geometry_info);
3969 flags=ParseGeometry(value,&geometry_info);
3970 sample_offset.x=sample_offset.y=geometry_info.rho/100.0-MagickEpsilon;
3971 if ((flags & SigmaValue) != 0)
3972 sample_offset.y=geometry_info.sigma/100.0-MagickEpsilon;
3978 x_offset=(ssize_t *) AcquireQuantumMemory((
size_t) sample_image->columns,
3980 if (x_offset == (ssize_t *) NULL)
3982 sample_image=DestroyImage(sample_image);
3983 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3985 for (j=0; j < (ssize_t) sample_image->columns; j++)
3986 x_offset[j]=(ssize_t) ((((double) j+sample_offset.x)*image->columns)/
3987 sample_image->columns);
3993 image_view=AcquireVirtualCacheView(image,exception);
3994 sample_view=AcquireAuthenticCacheView(sample_image,exception);
3995#if defined(MAGICKCORE_OPENMP_SUPPORT)
3996 #pragma omp parallel for schedule(static) shared(status) \
3997 magick_number_threads(image,sample_image,sample_image->rows,2)
3999 for (y=0; y < (ssize_t) sample_image->rows; y++)
4011 if (status == MagickFalse)
4013 y_offset=(ssize_t) ((((
double) y+sample_offset.y)*image->rows)/
4014 sample_image->rows);
4015 p=GetCacheViewVirtualPixels(image_view,0,y_offset,image->columns,1,
4017 q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
4019 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
4027 for (x=0; x < (ssize_t) sample_image->columns; x++)
4032 if (GetPixelWriteMask(sample_image,q) <= (QuantumRange/2))
4034 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4037 for (i=0; i < (ssize_t) GetPixelChannels(sample_image); i++)
4046 channel=GetPixelChannelChannel(sample_image,i);
4047 traits=GetPixelChannelTraits(sample_image,channel);
4048 image_traits=GetPixelChannelTraits(image,channel);
4049 if ((traits == UndefinedPixelTrait) ||
4050 (image_traits == UndefinedPixelTrait))
4052 SetPixelChannel(sample_image,channel,p[x_offset[x]*(ssize_t)
4053 GetPixelChannels(image)+i],q);
4055 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4057 if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
4059 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4064 proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
4065 if (proceed == MagickFalse)
4069 image_view=DestroyCacheView(image_view);
4070 sample_view=DestroyCacheView(sample_view);
4071 x_offset=(ssize_t *) RelinquishMagickMemory(x_offset);
4072 sample_image->type=image->type;
4073 if (status == MagickFalse)
4074 sample_image=DestroyImage(sample_image);
4075 return(sample_image);
4107MagickExport
Image *ScaleImage(
const Image *image,
const size_t columns,
4110#define ScaleImageTag "Scale/Image"
4118 pixel[CompositePixelChannel],
4149 assert(image != (
const Image *) NULL);
4150 assert(image->signature == MagickCoreSignature);
4152 assert(exception->signature == MagickCoreSignature);
4153 if (IsEventLogging() != MagickFalse)
4154 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4155 if ((columns == 0) || (rows == 0))
4156 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
4157 if ((columns == image->columns) && (rows == image->rows))
4158 return(CloneImage(image,0,0,MagickTrue,exception));
4159 scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
4160 if (scale_image == (
Image *) NULL)
4161 return((
Image *) NULL);
4162 if (SetImageStorageClass(scale_image,DirectClass,exception) == MagickFalse)
4164 scale_image=DestroyImage(scale_image);
4165 return((
Image *) NULL);
4170 x_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4171 MaxPixelChannels*
sizeof(*x_vector));
4173 if (image->rows != scale_image->rows)
4174 scanline=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4175 MaxPixelChannels*
sizeof(*scanline));
4176 scale_scanline=(
double *) AcquireQuantumMemory((
size_t) scale_image->columns,
4177 MaxPixelChannels*
sizeof(*scale_scanline));
4178 y_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4179 MaxPixelChannels*
sizeof(*y_vector));
4180 if ((scanline == (
double *) NULL) || (scale_scanline == (
double *) NULL) ||
4181 (x_vector == (
double *) NULL) || (y_vector == (
double *) NULL))
4183 if ((image->rows != scale_image->rows) && (scanline != (
double *) NULL))
4184 scanline=(
double *) RelinquishMagickMemory(scanline);
4185 if (scale_scanline != (
double *) NULL)
4186 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4187 if (x_vector != (
double *) NULL)
4188 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4189 if (y_vector != (
double *) NULL)
4190 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4191 scale_image=DestroyImage(scale_image);
4192 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4198 next_row=MagickTrue;
4200 scale.y=(double) scale_image->rows/(
double) image->rows;
4201 (void) memset(y_vector,0,(
size_t) MaxPixelChannels*image->columns*
4205 image_view=AcquireVirtualCacheView(image,exception);
4206 scale_view=AcquireAuthenticCacheView(scale_image,exception);
4207 for (y=0; y < (ssize_t) scale_image->rows; y++)
4218 if (status == MagickFalse)
4220 q=QueueCacheViewAuthenticPixels(scale_view,0,y,scale_image->columns,1,
4222 if (q == (Quantum *) NULL)
4228 if (scale_image->rows == image->rows)
4233 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4235 if (p == (
const Quantum *) NULL)
4240 for (x=0; x < (ssize_t) image->columns; x++)
4242 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4244 p+=(ptrdiff_t) GetPixelChannels(image);
4247 if (image->alpha_trait != UndefinedPixelTrait)
4248 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4249 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4251 PixelChannel channel = GetPixelChannelChannel(image,i);
4252 PixelTrait traits = GetPixelChannelTraits(image,channel);
4253 if ((traits & BlendPixelTrait) == 0)
4255 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=(double) p[i];
4258 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*(double) p[i];
4260 p+=(ptrdiff_t) GetPixelChannels(image);
4268 while (scale.y < span.y)
4270 if ((next_row != MagickFalse) &&
4271 (number_rows < (ssize_t) image->rows))
4276 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4278 if (p == (
const Quantum *) NULL)
4283 for (x=0; x < (ssize_t) image->columns; x++)
4285 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4287 p+=(ptrdiff_t) GetPixelChannels(image);
4290 if (image->alpha_trait != UndefinedPixelTrait)
4291 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4292 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4294 PixelChannel channel = GetPixelChannelChannel(image,i);
4295 PixelTrait traits = GetPixelChannelTraits(image,channel);
4296 if ((traits & BlendPixelTrait) == 0)
4298 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4302 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4305 p+=(ptrdiff_t) GetPixelChannels(image);
4309 for (x=0; x < (ssize_t) image->columns; x++)
4310 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4311 y_vector[x*(ssize_t) GetPixelChannels(image)+i]+=scale.y*
4312 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4314 scale.y=(double) scale_image->rows/(
double) image->rows;
4315 next_row=MagickTrue;
4317 if ((next_row != MagickFalse) && (number_rows < (ssize_t) image->rows))
4322 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4324 if (p == (
const Quantum *) NULL)
4329 for (x=0; x < (ssize_t) image->columns; x++)
4331 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4333 p+=(ptrdiff_t) GetPixelChannels(image);
4336 if (image->alpha_trait != UndefinedPixelTrait)
4337 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4338 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4340 PixelChannel channel = GetPixelChannelChannel(image,i);
4341 PixelTrait traits = GetPixelChannelTraits(image,channel);
4342 if ((traits & BlendPixelTrait) == 0)
4344 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4348 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4351 p+=(ptrdiff_t) GetPixelChannels(image);
4354 next_row=MagickFalse;
4356 for (x=0; x < (ssize_t) image->columns; x++)
4358 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4360 pixel[i]=y_vector[x*(ssize_t) GetPixelChannels(image)+i]+span.y*
4361 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4362 scanline[x*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4363 y_vector[x*(ssize_t) GetPixelChannels(image)+i]=0.0;
4369 scale.y=(double) scale_image->rows/(
double) image->rows;
4370 next_row=MagickTrue;
4374 if (scale_image->columns == image->columns)
4379 for (x=0; x < (ssize_t) scale_image->columns; x++)
4381 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4383 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4386 if (image->alpha_trait != UndefinedPixelTrait)
4388 alpha=QuantumScale*scanline[x*(ssize_t) GetPixelChannels(image)+
4389 GetPixelChannelOffset(image,AlphaPixelChannel)];
4390 alpha=PerceptibleReciprocal(alpha);
4392 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4394 PixelChannel channel = GetPixelChannelChannel(image,i);
4395 PixelTrait traits = GetPixelChannelTraits(image,channel);
4396 scale_traits=GetPixelChannelTraits(scale_image,channel);
4397 if ((traits == UndefinedPixelTrait) ||
4398 (scale_traits == UndefinedPixelTrait))
4400 if ((traits & BlendPixelTrait) == 0)
4402 SetPixelChannel(scale_image,channel,ClampToQuantum(
4403 scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4406 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*scanline[
4407 x*(ssize_t) GetPixelChannels(image)+i]),q);
4409 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4420 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4422 next_column=MagickFalse;
4425 for (x=0; x < (ssize_t) image->columns; x++)
4427 scale.x=(double) scale_image->columns/(
double) image->columns;
4428 while (scale.x >= span.x)
4430 if (next_column != MagickFalse)
4432 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4436 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4438 PixelChannel channel = GetPixelChannelChannel(image,i);
4439 PixelTrait traits = GetPixelChannelTraits(image,channel);
4440 if (traits == UndefinedPixelTrait)
4442 pixel[i]+=span.x*scanline[x*(ssize_t) GetPixelChannels(image)+i];
4443 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4447 next_column=MagickTrue;
4451 if (next_column != MagickFalse)
4453 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4455 next_column=MagickFalse;
4458 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4459 pixel[i]+=scale.x*scanline[x*(ssize_t)
4460 GetPixelChannels(image)+i];
4466 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4468 scanline[(x-1)*(ssize_t) GetPixelChannels(image)+i];
4470 if ((next_column == MagickFalse) && (t < (ssize_t) scale_image->columns))
4471 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4472 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4476 for (x=0; x < (ssize_t) scale_image->columns; x++)
4478 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4480 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4483 if (image->alpha_trait != UndefinedPixelTrait)
4485 alpha=QuantumScale*scale_scanline[x*(ssize_t)
4486 GetPixelChannels(image)+
4487 GetPixelChannelOffset(image,AlphaPixelChannel)];
4488 alpha=PerceptibleReciprocal(alpha);
4490 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4492 PixelChannel channel = GetPixelChannelChannel(image,i);
4493 PixelTrait traits = GetPixelChannelTraits(image,channel);
4494 scale_traits=GetPixelChannelTraits(scale_image,channel);
4495 if ((traits == UndefinedPixelTrait) ||
4496 (scale_traits == UndefinedPixelTrait))
4498 if ((traits & BlendPixelTrait) == 0)
4500 SetPixelChannel(scale_image,channel,ClampToQuantum(
4501 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4504 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*
4505 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4507 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4510 if (SyncCacheViewAuthenticPixels(scale_view,exception) == MagickFalse)
4515 proceed=SetImageProgress(image,ScaleImageTag,(MagickOffsetType) y,
4517 if (proceed == MagickFalse)
4523 scale_view=DestroyCacheView(scale_view);
4524 image_view=DestroyCacheView(image_view);
4528 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4529 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4530 if (scale_image->rows != image->rows)
4531 scanline=(
double *) RelinquishMagickMemory(scanline);
4532 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4533 scale_image->type=image->type;
4534 if (status == MagickFalse)
4535 scale_image=DestroyImage(scale_image);
4536 return(scale_image);
4570MagickExport
Image *ThumbnailImage(
const Image *image,
const size_t columns,
4573#define SampleFactor 5
4576 filename[MagickPathExtent],
4577 value[MagickPathExtent];
4588 assert(image != (
Image *) NULL);
4589 assert(image->signature == MagickCoreSignature);
4591 assert(exception->signature == MagickCoreSignature);
4592 if (IsEventLogging() != MagickFalse)
4593 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4594 thumbnail_image=CloneImage(image,0,0,MagickTrue,exception);
4595 if (thumbnail_image == (
Image *) NULL)
4596 return(thumbnail_image);
4597 if ((columns != image->columns) || (rows != image->rows))
4600 *clone_image = thumbnail_image;
4606 x_factor=(ssize_t) (image->columns*MagickSafeReciprocal((
double)
4608 y_factor=(ssize_t) (image->rows*MagickSafeReciprocal((
double) rows));
4609 if ((x_factor > 4) && (y_factor > 4))
4611 thumbnail_image=SampleImage(clone_image,4*columns,4*rows,exception);
4612 if (thumbnail_image != (
Image *) NULL)
4614 clone_image=DestroyImage(clone_image);
4615 clone_image=thumbnail_image;
4618 if ((x_factor > 2) && (y_factor > 2))
4620 thumbnail_image=ResizeImage(clone_image,2*columns,2*rows,BoxFilter,
4622 if (thumbnail_image != (
Image *) NULL)
4624 clone_image=DestroyImage(clone_image);
4625 clone_image=thumbnail_image;
4628 thumbnail_image=ResizeImage(clone_image,columns,rows,image->filter ==
4629 UndefinedFilter ? LanczosSharpFilter : image->filter,exception);
4630 clone_image=DestroyImage(clone_image);
4631 if (thumbnail_image == (
Image *) NULL)
4632 return(thumbnail_image);
4634 (void) ParseAbsoluteGeometry(
"0x0+0+0",&thumbnail_image->page);
4635 thumbnail_image->depth=8;
4636 thumbnail_image->interlace=NoInterlace;
4640 ResetImageProfileIterator(thumbnail_image);
4641 for (name=GetNextImageProfile(thumbnail_image); name != (
const char *) NULL; )
4643 if ((LocaleCompare(name,
"icc") != 0) && (LocaleCompare(name,
"icm") != 0))
4645 (void) DeleteImageProfile(thumbnail_image,name);
4646 ResetImageProfileIterator(thumbnail_image);
4648 name=GetNextImageProfile(thumbnail_image);
4650 (void) DeleteImageProperty(thumbnail_image,
"comment");
4651 (void) CopyMagickString(value,image->magick_filename,MagickPathExtent);
4652 if (strstr(image->magick_filename,
"//") == (
char *) NULL)
4653 (void) FormatLocaleString(value,MagickPathExtent,
"file://%s",
4654 image->magick_filename);
4655 (void) SetImageProperty(thumbnail_image,
"Thumb::URI",value,exception);
4656 GetPathComponent(image->magick_filename,TailPath,filename);
4657 (void) CopyMagickString(value,filename,MagickPathExtent);
4658 if ( GetPathAttributes(image->filename,&attributes) != MagickFalse )
4659 (
void) FormatImageProperty(thumbnail_image,
"Thumb::MTime",
"%.20g",(
double)
4660 attributes.st_mtime);
4661 (void) FormatLocaleString(value,MagickPathExtent,
"%.20g",(
double)
4662 attributes.st_mtime);
4663 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,
"B",MagickPathExtent,
4665 (void) SetImageProperty(thumbnail_image,
"Thumb::Size",value,exception);
4666 (void) FormatLocaleString(value,MagickPathExtent,
"image/%s",image->magick);
4668 (void) SetImageProperty(thumbnail_image,
"Thumb::Mimetype",value,exception);
4669 (void) SetImageProperty(thumbnail_image,
"software",MagickAuthoritativeURL,
4671 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Width",
"%.20g",
4672 (
double) image->magick_columns);
4673 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Height",
"%.20g",
4674 (
double) image->magick_rows);
4675 (void) FormatImageProperty(thumbnail_image,
"Thumb::Document::Pages",
"%.20g",
4676 (
double) GetImageListLength(image));
4677 return(thumbnail_image);