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)
94 (*filter)(
const double,
const ResizeFilter *),
95 (*window)(
const double,
const ResizeFilter *),
102 ResizeWeightingFunctionType
115 BesselOrderOne(
double),
116 Sinc(
const double,
const ResizeFilter *),
117 SincFast(
const double,
const ResizeFilter *);
151static double Blackman(
const double x,
152 const ResizeFilter *magick_unused(resize_filter))
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,
167 const ResizeFilter *magick_unused(resize_filter))
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),
184 const ResizeFilter *magick_unused(resize_filter))
186 magick_unreferenced(x);
187 magick_unreferenced(resize_filter);
197static double Cosine(
const double x,
198 const ResizeFilter *magick_unused(resize_filter))
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,
325 const ResizeFilter *magick_unused(resize_filter))
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,
337 const ResizeFilter *magick_unused(resize_filter))
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,
349 const ResizeFilter *magick_unused(resize_filter))
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,
418 const ResizeFilter *magick_unused(resize_filter))
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,
438 const ResizeFilter *magick_unused(resize_filter))
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,
462 const ResizeFilter *magick_unused(resize_filter))
464 magick_unreferenced(resize_filter);
472 return(0.5*(x-1.5)*(x-1.5));
476static double Sinc(
const double x,
477 const ResizeFilter *magick_unused(resize_filter))
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,
494 const ResizeFilter *magick_unused(resize_filter))
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,
590 const ResizeFilter *magick_unused(resize_filter))
592 magick_unreferenced(resize_filter);
604static double Welch(
const double x,
605 const ResizeFilter *magick_unused(resize_filter))
607 magick_unreferenced(resize_filter);
803MagickPrivate ResizeFilter *AcquireResizeFilter(
const Image *image,
804 const FilterType filter,
const MagickBooleanType cylindrical,
805 ExceptionInfo *exception)
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 },
891 (*function)(
const double,
const ResizeFilter*),
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);
981 assert(exception != (ExceptionInfo *) NULL);
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]=MagickSafeReciprocal(2.0*value*value);
1098 resize_filter->coefficient[2]=MagickSafeReciprocal(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]=MagickSafeReciprocal(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*=MagickSafeReciprocal(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))));
1577MagickPrivate ResizeFilter *DestroyResizeFilter(ResizeFilter *resize_filter)
1579 assert(resize_filter != (ResizeFilter *) NULL);
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(
1611 const ResizeFilter *resize_filter)
1613 assert(resize_filter != (ResizeFilter *) NULL);
1614 assert(resize_filter->signature == MagickCoreSignature);
1615 return((
double *) resize_filter->coefficient);
1618MagickPrivate
double GetResizeFilterBlur(
const ResizeFilter *resize_filter)
1620 assert(resize_filter != (ResizeFilter *) NULL);
1621 assert(resize_filter->signature == MagickCoreSignature);
1622 return(resize_filter->blur);
1625MagickPrivate
double GetResizeFilterScale(
const ResizeFilter *resize_filter)
1627 assert(resize_filter != (ResizeFilter *) NULL);
1628 assert(resize_filter->signature == MagickCoreSignature);
1629 return(resize_filter->scale);
1632MagickPrivate
double GetResizeFilterWindowSupport(
1633 const ResizeFilter *resize_filter)
1635 assert(resize_filter != (ResizeFilter *) NULL);
1636 assert(resize_filter->signature == MagickCoreSignature);
1637 return(resize_filter->window_support);
1640MagickPrivate ResizeWeightingFunctionType GetResizeFilterWeightingType(
1641 const ResizeFilter *resize_filter)
1643 assert(resize_filter != (ResizeFilter *) NULL);
1644 assert(resize_filter->signature == MagickCoreSignature);
1645 return(resize_filter->filterWeightingType);
1648MagickPrivate ResizeWeightingFunctionType GetResizeFilterWindowWeightingType(
1649 const ResizeFilter *resize_filter)
1651 assert(resize_filter != (ResizeFilter *) NULL);
1652 assert(resize_filter->signature == MagickCoreSignature);
1653 return(resize_filter->windowWeightingType);
1656MagickPrivate
double GetResizeFilterSupport(
const ResizeFilter *resize_filter)
1658 assert(resize_filter != (ResizeFilter *) NULL);
1659 assert(resize_filter->signature == MagickCoreSignature);
1660 return(resize_filter->support*resize_filter->blur);
1690MagickPrivate
double GetResizeFilterWeight(
const ResizeFilter *resize_filter,
1701 assert(resize_filter != (ResizeFilter *) NULL);
1702 assert(resize_filter->signature == MagickCoreSignature);
1703 x_blur=fabs((
double) x)*MagickSafeReciprocal(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,
1751 ExceptionInfo *exception)
1753#define InterpolativeResizeImageTag "Resize/Image"
1777 assert(image != (
const Image *) NULL);
1778 assert(image->signature == MagickCoreSignature);
1779 assert(exception != (ExceptionInfo *) NULL);
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+=(ptrdiff_t) 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,
1912 ExceptionInfo *exception)
1914#define LiquidRescaleImageTag "Rescale/Image"
1952 assert(image != (
const Image *) NULL);
1953 assert(image->signature == MagickCoreSignature);
1954 assert(exception != (ExceptionInfo *) NULL);
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*
1966 if (pixel_info == (MemoryInfo *) NULL)
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++=(gfloat) (QuantumScale*(double) p[i]);
1995 p+=(ptrdiff_t) 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,(gint) delta_x,(gfloat) rigidity);
2008 lqr_status=lqr_carver_resize(carver,(gint) columns,(gint) 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),
2067 ExceptionInfo *exception)
2069 assert(image != (
const Image *) NULL);
2070 assert(image->signature == MagickCoreSignature);
2071 assert(exception != (ExceptionInfo *) NULL);
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+=(ssize_t) 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]=(MagickFloatType) GetPixelIntensity(source,pixels+
2492 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);
2885MagickExport Image *MagnifyImage(
const Image *image,ExceptionInfo *exception)
2887#define MagnifyImageTag "Magnify/Image"
2888#define MaxMagnification 9
2921 (*scaling_method)(
const Image *,
const Quantum *,Quantum *,size_t);
2926 assert(image != (
const Image *) NULL);
2927 assert(image->signature == MagickCoreSignature);
2928 assert(exception != (ExceptionInfo *) NULL);
2929 assert(exception->signature == MagickCoreSignature);
2930 if (IsEventLogging() != MagickFalse)
2931 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2932 option=GetImageOption(image->image_info,
"magnify:method");
2933 if (option == (
char *) NULL)
2935 scaling_method=Scale2X;
2942 if (LocaleCompare(option,
"eagle2x") == 0)
2944 scaling_method=Eagle2X;
2949 if (LocaleCompare(option,
"eagle3x") == 0)
2951 scaling_method=Eagle3X;
2956 if (LocaleCompare(option,
"eagle3xb") == 0)
2958 scaling_method=Eagle3XB;
2963 if (LocaleCompare(option,
"epbx2x") == 0)
2965 scaling_method=Epbx2X;
2974 if (LocaleCompare(option,
"fish2x") == 0)
2976 scaling_method=Fish2X;
2985 if (LocaleCompare(option,
"hq2x") == 0)
2987 scaling_method=Hq2X;
2996 if (LocaleCompare(option,
"scale2x") == 0)
2998 scaling_method=Scale2X;
3003 if (LocaleCompare(option,
"scale3x") == 0)
3005 scaling_method=Scale3X;
3014 if (LocaleCompare(option,
"xbr2x") == 0)
3016 scaling_method=Xbr2X;
3025 assert((magnification*magnification) <= MaxMagnification);
3029 source_image=CloneImage(image,image->columns,image->rows,MagickTrue,
3031 if (source_image == (Image *) NULL)
3032 return((Image *) NULL);
3037 rectangle.width=image->columns;
3038 rectangle.height=image->rows;
3039 (void) CopyImagePixels(source_image,image,&rectangle,&offset,exception);
3040 if (IssRGBCompatibleColorspace(source_image->colorspace) == MagickFalse)
3041 (void) TransformImageColorspace(source_image,sRGBColorspace,exception);
3042 magnify_image=CloneImage(source_image,magnification*source_image->columns,
3043 magnification*source_image->rows,MagickTrue,exception);
3044 if (magnify_image == (Image *) NULL)
3046 source_image=DestroyImage(source_image);
3047 return((Image *) NULL);
3054 image_view=AcquireVirtualCacheView(source_image,exception);
3055 magnify_view=AcquireAuthenticCacheView(magnify_image,exception);
3056#if defined(MAGICKCORE_OPENMP_SUPPORT)
3057 #pragma omp parallel for schedule(static) shared(progress,status) \
3058 magick_number_threads(source_image,magnify_image,source_image->rows,1)
3060 for (y=0; y < (ssize_t) source_image->rows; y++)
3063 r[MaxMagnification*MaxPixelChannels];
3071 if (status == MagickFalse)
3073 q=QueueCacheViewAuthenticPixels(magnify_view,0,magnification*y,
3074 magnify_image->columns,magnification,exception);
3075 if (q == (Quantum *) NULL)
3083 for (x=0; x < (ssize_t) source_image->columns; x++)
3095 p=GetCacheViewVirtualPixels(image_view,x-width/2,y-width/2,width,width,
3097 if (p == (Quantum *) NULL)
3102 channels=GetPixelChannels(source_image);
3103 scaling_method(source_image,p,r,channels);
3107 for (j=0; j < (ssize_t) magnification; j++)
3108 for (i=0; i < (ssize_t) (channels*magnification); i++)
3109 q[j*(ssize_t) channels*(ssize_t) magnify_image->columns+i]=
3110 r[j*magnification*(ssize_t) channels+i];
3111 q+=(ptrdiff_t) magnification*GetPixelChannels(magnify_image);
3113 if (SyncCacheViewAuthenticPixels(magnify_view,exception) == MagickFalse)
3115 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3120#if defined(MAGICKCORE_OPENMP_SUPPORT)
3124 proceed=SetImageProgress(image,MagnifyImageTag,progress,image->rows);
3125 if (proceed == MagickFalse)
3129 magnify_view=DestroyCacheView(magnify_view);
3130 image_view=DestroyCacheView(image_view);
3131 source_image=DestroyImage(source_image);
3132 if (status == MagickFalse)
3133 magnify_image=DestroyImage(magnify_image);
3134 return(magnify_image);
3162MagickExport Image *MinifyImage(
const Image *image,ExceptionInfo *exception)
3167 assert(image != (Image *) NULL);
3168 assert(image->signature == MagickCoreSignature);
3169 assert(exception != (ExceptionInfo *) NULL);
3170 assert(exception->signature == MagickCoreSignature);
3171 if (IsEventLogging() != MagickFalse)
3172 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3173 minify_image=ResizeImage(image,image->columns/2,image->rows/2,SplineFilter,
3175 return(minify_image);
3212MagickExport Image *ResampleImage(
const Image *image,
const double x_resolution,
3213 const double y_resolution,
const FilterType filter,ExceptionInfo *exception)
3215#define ResampleImageTag "Resample/Image"
3227 assert(image != (
const Image *) NULL);
3228 assert(image->signature == MagickCoreSignature);
3229 assert(exception != (ExceptionInfo *) NULL);
3230 assert(exception->signature == MagickCoreSignature);
3231 if (IsEventLogging() != MagickFalse)
3232 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3233 width=(size_t) (x_resolution*image->columns/(image->resolution.x == 0.0 ?
3234 DefaultResolution : image->resolution.x)+0.5);
3235 height=(size_t) (y_resolution*image->rows/(image->resolution.y == 0.0 ?
3236 DefaultResolution : image->resolution.y)+0.5);
3237 resample_image=ResizeImage(image,width,height,filter,exception);
3238 if (resample_image != (Image *) NULL)
3240 resample_image->resolution.x=x_resolution;
3241 resample_image->resolution.y=y_resolution;
3243 return(resample_image);
3294static ContributionInfo **DestroyContributionTLS(
3295 ContributionInfo **contribution)
3300 assert(contribution != (ContributionInfo **) NULL);
3301 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3302 if (contribution[i] != (ContributionInfo *) NULL)
3303 contribution[i]=(ContributionInfo *) RelinquishAlignedMemory(
3305 contribution=(ContributionInfo **) RelinquishMagickMemory(contribution);
3306 return(contribution);
3309static ContributionInfo **AcquireContributionTLS(
const size_t count)
3320 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3321 contribution=(ContributionInfo **) AcquireQuantumMemory(number_threads,
3322 sizeof(*contribution));
3323 if (contribution == (ContributionInfo **) NULL)
3324 return((ContributionInfo **) NULL);
3325 (void) memset(contribution,0,number_threads*
sizeof(*contribution));
3326 for (i=0; i < (ssize_t) number_threads; i++)
3328 contribution[i]=(ContributionInfo *) MagickAssumeAligned(
3329 AcquireAlignedMemory(count,
sizeof(**contribution)));
3330 if (contribution[i] == (ContributionInfo *) NULL)
3331 return(DestroyContributionTLS(contribution));
3333 return(contribution);
3336static MagickBooleanType HorizontalFilter(
3337 const ResizeFilter *magick_restrict resize_filter,
3338 const Image *magick_restrict image,Image *magick_restrict resize_image,
3339 const double x_factor,
const MagickSizeType span,
3340 MagickOffsetType *magick_restrict progress,ExceptionInfo *exception)
3342#define ResizeImageTag "Resize/Image"
3352 **magick_restrict contributions;
3367 scale=MagickMax(1.0/x_factor+MagickEpsilon,1.0);
3368 support=scale*GetResizeFilterSupport(resize_filter);
3369 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3370 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3371 return(MagickFalse);
3377 support=(double) 0.5;
3380 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3381 if (contributions == (ContributionInfo **) NULL)
3383 (void) ThrowMagickException(exception,GetMagickModule(),
3384 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3385 return(MagickFalse);
3388 scale=MagickSafeReciprocal(scale);
3389 image_view=AcquireVirtualCacheView(image,exception);
3390 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3391#if defined(MAGICKCORE_OPENMP_SUPPORT)
3392 #pragma omp parallel for schedule(static) shared(progress,status) \
3393 magick_number_threads(image,resize_image,resize_image->columns,1)
3395 for (x=0; x < (ssize_t) resize_image->columns; x++)
3398 id = GetOpenMPThreadId();
3404 *magick_restrict contribution;
3419 if (status == MagickFalse)
3421 bisect=(double) (x+0.5)/x_factor+MagickEpsilon;
3422 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3423 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->columns);
3425 contribution=contributions[id];
3426 for (n=0; n < (stop-start); n++)
3428 contribution[n].pixel=start+n;
3429 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3430 ((
double) (start+n)-bisect+0.5));
3431 density+=contribution[n].weight;
3435 if ((density != 0.0) && (density != 1.0))
3443 density=MagickSafeReciprocal(density);
3444 for (i=0; i < n; i++)
3445 contribution[i].weight*=density;
3447 p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,(
size_t)
3448 (contribution[n-1].pixel-contribution[0].pixel+1),image->rows,exception);
3449 q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
3451 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3456 for (y=0; y < (ssize_t) resize_image->rows; y++)
3461 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3479 channel=GetPixelChannelChannel(image,i);
3480 traits=GetPixelChannelTraits(image,channel);
3481 resize_traits=GetPixelChannelTraits(resize_image,channel);
3482 if ((traits == UndefinedPixelTrait) ||
3483 (resize_traits == UndefinedPixelTrait))
3485 if (((resize_traits & CopyPixelTrait) != 0) ||
3486 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3488 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3490 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3491 (contribution[j-start].pixel-contribution[0].pixel);
3492 SetPixelChannel(resize_image,channel,
3493 p[k*(ssize_t) GetPixelChannels(image)+i],q);
3497 if ((resize_traits & BlendPixelTrait) == 0)
3502 for (j=0; j < n; j++)
3504 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3505 (contribution[j].pixel-contribution[0].pixel);
3506 alpha=contribution[j].weight;
3507 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3509 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3516 for (j=0; j < n; j++)
3518 k=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
3519 (contribution[j].pixel-contribution[0].pixel);
3520 alpha=contribution[j].weight*QuantumScale*
3521 (double) GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3522 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3525 gamma=MagickSafeReciprocal(gamma);
3526 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3528 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3530 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3532 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3537#if defined(MAGICKCORE_OPENMP_SUPPORT)
3541 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3542 if (proceed == MagickFalse)
3546 resize_view=DestroyCacheView(resize_view);
3547 image_view=DestroyCacheView(image_view);
3548 contributions=DestroyContributionTLS(contributions);
3552static MagickBooleanType VerticalFilter(
3553 const ResizeFilter *magick_restrict resize_filter,
3554 const Image *magick_restrict image,Image *magick_restrict resize_image,
3555 const double y_factor,
const MagickSizeType span,
3556 MagickOffsetType *magick_restrict progress,ExceptionInfo *exception)
3566 **magick_restrict contributions;
3581 scale=MagickMax(1.0/y_factor+MagickEpsilon,1.0);
3582 support=scale*GetResizeFilterSupport(resize_filter);
3583 storage_class=support > 0.5 ? DirectClass : image->storage_class;
3584 if (SetImageStorageClass(resize_image,storage_class,exception) == MagickFalse)
3585 return(MagickFalse);
3591 support=(double) 0.5;
3594 contributions=AcquireContributionTLS((
size_t) (2.0*support+3.0));
3595 if (contributions == (ContributionInfo **) NULL)
3597 (void) ThrowMagickException(exception,GetMagickModule(),
3598 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
3599 return(MagickFalse);
3602 scale=MagickSafeReciprocal(scale);
3603 image_view=AcquireVirtualCacheView(image,exception);
3604 resize_view=AcquireAuthenticCacheView(resize_image,exception);
3605#if defined(MAGICKCORE_OPENMP_SUPPORT)
3606 #pragma omp parallel for schedule(static) shared(progress,status) \
3607 magick_number_threads(image,resize_image,resize_image->rows,1)
3609 for (y=0; y < (ssize_t) resize_image->rows; y++)
3612 id = GetOpenMPThreadId();
3618 *magick_restrict contribution;
3633 if (status == MagickFalse)
3635 bisect=(double) (y+0.5)/y_factor+MagickEpsilon;
3636 start=(ssize_t) MagickMax(bisect-support+0.5,0.0);
3637 stop=(ssize_t) MagickMin(bisect+support+0.5,(
double) image->rows);
3639 contribution=contributions[id];
3640 for (n=0; n < (stop-start); n++)
3642 contribution[n].pixel=start+n;
3643 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
3644 ((
double) (start+n)-bisect+0.5));
3645 density+=contribution[n].weight;
3649 if ((density != 0.0) && (density != 1.0))
3657 density=MagickSafeReciprocal(density);
3658 for (i=0; i < n; i++)
3659 contribution[i].weight*=density;
3661 p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
3662 image->columns,(
size_t) (contribution[n-1].pixel-contribution[0].pixel+1),
3664 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
3666 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
3671 for (x=0; x < (ssize_t) resize_image->columns; x++)
3676 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3694 channel=GetPixelChannelChannel(image,i);
3695 traits=GetPixelChannelTraits(image,channel);
3696 resize_traits=GetPixelChannelTraits(resize_image,channel);
3697 if ((traits == UndefinedPixelTrait) ||
3698 (resize_traits == UndefinedPixelTrait))
3700 if (((resize_traits & CopyPixelTrait) != 0) ||
3701 (GetPixelWriteMask(resize_image,q) <= (QuantumRange/2)))
3703 j=(ssize_t) (MagickMin(MagickMax(bisect,(
double) start),(
double)
3705 k=(ssize_t) ((contribution[j-start].pixel-contribution[0].pixel)*
3706 (ssize_t) image->columns+x);
3707 SetPixelChannel(resize_image,channel,p[k*(ssize_t)
3708 GetPixelChannels(image)+i],q);
3712 if ((resize_traits & BlendPixelTrait) == 0)
3717 for (j=0; j < n; j++)
3719 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3720 (ssize_t) image->columns+x);
3721 alpha=contribution[j].weight;
3722 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3724 SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);
3728 for (j=0; j < n; j++)
3730 k=(ssize_t) ((contribution[j].pixel-contribution[0].pixel)*
3731 (ssize_t) image->columns+x);
3732 alpha=contribution[j].weight*QuantumScale*(double)
3733 GetPixelAlpha(image,p+k*(ssize_t) GetPixelChannels(image));
3734 pixel+=alpha*(double) p[k*(ssize_t) GetPixelChannels(image)+i];
3737 gamma=MagickSafeReciprocal(gamma);
3738 SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
3740 q+=(ptrdiff_t) GetPixelChannels(resize_image);
3742 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
3744 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3749#if defined(MAGICKCORE_OPENMP_SUPPORT)
3753 proceed=SetImageProgress(image,ResizeImageTag,*progress,span);
3754 if (proceed == MagickFalse)
3758 resize_view=DestroyCacheView(resize_view);
3759 image_view=DestroyCacheView(image_view);
3760 contributions=DestroyContributionTLS(contributions);
3764MagickExport Image *ResizeImage(
const Image *image,
const size_t columns,
3765 const size_t rows,
const FilterType filter,ExceptionInfo *exception)
3793 assert(image != (Image *) NULL);
3794 assert(image->signature == MagickCoreSignature);
3795 assert(exception != (ExceptionInfo *) NULL);
3796 assert(exception->signature == MagickCoreSignature);
3797 if (IsEventLogging() != MagickFalse)
3798 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3799 if ((columns == 0) || (rows == 0))
3800 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3801 if ((columns == image->columns) && (rows == image->rows) &&
3802 (filter == UndefinedFilter))
3803 return(CloneImage(image,0,0,MagickTrue,exception));
3807 x_factor=(double) (columns*MagickSafeReciprocal((
double) image->columns));
3808 y_factor=(double) (rows*MagickSafeReciprocal((
double) image->rows));
3809 filter_type=LanczosFilter;
3810 if (filter != UndefinedFilter)
3813 if ((x_factor == 1.0) && (y_factor == 1.0))
3814 filter_type=PointFilter;
3816 if ((image->storage_class == PseudoClass) ||
3817 (image->alpha_trait != UndefinedPixelTrait) ||
3818 ((x_factor*y_factor) > 1.0))
3819 filter_type=MitchellFilter;
3820 resize_filter=AcquireResizeFilter(image,filter_type,MagickFalse,exception);
3821#if defined(MAGICKCORE_OPENCL_SUPPORT)
3822 resize_image=AccelerateResizeImage(image,columns,rows,resize_filter,
3824 if (resize_image != (Image *) NULL)
3826 resize_filter=DestroyResizeFilter(resize_filter);
3827 return(resize_image);
3830 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
3831 if (resize_image == (Image *) NULL)
3833 resize_filter=DestroyResizeFilter(resize_filter);
3834 return(resize_image);
3836 if (x_factor > y_factor)
3837 filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
3839 filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
3840 if (filter_image == (Image *) NULL)
3842 resize_filter=DestroyResizeFilter(resize_filter);
3843 return(DestroyImage(resize_image));
3849 if (x_factor > y_factor)
3851 span=(MagickSizeType) (filter_image->columns+rows);
3852 status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
3854 status&=(MagickStatusType) VerticalFilter(resize_filter,filter_image,
3855 resize_image,y_factor,span,&offset,exception);
3859 span=(MagickSizeType) (filter_image->rows+columns);
3860 status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
3862 status&=(MagickStatusType) HorizontalFilter(resize_filter,filter_image,
3863 resize_image,x_factor,span,&offset,exception);
3868 filter_image=DestroyImage(filter_image);
3869 resize_filter=DestroyResizeFilter(resize_filter);
3870 if (status == MagickFalse)
3872 resize_image=DestroyImage(resize_image);
3873 return((Image *) NULL);
3875 resize_image->type=image->type;
3876 return(resize_image);
3910MagickExport Image *SampleImage(
const Image *image,
const size_t columns,
3911 const size_t rows,ExceptionInfo *exception)
3913#define SampleImageTag "Sample/Image"
3939 assert(image != (
const Image *) NULL);
3940 assert(image->signature == MagickCoreSignature);
3941 assert(exception != (ExceptionInfo *) NULL);
3942 assert(exception->signature == MagickCoreSignature);
3943 if (IsEventLogging() != MagickFalse)
3944 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3945 if ((columns == 0) || (rows == 0))
3946 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
3947 if ((columns == image->columns) && (rows == image->rows))
3948 return(CloneImage(image,0,0,MagickTrue,exception));
3949 sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
3950 if (sample_image == (Image *) NULL)
3951 return((Image *) NULL);
3955 sample_offset.x=0.5-MagickEpsilon;
3956 sample_offset.y=sample_offset.x;
3961 value=GetImageArtifact(image,
"sample:offset");
3962 if (value != (
char *) NULL)
3970 (void) ParseGeometry(value,&geometry_info);
3971 flags=ParseGeometry(value,&geometry_info);
3972 sample_offset.x=sample_offset.y=geometry_info.rho/100.0-MagickEpsilon;
3973 if ((flags & SigmaValue) != 0)
3974 sample_offset.y=geometry_info.sigma/100.0-MagickEpsilon;
3980 x_offset=(ssize_t *) AcquireQuantumMemory((
size_t) sample_image->columns,
3982 if (x_offset == (ssize_t *) NULL)
3984 sample_image=DestroyImage(sample_image);
3985 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
3987 for (j=0; j < (ssize_t) sample_image->columns; j++)
3988 x_offset[j]=(ssize_t) ((((double) j+sample_offset.x)*image->columns)/
3989 sample_image->columns);
3995 image_view=AcquireVirtualCacheView(image,exception);
3996 sample_view=AcquireAuthenticCacheView(sample_image,exception);
3997#if defined(MAGICKCORE_OPENMP_SUPPORT)
3998 #pragma omp parallel for schedule(static) shared(status) \
3999 magick_number_threads(image,sample_image,sample_image->rows,2)
4001 for (y=0; y < (ssize_t) sample_image->rows; y++)
4013 if (status == MagickFalse)
4015 y_offset=(ssize_t) ((((
double) y+sample_offset.y)*image->rows)/
4016 sample_image->rows);
4017 p=GetCacheViewVirtualPixels(image_view,0,y_offset,image->columns,1,
4019 q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
4021 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL))
4029 for (x=0; x < (ssize_t) sample_image->columns; x++)
4034 if (GetPixelWriteMask(sample_image,q) <= (QuantumRange/2))
4036 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4039 for (i=0; i < (ssize_t) GetPixelChannels(sample_image); i++)
4048 channel=GetPixelChannelChannel(sample_image,i);
4049 traits=GetPixelChannelTraits(sample_image,channel);
4050 image_traits=GetPixelChannelTraits(image,channel);
4051 if ((traits == UndefinedPixelTrait) ||
4052 (image_traits == UndefinedPixelTrait))
4054 SetPixelChannel(sample_image,channel,p[x_offset[x]*(ssize_t)
4055 GetPixelChannels(image)+i],q);
4057 q+=(ptrdiff_t) GetPixelChannels(sample_image);
4059 if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
4061 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4066 proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
4067 if (proceed == MagickFalse)
4071 image_view=DestroyCacheView(image_view);
4072 sample_view=DestroyCacheView(sample_view);
4073 x_offset=(ssize_t *) RelinquishMagickMemory(x_offset);
4074 sample_image->type=image->type;
4075 if (status == MagickFalse)
4076 sample_image=DestroyImage(sample_image);
4077 return(sample_image);
4109MagickExport Image *ScaleImage(
const Image *image,
const size_t columns,
4110 const size_t rows,ExceptionInfo *exception)
4112#define ScaleImageTag "Scale/Image"
4120 pixel[CompositePixelChannel],
4151 assert(image != (
const Image *) NULL);
4152 assert(image->signature == MagickCoreSignature);
4153 assert(exception != (ExceptionInfo *) NULL);
4154 assert(exception->signature == MagickCoreSignature);
4155 if (IsEventLogging() != MagickFalse)
4156 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4157 if ((columns == 0) || (rows == 0))
4158 ThrowImageException(ImageError,
"NegativeOrZeroImageSize");
4159 if ((columns == image->columns) && (rows == image->rows))
4160 return(CloneImage(image,0,0,MagickTrue,exception));
4161 scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
4162 if (scale_image == (Image *) NULL)
4163 return((Image *) NULL);
4164 if (SetImageStorageClass(scale_image,DirectClass,exception) == MagickFalse)
4166 scale_image=DestroyImage(scale_image);
4167 return((Image *) NULL);
4172 x_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4173 MaxPixelChannels*
sizeof(*x_vector));
4175 if (image->rows != scale_image->rows)
4176 scanline=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4177 MaxPixelChannels*
sizeof(*scanline));
4178 scale_scanline=(
double *) AcquireQuantumMemory((
size_t) scale_image->columns,
4179 MaxPixelChannels*
sizeof(*scale_scanline));
4180 y_vector=(
double *) AcquireQuantumMemory((
size_t) image->columns,
4181 MaxPixelChannels*
sizeof(*y_vector));
4182 if ((scanline == (
double *) NULL) || (scale_scanline == (
double *) NULL) ||
4183 (x_vector == (
double *) NULL) || (y_vector == (
double *) NULL))
4185 if ((image->rows != scale_image->rows) && (scanline != (
double *) NULL))
4186 scanline=(
double *) RelinquishMagickMemory(scanline);
4187 if (scale_scanline != (
double *) NULL)
4188 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4189 if (x_vector != (
double *) NULL)
4190 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4191 if (y_vector != (
double *) NULL)
4192 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4193 scale_image=DestroyImage(scale_image);
4194 ThrowImageException(ResourceLimitError,
"MemoryAllocationFailed");
4200 next_row=MagickTrue;
4202 scale.y=(double) scale_image->rows/(
double) image->rows;
4203 (void) memset(y_vector,0,(
size_t) MaxPixelChannels*image->columns*
4207 image_view=AcquireVirtualCacheView(image,exception);
4208 scale_view=AcquireAuthenticCacheView(scale_image,exception);
4209 for (y=0; y < (ssize_t) scale_image->rows; y++)
4220 if (status == MagickFalse)
4222 q=QueueCacheViewAuthenticPixels(scale_view,0,y,scale_image->columns,1,
4224 if (q == (Quantum *) NULL)
4230 if (scale_image->rows == image->rows)
4235 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4237 if (p == (
const Quantum *) NULL)
4242 for (x=0; x < (ssize_t) image->columns; x++)
4244 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4246 p+=(ptrdiff_t) GetPixelChannels(image);
4249 if (image->alpha_trait != UndefinedPixelTrait)
4250 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4251 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4253 PixelChannel channel = GetPixelChannelChannel(image,i);
4254 PixelTrait traits = GetPixelChannelTraits(image,channel);
4255 if ((traits & BlendPixelTrait) == 0)
4257 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=(double) p[i];
4260 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*(double) p[i];
4262 p+=(ptrdiff_t) GetPixelChannels(image);
4270 while (scale.y < span.y)
4272 if ((next_row != MagickFalse) &&
4273 (number_rows < (ssize_t) image->rows))
4278 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4280 if (p == (
const Quantum *) NULL)
4285 for (x=0; x < (ssize_t) image->columns; x++)
4287 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4289 p+=(ptrdiff_t) GetPixelChannels(image);
4292 if (image->alpha_trait != UndefinedPixelTrait)
4293 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4294 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4296 PixelChannel channel = GetPixelChannelChannel(image,i);
4297 PixelTrait traits = GetPixelChannelTraits(image,channel);
4298 if ((traits & BlendPixelTrait) == 0)
4300 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4304 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4307 p+=(ptrdiff_t) GetPixelChannels(image);
4311 for (x=0; x < (ssize_t) image->columns; x++)
4312 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4313 y_vector[x*(ssize_t) GetPixelChannels(image)+i]+=scale.y*
4314 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4316 scale.y=(double) scale_image->rows/(
double) image->rows;
4317 next_row=MagickTrue;
4319 if ((next_row != MagickFalse) && (number_rows < (ssize_t) image->rows))
4324 p=GetCacheViewVirtualPixels(image_view,0,n++,image->columns,1,
4326 if (p == (
const Quantum *) NULL)
4331 for (x=0; x < (ssize_t) image->columns; x++)
4333 if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
4335 p+=(ptrdiff_t) GetPixelChannels(image);
4338 if (image->alpha_trait != UndefinedPixelTrait)
4339 alpha=QuantumScale*(double) GetPixelAlpha(image,p);
4340 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4342 PixelChannel channel = GetPixelChannelChannel(image,i);
4343 PixelTrait traits = GetPixelChannelTraits(image,channel);
4344 if ((traits & BlendPixelTrait) == 0)
4346 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=
4350 x_vector[x*(ssize_t) GetPixelChannels(image)+i]=alpha*
4353 p+=(ptrdiff_t) GetPixelChannels(image);
4356 next_row=MagickFalse;
4358 for (x=0; x < (ssize_t) image->columns; x++)
4360 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4362 pixel[i]=y_vector[x*(ssize_t) GetPixelChannels(image)+i]+span.y*
4363 x_vector[x*(ssize_t) GetPixelChannels(image)+i];
4364 scanline[x*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4365 y_vector[x*(ssize_t) GetPixelChannels(image)+i]=0.0;
4371 scale.y=(double) scale_image->rows/(
double) image->rows;
4372 next_row=MagickTrue;
4376 if (scale_image->columns == image->columns)
4381 for (x=0; x < (ssize_t) scale_image->columns; x++)
4383 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4385 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4388 if (image->alpha_trait != UndefinedPixelTrait)
4390 alpha=QuantumScale*scanline[x*(ssize_t) GetPixelChannels(image)+
4391 GetPixelChannelOffset(image,AlphaPixelChannel)];
4392 alpha=MagickSafeReciprocal(alpha);
4394 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4396 PixelChannel channel = GetPixelChannelChannel(image,i);
4397 PixelTrait traits = GetPixelChannelTraits(image,channel);
4398 scale_traits=GetPixelChannelTraits(scale_image,channel);
4399 if ((traits == UndefinedPixelTrait) ||
4400 (scale_traits == UndefinedPixelTrait))
4402 if ((traits & BlendPixelTrait) == 0)
4404 SetPixelChannel(scale_image,channel,ClampToQuantum(
4405 scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4408 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*scanline[
4409 x*(ssize_t) GetPixelChannels(image)+i]),q);
4411 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4422 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4424 next_column=MagickFalse;
4427 for (x=0; x < (ssize_t) image->columns; x++)
4429 scale.x=(double) scale_image->columns/(
double) image->columns;
4430 while (scale.x >= span.x)
4432 if (next_column != MagickFalse)
4434 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4438 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4440 PixelChannel channel = GetPixelChannelChannel(image,i);
4441 PixelTrait traits = GetPixelChannelTraits(image,channel);
4442 if (traits == UndefinedPixelTrait)
4444 pixel[i]+=span.x*scanline[x*(ssize_t) GetPixelChannels(image)+i];
4445 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4449 next_column=MagickTrue;
4453 if (next_column != MagickFalse)
4455 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4457 next_column=MagickFalse;
4460 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4461 pixel[i]+=scale.x*scanline[x*(ssize_t)
4462 GetPixelChannels(image)+i];
4468 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4470 scanline[(x-1)*(ssize_t) GetPixelChannels(image)+i];
4472 if ((next_column == MagickFalse) && (t < (ssize_t) scale_image->columns))
4473 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4474 scale_scanline[t*(ssize_t) GetPixelChannels(image)+i]=pixel[i];
4478 for (x=0; x < (ssize_t) scale_image->columns; x++)
4480 if (GetPixelWriteMask(scale_image,q) <= (QuantumRange/2))
4482 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4485 if (image->alpha_trait != UndefinedPixelTrait)
4487 alpha=QuantumScale*scale_scanline[x*(ssize_t)
4488 GetPixelChannels(image)+
4489 GetPixelChannelOffset(image,AlphaPixelChannel)];
4490 alpha=MagickSafeReciprocal(alpha);
4492 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4494 PixelChannel channel = GetPixelChannelChannel(image,i);
4495 PixelTrait traits = GetPixelChannelTraits(image,channel);
4496 scale_traits=GetPixelChannelTraits(scale_image,channel);
4497 if ((traits == UndefinedPixelTrait) ||
4498 (scale_traits == UndefinedPixelTrait))
4500 if ((traits & BlendPixelTrait) == 0)
4502 SetPixelChannel(scale_image,channel,ClampToQuantum(
4503 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4506 SetPixelChannel(scale_image,channel,ClampToQuantum(alpha*
4507 scale_scanline[x*(ssize_t) GetPixelChannels(image)+i]),q);
4509 q+=(ptrdiff_t) GetPixelChannels(scale_image);
4512 if (SyncCacheViewAuthenticPixels(scale_view,exception) == MagickFalse)
4517 proceed=SetImageProgress(image,ScaleImageTag,(MagickOffsetType) y,
4519 if (proceed == MagickFalse)
4525 scale_view=DestroyCacheView(scale_view);
4526 image_view=DestroyCacheView(image_view);
4530 y_vector=(
double *) RelinquishMagickMemory(y_vector);
4531 scale_scanline=(
double *) RelinquishMagickMemory(scale_scanline);
4532 if (scale_image->rows != image->rows)
4533 scanline=(
double *) RelinquishMagickMemory(scanline);
4534 x_vector=(
double *) RelinquishMagickMemory(x_vector);
4535 scale_image->type=image->type;
4536 if (status == MagickFalse)
4537 scale_image=DestroyImage(scale_image);
4538 return(scale_image);
4573static void url_encode(
const char *uri,
char *encode_uri)
4579 *hex =
"0123456789ABCDEF";
4581 for (p=encode_uri; *uri !=
'\0'; uri++)
4582 if (((
'a' <= *uri) && (*uri <=
'z')) || ((
'A' <= *uri) && (*uri <=
'Z')) ||
4583 ((
'0' <= *uri) && (*uri <=
'9')) || (strchr(
"/-_.~",*uri) != 0))
4588 *p++=hex[(*uri >> 4) & 0xF];
4589 *p++=hex[*uri & 0xF];
4594MagickExport Image *ThumbnailImage(
const Image *image,
const size_t columns,
4595 const size_t rows,ExceptionInfo *exception)
4597#define SampleFactor 5
4600 encode_uri[3*MagickPathExtent+1] =
"/0";
4612 assert(image != (Image *) NULL);
4613 assert(image->signature == MagickCoreSignature);
4614 assert(exception != (ExceptionInfo *) NULL);
4615 assert(exception->signature == MagickCoreSignature);
4616 if (IsEventLogging() != MagickFalse)
4617 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4618 thumbnail_image=CloneImage(image,0,0,MagickTrue,exception);
4619 if (thumbnail_image == (Image *) NULL)
4620 return(thumbnail_image);
4621 if ((columns != image->columns) || (rows != image->rows))
4624 *clone_image = thumbnail_image;
4630 x_factor=(ssize_t) (image->columns*MagickSafeReciprocal((
double)
4632 y_factor=(ssize_t) (image->rows*MagickSafeReciprocal((
double) rows));
4633 if ((x_factor > 4) && (y_factor > 4))
4635 thumbnail_image=SampleImage(clone_image,4*columns,4*rows,exception);
4636 if (thumbnail_image != (Image *) NULL)
4638 clone_image=DestroyImage(clone_image);
4639 clone_image=thumbnail_image;
4642 if ((x_factor > 2) && (y_factor > 2))
4644 thumbnail_image=ResizeImage(clone_image,2*columns,2*rows,BoxFilter,
4646 if (thumbnail_image != (Image *) NULL)
4648 clone_image=DestroyImage(clone_image);
4649 clone_image=thumbnail_image;
4652 thumbnail_image=ResizeImage(clone_image,columns,rows,image->filter ==
4653 UndefinedFilter ? LanczosSharpFilter : image->filter,exception);
4654 clone_image=DestroyImage(clone_image);
4655 if (thumbnail_image == (Image *) NULL)
4656 return(thumbnail_image);
4658 (void) ParseAbsoluteGeometry(
"0x0+0+0",&thumbnail_image->page);
4659 thumbnail_image->depth=8;
4660 thumbnail_image->interlace=NoInterlace;
4664 ResetImageProfileIterator(thumbnail_image);
4665 for (name=GetNextImageProfile(thumbnail_image); name != (
const char *) NULL; )
4667 if ((LocaleCompare(name,
"icc") != 0) && (LocaleCompare(name,
"icm") != 0))
4669 (void) DeleteImageProfile(thumbnail_image,name);
4670 ResetImageProfileIterator(thumbnail_image);
4672 name=GetNextImageProfile(thumbnail_image);
4674 (void) DeleteImageProperty(thumbnail_image,
"comment");
4675 url_encode(image->filename,encode_uri);
4676 if (*image->filename !=
'/')
4677 (void) FormatImageProperty(thumbnail_image,
"Thumb::URI",
"./%s",encode_uri);
4679 (
void) FormatImageProperty(thumbnail_image,
"Thumb::URI",
"file://%s",
4681 if (GetPathAttributes(image->filename,&attributes) != MagickFalse )
4682 (void) FormatImageProperty(thumbnail_image,
"Thumb::MTime",
"%.20g",(
double)
4683 attributes.st_mtime);
4684 (void) FormatImageProperty(thumbnail_image,
"Thumb::Size",
"%.20g",
4685 (
double) GetBlobSize(image));
4686 mime_type=GetImageProperty(image,
"mime:type",exception);
4687 if (mime_type != (
const char *) NULL)
4688 (void) SetImageProperty(thumbnail_image,
"Thumb::Mimetype",mime_type,
4690 (void) SetImageProperty(thumbnail_image,
"software",MagickAuthoritativeURL,
4692 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Width",
"%.20g",
4693 (
double) image->magick_columns);
4694 (void) FormatImageProperty(thumbnail_image,
"Thumb::Image::Height",
"%.20g",
4695 (
double) image->magick_rows);
4696 (void) FormatImageProperty(thumbnail_image,
"Thumb::Document::Pages",
"%.20g",
4697 (
double) GetImageListLength(image));
4698 return(thumbnail_image);