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 MagicKernelSharp2013(
const double x,
420 magick_unreferenced(resize_filter);
429 return(0.625+1.75*(0.5-x)*(0.5+x));
431 return((1.0-x)*(1.75-x));
433 return(-0.125*(2.5-x)*(2.5-x));
437static double MagicKernelSharp2021(
const double x,
440 magick_unreferenced(resize_filter);
449 return(577.0/576.0-239.0/144.0*x*x);
451 return(35.0/36.0*(x-1.0)*(x-239.0/140.0));
453 return(1.0/6.0*(x-2.0)*(65.0/24.0-x));
455 return(1.0/36.0*(x-3.0)*(x-3.75));
457 return(-1.0/288.0*(x-4.5)*(x-4.5));
461static double Quadratic(
const double x,
464 magick_unreferenced(resize_filter);
472 return(0.5*(x-1.5)*(x-1.5));
476static double Sinc(
const double x,
479 magick_unreferenced(resize_filter);
487 const double alpha=(double) (MagickPI*x);
488 return(sin((
double) alpha)/alpha);
490 return((
double) 1.0);
493static double SincFast(
const double x,
496 magick_unreferenced(resize_filter);
524 const double alpha=(double) (MagickPI*x);
525 return(sin((
double) alpha)/alpha);
531 const double xx = x*x;
532#if MAGICKCORE_QUANTUM_DEPTH <= 8
536 const double c0 = 0.173610016489197553621906385078711564924e-2L;
537 const double c1 = -0.384186115075660162081071290162149315834e-3L;
538 const double c2 = 0.393684603287860108352720146121813443561e-4L;
539 const double c3 = -0.248947210682259168029030370205389323899e-5L;
540 const double c4 = 0.107791837839662283066379987646635416692e-6L;
541 const double c5 = -0.324874073895735800961260474028013982211e-8L;
542 const double c6 = 0.628155216606695311524920882748052490116e-10L;
543 const double c7 = -0.586110644039348333520104379959307242711e-12L;
545 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
546 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
547#elif MAGICKCORE_QUANTUM_DEPTH <= 16
551 const double c0 = 0.173611107357320220183368594093166520811e-2L;
552 const double c1 = -0.384240921114946632192116762889211361285e-3L;
553 const double c2 = 0.394201182359318128221229891724947048771e-4L;
554 const double c3 = -0.250963301609117217660068889165550534856e-5L;
555 const double c4 = 0.111902032818095784414237782071368805120e-6L;
556 const double c5 = -0.372895101408779549368465614321137048875e-8L;
557 const double c6 = 0.957694196677572570319816780188718518330e-10L;
558 const double c7 = -0.187208577776590710853865174371617338991e-11L;
559 const double c8 = 0.253524321426864752676094495396308636823e-13L;
560 const double c9 = -0.177084805010701112639035485248501049364e-15L;
562 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*(c7+xx*(c8+xx*c9))))))));
563 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
568 const double c0 = 0.173611111110910715186413700076827593074e-2L;
569 const double c1 = -0.289105544717893415815859968653611245425e-3L;
570 const double c2 = 0.206952161241815727624413291940849294025e-4L;
571 const double c3 = -0.834446180169727178193268528095341741698e-6L;
572 const double c4 = 0.207010104171026718629622453275917944941e-7L;
573 const double c5 = -0.319724784938507108101517564300855542655e-9L;
574 const double c6 = 0.288101675249103266147006509214934493930e-11L;
575 const double c7 = -0.118218971804934245819960233886876537953e-13L;
577 c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
578 const double d0 = 1.0L;
579 const double d1 = 0.547981619622284827495856984100563583948e-1L;
580 const double d2 = 0.134226268835357312626304688047086921806e-2L;
581 const double d3 = 0.178994697503371051002463656833597608689e-4L;
582 const double d4 = 0.114633394140438168641246022557689759090e-6L;
583 const double q = d0+xx*(d1+xx*(d2+xx*(d3+xx*d4)));
584 return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)/q*p);
589static double Triangle(
const double x,
592 magick_unreferenced(resize_filter);
604static double Welch(
const double x,
607 magick_unreferenced(resize_filter);
804 const FilterType filter,
const MagickBooleanType cylindrical,
840 }
const mapping[SentinelFilter] =
842 { UndefinedFilter, BoxFilter },
843 { PointFilter, BoxFilter },
844 { BoxFilter, BoxFilter },
845 { TriangleFilter, BoxFilter },
846 { HermiteFilter, BoxFilter },
847 { SincFastFilter, HannFilter },
848 { SincFastFilter, HammingFilter },
849 { SincFastFilter, BlackmanFilter },
850 { GaussianFilter, BoxFilter },
851 { QuadraticFilter, BoxFilter },
852 { CubicFilter, BoxFilter },
853 { CatromFilter, BoxFilter },
854 { MitchellFilter, BoxFilter },
855 { JincFilter, BoxFilter },
856 { SincFilter, BoxFilter },
857 { SincFastFilter, BoxFilter },
858 { SincFastFilter, KaiserFilter },
859 { LanczosFilter, WelchFilter },
860 { SincFastFilter, CubicFilter },
861 { SincFastFilter, BohmanFilter },
862 { SincFastFilter, TriangleFilter },
863 { LagrangeFilter, BoxFilter },
864 { LanczosFilter, LanczosFilter },
865 { LanczosSharpFilter, LanczosSharpFilter },
866 { Lanczos2Filter, Lanczos2Filter },
867 { Lanczos2SharpFilter, Lanczos2SharpFilter },
868 { RobidouxFilter, BoxFilter },
869 { RobidouxSharpFilter, BoxFilter },
870 { LanczosFilter, CosineFilter },
871 { SplineFilter, BoxFilter },
872 { LanczosRadiusFilter, LanczosFilter },
873 { CubicSplineFilter, BoxFilter },
874 { MagicKernelSharp2013Filter, BoxFilter },
875 { MagicKernelSharp2021Filter, BoxFilter },
896 ResizeWeightingFunctionType weightingFunctionType;
897 }
const filters[SentinelFilter] =
904 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
905 { Box, 0.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
906 { Box, 0.5, 0.5, 0.0, 0.0, BoxWeightingFunction },
907 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
908 { CubicBC, 1.0, 1.0, 0.0, 0.0, CubicBCWeightingFunction },
909 { Hann, 1.0, 1.0, 0.0, 0.0, HannWeightingFunction },
910 { Hamming, 1.0, 1.0, 0.0, 0.0, HammingWeightingFunction },
911 { Blackman, 1.0, 1.0, 0.0, 0.0, BlackmanWeightingFunction },
912 { Gaussian, 2.0, 1.5, 0.0, 0.0, GaussianWeightingFunction },
913 { Quadratic, 1.5, 1.5, 0.0, 0.0, QuadraticWeightingFunction },
914 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
915 { CubicBC, 2.0, 1.0, 0.0, 0.5, CubicBCWeightingFunction },
916 { CubicBC, 2.0, 8.0/7.0, 1./3., 1./3., CubicBCWeightingFunction },
917 { Jinc, 3.0, 1.2196698912665045, 0.0, 0.0, JincWeightingFunction },
918 { Sinc, 4.0, 1.0, 0.0, 0.0, SincWeightingFunction },
919 { SincFast, 4.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
920 { Kaiser, 1.0, 1.0, 0.0, 0.0, KaiserWeightingFunction },
921 { Welch, 1.0, 1.0, 0.0, 0.0, WelchWeightingFunction },
922 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
923 { Bohman, 1.0, 1.0, 0.0, 0.0, BohmanWeightingFunction },
924 { Triangle, 1.0, 1.0, 0.0, 0.0, TriangleWeightingFunction },
925 { Lagrange, 2.0, 1.0, 0.0, 0.0, LagrangeWeightingFunction },
926 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
927 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
928 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
929 { SincFast, 2.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
931 { CubicBC, 2.0, 1.1685777620836932,
932 0.37821575509399867, 0.31089212245300067, CubicBCWeightingFunction },
934 { CubicBC, 2.0, 1.105822933719019,
935 0.2620145123990142, 0.3689927438004929, CubicBCWeightingFunction },
936 { Cosine, 1.0, 1.0, 0.0, 0.0, CosineWeightingFunction },
937 { CubicBC, 2.0, 2.0, 1.0, 0.0, CubicBCWeightingFunction },
938 { SincFast, 3.0, 1.0, 0.0, 0.0, SincFastWeightingFunction },
939 { CubicSpline,2.0, 0.5, 0.0, 0.0, BoxWeightingFunction },
940 { MagicKernelSharp2013, 2.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
941 { MagicKernelSharp2021, 4.5, 1.0, 0.0, 0.0, MagicKernelSharpWeightingFunction },
978 assert(image != (
const Image *) NULL);
979 assert(image->signature == MagickCoreSignature);
980 assert(UndefinedFilter < filter && filter < SentinelFilter);
982 assert(exception->signature == MagickCoreSignature);
983 if (IsEventLogging() != MagickFalse)
984 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
986 resize_filter=(
ResizeFilter *) AcquireCriticalMemory(
sizeof(*resize_filter));
987 (void) memset(resize_filter,0,
sizeof(*resize_filter));
991 filter_type=mapping[filter].filter;
992 window_type=mapping[filter].window;
993 resize_filter->blur=1.0;
995 if ((cylindrical != MagickFalse) && (filter_type == SincFastFilter) &&
996 (filter != SincFastFilter))
997 filter_type=JincFilter;
1000 artifact=GetImageArtifact(image,
"filter:filter");
1001 if (IsStringTrue(artifact) != MagickFalse)
1006 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1007 if ((UndefinedFilter < option) && (option < SentinelFilter))
1009 filter_type=(FilterType) option;
1010 window_type=BoxFilter;
1013 artifact=GetImageArtifact(image,
"filter:window");
1014 if (artifact != (
const char *) NULL)
1016 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1017 if ((UndefinedFilter < option) && (option < SentinelFilter))
1018 window_type=(FilterType) option;
1024 artifact=GetImageArtifact(image,
"filter:window");
1025 if (artifact != (
const char *) NULL)
1030 option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
1031 if ((UndefinedFilter < option) && (option < SentinelFilter))
1033 filter_type= cylindrical != MagickFalse ? JincFilter
1035 window_type=(FilterType) option;
1041 resize_filter->filter=filters[filter_type].function;
1042 resize_filter->support=filters[filter_type].support;
1043 resize_filter->filterWeightingType=filters[filter_type].weightingFunctionType;
1044 resize_filter->window=filters[window_type].function;
1045 resize_filter->windowWeightingType=filters[window_type].weightingFunctionType;
1046 resize_filter->scale=filters[window_type].scale;
1047 resize_filter->signature=MagickCoreSignature;
1050 if (cylindrical != MagickFalse)
1051 switch (filter_type)
1055 resize_filter->support=(double) MagickSQ1_2;
1058 case LanczosSharpFilter:
1059 case Lanczos2Filter:
1060 case Lanczos2SharpFilter:
1061 case LanczosRadiusFilter:
1062 resize_filter->filter=filters[JincFilter].function;
1063 resize_filter->window=filters[JincFilter].function;
1064 resize_filter->scale=filters[JincFilter].scale;
1071 switch (filter_type)
1073 case LanczosSharpFilter:
1074 resize_filter->blur *= 0.9812505644269356;
1076 case Lanczos2SharpFilter:
1077 resize_filter->blur *= 0.9549963639785485;
1089 if ((resize_filter->filter == Gaussian) ||
1090 (resize_filter->window == Gaussian) ) {
1092 artifact=GetImageArtifact(image,
"filter:sigma");
1093 if (artifact != (
const char *) NULL)
1094 value=StringToDouble(artifact,(
char **) NULL);
1096 resize_filter->coefficient[0]=value;
1097 resize_filter->coefficient[1]=PerceptibleReciprocal(2.0*value*value);
1098 resize_filter->coefficient[2]=PerceptibleReciprocal(Magick2PI*value*value);
1101 resize_filter->support *= 2*value;
1105 if ((resize_filter->filter == Kaiser) ||
1106 (resize_filter->window == Kaiser) ) {
1108 artifact=GetImageArtifact(image,
"filter:alpha");
1109 if (artifact != (
const char *) NULL)
1110 value=StringToDouble(artifact,(
char **) NULL);
1111 artifact=GetImageArtifact(image,
"filter:kaiser-beta");
1112 if (artifact != (
const char *) NULL)
1113 value=StringToDouble(artifact,(
char **) NULL);
1114 artifact=GetImageArtifact(image,
"filter:kaiser-alpha");
1115 if (artifact != (
const char *) NULL)
1116 value=StringToDouble(artifact,(
char **) NULL)*MagickPI;
1118 resize_filter->coefficient[0]=value;
1119 resize_filter->coefficient[1]=PerceptibleReciprocal(I0(value));
1124 artifact=GetImageArtifact(image,
"filter:lobes");
1125 if (artifact != (
const char *) NULL)
1130 lobes=(ssize_t) StringToLong(artifact);
1133 resize_filter->support=(double) lobes;
1135 if (resize_filter->filter == Jinc)
1140 if (resize_filter->support > 16)
1141 resize_filter->support=jinc_zeros[15];
1143 resize_filter->support=jinc_zeros[((long) resize_filter->support)-1];
1147 if (filter_type == LanczosRadiusFilter)
1148 resize_filter->blur*=floor(resize_filter->support)/
1149 resize_filter->support;
1154 artifact=GetImageArtifact(image,
"filter:blur");
1155 if (artifact != (
const char *) NULL)
1156 resize_filter->blur*=StringToDouble(artifact,(
char **) NULL);
1157 if (resize_filter->blur < MagickEpsilon)
1158 resize_filter->blur=(double) MagickEpsilon;
1162 artifact=GetImageArtifact(image,
"filter:support");
1163 if (artifact != (
const char *) NULL)
1164 resize_filter->support=fabs(StringToDouble(artifact,(
char **) NULL));
1169 resize_filter->window_support=resize_filter->support;
1170 artifact=GetImageArtifact(image,
"filter:win-support");
1171 if (artifact != (
const char *) NULL)
1172 resize_filter->window_support=fabs(StringToDouble(artifact,(
char **) NULL));
1177 resize_filter->scale*=PerceptibleReciprocal(resize_filter->window_support);
1183 if ((resize_filter->filter == CubicBC) ||
1184 (resize_filter->window == CubicBC) )
1186 B=filters[filter_type].B;
1187 C=filters[filter_type].C;
1188 if (filters[window_type].function == CubicBC)
1190 B=filters[window_type].B;
1191 C=filters[window_type].C;
1193 artifact=GetImageArtifact(image,
"filter:b");
1194 if (artifact != (
const char *) NULL)
1196 B=StringToDouble(artifact,(
char **) NULL);
1198 artifact=GetImageArtifact(image,
"filter:c");
1199 if (artifact != (
const char *) NULL)
1200 C=StringToDouble(artifact,(
char **) NULL);
1204 artifact=GetImageArtifact(image,
"filter:c");
1205 if (artifact != (
const char *) NULL)
1207 C=StringToDouble(artifact,(
char **) NULL);
1218 resize_filter->coefficient[0]=1.0-(1.0/3.0)*B;
1219 resize_filter->coefficient[1]=-3.0+twoB+C;
1220 resize_filter->coefficient[2]=2.0-1.5*B-C;
1221 resize_filter->coefficient[3]=(4.0/3.0)*B+4.0*C;
1222 resize_filter->coefficient[4]=-8.0*C-twoB;
1223 resize_filter->coefficient[5]=B+5.0*C;
1224 resize_filter->coefficient[6]=(-1.0/6.0)*B-C;
1231 if (IsStringTrue(GetImageArtifact(image,
"filter:verbose")) != MagickFalse)
1232#if defined(MAGICKCORE_OPENMP_SUPPORT)
1246 if (resize_filter->filter == Box) filter_type=BoxFilter;
1247 if (resize_filter->filter == Sinc) filter_type=SincFilter;
1248 if (resize_filter->filter == SincFast) filter_type=SincFastFilter;
1249 if (resize_filter->filter == Jinc) filter_type=JincFilter;
1250 if (resize_filter->filter == CubicBC) filter_type=CubicFilter;
1251 if (resize_filter->window == Box) window_type=BoxFilter;
1252 if (resize_filter->window == Sinc) window_type=SincFilter;
1253 if (resize_filter->window == SincFast) window_type=SincFastFilter;
1254 if (resize_filter->window == Jinc) window_type=JincFilter;
1255 if (resize_filter->window == CubicBC) window_type=CubicFilter;
1259 support=GetResizeFilterSupport(resize_filter);
1260 (void) FormatLocaleFile(stdout,
"# Resampling Filter (for graphing)\n#\n");
1261 (void) FormatLocaleFile(stdout,
"# filter = %s\n",
1262 CommandOptionToMnemonic(MagickFilterOptions,filter_type));
1263 (void) FormatLocaleFile(stdout,
"# window = %s\n",
1264 CommandOptionToMnemonic(MagickFilterOptions,window_type));
1265 (void) FormatLocaleFile(stdout,
"# support = %.*g\n",
1266 GetMagickPrecision(),(
double) resize_filter->support);
1267 (void) FormatLocaleFile(stdout,
"# window-support = %.*g\n",
1268 GetMagickPrecision(),(
double) resize_filter->window_support);
1269 (void) FormatLocaleFile(stdout,
"# scale-blur = %.*g\n",
1270 GetMagickPrecision(),(
double) resize_filter->blur);
1271 if ((filter_type == GaussianFilter) || (window_type == GaussianFilter))
1272 (void) FormatLocaleFile(stdout,
"# gaussian-sigma = %.*g\n",
1273 GetMagickPrecision(),(
double) resize_filter->coefficient[0]);
1274 if ((filter_type == KaiserFilter) || (window_type == KaiserFilter))
1275 (void) FormatLocaleFile(stdout,
"# kaiser-beta = %.*g\n",
1276 GetMagickPrecision(),(
double) resize_filter->coefficient[0]);
1277 (void) FormatLocaleFile(stdout,
"# practical-support = %.*g\n",
1278 GetMagickPrecision(), (
double) support);
1279 if ((filter_type == CubicFilter) || (window_type == CubicFilter))
1280 (void) FormatLocaleFile(stdout,
"# B,C = %.*g,%.*g\n",
1281 GetMagickPrecision(),(
double) B,GetMagickPrecision(),(
double) C);
1282 (void) FormatLocaleFile(stdout,
"\n");
1286 for (x=0.0; x <= support; x+=0.01)
1287 (
void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",x,GetMagickPrecision(),
1288 (
double) GetResizeFilterWeight(resize_filter,x));
1292 (void) FormatLocaleFile(stdout,
"%5.2lf\t%.*g\n",support,
1293 GetMagickPrecision(),0.0);
1295 (void) DeleteImageArtifact((
Image *) image,
"filter:verbose");
1297 return(resize_filter);
1334MagickExport
Image *AdaptiveResizeImage(
const Image *image,
1335 const size_t columns,
const size_t rows,
ExceptionInfo *exception)
1340 resize_image=InterpolativeResizeImage(image,columns,rows,MeshInterpolatePixel,
1342 return(resize_image);
1385static double I0(
double x)
1401 for (i=2; t > MagickEpsilon; i++)
1404 t*=y/((double) i*i);
1410static double J1(
double x)
1422 0.581199354001606143928050809e+21,
1423 -0.6672106568924916298020941484e+20,
1424 0.2316433580634002297931815435e+19,
1425 -0.3588817569910106050743641413e+17,
1426 0.2908795263834775409737601689e+15,
1427 -0.1322983480332126453125473247e+13,
1428 0.3413234182301700539091292655e+10,
1429 -0.4695753530642995859767162166e+7,
1430 0.270112271089232341485679099e+4
1434 0.11623987080032122878585294e+22,
1435 0.1185770712190320999837113348e+20,
1436 0.6092061398917521746105196863e+17,
1437 0.2081661221307607351240184229e+15,
1438 0.5243710262167649715406728642e+12,
1439 0.1013863514358673989967045588e+10,
1440 0.1501793594998585505921097578e+7,
1441 0.1606931573481487801970916749e+4,
1447 for (i=7; i >= 0; i--)
1456static double P1(
double x)
1468 0.352246649133679798341724373e+5,
1469 0.62758845247161281269005675e+5,
1470 0.313539631109159574238669888e+5,
1471 0.49854832060594338434500455e+4,
1472 0.2111529182853962382105718e+3,
1473 0.12571716929145341558495e+1
1477 0.352246649133679798068390431e+5,
1478 0.626943469593560511888833731e+5,
1479 0.312404063819041039923015703e+5,
1480 0.4930396490181088979386097e+4,
1481 0.2030775189134759322293574e+3,
1487 for (i=4; i >= 0; i--)
1489 p=p*(8.0/x)*(8.0/x)+Pone[i];
1490 q=q*(8.0/x)*(8.0/x)+Qone[i];
1496static double Q1(
double x)
1508 0.3511751914303552822533318e+3,
1509 0.7210391804904475039280863e+3,
1510 0.4259873011654442389886993e+3,
1511 0.831898957673850827325226e+2,
1512 0.45681716295512267064405e+1,
1513 0.3532840052740123642735e-1
1517 0.74917374171809127714519505e+4,
1518 0.154141773392650970499848051e+5,
1519 0.91522317015169922705904727e+4,
1520 0.18111867005523513506724158e+4,
1521 0.1038187585462133728776636e+3,
1527 for (i=4; i >= 0; i--)
1529 p=p*(8.0/x)*(8.0/x)+Pone[i];
1530 q=q*(8.0/x)*(8.0/x)+Qone[i];
1535static double BesselOrderOne(
double x)
1548 q=sqrt((
double) (2.0/(MagickPI*x)))*(P1(x)*(1.0/sqrt(2.0)*(sin(x)-
1549 cos(x)))-8.0/x*Q1(x)*(-1.0/sqrt(2.0)*(sin(x)+cos(x))));
1580 assert(resize_filter->signature == MagickCoreSignature);
1581 resize_filter->signature=(~MagickCoreSignature);
1582 resize_filter=(
ResizeFilter *) RelinquishMagickMemory(resize_filter);
1583 return(resize_filter);
1610MagickPrivate
double *GetResizeFilterCoefficient(
1614 assert(resize_filter->signature == MagickCoreSignature);
1615 return((
double *) resize_filter->coefficient);
1618MagickPrivate
double GetResizeFilterBlur(
const ResizeFilter *resize_filter)
1621 assert(resize_filter->signature == MagickCoreSignature);
1622 return(resize_filter->blur);
1625MagickPrivate
double GetResizeFilterScale(
const ResizeFilter *resize_filter)
1628 assert(resize_filter->signature == MagickCoreSignature);
1629 return(resize_filter->scale);
1632MagickPrivate
double GetResizeFilterWindowSupport(
1636 assert(resize_filter->signature == MagickCoreSignature);
1637 return(resize_filter->window_support);
1640MagickPrivate ResizeWeightingFunctionType GetResizeFilterWeightingType(
1644 assert(resize_filter->signature == MagickCoreSignature);
1645 return(resize_filter->filterWeightingType);
1648MagickPrivate ResizeWeightingFunctionType GetResizeFilterWindowWeightingType(
1652 assert(resize_filter->signature == MagickCoreSignature);
1653 return(resize_filter->windowWeightingType);
1656MagickPrivate
double GetResizeFilterSupport(
const ResizeFilter *resize_filter)
1659 assert(resize_filter->signature == MagickCoreSignature);
1660 return(resize_filter->support*resize_filter->blur);
1690MagickPrivate
double GetResizeFilterWeight(
const ResizeFilter *resize_filter,
1702 assert(resize_filter->signature == MagickCoreSignature);
1703 x_blur=fabs((
double) x)*PerceptibleReciprocal(resize_filter->blur);
1704 if ((resize_filter->window_support < MagickEpsilon) ||
1705 (resize_filter->window == Box))
1709 scale=resize_filter->scale;
1710 scale=resize_filter->window(x_blur*scale,resize_filter);
1712 weight=scale*resize_filter->filter(x_blur,resize_filter);
1749MagickExport
Image *InterpolativeResizeImage(
const Image *image,
1750 const size_t columns,
const size_t rows,
const PixelInterpolateMethod method,
1753#define InterpolativeResizeImageTag "Resize/Image"
1777 assert(image != (
const Image *) NULL);
1778 assert(image->signature == MagickCoreSignature);
1780 assert(exception->signature == MagickCoreSignature);
1781 if (IsEventLogging() != MagickFalse)
1782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1783 if ((columns == 0) || (rows == 0))
1784 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1785 if ((columns == image->columns) && (rows == image->rows))
1786 return(CloneImage(image,0,0,MagickTrue,exception));
1787 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
1788 if (resize_image == (
Image *) NULL)
1789 return((
Image *) NULL);
1790 if (SetImageStorageClass(resize_image,DirectClass,exception) == MagickFalse)
1792 resize_image=DestroyImage(resize_image);
1793 return((
Image *) NULL);
1797 image_view=AcquireVirtualCacheView(image,exception);
1798 resize_view=AcquireAuthenticCacheView(resize_image,exception);
1799 scale.x=(double) image->columns/resize_image->columns;
1800 scale.y=(double) image->rows/resize_image->rows;
1801#if defined(MAGICKCORE_OPENMP_SUPPORT)
1802 #pragma omp parallel for schedule(static) shared(progress,status) \
1803 magick_number_threads(image,resize_image,resize_image->rows,1)
1805 for (y=0; y < (ssize_t) resize_image->rows; y++)
1816 if (status == MagickFalse)
1818 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
1820 if (q == (Quantum *) NULL)
1822 offset.y=((double) y+0.5)*scale.y-0.5;
1823 for (x=0; x < (ssize_t) resize_image->columns; x++)
1828 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1837 channel=GetPixelChannelChannel(image,i);
1838 traits=GetPixelChannelTraits(image,channel);
1839 resize_traits=GetPixelChannelTraits(resize_image,channel);
1840 if ((traits == UndefinedPixelTrait) ||
1841 (resize_traits == UndefinedPixelTrait))
1843 offset.x=((double) x+0.5)*scale.x-0.5;
1844 status=InterpolatePixelChannels(image,image_view,resize_image,method,
1845 offset.x,offset.y,q,exception);
1846 if (status == MagickFalse)
1849 q+=GetPixelChannels(resize_image);
1851 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
1853 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1858#if defined(MAGICKCORE_OPENMP_SUPPORT)
1862 proceed=SetImageProgress(image,InterpolativeResizeImageTag,progress,
1864 if (proceed == MagickFalse)
1868 resize_view=DestroyCacheView(resize_view);
1869 image_view=DestroyCacheView(image_view);
1870 if (status == MagickFalse)
1871 resize_image=DestroyImage(resize_image);
1872 return(resize_image);
1874#if defined(MAGICKCORE_LQR_DELEGATE)
1910MagickExport
Image *LiquidRescaleImage(
const Image *image,
const size_t columns,
1911 const size_t rows,
const double delta_x,
const double rigidity,
1914#define LiquidRescaleImageTag "Rescale/Image"
1952 assert(image != (
const Image *) NULL);
1953 assert(image->signature == MagickCoreSignature);
1955 assert(exception->signature == MagickCoreSignature);
1956 if (IsEventLogging() != MagickFalse)
1957 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1958 if ((columns == 0) || (rows == 0))
1959 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
1960 if ((columns == image->columns) && (rows == image->rows))
1961 return(CloneImage(image,0,0,MagickTrue,exception));
1962 if ((columns <= 2) || (rows <= 2))
1963 return(ResizeImage(image,columns,rows,image->filter,exception));
1964 pixel_info=AcquireVirtualMemory(image->columns,image->rows*MaxPixelChannels*
1967 return((
Image *) NULL);
1968 pixels=(gfloat *) GetVirtualMemoryBlob(pixel_info);
1971 image_view=AcquireVirtualCacheView(image,exception);
1972 for (y=0; y < (ssize_t) image->rows; y++)
1980 if (status == MagickFalse)
1982 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1983 if (p == (
const Quantum *) NULL)
1988 for (x=0; x < (ssize_t) image->columns; x++)
1993 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1994 *q++=QuantumScale*(
double) p[i];
1995 p+=GetPixelChannels(image);
1998 image_view=DestroyCacheView(image_view);
1999 carver=lqr_carver_new_ext(pixels,(
int) image->columns,(
int) image->rows,
2000 (
int) GetPixelChannels(image),LQR_COLDEPTH_32F);
2001 if (carver == (LqrCarver *) NULL)
2003 pixel_info=RelinquishVirtualMemory(pixel_info);
2004 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
2006 lqr_carver_set_preserve_input_image(carver);
2007 lqr_status=lqr_carver_init(carver,(
int) delta_x,rigidity);
2008 lqr_status=lqr_carver_resize(carver,(
int) columns,(
int) rows);
2010 rescale_image=CloneImage(image,(
size_t) lqr_carver_get_width(carver),
2011 (
size_t) lqr_carver_get_height(carver),MagickTrue,exception);
2012 if (rescale_image == (
Image *) NULL)
2014 pixel_info=RelinquishVirtualMemory(pixel_info);
2015 return((
Image *) NULL);
2017 if (SetImageStorageClass(rescale_image,DirectClass,exception) == MagickFalse)
2019 pixel_info=RelinquishVirtualMemory(pixel_info);
2020 rescale_image=DestroyImage(rescale_image);
2021 return((
Image *) NULL);
2023 rescale_view=AcquireAuthenticCacheView(rescale_image,exception);
2024 (void) lqr_carver_scan_reset(carver);
2025 while (lqr_carver_scan_ext(carver,&x_offset,&y_offset,(
void **) &packet) != 0)
2033 p=QueueCacheViewAuthenticPixels(rescale_view,x_offset,y_offset,1,1,
2035 if (p == (Quantum *) NULL)
2037 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2046 channel=GetPixelChannelChannel(image,i);
2047 traits=GetPixelChannelTraits(image,channel);
2048 rescale_traits=GetPixelChannelTraits(rescale_image,channel);
2049 if ((traits == UndefinedPixelTrait) ||
2050 (rescale_traits == UndefinedPixelTrait))
2052 SetPixelChannel(rescale_image,channel,ClampToQuantum(QuantumRange*
2055 if (SyncCacheViewAuthenticPixels(rescale_view,exception) == MagickFalse)
2058 rescale_view=DestroyCacheView(rescale_view);
2059 pixel_info=RelinquishVirtualMemory(pixel_info);
2060 lqr_carver_destroy(carver);
2061 return(rescale_image);
2064MagickExport
Image *LiquidRescaleImage(
const Image *image,
2065 const size_t magick_unused(columns),
const size_t magick_unused(rows),
2066 const double magick_unused(delta_x),
const double magick_unused(rigidity),
2069 assert(image != (
const Image *) NULL);
2070 assert(image->signature == MagickCoreSignature);
2072 assert(exception->signature == MagickCoreSignature);
2073 magick_unreferenced(columns);
2074 magick_unreferenced(rows);
2075 magick_unreferenced(delta_x);
2076 magick_unreferenced(rigidity);
2077 if (IsEventLogging() != MagickFalse)
2078 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2079 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
2080 "DelegateLibrarySupportNotBuiltIn",
"'%s' (LQR)",image->filename);
2081 return((
Image *) NULL);
2111static inline void CopyPixels(
const Quantum *source,
const ssize_t source_offset,
2112 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2117 for (i=0; i < (ssize_t) channels; i++)
2118 destination[(ssize_t) channels*destination_offset+i]=
2119 source[source_offset*(ssize_t) channels+i];
2122static inline void MixPixels(
const Quantum *source,
const ssize_t *source_offset,
2123 const size_t source_size,Quantum *destination,
2124 const ssize_t destination_offset,
const size_t channels)
2129 for (i=0; i < (ssize_t) channels; i++)
2135 for (j=0; j < (ssize_t) source_size; j++)
2136 sum+=source[source_offset[j]*(ssize_t) channels+i];
2137 destination[(ssize_t) channels*destination_offset+i]=(Quantum) (sum/
2138 (ssize_t) source_size);
2142static inline void Mix2Pixels(
const Quantum *source,
2143 const ssize_t source_offset1,
const ssize_t source_offset2,
2144 Quantum *destination,
const ssize_t destination_offset,
const size_t channels)
2147 offsets[2] = { source_offset1, source_offset2 };
2149 MixPixels(source,offsets,2,destination,destination_offset,channels);
2152static inline int PixelsEqual(
const Quantum *source1,ssize_t offset1,
2153 const Quantum *source2,ssize_t offset2,
const size_t channels)
2158 offset1*=(ssize_t) channels;
2159 offset2*=(ssize_t) channels;
2160 for (i=0; i < (ssize_t) channels; i++)
2161 if (source1[offset1+i] != source2[offset2+i])
2166static inline void Eagle2X(
const Image *source,
const Quantum *pixels,
2167 Quantum *result,
const size_t channels)
2173 for (i=0; i < 4; i++)
2174 CopyPixels(pixels,4,result,i,channels);
2175 if (PixelsEqual(pixels,0,pixels,1,channels) &&
2176 PixelsEqual(pixels,1,pixels,3,channels))
2177 CopyPixels(pixels,0,result,0,channels);
2178 if (PixelsEqual(pixels,1,pixels,2,channels) &&
2179 PixelsEqual(pixels,2,pixels,5,channels))
2180 CopyPixels(pixels,2,result,1,channels);
2181 if (PixelsEqual(pixels,3,pixels,6,channels) &&
2182 PixelsEqual(pixels,6,pixels,7,channels))
2183 CopyPixels(pixels,6,result,2,channels);
2184 if (PixelsEqual(pixels,5,pixels,8,channels) &&
2185 PixelsEqual(pixels,8,pixels,7,channels))
2186 CopyPixels(pixels,8,result,3,channels);
2189static void Hq2XHelper(
const unsigned int rule,
const Quantum *source,
2190 Quantum *destination,
const ssize_t destination_offset,
const size_t channels,
2191 const ssize_t e,
const ssize_t a,
const ssize_t b,
const ssize_t d,
2192 const ssize_t f,
const ssize_t h)
2194#define caseA(N,A,B,C,D) \
2198 offsets[4] = { A, B, C, D }; \
2200 MixPixels(source,offsets,4,destination,destination_offset,channels);\
2203#define caseB(N,A,B,C,D,E,F,G,H) \
2207 offsets[8] = { A, B, C, D, E, F, G, H }; \
2209 MixPixels(source,offsets,8,destination,destination_offset,channels);\
2217 CopyPixels(source,e,destination,destination_offset,channels);
2226 caseB(7,e,e,e,e,e,b,b,d)
2227 caseB(8,e,e,e,e,e,d,d,b)
2228 caseB(9,e,e,e,e,e,e,d,b)
2229 caseB(10,e,e,d,d,d,b,b,b)
2233 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2235 MixPixels(source,offsets,16,destination,destination_offset,channels);
2240 if (PixelsEqual(source,b,source,d,channels))
2243 offsets[4] = { e, e, d, b };
2245 MixPixels(source,offsets,4,destination,destination_offset,channels);
2248 CopyPixels(source,e,destination,destination_offset,channels);
2253 if (PixelsEqual(source,b,source,d,channels))
2256 offsets[8] = { e, e, d, d, d, b, b, b };
2258 MixPixels(source,offsets,8,destination,destination_offset,channels);
2261 CopyPixels(source,e,destination,destination_offset,channels);
2266 if (PixelsEqual(source,b,source,d,channels))
2269 offsets[16] = { e, e, e, e, e, e, e, e, e, e, e, e, e, e, d, b };
2271 MixPixels(source,offsets,16,destination,destination_offset,channels);
2274 CopyPixels(source,e,destination,destination_offset,channels);
2279 if (PixelsEqual(source,b,source,d,channels))
2282 offsets[4] = { e, e, d, b };
2284 MixPixels(source,offsets,4,destination,destination_offset,channels);
2289 offsets[4] = { e, e, e, a };
2291 MixPixels(source,offsets,4,destination,destination_offset,channels);
2297 if (PixelsEqual(source,b,source,d,channels))
2300 offsets[8] = { e, e, e, e, e, e, d, b };
2302 MixPixels(source,offsets,8,destination,destination_offset,channels);
2307 offsets[4] = { e, e, e, a };
2309 MixPixels(source,offsets,4,destination,destination_offset,channels);
2315 if (PixelsEqual(source,b,source,d,channels))
2318 offsets[8] = { e, e, d, d, d, b, b, b };
2320 MixPixels(source,offsets,8,destination,destination_offset,channels);
2325 offsets[4] = { e, e, e, a };
2327 MixPixels(source,offsets,4,destination,destination_offset,channels);
2333 if (PixelsEqual(source,b,source,f,channels))
2336 offsets[8] = { e, e, e, e, e, b, b, d };
2338 MixPixels(source,offsets,8,destination,destination_offset,channels);
2343 offsets[4] = { e, e, e, d };
2345 MixPixels(source,offsets,4,destination,destination_offset,channels);
2351 if (PixelsEqual(source,d,source,h,channels))
2354 offsets[8] = { e, e, e, e, e, d, d, b };
2356 MixPixels(source,offsets,8,destination,destination_offset,channels);
2361 offsets[4] = { e, e, e, b };
2363 MixPixels(source,offsets,4,destination,destination_offset,channels);
2372static inline unsigned int Hq2XPatternToNumber(
const int *pattern)
2383 for (i=7; i >= 0; i--)
2385 result+=order*(
unsigned int) pattern[i];
2391static inline void Hq2X(
const Image *source,
const Quantum *pixels,
2392 Quantum *result,
const size_t channels)
2394 static const unsigned int
2397 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2398 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
2399 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2400 4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
2401 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
2402 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2403 4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
2404 4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
2405 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
2406 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
2407 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
2408 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
2409 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
2410 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
2411 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
2412 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14
2418 !PixelsEqual(pixels,4,pixels,8,channels),
2419 !PixelsEqual(pixels,4,pixels,7,channels),
2420 !PixelsEqual(pixels,4,pixels,6,channels),
2421 !PixelsEqual(pixels,4,pixels,5,channels),
2422 !PixelsEqual(pixels,4,pixels,3,channels),
2423 !PixelsEqual(pixels,4,pixels,2,channels),
2424 !PixelsEqual(pixels,4,pixels,1,channels),
2425 !PixelsEqual(pixels,4,pixels,0,channels)
2428#define Rotated(p) p[2], p[4], p[7], p[1], p[6], p[0], p[3], p[5]
2429 const int pattern2[] = { Rotated(pattern1) };
2430 const int pattern3[] = { Rotated(pattern2) };
2431 const int pattern4[] = { Rotated(pattern3) };
2434 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern1)],pixels,result,0,
2435 channels,4,0,1,3,5,7);
2436 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern2)],pixels,result,1,
2437 channels,4,2,5,1,7,3);
2438 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern3)],pixels,result,3,
2439 channels,4,8,7,5,3,1);
2440 Hq2XHelper(Hq2XTable[Hq2XPatternToNumber(pattern4)],pixels,result,2,
2441 channels,4,6,3,7,1,5);
2444static void Fish2X(
const Image *source,
const Quantum *pixels,Quantum *result,
2445 const size_t channels)
2447#define Corner(A,B,C,D) \
2449 if (intensities[B] > intensities[A]) \
2452 offsets[3] = { B, C, D }; \
2454 MixPixels(pixels,offsets,3,result,3,channels); \
2459 offsets[3] = { A, B, C }; \
2461 MixPixels(pixels,offsets,3,result,3,channels); \
2465#define Line(A,B,C,D) \
2467 if (intensities[C] > intensities[A]) \
2468 Mix2Pixels(pixels,C,D,result,3,channels); \
2470 Mix2Pixels(pixels,A,B,result,3,channels); \
2474 pixels_offsets[4] = { 0, 1, 3, 4 };
2490 for (i=0; i < 9; i++)
2491 intensities[i]=GetPixelIntensity(source,pixels+i*(ssize_t) channels);
2492 CopyPixels(pixels,0,result,0,channels);
2493 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[1] ? 0 : 1),result,
2495 CopyPixels(pixels,(ssize_t) (intensities[0] > intensities[3] ? 0 : 3),result,
2497 ae=PixelsEqual(pixels,0,pixels,4,channels);
2498 bd=PixelsEqual(pixels,1,pixels,3,channels);
2499 ab=PixelsEqual(pixels,0,pixels,1,channels);
2500 de=PixelsEqual(pixels,3,pixels,4,channels);
2501 ad=PixelsEqual(pixels,0,pixels,3,channels);
2502 be=PixelsEqual(pixels,1,pixels,4,channels);
2505 CopyPixels(pixels,0,result,3,channels);
2508 if (ad && de && !ab)
2513 if (be && de && !ab)
2518 if (ad && ab && !be)
2523 if (ab && be && !ad)
2528 if (ae && (!bd || intensities[1] > intensities[0]))
2530 Mix2Pixels(pixels,0,4,result,3,channels);
2533 if (bd && (!ae || intensities[0] > intensities[1]))
2535 Mix2Pixels(pixels,1,3,result,3,channels);
2558 MixPixels(pixels,pixels_offsets,4,result,3,channels);
2563static void Xbr2X(
const Image *magick_unused(source),
const Quantum *pixels,
2564 Quantum *result,
const size_t channels)
2566#define WeightVar(M,N) const int w_##M##_##N = \
2567 PixelsEqual(pixels,M,pixels,N,channels) ? 0 : 1;
2599 magick_unreferenced(source);
2602 w_12_16 + w_12_8 + w_6_10 + w_6_2 + (4 * w_11_7) <
2603 w_11_17 + w_11_5 + w_7_13 + w_7_1 + (4 * w_12_6)
2605 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_7 ? 11 : 7),12,result,0,
2608 CopyPixels(pixels,12,result,0,channels);
2610 w_12_18 + w_12_6 + w_8_14 + w_8_2 + (4 * w_7_13) <
2611 w_13_17 + w_13_9 + w_11_7 + w_7_3 + (4 * w_12_8)
2613 Mix2Pixels(pixels,(ssize_t) (w_12_7 <= w_12_13 ? 7 : 13),12,result,1,
2616 CopyPixels(pixels,12,result,1,channels);
2618 w_12_6 + w_12_18 + w_16_10 + w_16_22 + (4 * w_11_17) <
2619 w_11_7 + w_11_15 + w_13_17 + w_17_21 + (4 * w_12_16)
2621 Mix2Pixels(pixels,(ssize_t) (w_12_11 <= w_12_17 ? 11 : 17),12,result,2,
2624 CopyPixels(pixels,12,result,2,channels);
2626 w_12_8 + w_12_16 + w_18_14 + w_18_22 + (4 * w_13_17) <
2627 w_11_17 + w_17_23 + w_17_19 + w_7_13 + (4 * w_12_18)
2629 Mix2Pixels(pixels,(ssize_t) (w_12_13 <= w_12_17 ? 13 : 17),12,result,3,
2632 CopyPixels(pixels,12,result,3,channels);
2635static void Scale2X(
const Image *magick_unused(source),
const Quantum *pixels,
2636 Quantum *result,
const size_t channels)
2638 magick_unreferenced(source);
2640 if (PixelsEqual(pixels,1,pixels,7,channels) ||
2641 PixelsEqual(pixels,3,pixels,5,channels))
2646 for (i=0; i < 4; i++)
2647 CopyPixels(pixels,4,result,i,channels);
2650 if (PixelsEqual(pixels,1,pixels,3,channels))
2651 CopyPixels(pixels,3,result,0,channels);
2653 CopyPixels(pixels,4,result,0,channels);
2654 if (PixelsEqual(pixels,1,pixels,5,channels))
2655 CopyPixels(pixels,5,result,1,channels);
2657 CopyPixels(pixels,4,result,1,channels);
2658 if (PixelsEqual(pixels,3,pixels,7,channels))
2659 CopyPixels(pixels,3,result,2,channels);
2661 CopyPixels(pixels,4,result,2,channels);
2662 if (PixelsEqual(pixels,5,pixels,7,channels))
2663 CopyPixels(pixels,5,result,3,channels);
2665 CopyPixels(pixels,4,result,3,channels);
2668static void Epbx2X(
const Image *magick_unused(source),
const Quantum *pixels,
2669 Quantum *result,
const size_t channels)
2671#define HelperCond(a,b,c,d,e,f,g) ( \
2672 PixelsEqual(pixels,a,pixels,b,channels) && ( \
2673 PixelsEqual(pixels,c,pixels,d,channels) || \
2674 PixelsEqual(pixels,c,pixels,e,channels) || \
2675 PixelsEqual(pixels,a,pixels,f,channels) || \
2676 PixelsEqual(pixels,b,pixels,g,channels) \
2683 magick_unreferenced(source);
2685 for (i=0; i < 4; i++)
2686 CopyPixels(pixels,4,result,i,channels);
2688 !PixelsEqual(pixels,3,pixels,5,channels) &&
2689 !PixelsEqual(pixels,1,pixels,7,channels) &&
2691 PixelsEqual(pixels,4,pixels,3,channels) ||
2692 PixelsEqual(pixels,4,pixels,7,channels) ||
2693 PixelsEqual(pixels,4,pixels,5,channels) ||
2694 PixelsEqual(pixels,4,pixels,1,channels) ||
2697 !PixelsEqual(pixels,0,pixels,8,channels) ||
2698 PixelsEqual(pixels,4,pixels,6,channels) ||
2699 PixelsEqual(pixels,3,pixels,2,channels)
2702 !PixelsEqual(pixels,6,pixels,2,channels) ||
2703 PixelsEqual(pixels,4,pixels,0,channels) ||
2704 PixelsEqual(pixels,4,pixels,8,channels)
2710 if (HelperCond(1,3,4,0,8,2,6))
2711 Mix2Pixels(pixels,1,3,result,0,channels);
2712 if (HelperCond(5,1,4,2,6,8,0))
2713 Mix2Pixels(pixels,5,1,result,1,channels);
2714 if (HelperCond(3,7,4,6,2,0,8))
2715 Mix2Pixels(pixels,3,7,result,2,channels);
2716 if (HelperCond(7,5,4,8,0,6,2))
2717 Mix2Pixels(pixels,7,5,result,3,channels);
2723static inline void Eagle3X(
const Image *magick_unused(source),
2724 const Quantum *pixels,Quantum *result,
const size_t channels)
2732 magick_unreferenced(source);
2734 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2735 PixelsEqual(pixels,0,pixels,3,channels);
2736 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2737 PixelsEqual(pixels,2,pixels,5,channels);
2738 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2739 PixelsEqual(pixels,6,pixels,7,channels);
2740 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2741 PixelsEqual(pixels,7,pixels,8,channels);
2742 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2743 if (corner_tl && corner_tr)
2744 Mix2Pixels(pixels,0,2,result,1,channels);
2746 CopyPixels(pixels,4,result,1,channels);
2747 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2748 if (corner_tl && corner_bl)
2749 Mix2Pixels(pixels,0,6,result,3,channels);
2751 CopyPixels(pixels,4,result,3,channels);
2752 CopyPixels(pixels,4,result,4,channels);
2753 if (corner_tr && corner_br)
2754 Mix2Pixels(pixels,2,8,result,5,channels);
2756 CopyPixels(pixels,4,result,5,channels);
2757 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2758 if (corner_bl && corner_br)
2759 Mix2Pixels(pixels,6,8,result,7,channels);
2761 CopyPixels(pixels,4,result,7,channels);
2762 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2765static inline void Eagle3XB(
const Image *magick_unused(source),
2766 const Quantum *pixels,Quantum *result,
const size_t channels)
2774 magick_unreferenced(source);
2776 corner_tl=PixelsEqual(pixels,0,pixels,1,channels) &&
2777 PixelsEqual(pixels,0,pixels,3,channels);
2778 corner_tr=PixelsEqual(pixels,1,pixels,2,channels) &&
2779 PixelsEqual(pixels,2,pixels,5,channels);
2780 corner_bl=PixelsEqual(pixels,3,pixels,6,channels) &&
2781 PixelsEqual(pixels,6,pixels,7,channels);
2782 corner_br=PixelsEqual(pixels,5,pixels,7,channels) &&
2783 PixelsEqual(pixels,7,pixels,8,channels);
2784 CopyPixels(pixels,(ssize_t) (corner_tl ? 0 : 4),result,0,channels);
2785 CopyPixels(pixels,4,result,1,channels);
2786 CopyPixels(pixels,(ssize_t) (corner_tr ? 1 : 4),result,2,channels);
2787 CopyPixels(pixels,4,result,3,channels);
2788 CopyPixels(pixels,4,result,4,channels);
2789 CopyPixels(pixels,4,result,5,channels);
2790 CopyPixels(pixels,(ssize_t) (corner_bl ? 3 : 4),result,6,channels);
2791 CopyPixels(pixels,4,result,7,channels);
2792 CopyPixels(pixels,(ssize_t) (corner_br ? 5 : 4),result,8,channels);
2795static inline void Scale3X(
const Image *magick_unused(source),
2796 const Quantum *pixels,Quantum *result,
const size_t channels)
2798 magick_unreferenced(source);
2800 if (!PixelsEqual(pixels,1,pixels,7,channels) &&
2801 !PixelsEqual(pixels,3,pixels,5,channels))
2803 if (PixelsEqual(pixels,3,pixels,1,channels))
2804 CopyPixels(pixels,3,result,0,channels);
2806 CopyPixels(pixels,4,result,0,channels);
2810 PixelsEqual(pixels,3,pixels,1,channels) &&
2811 !PixelsEqual(pixels,4,pixels,2,channels)
2814 PixelsEqual(pixels,5,pixels,1,channels) &&
2815 !PixelsEqual(pixels,4,pixels,0,channels)
2818 CopyPixels(pixels,1,result,1,channels);
2820 CopyPixels(pixels,4,result,1,channels);
2821 if (PixelsEqual(pixels,5,pixels,1,channels))
2822 CopyPixels(pixels,5,result,2,channels);
2824 CopyPixels(pixels,4,result,2,channels);
2827 PixelsEqual(pixels,3,pixels,1,channels) &&
2828 !PixelsEqual(pixels,4,pixels,6,channels)
2831 PixelsEqual(pixels,3,pixels,7,channels) &&
2832 !PixelsEqual(pixels,4,pixels,0,channels)
2835 CopyPixels(pixels,3,result,3,channels);
2837 CopyPixels(pixels,4,result,3,channels);
2838 CopyPixels(pixels,4,result,4,channels);
2841 PixelsEqual(pixels,5,pixels,1,channels) &&
2842 !PixelsEqual(pixels,4,pixels,8,channels)
2845 PixelsEqual(pixels,5,pixels,7,channels) &&
2846 !PixelsEqual(pixels,4,pixels,2,channels)
2849 CopyPixels(pixels,5,result,5,channels);
2851 CopyPixels(pixels,4,result,5,channels);
2852 if (PixelsEqual(pixels,3,pixels,7,channels))
2853 CopyPixels(pixels,3,result,6,channels);
2855 CopyPixels(pixels,4,result,6,channels);
2858 PixelsEqual(pixels,3,pixels,7,channels) &&
2859 !PixelsEqual(pixels,4,pixels,8,channels)
2862 PixelsEqual(pixels,5,pixels,7,channels) &&
2863 !PixelsEqual(pixels,4,pixels,6,channels)
2866 CopyPixels(pixels,7,result,7,channels);
2868 CopyPixels(pixels,4,result,7,channels);
2869 if (PixelsEqual(pixels,5,pixels,7,channels))
2870 CopyPixels(pixels,5,result,8,channels);
2872 CopyPixels(pixels,4,result,8,channels);
2879 for (i=0; i < 9; i++)
2880 CopyPixels(pixels,4,result,i,channels);
2886#define MagnifyImageTag "Magnify/Image"
2919 (*scaling_method)(
const Image *,
const Quantum *,Quantum *,size_t);
2924 assert(image != (
const Image *) NULL);
2925 assert(image->signature == MagickCoreSignature);
2927 assert(exception->signature == MagickCoreSignature);
2928 if (IsEventLogging() != MagickFalse)
2929 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2930 option=GetImageOption(image->image_info,
"magnify:method");
2931 if (option == (
char *) NULL)
2933 scaling_method=Scale2X;
2940 if (LocaleCompare(option,
"eagle2x") == 0)
2942 scaling_method=Eagle2X;
2947 if (LocaleCompare(option,
"eagle3x") == 0)
2949 scaling_method=Eagle3X;
2954 if (LocaleCompare(option,
"eagle3xb") == 0)
2956 scaling_method=Eagle3XB;
2961 if (LocaleCompare(option,
"epbx2x") == 0)
2963 scaling_method=Epbx2X;
2972 if (LocaleCompare(option,
"fish2x") == 0)
2974 scaling_method=Fish2X;
2983 if (LocaleCompare(option,
"hq2x") == 0)
2985 scaling_method=Hq2X;
2994 if (LocaleCompare(option,
"scale2x") == 0)
2996 scaling_method=Scale2X;
3001 if (LocaleCompare(option,
"scale3x") == 0)
3003 scaling_method=Scale3X;
3012 if (LocaleCompare(option,
"xbr2x") == 0)
3014 scaling_method=Xbr2X;
3026 source_image=CloneImage(image,image->columns,image->rows,MagickTrue,
3028 if (source_image == (
Image *) NULL)
3029 return((
Image *) NULL);
3034 rectangle.width=image->columns;
3035 rectangle.height=image->rows;
3036 (void) CopyImagePixels(source_image,image,&rectangle,&offset,exception);
3037 if (IssRGBCompatibleColorspace(source_image->colorspace) == MagickFalse)
3038 (void) TransformImageColorspace(source_image,sRGBColorspace,exception);
3039 magnify_image=CloneImage(source_image,magnification*source_image->columns,
3040 magnification*source_image->rows,MagickTrue,exception);
3041 if (magnify_image == (
Image *) NULL)
3043 source_image=DestroyImage(source_image);
3044 return((
Image *) NULL);
3051 image_view=AcquireVirtualCacheView(source_image,exception);
3052 magnify_view=AcquireAuthenticCacheView(magnify_image,exception);
3053#if defined(MAGICKCORE_OPENMP_SUPPORT)
3054 #pragma omp parallel for schedule(static) shared(progress,status) \
3055 magick_number_threads(source_image,magnify_image,source_image->rows,1)
3057 for (y=0; y < (ssize_t) source_image->rows; y++)
3068 if (status == MagickFalse)
3070 q=QueueCacheViewAuthenticPixels(magnify_view,0,magnification*y,
3071 magnify_image->columns,magnification,exception);
3072 if (q == (Quantum *) NULL)
3080 for (x=0; x < (ssize_t) source_image->columns; x++)
3092 p=GetCacheViewVirtualPixels(image_view,x-width/2,y-width/2,width,width,
3094 if (p == (Quantum *) NULL)
3099 channels=GetPixelChannels(source_image);
3100 scaling_method(source_image,p,r,channels);
3104 for (j=0; j < (ssize_t) magnification; j++)
3105 for (i=0; i < (ssize_t) (channels*magnification); i++)
3106 q[j*(ssize_t) channels*(ssize_t) magnify_image->columns+i]=
3107 r[j*magnification*(ssize_t) channels+i];
3108 q+=magnification*GetPixelChannels(magnify_image);
3110 if (SyncCacheViewAuthenticPixels(magnify_view,exception) == MagickFalse)
3112 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3117#if defined(MAGICKCORE_OPENMP_SUPPORT)
3121 proceed=SetImageProgress(image,MagnifyImageTag,progress,image->rows);
3122 if (proceed == MagickFalse)
3126 magnify_view=DestroyCacheView(magnify_view);
3127 image_view=DestroyCacheView(image_view);
3128 source_image=DestroyImage(source_image);
3129 if (status == MagickFalse)
3130 magnify_image=DestroyImage(magnify_image);
3131 return(magnify_image);
3164 assert(image != (
Image *) NULL);
3165 assert(image->signature == MagickCoreSignature);
3167 assert(exception->signature == MagickCoreSignature);
3168 if (IsEventLogging() != MagickFalse)
3169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3170 minify_image=ResizeImage(image,image->columns/2,image->rows/2,SplineFilter,
3172 return(minify_image);
3209MagickExport
Image *ResampleImage(
const Image *image,
const double x_resolution,
3210 const double y_resolution,
const FilterType filter,
ExceptionInfo *exception)
3212#define ResampleImageTag "Resample/Image"
3224 assert(image != (
const Image *) NULL);
3225 assert(image->signature == MagickCoreSignature);
3227 assert(exception->signature == MagickCoreSignature);
3228 if (IsEventLogging() != MagickFalse)
3229 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3230 width=(size_t) (x_resolution*image->columns/(image->resolution.x == 0.0 ?
3231 DefaultResolution : image->resolution.x)+0.5);
3232 height=(size_t) (y_resolution*image->rows/(image->resolution.y == 0.0 ?
3233 DefaultResolution : image->resolution.y)+0.5);
3234 resample_image=ResizeImage(image,width,height,filter,exception);
3235 if (resample_image != (
Image *) NULL)
3237 resample_image->resolution.x=x_resolution;
3238 resample_image->resolution.y=y_resolution;
3240 return(resample_image);
3298 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3303 return(contribution);
3317 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3319 sizeof(*contribution));
3322 (void) memset(contribution,0,number_threads*
sizeof(*contribution));
3323 for (i=0; i < (ssize_t) number_threads; i++)
3326 AcquireAlignedMemory(count,
sizeof(**contribution)));
3328 return(DestroyContributionTLS(contribution));
3330 return(contribution);
3333static MagickBooleanType HorizontalFilter(
3335 const Image *magick_restrict image,
Image *magick_restrict resize_image,
3336 const double x_factor,
const MagickSizeType span,
3337 MagickOffsetType *magick_restrict progress,
ExceptionInfo *exception)
3339#define ResizeImageTag "Resize/Image"
3349 **magick_restrict contributions;
3364 scale=MagickMax(1.0/x_factor+MagickEpsilon,1.0);
3365 support=scale*GetResizeFilterSupport(resize_filter);
3366 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3367 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3368 return(MagickFalse);
3374 support=(double) 0.5;
3377 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3380 (void) ThrowMagickException(exception,GetMagickModule(),
3381 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3382 return(MagickFalse);
3385 scale=PerceptibleReciprocal(scale);
3386 image_view=AcquireVirtualCacheView(image,exception);
3387 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3388#if defined(MAGICKCORE_OPENMP_SUPPORT)
3389 #pragma omp parallel for schedule(static) shared(progress,status) \
3390 magick_number_threads(image,resize_image,resize_image->columns,1)
3392 for (x=0; x < (ssize_t) resize_image->columns; x++)
3395 id = GetOpenMPThreadId();
3401 *magick_restrict contribution;
3416 if (status == MagickFalse)
3418 bisect=(double) (x+0.5)/x_factor+MagickEpsilon;
3419 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3420 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->columns);
3422 contribution=contributions[id];
3423 for (n=0; n < (stop-start); n++)
3425 contribution[n].pixel=start+n;
3426 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3427 ((
double) (start+n)-bisect+0.5));
3428 density+=contribution[n].weight;
3432 if ((density != 0.0) && (density != 1.0))
3440 density=PerceptibleReciprocal(density);
3441 for (i=0; i < n; i++)
3442 contribution[i].weight*=density;
3444 p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,(
size_t)
3445 (contribution[n-1].pixel-contribution[0].pixel+1),image->rows,exception);
3446 q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
3448 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3453 for (y=0; y < (ssize_t) resize_image->rows; y++)
3458 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3476 channel=GetPixelChannelChannel(image,i);
3477 traits=GetPixelChannelTraits(image,channel);
3478 resize_traits=GetPixelChannelTraits(resize_image,channel);
3479 if ((traits == UndefinedPixelTrait) ||
3480 (resize_traits == UndefinedPixelTrait))
3482 if (((resize_traits & CopyPixelTrait) != 0) ||
3483 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3485 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3487 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3488 (contribution[j-start].pixel-contribution[0].pixel);
3489 SetPixelChannel(resize_image,channel,
3490 p[k*(ssize_t) GetPixelChannels(image)+i],q);
3494 if ((resize_traits & BlendPixelTrait) == 0)
3499 for (j=0; j < n; j++)
3501 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3502 (contribution[j].pixel-contribution[0].pixel);
3503 alpha=contribution[j].weight;
3504 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3506 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3513 for (j=0; j < n; j++)
3515 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3516 (contribution[j].pixel-contribution[0].pixel);
3517 alpha=contribution[j].weight*QuantumScale*
3518 (double) GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3519 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3522 gamma=PerceptibleReciprocal(gamma);
3523 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3525 q+=GetPixelChannels(resize_image);
3527 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3529 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3534#if defined(MAGICKCORE_OPENMP_SUPPORT)
3538 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3539 if (proceed == MagickFalse)
3543 resize_view=DestroyCacheView(resize_view);
3544 image_view=DestroyCacheView(image_view);
3545 contributions=DestroyContributionTLS(contributions);
3549static MagickBooleanType VerticalFilter(
3551 const Image *magick_restrict image,
Image *magick_restrict resize_image,
3552 const double y_factor,
const MagickSizeType span,
3553 MagickOffsetType *magick_restrict progress,
ExceptionInfo *exception)
3563 **magick_restrict contributions;
3578 scale=MagickMax(1.0/y_factor+MagickEpsilon,1.0);
3579 support=scale*GetResizeFilterSupport(resize_filter);
3580 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3581 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3582 return(MagickFalse);
3588 support=(double) 0.5;
3591 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3594 (void) ThrowMagickException(exception,GetMagickModule(),
3595 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3596 return(MagickFalse);
3599 scale=PerceptibleReciprocal(scale);
3600 image_view=AcquireVirtualCacheView(image,exception);
3601 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3602#if defined(MAGICKCORE_OPENMP_SUPPORT)
3603 #pragma omp parallel for schedule(static) shared(progress,status) \
3604 magick_number_threads(image,resize_image,resize_image->rows,1)
3606 for (y=0; y < (ssize_t) resize_image->rows; y++)
3609 id = GetOpenMPThreadId();
3615 *magick_restrict contribution;
3630 if (status == MagickFalse)
3632 bisect=(double) (y+0.5)/y_factor+MagickEpsilon;
3633 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3634 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->rows);
3636 contribution=contributions[id];
3637 for (n=0; n < (stop-start); n++)
3639 contribution[n].pixel=start+n;
3640 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3641 ((
double) (start+n)-bisect+0.5));
3642 density+=contribution[n].weight;
3646 if ((density != 0.0) && (density != 1.0))
3654 density=PerceptibleReciprocal(density);
3655 for (i=0; i < n; i++)
3656 contribution[i].weight*=density;
3658 p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
3659 image->columns,(
size_t) (contribution[n-1].pixel-contribution[0].pixel+1),
3661 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
3663 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3668 for (x=0; x < (ssize_t) resize_image->columns; x++)
3673 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3691 channel=GetPixelChannelChannel(image,i);
3692 traits=GetPixelChannelTraits(image,channel);
3693 resize_traits=GetPixelChannelTraits(resize_image,channel);
3694 if ((traits == UndefinedPixelTrait) ||
3695 (resize_traits == UndefinedPixelTrait))
3697 if (((resize_traits & CopyPixelTrait) != 0) ||
3698 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3700 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3702 k=(ssize_t) ((contribution[j-start].pixel-contribution[0].pixel)*
3703 (ssize_t) image->columns+x);
3704 SetPixelChannel(resize_image,channel,p[k*(ssize_t)
3705 GetPixelChannels(image)+i],q);
3709 if ((resize_traits & BlendPixelTrait) == 0)
3714 for (j=0; j < n; j++)
3716 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3717 (ssize_t) image->columns+x);
3718 alpha=contribution[j].weight;
3719 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3721 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3725 for (j=0; j < n; j++)
3727 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3728 (ssize_t) image->columns+x);
3729 alpha=contribution[j].weight*QuantumScale*(double)
3730 GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3731 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3734 gamma=PerceptibleReciprocal(gamma);
3735 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3737 q+=GetPixelChannels(resize_image);
3739 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3741 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3746#if defined(MAGICKCORE_OPENMP_SUPPORT)
3750 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3751 if (proceed == MagickFalse)
3755 resize_view=DestroyCacheView(resize_view);
3756 image_view=DestroyCacheView(image_view);
3757 contributions=DestroyContributionTLS(contributions);
3761MagickExport
Image *ResizeImage(
const Image *image,
const size_t columns,
3762 const size_t rows,
const FilterType filter,
ExceptionInfo *exception)
3790 assert(image != (
Image *) NULL);
3791 assert(image->signature == MagickCoreSignature);
3793 assert(exception->signature == MagickCoreSignature);
3794 if (IsEventLogging() != MagickFalse)
3795 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3796 if ((columns == 0) || (rows == 0))
3797 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3798 if ((columns == image->columns) && (rows == image->rows) &&
3799 (filter == UndefinedFilter))
3800 return(CloneImage(image,0,0,MagickTrue,exception));
3804 x_factor=(double) (columns*PerceptibleReciprocal((
double) image->columns));
3805 y_factor=(double) (rows*PerceptibleReciprocal((
double) image->rows));
3806 filter_type=LanczosFilter;
3807 if (filter != UndefinedFilter)
3810 if ((x_factor == 1.0) && (y_factor == 1.0))
3811 filter_type=PointFilter;
3813 if ((image->storage_class == PseudoClass) ||
3814 (image->alpha_trait != UndefinedPixelTrait) ||
3815 ((x_factor*y_factor) > 1.0))
3816 filter_type=MitchellFilter;
3817 resize_filter=AcquireResizeFilter(image,filter_type,MagickFalse,exception);
3818#if defined(MAGICKCORE_OPENCL_SUPPORT)
3819 resize_image=AccelerateResizeImage(image,columns,rows,resize_filter,
3821 if (resize_image != (
Image *) NULL)
3823 resize_filter=DestroyResizeFilter(resize_filter);
3824 return(resize_image);
3827 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
3828 if (resize_image == (
Image *) NULL)
3830 resize_filter=DestroyResizeFilter(resize_filter);
3831 return(resize_image);
3833 if (x_factor > y_factor)
3834 filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
3836 filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
3837 if (filter_image == (
Image *) NULL)
3839 resize_filter=DestroyResizeFilter(resize_filter);
3840 return(DestroyImage(resize_image));
3846 if (x_factor > y_factor)
3848 span=(MagickSizeType) (filter_image->columns+rows);
3849 status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
3851 status&=(MagickStatusType) VerticalFilter(resize_filter,filter_image,
3852 resize_image,y_factor,span,&offset,exception);
3856 span=(MagickSizeType) (filter_image->rows+columns);
3857 status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
3859 status&=(MagickStatusType) HorizontalFilter(resize_filter,filter_image,
3860 resize_image,x_factor,span,&offset,exception);
3865 filter_image=DestroyImage(filter_image);
3866 resize_filter=DestroyResizeFilter(resize_filter);
3867 if (status == MagickFalse)
3869 resize_image=DestroyImage(resize_image);
3870 return((
Image *) NULL);
3872 resize_image->type=image->type;
3873 return(resize_image);
3907MagickExport
Image *SampleImage(
const Image *image,
const size_t columns,
3910#define SampleImageTag "Sample/Image"
3936 assert(image != (
const Image *) NULL);
3937 assert(image->signature == MagickCoreSignature);
3939 assert(exception->signature == MagickCoreSignature);
3940 if (IsEventLogging() != MagickFalse)
3941 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3942 if ((columns == 0) || (rows == 0))
3943 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3944 if ((columns == image->columns) && (rows == image->rows))
3945 return(CloneImage(image,0,0,MagickTrue,exception));
3946 sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
3947 if (sample_image == (
Image *) NULL)
3948 return((
Image *) NULL);
3952 sample_offset.x=0.5-MagickEpsilon;
3953 sample_offset.y=sample_offset.x;
3958 value=GetImageArtifact(image,
"sample:offset");
3959 if (value != (
char *) NULL)
3967 (void) ParseGeometry(value,&geometry_info);
3968 flags=ParseGeometry(value,&geometry_info);
3969 sample_offset.x=sample_offset.y=geometry_info.rho/100.0-MagickEpsilon;
3970 if ((flags & SigmaValue) != 0)
3971 sample_offset.y=geometry_info.sigma/100.0-MagickEpsilon;
3977 x_offset=(ssize_t *) AcquireQuantumMemory((
size_t) sample_image->columns,
3979 if (x_offset == (ssize_t *) NULL)
3981 sample_image=DestroyImage(sample_image);
3982 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3984 for (j=0; j < (ssize_t) sample_image->columns; j++)
3985 x_offset[j]=(ssize_t) ((((double) j+sample_offset.x)*image->columns)/
3986 sample_image->columns);
3992 image_view=AcquireVirtualCacheView(image,exception);
3993 sample_view=AcquireAuthenticCacheView(sample_image,exception);
3994#if defined(MAGICKCORE_OPENMP_SUPPORT)
3995 #pragma omp parallel for schedule(static) shared(status) \
3996 magick_number_threads(image,sample_image,sample_image->rows,2)
3998 for (y=0; y < (ssize_t) sample_image->rows; y++)
4010 if (status == MagickFalse)
4012 y_offset=(ssize_t) ((((
double) y+sample_offset.y)*image->rows)/
4013 sample_image->rows);
4014 p=GetCacheViewVirtualPixels(image_view,0,y_offset,image->columns,1,
4016 q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
4018 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
4026 for (x=0; x < (ssize_t) sample_image->columns; x++)
4031 if (GetPixelWriteMask(sample_image,q) <= (QuantumRange/2))
4033 q+=GetPixelChannels(sample_image);
4036 for (i=0; i < (ssize_t) GetPixelChannels(sample_image); i++)
4045 channel=GetPixelChannelChannel(sample_image,i);
4046 traits=GetPixelChannelTraits(sample_image,channel);
4047 image_traits=GetPixelChannelTraits(image,channel);
4048 if ((traits == UndefinedPixelTrait) ||
4049 (image_traits == UndefinedPixelTrait))
4051 SetPixelChannel(sample_image,channel,p[x_offset[x]*(ssize_t)
4052 GetPixelChannels(image)+i],q);
4054 q+=GetPixelChannels(sample_image);
4056 if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
4058 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4063 proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
4064 if (proceed == MagickFalse)
4068 image_view=DestroyCacheView(image_view);
4069 sample_view=DestroyCacheView(sample_view);
4070 x_offset=(ssize_t *) RelinquishMagickMemory(x_offset);
4071 sample_image->type=image->type;
4072 if (status == MagickFalse)
4073 sample_image=DestroyImage(sample_image);
4074 return(sample_image);
4106MagickExport
Image *ScaleImage(
const Image *image,
const size_t columns,
4109#define ScaleImageTag "Scale/Image"
4117 pixel[CompositePixelChannel],
4148 assert(image != (
const Image *) NULL);
4149 assert(image->signature == MagickCoreSignature);
4151 assert(exception->signature == MagickCoreSignature);
4152 if (IsEventLogging() != MagickFalse)
4153 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4154 if ((columns == 0) || (rows == 0))
4155 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
4156 if ((columns == image->columns) && (rows == image->rows))
4157 return(CloneImage(image,0,0,MagickTrue,exception));
4158 scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
4159 if (scale_image == (
Image *) NULL)
4160 return((
Image *) NULL);
4161 if (SetImageStorageClass(scale_image,DirectClass,exception) == MagickFalse)
4163 scale_image=DestroyImage(scale_image);
4164 return((
Image *) NULL);
4169 x_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4170 MaxPixelChannels*
sizeof(*x_vector));
4172 if (image->rows != scale_image->rows)
4173 scanline=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4174 MaxPixelChannels*
sizeof(*scanline));
4175 scale_scanline=(
double *) AcquireQuantumMemory((
size_t) scale_image->columns,
4176 MaxPixelChannels*
sizeof(*scale_scanline));
4177 y_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4178 MaxPixelChannels*
sizeof(*y_vector));
4179 if ((scanline == (
double *) NULL) || (scale_scanline == (
double *) NULL) ||
4180 (x_vector == (
double *) NULL) || (y_vector == (
double *) NULL))
4182 if ((image->rows != scale_image->rows) && (scanline != (
double *) NULL))
4183 scanline=(
double *) RelinquishMagickMemory(scanline);
4184 if (scale_scanline != (
double *) NULL)
4185 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4186 if (x_vector != (
double *) NULL)
4187 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4188 if (y_vector != (
double *) NULL)
4189 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4190 scale_image=DestroyImage(scale_image);
4191 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4197 next_row=MagickTrue;
4199 scale.y=(double) scale_image->rows/(
double) image->rows;
4200 (void) memset(y_vector,0,(
size_t) MaxPixelChannels*image->columns*
4204 image_view=AcquireVirtualCacheView(image,exception);
4205 scale_view=AcquireAuthenticCacheView(scale_image,exception);
4206 for (y=0; y < (ssize_t) scale_image->rows; y++)
4217 if (status == MagickFalse)
4219 q=QueueCacheViewAuthenticPixels(scale_view,0,y,scale_image->columns,1,
4221 if (q == (Quantum *) NULL)
4227 if (scale_image->rows == image->rows)
4232 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4234 if (p == (
const Quantum *) NULL)
4239 for (x=0; x < (ssize_t) image->columns; x++)
4241 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4243 p+=GetPixelChannels(image);
4246 if (image->alpha_trait != UndefinedPixelTrait)
4247 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4248 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4250 PixelChannel channel = GetPixelChannelChannel(image,i);
4251 PixelTrait traits = GetPixelChannelTraits(image,channel);
4252 if ((traits & BlendPixelTrait) == 0)
4254 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=(double) p[i];
4257 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*(double) p[i];
4259 p+=GetPixelChannels(image);
4267 while (scale.y < span.y)
4269 if ((next_row != MagickFalse) &&
4270 (number_rows < (ssize_t) image->rows))
4275 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4277 if (p == (
const Quantum *) NULL)
4282 for (x=0; x < (ssize_t) image->columns; x++)
4284 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4286 p+=GetPixelChannels(image);
4289 if (image->alpha_trait != UndefinedPixelTrait)
4290 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4291 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4293 PixelChannel channel = GetPixelChannelChannel(image,i);
4294 PixelTrait traits = GetPixelChannelTraits(image,channel);
4295 if ((traits & BlendPixelTrait) == 0)
4297 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4301 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4304 p+=GetPixelChannels(image);
4308 for (x=0; x < (ssize_t) image->columns; x++)
4309 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4310 y_vector[x*(ssize_t) GetPixelChannels(image)+i]+=scale.y*
4311 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4313 scale.y=(double) scale_image->rows/(
double) image->rows;
4314 next_row=MagickTrue;
4316 if ((next_row != MagickFalse) && (number_rows < (ssize_t) image->rows))
4321 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4323 if (p == (
const Quantum *) NULL)
4328 for (x=0; x < (ssize_t) image->columns; x++)
4330 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4332 p+=GetPixelChannels(image);
4335 if (image->alpha_trait != UndefinedPixelTrait)
4336 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4337 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4339 PixelChannel channel = GetPixelChannelChannel(image,i);
4340 PixelTrait traits = GetPixelChannelTraits(image,channel);
4341 if ((traits & BlendPixelTrait) == 0)
4343 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4347 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4350 p+=GetPixelChannels(image);
4353 next_row=MagickFalse;
4355 for (x=0; x < (ssize_t) image->columns; x++)
4357 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4359 pixel[i]=y_vector[x*(ssize_t) GetPixelChannels(image)+i]+span.y*
4360 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4361 scanline[x*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4362 y_vector[x*(ssize_t) GetPixelChannels(image)+i]=0.0;
4368 scale.y=(double) scale_image->rows/(
double) image->rows;
4369 next_row=MagickTrue;
4373 if (scale_image->columns == image->columns)
4378 for (x=0; x < (ssize_t) scale_image->columns; x++)
4380 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4382 q+=GetPixelChannels(scale_image);
4385 if (image->alpha_trait != UndefinedPixelTrait)
4387 alpha=QuantumScale*scanline[x*(ssize_t) GetPixelChannels(image)+
4388 GetPixelChannelOffset(image,AlphaPixelChannel)];
4389 alpha=PerceptibleReciprocal(alpha);
4391 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4393 PixelChannel channel = GetPixelChannelChannel(image,i);
4394 PixelTrait traits = GetPixelChannelTraits(image,channel);
4395 scale_traits=GetPixelChannelTraits(scale_image,channel);
4396 if ((traits == UndefinedPixelTrait) ||
4397 (scale_traits == UndefinedPixelTrait))
4399 if ((traits & BlendPixelTrait) == 0)
4401 SetPixelChannel(scale_image,channel,ClampToQuantum(
4402 scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4405 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*scanline[
4406 x*(ssize_t) GetPixelChannels(image)+i]),q);
4408 q+=GetPixelChannels(scale_image);
4419 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4421 next_column=MagickFalse;
4424 for (x=0; x < (ssize_t) image->columns; x++)
4426 scale.x=(double) scale_image->columns/(
double) image->columns;
4427 while (scale.x >= span.x)
4429 if (next_column != MagickFalse)
4431 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4435 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4437 PixelChannel channel = GetPixelChannelChannel(image,i);
4438 PixelTrait traits = GetPixelChannelTraits(image,channel);
4439 if (traits == UndefinedPixelTrait)
4441 pixel[i]+=span.x*scanline[x*(ssize_t) GetPixelChannels(image)+i];
4442 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4446 next_column=MagickTrue;
4450 if (next_column != MagickFalse)
4452 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4454 next_column=MagickFalse;
4457 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4458 pixel[i]+=scale.x*scanline[x*(ssize_t)
4459 GetPixelChannels(image)+i];
4465 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4467 scanline[(x-1)*(ssize_t) GetPixelChannels(image)+i];
4469 if ((next_column == MagickFalse) && (t < (ssize_t) scale_image->columns))
4470 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4471 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4475 for (x=0; x < (ssize_t) scale_image->columns; x++)
4477 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4479 q+=GetPixelChannels(scale_image);
4482 if (image->alpha_trait != UndefinedPixelTrait)
4484 alpha=QuantumScale*scale_scanline[x*(ssize_t)
4485 GetPixelChannels(image)+
4486 GetPixelChannelOffset(image,AlphaPixelChannel)];
4487 alpha=PerceptibleReciprocal(alpha);
4489 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4491 PixelChannel channel = GetPixelChannelChannel(image,i);
4492 PixelTrait traits = GetPixelChannelTraits(image,channel);
4493 scale_traits=GetPixelChannelTraits(scale_image,channel);
4494 if ((traits == UndefinedPixelTrait) ||
4495 (scale_traits == UndefinedPixelTrait))
4497 if ((traits & BlendPixelTrait) == 0)
4499 SetPixelChannel(scale_image,channel,ClampToQuantum(
4500 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4503 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*
4504 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4506 q+=GetPixelChannels(scale_image);
4509 if (SyncCacheViewAuthenticPixels(scale_view,exception) == MagickFalse)
4514 proceed=SetImageProgress(image,ScaleImageTag,(MagickOffsetType) y,
4516 if (proceed == MagickFalse)
4522 scale_view=DestroyCacheView(scale_view);
4523 image_view=DestroyCacheView(image_view);
4527 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4528 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4529 if (scale_image->rows != image->rows)
4530 scanline=(
double *) RelinquishMagickMemory(scanline);
4531 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4532 scale_image->type=image->type;
4533 if (status == MagickFalse)
4534 scale_image=DestroyImage(scale_image);
4535 return(scale_image);
4569MagickExport
Image *ThumbnailImage(
const Image *image,
const size_t columns,
4572#define SampleFactor 5
4575 filename[MagickPathExtent],
4576 value[MagickPathExtent];
4587 assert(image != (
Image *) NULL);
4588 assert(image->signature == MagickCoreSignature);
4590 assert(exception->signature == MagickCoreSignature);
4591 if (IsEventLogging() != MagickFalse)
4592 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4593 thumbnail_image=CloneImage(image,0,0,MagickTrue,exception);
4594 if (thumbnail_image == (
Image *) NULL)
4595 return(thumbnail_image);
4596 if ((columns != image->columns) || (rows != image->rows))
4599 *clone_image = thumbnail_image;
4605 x_factor=(ssize_t) image->columns/(ssize_t) columns;
4606 y_factor=(ssize_t) image->rows/(ssize_t) rows;
4607 if ((x_factor > 4) && (y_factor > 4))
4609 thumbnail_image=SampleImage(clone_image,4*columns,4*rows,exception);
4610 if (thumbnail_image != (
Image *) NULL)
4612 clone_image=DestroyImage(clone_image);
4613 clone_image=thumbnail_image;
4616 if ((x_factor > 2) && (y_factor > 2))
4618 thumbnail_image=ResizeImage(clone_image,2*columns,2*rows,BoxFilter,
4620 if (thumbnail_image != (
Image *) NULL)
4622 clone_image=DestroyImage(clone_image);
4623 clone_image=thumbnail_image;
4626 thumbnail_image=ResizeImage(clone_image,columns,rows,image->filter ==
4627 UndefinedFilter ? LanczosSharpFilter : image->filter,exception);
4628 clone_image=DestroyImage(clone_image);
4629 if (thumbnail_image == (
Image *) NULL)
4630 return(thumbnail_image);
4632 (void) ParseAbsoluteGeometry(
"0x0+0+0",&thumbnail_image->page);
4633 thumbnail_image->depth=8;
4634 thumbnail_image->interlace=NoInterlace;
4638 ResetImageProfileIterator(thumbnail_image);
4639 for (name=GetNextImageProfile(thumbnail_image); name != (
const char *) NULL; )
4641 if ((LocaleCompare(name,
"icc") != 0) && (LocaleCompare(name,
"icm") != 0))
4643 (void) DeleteImageProfile(thumbnail_image,name);
4644 ResetImageProfileIterator(thumbnail_image);
4646 name=GetNextImageProfile(thumbnail_image);
4648 (void) DeleteImageProperty(thumbnail_image,
"comment");
4649 (void) CopyMagickString(value,image->magick_filename,MagickPathExtent);
4650 if (strstr(image->magick_filename,
"//") == (
char *) NULL)
4651 (void) FormatLocaleString(value,MagickPathExtent,
"file://%s",
4652 image->magick_filename);
4653 (void) SetImageProperty(thumbnail_image,
"Thumb::URI",value,exception);
4654 GetPathComponent(image->magick_filename,TailPath,filename);
4655 (void) CopyMagickString(value,filename,MagickPathExtent);
4656 if ( GetPathAttributes(image->filename,&attributes) != MagickFalse )
4657 (void) FormatImageProperty(thumbnail_image,
"Thumb::MTime",
"%.20g",(
double)
4658 attributes.st_mtime);
4659 (void) FormatLocaleString(value,MagickPathExtent,
"%.20g",(
double)
4660 attributes.st_mtime);
4661 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,
"B",MagickPathExtent,
4663 (void) SetImageProperty(thumbnail_image,
"Thumb::Size",value,exception);
4664 (void) FormatLocaleString(value,MagickPathExtent,
"image/%s",image->magick);
4666 (void) SetImageProperty(thumbnail_image,
"Thumb::Mimetype",value,exception);
4667 (void) SetImageProperty(thumbnail_image,
"software",MagickAuthoritativeURL,
4669 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Width",
"%.20g",
4670 (
double) image->magick_columns);
4671 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Height",
"%.20g",
4672 (
double) image->magick_rows);
4673 (void) FormatImageProperty(thumbnail_image,
"Thumb::Document::Pages",
"%.20g",
4674 (
double) GetImageListLength(image));
4675 return(thumbnail_image);