00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "magick/studio.h"
00043 #include "magick/artifact.h"
00044 #include "magick/blob.h"
00045 #include "magick/cache.h"
00046 #include "magick/cache-view.h"
00047 #include "magick/color.h"
00048 #include "magick/color-private.h"
00049 #include "magick/draw.h"
00050 #include "magick/exception.h"
00051 #include "magick/exception-private.h"
00052 #include "magick/gem.h"
00053 #include "magick/image.h"
00054 #include "magick/image-private.h"
00055 #include "magick/list.h"
00056 #include "magick/memory_.h"
00057 #include "magick/pixel-private.h"
00058 #include "magick/property.h"
00059 #include "magick/monitor.h"
00060 #include "magick/monitor-private.h"
00061 #include "magick/pixel.h"
00062 #include "magick/option.h"
00063 #include "magick/resample.h"
00064 #include "magick/resize.h"
00065 #include "magick/resize-private.h"
00066 #include "magick/string_.h"
00067 #include "magick/thread-private.h"
00068 #include "magick/utility.h"
00069 #include "magick/version.h"
00070 #if defined(MAGICKCORE_LQR_DELEGATE)
00071 #include <lqr.h>
00072 #endif
00073
00074
00075
00076
00077 struct _ResizeFilter
00078 {
00079 MagickRealType
00080 (*filter)(const MagickRealType,const ResizeFilter *),
00081 (*window)(const MagickRealType,const ResizeFilter *),
00082 support,
00083 window_support,
00084 scale,
00085 blur,
00086 cubic[8];
00087
00088 unsigned long
00089 signature;
00090 };
00091
00092
00093
00094
00095 static MagickRealType
00096 I0(MagickRealType x),
00097 BesselOrderOne(MagickRealType);
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 static MagickRealType Bessel(const MagickRealType x,
00132 const ResizeFilter *magick_unused(resize_filter))
00133 {
00134
00135
00136
00137
00138
00139
00140
00141
00142 if (x == 0.0)
00143 return((MagickRealType) (MagickPI/4.0));
00144 return(BesselOrderOne(MagickPI*x)/(2.0*x));
00145 }
00146
00147 static MagickRealType Blackman(const MagickRealType x,
00148 const ResizeFilter *magick_unused(resize_filter))
00149 {
00150
00151
00152
00153 return(0.42+0.5*cos(MagickPI*(double) x)+0.08*cos(2.0*MagickPI*(double) x));
00154 }
00155
00156 static MagickRealType Bohman(const MagickRealType x,
00157 const ResizeFilter *magick_unused(resize_filter))
00158 {
00159
00160
00161
00162 return((1-x)*cos(MagickPI*(double) x)+sin(MagickPI*(double) x)/MagickPI);
00163 }
00164
00165 static MagickRealType Box(const MagickRealType magick_unused(x),
00166 const ResizeFilter *magick_unused(resize_filter))
00167 {
00168
00169
00170
00171 return(1.0);
00172 }
00173
00174 static MagickRealType CubicBC(const MagickRealType x,
00175 const ResizeFilter *resize_filter)
00176 {
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 if (x < 1.0)
00208 return(resize_filter->cubic[0]+x*(resize_filter->cubic[1]+x*
00209 (resize_filter->cubic[2]+x*resize_filter->cubic[3])));
00210 if (x < 2.0)
00211 return(resize_filter->cubic[4] +x*(resize_filter->cubic[5]+x*
00212 (resize_filter->cubic[6] +x*resize_filter->cubic[7])));
00213 return(0.0);
00214 }
00215
00216 static MagickRealType Gaussian(const MagickRealType x,
00217 const ResizeFilter *magick_unused(resize_filter))
00218 {
00219 return(exp((double) (-2.0*x*x))*sqrt(2.0/MagickPI));
00220 }
00221
00222 static MagickRealType Hanning(const MagickRealType x,
00223 const ResizeFilter *magick_unused(resize_filter))
00224 {
00225
00226
00227
00228 return(0.5+0.5*cos(MagickPI*(double) x));
00229 }
00230
00231 static MagickRealType Hamming(const MagickRealType x,
00232 const ResizeFilter *magick_unused(resize_filter))
00233 {
00234
00235
00236
00237 return(0.54+0.46*cos(MagickPI*(double) x));
00238 }
00239
00240 static MagickRealType Kaiser(const MagickRealType x,
00241 const ResizeFilter *magick_unused(resize_filter))
00242 {
00243 #define Alpha 6.5
00244 #define I0A (1.0/I0(Alpha))
00245
00246
00247
00248
00249
00250
00251 return(I0A*I0(Alpha*sqrt((double) (1.0-x*x))));
00252 }
00253
00254 static MagickRealType Lagrange(const MagickRealType x,
00255 const ResizeFilter *resize_filter)
00256 {
00257 long
00258 n,
00259 order;
00260
00261 MagickRealType
00262 value;
00263
00264 register long
00265 i;
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 if (x > resize_filter->support)
00279 return(0.0);
00280 order=(long) (2.0*resize_filter->window_support);
00281 n=(long) ((1.0*order)/2.0+x);
00282 value=1.0f;
00283 for (i=0; i < order; i++)
00284 if (i != n)
00285 value*=(n-i-x)/(n-i);
00286 return(value);
00287 }
00288
00289 static MagickRealType Quadratic(const MagickRealType x,
00290 const ResizeFilter *magick_unused(resize_filter))
00291 {
00292
00293
00294
00295 if (x < 0.5)
00296 return(0.75-x*x);
00297 if (x < 1.5)
00298 return(0.5*(x-1.5)*(x-1.5));
00299 return(0.0);
00300 }
00301
00302 static MagickRealType Sinc(const MagickRealType x,
00303 const ResizeFilter *magick_unused(resize_filter))
00304 {
00305
00306
00307
00308 if (x == 0.0)
00309 return(1.0);
00310 return(sin(MagickPI*(double) x)/(MagickPI*(double) x));
00311 }
00312
00313 static MagickRealType Triangle(const MagickRealType x,
00314 const ResizeFilter *magick_unused(resize_filter))
00315 {
00316
00317
00318
00319
00320 if (x < 1.0)
00321 return(1.0-x);
00322 return(0.0);
00323 }
00324
00325 static MagickRealType Welsh(const MagickRealType x,
00326 const ResizeFilter *magick_unused(resize_filter))
00327 {
00328
00329
00330
00331 if (x < 1.0)
00332 return(1.0-x*x);
00333 return(0.0);
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
00455 const FilterTypes filter, const MagickRealType blur,
00456 const MagickBooleanType cylindrical,ExceptionInfo *exception)
00457 {
00458 const char
00459 *artifact;
00460
00461 FilterTypes
00462 filter_type,
00463 window_type;
00464
00465 long
00466 filter_artifact;
00467
00468 MagickRealType
00469 B,
00470 C;
00471
00472 register ResizeFilter
00473 *resize_filter;
00474
00475
00476
00477
00478
00479
00480
00481
00482 static struct
00483 {
00484 FilterTypes
00485 filter,
00486 window;
00487 } const mapping[SentinelFilter] =
00488 {
00489 { UndefinedFilter, BoxFilter },
00490 { PointFilter, BoxFilter },
00491 { BoxFilter, BoxFilter },
00492 { TriangleFilter, BoxFilter },
00493 { HermiteFilter, BoxFilter },
00494 { SincFilter, HanningFilter },
00495 { SincFilter, HammingFilter },
00496 { SincFilter, BlackmanFilter },
00497 { GaussianFilter, BoxFilter },
00498 { QuadraticFilter, BoxFilter },
00499 { CubicFilter, BoxFilter },
00500 { CatromFilter, BoxFilter },
00501 { MitchellFilter, BoxFilter },
00502 { LanczosFilter, SincFilter },
00503 { BesselFilter, BlackmanFilter },
00504 { SincFilter, BlackmanFilter },
00505 { SincFilter, KaiserFilter },
00506 { SincFilter, WelshFilter },
00507 { SincFilter, CubicFilter },
00508 { LagrangeFilter, BoxFilter },
00509 { SincFilter, BohmanFilter },
00510 { SincFilter, TriangleFilter }
00511 };
00512
00513
00514
00515
00516
00517
00518 static struct
00519 {
00520 MagickRealType
00521 (*function)(const MagickRealType, const ResizeFilter*),
00522 support,
00523 scale,
00524 B,
00525 C;
00526 } const filters[SentinelFilter] =
00527 {
00528 { Box, 0.0f, 0.5f, 0.0f, 0.0f },
00529 { Box, 0.0f, 0.5f, 0.0f, 0.0f },
00530 { Box, 0.5f, 0.5f, 0.0f, 0.0f },
00531 { Triangle, 1.0f, 1.0f, 0.0f, 0.0f },
00532 { CubicBC, 1.0f, 1.0f, 0.0f, 0.0f },
00533 { Hanning, 1.0f, 1.0f, 0.0f, 0.0f },
00534 { Hamming, 1.0f, 1.0f, 0.0f, 0.0f },
00535 { Blackman, 1.0f, 1.0f, 0.0f, 0.0f },
00536 { Gaussian, 1.5f, 1.5f, 0.0f, 0.0f },
00537 { Quadratic, 1.5f, 1.5f, 0.0f, 0.0f },
00538 { CubicBC, 2.0f, 2.0f, 1.0f, 0.0f },
00539 { CubicBC, 2.0f, 1.0f, 0.0f, 0.5f },
00540 { CubicBC, 2.0f, 1.0f, 1.0f/3.0f, 1.0f/3.0f },
00541 { Sinc, 3.0f, 1.0f, 0.0f, 0.0f },
00542 { Bessel, 3.2383f,1.2197f,.0f,.0f },
00543 { Sinc, 4.0f, 1.0f, 0.0f, 0.0f },
00544 { Kaiser, 1.0f, 1.0f, 0.0f, 0.0f },
00545 { Welsh, 1.0f, 1.0f, 0.0f, 0.0f },
00546 { CubicBC, 2.0f, 2.0f, 1.0f, 0.0f },
00547 { Lagrange, 2.0f, 1.0f, 0.0f, 0.0f },
00548 { Bohman, 1.0f, 1.0f, 0.0f, 0.0f },
00549 { Triangle, 1.0f, 1.0f, 0.0f, 0.0f }
00550 };
00551
00552
00553
00554
00555
00556
00557 static MagickRealType
00558 bessel_zeros[16] =
00559 {
00560 1.21966989126651f,
00561 2.23313059438153f,
00562 3.23831548416624f,
00563 4.24106286379607f,
00564 5.24276437687019f,
00565 6.24392168986449f,
00566 7.24475986871996f,
00567 8.24539491395205f,
00568 9.24589268494948f,
00569 10.2462933487549f,
00570 11.2466227948779f,
00571 12.2468984611381f,
00572 13.2471325221811f,
00573 14.2473337358069f,
00574 15.2475085630373f,
00575 16.247661874701f
00576 };
00577
00578 assert(image != (const Image *) NULL);
00579 assert(image->signature == MagickSignature);
00580 if (image->debug != MagickFalse)
00581 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00582 assert(UndefinedFilter < filter && filter < SentinelFilter);
00583 assert(exception != (ExceptionInfo *) NULL);
00584 assert(exception->signature == MagickSignature);
00585
00586 resize_filter=(ResizeFilter *) AcquireMagickMemory(sizeof(*resize_filter));
00587 if (resize_filter == (ResizeFilter *) NULL)
00588 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00589
00590
00591 filter_type = mapping[filter].filter;
00592 window_type = mapping[filter].window;
00593
00594
00595
00596 resize_filter->blur = blur;
00597 artifact=GetImageArtifact(image,"filter:blur");
00598 if (artifact != (const char *) NULL)
00599 resize_filter->blur = atof(artifact);
00600 if ( resize_filter->blur < MagickEpsilon )
00601 resize_filter->blur = (MagickRealType) MagickEpsilon;
00602
00603
00604 if ( cylindrical != MagickFalse && filter != SincFilter ) {
00605
00606 if ( filter_type == SincFilter )
00607 filter_type = BesselFilter;
00608
00609 else if ( filter_type == LanczosFilter ) {
00610 filter_type = BesselFilter;
00611 window_type = BesselFilter;
00612 }
00613
00614 else if ( filter_type == GaussianFilter )
00615
00616
00617 resize_filter->blur *= 2.0*log(2.0)/sqrt(2.0/MagickPI);
00618 else if ( filter_type != BesselFilter )
00619
00620 resize_filter->blur *= bessel_zeros[0];
00621 }
00622
00623
00624 artifact=GetImageArtifact(image,"filter:filter");
00625 if (artifact != (const char *) NULL) {
00626
00627 filter_artifact=ParseMagickOption(MagickFilterOptions,
00628 MagickFalse,artifact);
00629 if ( UndefinedFilter < filter_artifact &&
00630 filter_artifact < SentinelFilter ) {
00631 filter_type = (FilterTypes) filter_artifact;
00632 window_type = BoxFilter;
00633 }
00634
00635 if ( filter_artifact == LanczosFilter ) {
00636 filter_type = (cylindrical!=MagickFalse) ? BesselFilter : LanczosFilter;
00637 window_type = (cylindrical!=MagickFalse) ? BesselFilter : SincFilter;
00638 }
00639
00640 artifact=GetImageArtifact(image,"filter:window");
00641 if (artifact != (const char *) NULL) {
00642 filter_artifact=ParseMagickOption(MagickFilterOptions,
00643 MagickFalse,artifact);
00644 if ( UndefinedFilter < filter_artifact &&
00645 filter_artifact < SentinelFilter ) {
00646 if ( filter_artifact != LanczosFilter )
00647 window_type = (FilterTypes) filter_artifact;
00648 else
00649 window_type = (cylindrical!=MagickFalse) ? BesselFilter : SincFilter;
00650 }
00651 }
00652 }
00653 else {
00654
00655 artifact=GetImageArtifact(image,"filter:window");
00656 if (artifact != (const char *) NULL) {
00657 filter_artifact=ParseMagickOption(MagickFilterOptions,MagickFalse,
00658 artifact);
00659 if ( UndefinedFilter < filter_artifact &&
00660 filter_artifact < SentinelFilter ) {
00661 filter_type = (cylindrical!=MagickFalse) ? BesselFilter : SincFilter;
00662 if ( filter_artifact != LanczosFilter )
00663 window_type = (FilterTypes) filter_artifact;
00664 else
00665 window_type = filter_type;
00666 }
00667 }
00668 }
00669
00670 resize_filter->filter = filters[filter_type].function;
00671 resize_filter->support = filters[filter_type].support;
00672 resize_filter->window = filters[window_type].function;
00673 resize_filter->scale = filters[window_type].scale;
00674 resize_filter->signature=MagickSignature;
00675
00676
00677 artifact=GetImageArtifact(image,"filter:lobes");
00678 if (artifact != (const char *) NULL) {
00679 long lobes = atol(artifact);
00680 if ( lobes < 1 ) lobes = 1;
00681 resize_filter->support = (MagickRealType) lobes;
00682 if ( filter_type == BesselFilter ) {
00683 if ( lobes > 16 ) lobes = 16;
00684 resize_filter->support = bessel_zeros[lobes-1];
00685 }
00686 }
00687 artifact=GetImageArtifact(image,"filter:support");
00688 if (artifact != (const char *) NULL)
00689 resize_filter->support = fabs(atof(artifact));
00690
00691
00692
00693
00694 resize_filter->window_support = resize_filter->support;
00695 artifact=GetImageArtifact(image,"filter:win-support");
00696 if (artifact != (const char *) NULL)
00697 resize_filter->window_support = fabs(atof(artifact));
00698
00699
00700 B=0.0;
00701 C=0.0;
00702 if ( filters[filter_type].function == CubicBC
00703 || filters[window_type].function == CubicBC ) {
00704 if ( filters[filter_type].function == CubicBC ) {
00705 B=filters[filter_type].B;
00706 C=filters[filter_type].C;
00707 }
00708 else if ( filters[window_type].function == CubicBC ) {
00709 B=filters[window_type].B;
00710 C=filters[window_type].C;
00711 }
00712 artifact=GetImageArtifact(image,"filter:b");
00713 if (artifact != (const char *) NULL) {
00714 B=atof(artifact);
00715 C=(1.0-B)/2.0;
00716 artifact=GetImageArtifact(image,"filter:c");
00717 if (artifact != (const char *) NULL)
00718 C=atof(artifact);
00719 }
00720 else {
00721 artifact=GetImageArtifact(image,"filter:c");
00722 if (artifact != (const char *) NULL) {
00723 C=atof(artifact);
00724 B=1.0-2.0*C;
00725 }
00726 }
00727
00728 resize_filter->cubic[0]=( 6.0 -2.0*B )/6.0;
00729 resize_filter->cubic[1]=0.0;
00730 resize_filter->cubic[2]=(-18.0+12.0*B+ 6.0*C)/6.0;
00731 resize_filter->cubic[3]=( 12.0- 9.0*B- 6.0*C)/6.0;
00732 resize_filter->cubic[4]=( 8.0*B+24.0*C)/6.0;
00733 resize_filter->cubic[5]=( -12.0*B-48.0*C)/6.0;
00734 resize_filter->cubic[6]=( 6.0*B+30.0*C)/6.0;
00735 resize_filter->cubic[7]=( - 1.0*B- 6.0*C)/6.0;
00736 }
00737 artifact=GetImageArtifact(image,"filter:verbose");
00738 if (artifact != (const char *) NULL)
00739 {
00740 double
00741 support,
00742 x;
00743
00744
00745
00746
00747 support=GetResizeFilterSupport(resize_filter);
00748 (void) printf("# support = %lg\n",support);
00749 for (x=0.0; x <= support; x+=0.01f)
00750 (void) printf("%5.2lf\t%lf\n",x,(double) GetResizeFilterWeight(
00751 resize_filter,x));
00752 (void) printf("%5.2lf\t%lf\n",support,0.0);
00753 }
00754 return(resize_filter);
00755 }
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787 MagickExport Image *AdaptiveResizeImage(const Image *image,
00788 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
00789 {
00790 #define AdaptiveResizeImageTag "Resize/Image"
00791
00792 Image
00793 *resize_image;
00794
00795 long
00796 y;
00797
00798 MagickBooleanType
00799 proceed;
00800
00801 MagickPixelPacket
00802 pixel;
00803
00804 PointInfo
00805 offset;
00806
00807 ResampleFilter
00808 *resample_filter;
00809
00810 CacheView
00811 *resize_view;
00812
00813
00814
00815
00816 assert(image != (const Image *) NULL);
00817 assert(image->signature == MagickSignature);
00818 if (image->debug != MagickFalse)
00819 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00820 assert(exception != (ExceptionInfo *) NULL);
00821 assert(exception->signature == MagickSignature);
00822 if ((columns == 0) || (rows == 0))
00823 return((Image *) NULL);
00824 if ((columns == image->columns) && (rows == image->rows))
00825 return(CloneImage(image,0,0,MagickTrue,exception));
00826 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
00827 if (resize_image == (Image *) NULL)
00828 return((Image *) NULL);
00829 if (SetImageStorageClass(resize_image,DirectClass) == MagickFalse)
00830 {
00831 InheritException(exception,&resize_image->exception);
00832 resize_image=DestroyImage(resize_image);
00833 return((Image *) NULL);
00834 }
00835 GetMagickPixelPacket(image,&pixel);
00836 resample_filter=AcquireResampleFilter(image,exception);
00837 if (image->interpolate == UndefinedInterpolatePixel)
00838 (void) SetResampleFilterInterpolateMethod(resample_filter,
00839 MeshInterpolatePixel);
00840 resize_view=AcquireCacheView(resize_image);
00841 for (y=0; y < (long) resize_image->rows; y++)
00842 {
00843 register IndexPacket
00844 *__restrict resize_indexes;
00845
00846 register long
00847 x;
00848
00849 register PixelPacket
00850 *__restrict q;
00851
00852 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
00853 exception);
00854 if (q == (PixelPacket *) NULL)
00855 break;
00856 resize_indexes=GetCacheViewAuthenticIndexQueue(resize_view);
00857 offset.y=((MagickRealType) y*image->rows/resize_image->rows);
00858 for (x=0; x < (long) resize_image->columns; x++)
00859 {
00860 offset.x=((MagickRealType) x*image->columns/resize_image->columns);
00861 (void) ResamplePixelColor(resample_filter,offset.x-0.5,offset.y-0.5,
00862 &pixel);
00863 SetPixelPacket(resize_image,&pixel,q,resize_indexes+x);
00864 q++;
00865 }
00866 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
00867 break;
00868 proceed=SetImageProgress(image,AdaptiveResizeImageTag,y,image->rows);
00869 if (proceed == MagickFalse)
00870 break;
00871 }
00872 resample_filter=DestroyResampleFilter(resample_filter);
00873 resize_view=DestroyCacheView(resize_view);
00874 return(resize_image);
00875 }
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916 #undef I0
00917 static MagickRealType I0(MagickRealType x)
00918 {
00919 MagickRealType
00920 sum,
00921 t,
00922 y;
00923
00924 register long
00925 i;
00926
00927
00928
00929
00930 sum=1.0;
00931 y=x*x/4.0;
00932 t=y;
00933 for (i=2; t > MagickEpsilon; i++)
00934 {
00935 sum+=t;
00936 t*=y/((MagickRealType) i*i);
00937 }
00938 return(sum);
00939 }
00940
00941 #undef J1
00942 static MagickRealType J1(MagickRealType x)
00943 {
00944 MagickRealType
00945 p,
00946 q;
00947
00948 register long
00949 i;
00950
00951 static const double
00952 Pone[] =
00953 {
00954 0.581199354001606143928050809e+21,
00955 -0.6672106568924916298020941484e+20,
00956 0.2316433580634002297931815435e+19,
00957 -0.3588817569910106050743641413e+17,
00958 0.2908795263834775409737601689e+15,
00959 -0.1322983480332126453125473247e+13,
00960 0.3413234182301700539091292655e+10,
00961 -0.4695753530642995859767162166e+7,
00962 0.270112271089232341485679099e+4
00963 },
00964 Qone[] =
00965 {
00966 0.11623987080032122878585294e+22,
00967 0.1185770712190320999837113348e+20,
00968 0.6092061398917521746105196863e+17,
00969 0.2081661221307607351240184229e+15,
00970 0.5243710262167649715406728642e+12,
00971 0.1013863514358673989967045588e+10,
00972 0.1501793594998585505921097578e+7,
00973 0.1606931573481487801970916749e+4,
00974 0.1e+1
00975 };
00976
00977 p=Pone[8];
00978 q=Qone[8];
00979 for (i=7; i >= 0; i--)
00980 {
00981 p=p*x*x+Pone[i];
00982 q=q*x*x+Qone[i];
00983 }
00984 return(p/q);
00985 }
00986
00987 #undef P1
00988 static MagickRealType P1(MagickRealType x)
00989 {
00990 MagickRealType
00991 p,
00992 q;
00993
00994 register long
00995 i;
00996
00997 static const double
00998 Pone[] =
00999 {
01000 0.352246649133679798341724373e+5,
01001 0.62758845247161281269005675e+5,
01002 0.313539631109159574238669888e+5,
01003 0.49854832060594338434500455e+4,
01004 0.2111529182853962382105718e+3,
01005 0.12571716929145341558495e+1
01006 },
01007 Qone[] =
01008 {
01009 0.352246649133679798068390431e+5,
01010 0.626943469593560511888833731e+5,
01011 0.312404063819041039923015703e+5,
01012 0.4930396490181088979386097e+4,
01013 0.2030775189134759322293574e+3,
01014 0.1e+1
01015 };
01016
01017 p=Pone[5];
01018 q=Qone[5];
01019 for (i=4; i >= 0; i--)
01020 {
01021 p=p*(8.0/x)*(8.0/x)+Pone[i];
01022 q=q*(8.0/x)*(8.0/x)+Qone[i];
01023 }
01024 return(p/q);
01025 }
01026
01027 #undef Q1
01028 static MagickRealType Q1(MagickRealType x)
01029 {
01030 MagickRealType
01031 p,
01032 q;
01033
01034 register long
01035 i;
01036
01037 static const double
01038 Pone[] =
01039 {
01040 0.3511751914303552822533318e+3,
01041 0.7210391804904475039280863e+3,
01042 0.4259873011654442389886993e+3,
01043 0.831898957673850827325226e+2,
01044 0.45681716295512267064405e+1,
01045 0.3532840052740123642735e-1
01046 },
01047 Qone[] =
01048 {
01049 0.74917374171809127714519505e+4,
01050 0.154141773392650970499848051e+5,
01051 0.91522317015169922705904727e+4,
01052 0.18111867005523513506724158e+4,
01053 0.1038187585462133728776636e+3,
01054 0.1e+1
01055 };
01056
01057 p=Pone[5];
01058 q=Qone[5];
01059 for (i=4; i >= 0; i--)
01060 {
01061 p=p*(8.0/x)*(8.0/x)+Pone[i];
01062 q=q*(8.0/x)*(8.0/x)+Qone[i];
01063 }
01064 return(p/q);
01065 }
01066
01067 static MagickRealType BesselOrderOne(MagickRealType x)
01068 {
01069 MagickRealType
01070 p,
01071 q;
01072
01073 if (x == 0.0)
01074 return(0.0);
01075 p=x;
01076 if (x < 0.0)
01077 x=(-x);
01078 if (x < 8.0)
01079 return(p*J1(x));
01080 q=sqrt((double) (2.0/(MagickPI*x)))*(P1(x)*(1.0/sqrt(2.0)*(sin((double) x)-
01081 cos((double) x)))-8.0/x*Q1(x)*(-1.0/sqrt(2.0)*(sin((double) x)+
01082 cos((double) x))));
01083 if (p < 0.0)
01084 q=(-q);
01085 return(q);
01086 }
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110 MagickExport ResizeFilter *DestroyResizeFilter(ResizeFilter *resize_filter)
01111 {
01112 assert(resize_filter != (ResizeFilter *) NULL);
01113 assert(resize_filter->signature == MagickSignature);
01114 resize_filter->signature=(~MagickSignature);
01115 resize_filter=(ResizeFilter *) RelinquishMagickMemory(resize_filter);
01116 return(resize_filter);
01117 }
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142 MagickExport MagickRealType GetResizeFilterSupport(
01143 const ResizeFilter *resize_filter)
01144 {
01145 assert(resize_filter != (ResizeFilter *) NULL);
01146 assert(resize_filter->signature == MagickSignature);
01147 return(resize_filter->support*resize_filter->blur);
01148 }
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177 MagickExport MagickRealType GetResizeFilterWeight(
01178 const ResizeFilter *resize_filter,const MagickRealType x)
01179 {
01180 MagickRealType
01181 blur,
01182 scale;
01183
01184
01185
01186
01187 assert(resize_filter != (ResizeFilter *) NULL);
01188 assert(resize_filter->signature == MagickSignature);
01189 blur=fabs(x)/resize_filter->blur;
01190 if ((resize_filter->window_support < MagickEpsilon) ||
01191 (resize_filter->window == Box))
01192 scale=1.0;
01193 else
01194 {
01195 scale=resize_filter->scale/resize_filter->window_support;
01196 scale=resize_filter->window(blur*scale,resize_filter);
01197 }
01198 return(scale*resize_filter->filter(blur,resize_filter));
01199 }
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226 MagickExport Image *MagnifyImage(const Image *image,ExceptionInfo *exception)
01227 {
01228 Image
01229 *magnify_image;
01230
01231 assert(image != (Image *) NULL);
01232 assert(image->signature == MagickSignature);
01233 if (image->debug != MagickFalse)
01234 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01235 assert(exception != (ExceptionInfo *) NULL);
01236 assert(exception->signature == MagickSignature);
01237 magnify_image=ResizeImage(image,2*image->columns,2*image->rows,CubicFilter,
01238 1.0,exception);
01239 return(magnify_image);
01240 }
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267 MagickExport Image *MinifyImage(const Image *image,ExceptionInfo *exception)
01268 {
01269 Image
01270 *minify_image;
01271
01272 assert(image != (Image *) NULL);
01273 assert(image->signature == MagickSignature);
01274 if (image->debug != MagickFalse)
01275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01276 assert(exception != (ExceptionInfo *) NULL);
01277 assert(exception->signature == MagickSignature);
01278 minify_image=ResizeImage(image,image->columns/2,image->rows/2,CubicFilter,
01279 1.0,exception);
01280 return(minify_image);
01281 }
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317 MagickExport Image *ResampleImage(const Image *image,const double x_resolution,
01318 const double y_resolution,const FilterTypes filter,const double blur,
01319 ExceptionInfo *exception)
01320 {
01321 #define ResampleImageTag "Resample/Image"
01322
01323 Image
01324 *resample_image;
01325
01326 unsigned long
01327 height,
01328 width;
01329
01330
01331
01332
01333 assert(image != (const Image *) NULL);
01334 assert(image->signature == MagickSignature);
01335 if (image->debug != MagickFalse)
01336 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01337 assert(exception != (ExceptionInfo *) NULL);
01338 assert(exception->signature == MagickSignature);
01339 width=(unsigned long) (x_resolution*image->columns/
01340 (image->x_resolution == 0.0 ? 72.0 : image->x_resolution)+0.5);
01341 height=(unsigned long) (y_resolution*image->rows/
01342 (image->y_resolution == 0.0 ? 72.0 : image->y_resolution)+0.5);
01343 resample_image=ResizeImage(image,width,height,filter,blur,exception);
01344 if (resample_image != (Image *) NULL)
01345 {
01346 resample_image->x_resolution=x_resolution;
01347 resample_image->y_resolution=y_resolution;
01348 }
01349 return(resample_image);
01350 }
01351 #if defined(MAGICKCORE_LQR_DELEGATE)
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387 MagickExport Image *LiquidRescaleImage(const Image *image,
01388 const unsigned long columns,const unsigned long rows,
01389 const double delta_x,const double rigidity,ExceptionInfo *exception)
01390 {
01391 #define LiquidRescaleImageTag "Rescale/Image"
01392
01393 const char
01394 *map;
01395
01396 guchar
01397 *packet;
01398
01399 Image
01400 *rescale_image;
01401
01402 int
01403 x,
01404 y;
01405
01406 LqrCarver
01407 *carver;
01408
01409 LqrRetVal
01410 lqr_status;
01411
01412 MagickBooleanType
01413 status;
01414
01415 MagickPixelPacket
01416 pixel;
01417
01418 unsigned char
01419 *pixels;
01420
01421
01422
01423
01424 assert(image != (const Image *) NULL);
01425 assert(image->signature == MagickSignature);
01426 if (image->debug != MagickFalse)
01427 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01428 assert(exception != (ExceptionInfo *) NULL);
01429 assert(exception->signature == MagickSignature);
01430 if ((columns == 0) || (rows == 0))
01431 return((Image *) NULL);
01432 if ((columns == image->columns) && (rows == image->rows))
01433 return(CloneImage(image,0,0,MagickTrue,exception));
01434 if ((columns <= 2) || (rows <= 2))
01435 return(ZoomImage(image,columns,rows,exception));
01436 if ((columns >= (2*image->columns)) || (rows >= (2*image->rows)))
01437 {
01438 Image
01439 *resize_image;
01440
01441 unsigned long
01442 height,
01443 width;
01444
01445
01446
01447
01448 for (width=image->columns; columns >= (2*width-1); width*=2);
01449 for (height=image->rows; rows >= (2*height-1); height*=2);
01450 resize_image=ResizeImage(image,width,height,image->filter,image->blur,
01451 exception);
01452 if (resize_image == (Image *) NULL)
01453 return((Image *) NULL);
01454 rescale_image=LiquidRescaleImage(resize_image,columns,rows,delta_x,
01455 rigidity,exception);
01456 resize_image=DestroyImage(resize_image);
01457 return(rescale_image);
01458 }
01459 map="RGB";
01460 if (image->matte == MagickFalse)
01461 map="RGBA";
01462 if (image->colorspace == CMYKColorspace)
01463 {
01464 map="CMYK";
01465 if (image->matte == MagickFalse)
01466 map="CMYKA";
01467 }
01468 pixels=(unsigned char *) AcquireQuantumMemory(image->columns,image->rows*
01469 strlen(map)*sizeof(*pixels));
01470 if (pixels == (unsigned char *) NULL)
01471 return((Image *) NULL);
01472 status=ExportImagePixels(image,0,0,image->columns,image->rows,map,CharPixel,
01473 pixels,exception);
01474 if (status == MagickFalse)
01475 {
01476 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
01477 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
01478 }
01479 carver=lqr_carver_new(pixels,image->columns,image->rows,strlen(map));
01480 if (carver == (LqrCarver *) NULL)
01481 {
01482 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
01483 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
01484 }
01485 lqr_status=lqr_carver_init(carver,(int) delta_x,rigidity);
01486 lqr_status=lqr_carver_resize(carver,columns,rows);
01487 rescale_image=CloneImage(image,lqr_carver_get_width(carver),
01488 lqr_carver_get_height(carver),MagickTrue,exception);
01489 if (rescale_image == (Image *) NULL)
01490 {
01491 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
01492 return((Image *) NULL);
01493 }
01494 if (SetImageStorageClass(rescale_image,DirectClass) == MagickFalse)
01495 {
01496 InheritException(exception,&rescale_image->exception);
01497 rescale_image=DestroyImage(rescale_image);
01498 return((Image *) NULL);
01499 }
01500 GetMagickPixelPacket(rescale_image,&pixel);
01501 (void) lqr_carver_scan_reset(carver);
01502 while (lqr_carver_scan(carver,&x,&y,&packet) != 0)
01503 {
01504 register IndexPacket
01505 *__restrict rescale_indexes;
01506
01507 register PixelPacket
01508 *__restrict q;
01509
01510 q=QueueAuthenticPixels(rescale_image,x,y,1,1,exception);
01511 if (q == (PixelPacket *) NULL)
01512 break;
01513 rescale_indexes=GetAuthenticIndexQueue(rescale_image);
01514 pixel.red=QuantumRange*(packet[0]/255.0);
01515 pixel.green=QuantumRange*(packet[1]/255.0);
01516 pixel.blue=QuantumRange*(packet[2]/255.0);
01517 if (image->colorspace != CMYKColorspace)
01518 {
01519 if (image->matte == MagickFalse)
01520 pixel.opacity=QuantumRange*(packet[3]/255.0);
01521 }
01522 else
01523 {
01524 pixel.index=QuantumRange*(packet[3]/255.0);
01525 if (image->matte == MagickFalse)
01526 pixel.opacity=QuantumRange*(packet[4]/255.0);
01527 }
01528 SetPixelPacket(rescale_image,&pixel,q,rescale_indexes);
01529 if (SyncAuthenticPixels(rescale_image,exception) == MagickFalse)
01530 break;
01531 }
01532
01533
01534
01535 lqr_carver_destroy(carver);
01536 return(rescale_image);
01537 }
01538 #else
01539 MagickExport Image *LiquidRescaleImage(const Image *image,
01540 const unsigned long magick_unused(columns),
01541 const unsigned long magick_unused(rows),const double magick_unused(delta_x),
01542 const double magick_unused(rigidity),ExceptionInfo *exception)
01543 {
01544 assert(image != (const Image *) NULL);
01545 assert(image->signature == MagickSignature);
01546 if (image->debug != MagickFalse)
01547 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01548 assert(exception != (ExceptionInfo *) NULL);
01549 assert(exception->signature == MagickSignature);
01550 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
01551 "DelegateLibrarySupportNotBuiltIn","`%s' (LQR)",image->filename);
01552 return((Image *) NULL);
01553 }
01554 #endif
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599 typedef struct _ContributionInfo
01600 {
01601 MagickRealType
01602 weight;
01603
01604 long
01605 pixel;
01606 } ContributionInfo;
01607
01608 static ContributionInfo **DestroyContributionThreadSet(
01609 ContributionInfo **contribution)
01610 {
01611 register long
01612 i;
01613
01614 assert(contribution != (ContributionInfo **) NULL);
01615 for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
01616 if (contribution[i] != (ContributionInfo *) NULL)
01617 contribution[i]=(ContributionInfo *) RelinquishMagickMemory(
01618 contribution[i]);
01619 contribution=(ContributionInfo **) RelinquishAlignedMemory(contribution);
01620 return(contribution);
01621 }
01622
01623 static ContributionInfo **AcquireContributionThreadSet(const size_t count)
01624 {
01625 register long
01626 i;
01627
01628 ContributionInfo
01629 **contribution;
01630
01631 unsigned long
01632 number_threads;
01633
01634 number_threads=GetOpenMPMaximumThreads();
01635 contribution=(ContributionInfo **) AcquireAlignedMemory(number_threads,
01636 sizeof(*contribution));
01637 if (contribution == (ContributionInfo **) NULL)
01638 return((ContributionInfo **) NULL);
01639 (void) ResetMagickMemory(contribution,0,number_threads*sizeof(*contribution));
01640 for (i=0; i < (long) number_threads; i++)
01641 {
01642 contribution[i]=(ContributionInfo *) AcquireQuantumMemory(count,
01643 sizeof(**contribution));
01644 if (contribution[i] == (ContributionInfo *) NULL)
01645 return(DestroyContributionThreadSet(contribution));
01646 }
01647 return(contribution);
01648 }
01649
01650 static inline double MagickMax(const double x,const double y)
01651 {
01652 if (x > y)
01653 return(x);
01654 return(y);
01655 }
01656
01657 static inline double MagickMin(const double x,const double y)
01658 {
01659 if (x < y)
01660 return(x);
01661 return(y);
01662 }
01663
01664 static MagickBooleanType HorizontalFilter(const ResizeFilter *resize_filter,
01665 const Image *image,Image *resize_image,const MagickRealType x_factor,
01666 const MagickSizeType span,MagickOffsetType *quantum,ExceptionInfo *exception)
01667 {
01668 #define ResizeImageTag "Resize/Image"
01669
01670 ClassType
01671 storage_class;
01672
01673 ContributionInfo
01674 **contributions;
01675
01676 long
01677 x;
01678
01679 MagickBooleanType
01680 status;
01681
01682 MagickPixelPacket
01683 zero;
01684
01685 MagickRealType
01686 scale,
01687 support;
01688
01689 CacheView
01690 *image_view,
01691 *resize_view;
01692
01693
01694
01695
01696 scale=MagickMax(1.0/x_factor,1.0);
01697 support=scale*GetResizeFilterSupport(resize_filter);
01698 storage_class=support > 0.5 ? DirectClass : image->storage_class;
01699 if (SetImageStorageClass(resize_image,storage_class) == MagickFalse)
01700 {
01701 InheritException(exception,&resize_image->exception);
01702 return(MagickFalse);
01703 }
01704 if (support < 0.5)
01705 {
01706
01707
01708
01709 support=(MagickRealType) 0.5;
01710 scale=1.0;
01711 }
01712 contributions=AcquireContributionThreadSet((size_t) (2.0*support+3.0));
01713 if (contributions == (ContributionInfo **) NULL)
01714 {
01715 (void) ThrowMagickException(exception,GetMagickModule(),
01716 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
01717 return(MagickFalse);
01718 }
01719 status=MagickTrue;
01720 scale=1.0/scale;
01721 (void) ResetMagickMemory(&zero,0,sizeof(zero));
01722 image_view=AcquireCacheView(image);
01723 resize_view=AcquireCacheView(resize_image);
01724 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01725 #pragma omp parallel for shared(status)
01726 #endif
01727 for (x=0; x < (long) resize_image->columns; x++)
01728 {
01729 long
01730 n,
01731 start,
01732 stop;
01733
01734 MagickRealType
01735 center,
01736 density;
01737
01738 register const IndexPacket
01739 *__restrict indexes;
01740
01741 register const PixelPacket
01742 *__restrict p;
01743
01744 register ContributionInfo
01745 *__restrict contribution;
01746
01747 register IndexPacket
01748 *__restrict resize_indexes;
01749
01750 register long
01751 y;
01752
01753 register PixelPacket
01754 *__restrict q;
01755
01756 if (status == MagickFalse)
01757 continue;
01758 center=(MagickRealType) (x+0.5)/x_factor;
01759 start=(long) (MagickMax(center-support-MagickEpsilon,0.0)+0.5);
01760 stop=(long) (MagickMin(center+support,(double) image->columns)+0.5);
01761 density=0.0;
01762 contribution=contributions[GetOpenMPThreadId()];
01763 for (n=0; n < (stop-start); n++)
01764 {
01765 contribution[n].pixel=start+n;
01766 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
01767 ((MagickRealType) (start+n)-center+0.5));
01768 density+=contribution[n].weight;
01769 }
01770 if ((density != 0.0) && (density != 1.0))
01771 {
01772 register long
01773 i;
01774
01775
01776
01777
01778 density=1.0/density;
01779 for (i=0; i < n; i++)
01780 contribution[i].weight*=density;
01781 }
01782 p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,
01783 (unsigned long) (contribution[n-1].pixel-contribution[0].pixel+1),
01784 image->rows,exception);
01785 q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
01786 exception);
01787 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
01788 {
01789 status=MagickFalse;
01790 continue;
01791 }
01792 indexes=GetCacheViewVirtualIndexQueue(image_view);
01793 resize_indexes=GetCacheViewAuthenticIndexQueue(resize_view);
01794 for (y=0; y < (long) resize_image->rows; y++)
01795 {
01796 long
01797 j;
01798
01799 MagickPixelPacket
01800 pixel;
01801
01802 MagickRealType
01803 alpha;
01804
01805 register long
01806 i;
01807
01808 pixel=zero;
01809 if (image->matte == MagickFalse)
01810 {
01811 for (i=0; i < n; i++)
01812 {
01813 j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
01814 (contribution[i].pixel-contribution[0].pixel);
01815 alpha=contribution[i].weight;
01816 pixel.red+=alpha*(p+j)->red;
01817 pixel.green+=alpha*(p+j)->green;
01818 pixel.blue+=alpha*(p+j)->blue;
01819 pixel.opacity+=alpha*(p+j)->opacity;
01820 }
01821 q->red=RoundToQuantum(pixel.red);
01822 q->green=RoundToQuantum(pixel.green);
01823 q->blue=RoundToQuantum(pixel.blue);
01824 q->opacity=RoundToQuantum(pixel.opacity);
01825 if ((image->colorspace == CMYKColorspace) &&
01826 (resize_image->colorspace == CMYKColorspace))
01827 {
01828 for (i=0; i < n; i++)
01829 {
01830 j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
01831 (contribution[i].pixel-contribution[0].pixel);
01832 alpha=contribution[i].weight;
01833 pixel.index+=alpha*indexes[j];
01834 }
01835 resize_indexes[y]=(IndexPacket) RoundToQuantum(pixel.index);
01836 }
01837 }
01838 else
01839 {
01840 MagickRealType
01841 gamma;
01842
01843 gamma=0.0;
01844 for (i=0; i < n; i++)
01845 {
01846 j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
01847 (contribution[i].pixel-contribution[0].pixel);
01848 alpha=contribution[i].weight*QuantumScale*((MagickRealType)
01849 QuantumRange-(p+j)->opacity);
01850 pixel.red+=alpha*(p+j)->red;
01851 pixel.green+=alpha*(p+j)->green;
01852 pixel.blue+=alpha*(p+j)->blue;
01853 pixel.opacity+=contribution[i].weight*(p+j)->opacity;
01854 gamma+=alpha;
01855 }
01856 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
01857 q->red=RoundToQuantum(gamma*pixel.red);
01858 q->green=RoundToQuantum(gamma*pixel.green);
01859 q->blue=RoundToQuantum(gamma*pixel.blue);
01860 q->opacity=RoundToQuantum(pixel.opacity);
01861 if ((image->colorspace == CMYKColorspace) &&
01862 (resize_image->colorspace == CMYKColorspace))
01863 {
01864 for (i=0; i < n; i++)
01865 {
01866 j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
01867 (contribution[i].pixel-contribution[0].pixel);
01868 alpha=contribution[i].weight*QuantumScale*((MagickRealType)
01869 QuantumRange-(p+j)->opacity);
01870 pixel.index+=alpha*indexes[j];
01871 }
01872 resize_indexes[y]=(IndexPacket) RoundToQuantum(gamma*pixel.index);
01873 }
01874 }
01875 if ((resize_image->storage_class == PseudoClass) &&
01876 (image->storage_class == PseudoClass))
01877 {
01878 i=(long) (MagickMin(MagickMax(center,(double) start),(double) stop-
01879 1.0)+0.5);
01880 j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
01881 (contribution[i-start].pixel-contribution[0].pixel);
01882 resize_indexes[y]=indexes[j];
01883 }
01884 q++;
01885 }
01886 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
01887 status=MagickFalse;
01888 if (image->progress_monitor != (MagickProgressMonitor) NULL)
01889 {
01890 MagickBooleanType
01891 proceed;
01892
01893 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01894 #pragma omp critical (MagickCore_HorizontalFilter)
01895 #endif
01896 proceed=SetImageProgress(image,ResizeImageTag,(*quantum)++,span);
01897 if (proceed == MagickFalse)
01898 status=MagickFalse;
01899 }
01900 }
01901 resize_view=DestroyCacheView(resize_view);
01902 image_view=DestroyCacheView(image_view);
01903 contributions=DestroyContributionThreadSet(contributions);
01904 return(status);
01905 }
01906
01907 static MagickBooleanType VerticalFilter(const ResizeFilter *resize_filter,
01908 const Image *image,Image *resize_image,const MagickRealType y_factor,
01909 const MagickSizeType span,MagickOffsetType *quantum,ExceptionInfo *exception)
01910 {
01911 ClassType
01912 storage_class;
01913
01914 ContributionInfo
01915 **contributions;
01916
01917 long
01918 y;
01919
01920 MagickBooleanType
01921 status;
01922
01923 MagickPixelPacket
01924 zero;
01925
01926 MagickRealType
01927 scale,
01928 support;
01929
01930 CacheView
01931 *image_view,
01932 *resize_view;
01933
01934
01935
01936
01937 scale=MagickMax(1.0/y_factor,1.0);
01938 support=scale*GetResizeFilterSupport(resize_filter);
01939 storage_class=support > 0.5 ? DirectClass : image->storage_class;
01940 if (SetImageStorageClass(resize_image,storage_class) == MagickFalse)
01941 {
01942 InheritException(exception,&resize_image->exception);
01943 return(MagickFalse);
01944 }
01945 if (support < 0.5)
01946 {
01947
01948
01949
01950 support=(MagickRealType) 0.5;
01951 scale=1.0;
01952 }
01953 contributions=AcquireContributionThreadSet((size_t) (2.0*support+3.0));
01954 if (contributions == (ContributionInfo **) NULL)
01955 {
01956 (void) ThrowMagickException(exception,GetMagickModule(),
01957 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
01958 return(MagickFalse);
01959 }
01960 status=MagickTrue;
01961 scale=1.0/scale;
01962 (void) ResetMagickMemory(&zero,0,sizeof(zero));
01963 image_view=AcquireCacheView(image);
01964 resize_view=AcquireCacheView(resize_image);
01965 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01966 #pragma omp parallel for shared(status)
01967 #endif
01968 for (y=0; y < (long) resize_image->rows; y++)
01969 {
01970 long
01971 n,
01972 start,
01973 stop;
01974
01975 MagickRealType
01976 center,
01977 density;
01978
01979 register const IndexPacket
01980 *__restrict indexes;
01981
01982 register const PixelPacket
01983 *__restrict p;
01984
01985 register ContributionInfo
01986 *__restrict contribution;
01987
01988 register IndexPacket
01989 *__restrict resize_indexes;
01990
01991 register long
01992 x;
01993
01994 register PixelPacket
01995 *__restrict q;
01996
01997 if (status == MagickFalse)
01998 continue;
01999 center=(MagickRealType) (y+0.5)/y_factor;
02000 start=(long) (MagickMax(center-support-MagickEpsilon,0.0)+0.5);
02001 stop=(long) (MagickMin(center+support,(double) image->rows)+0.5);
02002 density=0.0;
02003 contribution=contributions[GetOpenMPThreadId()];
02004 for (n=0; n < (stop-start); n++)
02005 {
02006 contribution[n].pixel=start+n;
02007 contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
02008 ((MagickRealType) (start+n)-center+0.5));
02009 density+=contribution[n].weight;
02010 }
02011 if ((density != 0.0) && (density != 1.0))
02012 {
02013 register long
02014 i;
02015
02016
02017
02018
02019 density=1.0/density;
02020 for (i=0; i < n; i++)
02021 contribution[i].weight*=density;
02022 }
02023 p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
02024 image->columns,(unsigned long) (contribution[n-1].pixel-
02025 contribution[0].pixel+1),exception);
02026 q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
02027 exception);
02028 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
02029 {
02030 status=MagickFalse;
02031 continue;
02032 }
02033 indexes=GetCacheViewVirtualIndexQueue(image_view);
02034 resize_indexes=GetCacheViewAuthenticIndexQueue(resize_view);
02035 for (x=0; x < (long) resize_image->columns; x++)
02036 {
02037 long
02038 j;
02039
02040 MagickPixelPacket
02041 pixel;
02042
02043 MagickRealType
02044 alpha;
02045
02046 register long
02047 i;
02048
02049 pixel=zero;
02050 if (image->matte == MagickFalse)
02051 {
02052 for (i=0; i < n; i++)
02053 {
02054 j=(long) ((contribution[i].pixel-contribution[0].pixel)*
02055 image->columns+x);
02056 alpha=contribution[i].weight;
02057 pixel.red+=alpha*(p+j)->red;
02058 pixel.green+=alpha*(p+j)->green;
02059 pixel.blue+=alpha*(p+j)->blue;
02060 pixel.opacity+=alpha*(p+j)->opacity;
02061 }
02062 q->red=RoundToQuantum(pixel.red);
02063 q->green=RoundToQuantum(pixel.green);
02064 q->blue=RoundToQuantum(pixel.blue);
02065 q->opacity=RoundToQuantum(pixel.opacity);
02066 if ((image->colorspace == CMYKColorspace) &&
02067 (resize_image->colorspace == CMYKColorspace))
02068 {
02069 for (i=0; i < n; i++)
02070 {
02071 j=(long) ((contribution[i].pixel-contribution[0].pixel)*
02072 image->columns+x);
02073 alpha=contribution[i].weight;
02074 pixel.index+=alpha*indexes[j];
02075 }
02076 resize_indexes[x]=(IndexPacket) RoundToQuantum(pixel.index);
02077 }
02078 }
02079 else
02080 {
02081 MagickRealType
02082 gamma;
02083
02084 gamma=0.0;
02085 for (i=0; i < n; i++)
02086 {
02087 j=(long) ((contribution[i].pixel-contribution[0].pixel)*
02088 image->columns+x);
02089 alpha=contribution[i].weight*QuantumScale*((MagickRealType)
02090 QuantumRange-(p+j)->opacity);
02091 pixel.red+=alpha*(p+j)->red;
02092 pixel.green+=alpha*(p+j)->green;
02093 pixel.blue+=alpha*(p+j)->blue;
02094 pixel.opacity+=contribution[i].weight*(p+j)->opacity;
02095 gamma+=alpha;
02096 }
02097 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
02098 q->red=RoundToQuantum(gamma*pixel.red);
02099 q->green=RoundToQuantum(gamma*pixel.green);
02100 q->blue=RoundToQuantum(gamma*pixel.blue);
02101 q->opacity=RoundToQuantum(pixel.opacity);
02102 if ((image->colorspace == CMYKColorspace) &&
02103 (resize_image->colorspace == CMYKColorspace))
02104 {
02105 for (i=0; i < n; i++)
02106 {
02107 j=(long) ((contribution[i].pixel-contribution[0].pixel)*
02108 image->columns+x);
02109 alpha=contribution[i].weight*QuantumScale*((MagickRealType)
02110 QuantumRange-(p+j)->opacity);
02111 pixel.index+=alpha*indexes[j];
02112 }
02113 resize_indexes[x]=(IndexPacket) RoundToQuantum(gamma*pixel.index);
02114 }
02115 }
02116 if ((resize_image->storage_class == PseudoClass) &&
02117 (image->storage_class == PseudoClass))
02118 {
02119 i=(long) (MagickMin(MagickMax(center,(double) start),(double) stop-
02120 1.0)+0.5);
02121 j=(long) ((contribution[i-start].pixel-contribution[0].pixel)*
02122 image->columns+x);
02123 resize_indexes[x]=indexes[j];
02124 }
02125 q++;
02126 }
02127 if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
02128 status=MagickFalse;
02129 if (image->progress_monitor != (MagickProgressMonitor) NULL)
02130 {
02131 MagickBooleanType
02132 proceed;
02133
02134 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02135 #pragma omp critical (MagickCore_VerticalFilter)
02136 #endif
02137 proceed=SetImageProgress(image,ResizeImageTag,(*quantum)++,span);
02138 if (proceed == MagickFalse)
02139 status=MagickFalse;
02140 }
02141 }
02142 resize_view=DestroyCacheView(resize_view);
02143 image_view=DestroyCacheView(image_view);
02144 contributions=DestroyContributionThreadSet(contributions);
02145 return(status);
02146 }
02147
02148 MagickExport Image *ResizeImage(const Image *image,const unsigned long columns,
02149 const unsigned long rows,const FilterTypes filter,const double blur,
02150 ExceptionInfo *exception)
02151 {
02152 #define WorkLoadFactor 0.265
02153
02154 FilterTypes
02155 filter_type;
02156
02157 Image
02158 *filter_image,
02159 *resize_image;
02160
02161 MagickRealType
02162 x_factor,
02163 y_factor;
02164
02165 MagickSizeType
02166 span;
02167
02168 MagickStatusType
02169 status;
02170
02171 ResizeFilter
02172 *resize_filter;
02173
02174 MagickOffsetType
02175 quantum;
02176
02177
02178
02179
02180 assert(image != (Image *) NULL);
02181 assert(image->signature == MagickSignature);
02182 if (image->debug != MagickFalse)
02183 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02184 assert(exception != (ExceptionInfo *) NULL);
02185 assert(exception->signature == MagickSignature);
02186 if ((columns == 0) || (rows == 0))
02187 ThrowImageException(ImageError,"NegativeOrZeroImageSize");
02188 if ((columns == image->columns) && (rows == image->rows) &&
02189 (filter == UndefinedFilter) && (blur == 1.0))
02190 return(CloneImage(image,0,0,MagickTrue,exception));
02191 resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
02192 if (resize_image == (Image *) NULL)
02193 return(resize_image);
02194
02195
02196
02197 x_factor=(MagickRealType) columns/(MagickRealType) image->columns;
02198 y_factor=(MagickRealType) rows/(MagickRealType) image->rows;
02199 if ((x_factor*y_factor) > WorkLoadFactor)
02200 filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
02201 else
02202 filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
02203 if (filter_image == (Image *) NULL)
02204 return(DestroyImage(resize_image));
02205 filter_type=LanczosFilter;
02206 if (filter != UndefinedFilter)
02207 filter_type=filter;
02208 else
02209 if ((x_factor == 1.0) && (y_factor == 1.0))
02210 filter_type=PointFilter;
02211 else
02212 if ((image->storage_class == PseudoClass) ||
02213 (image->matte != MagickFalse) || ((x_factor*y_factor) > 1.0))
02214 filter_type=MitchellFilter;
02215 resize_filter=AcquireResizeFilter(image,filter_type,blur,MagickFalse,
02216 exception);
02217
02218
02219
02220 quantum=0;
02221 if ((x_factor*y_factor) > WorkLoadFactor)
02222 {
02223 span=(MagickSizeType) (filter_image->columns+rows);
02224 status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
02225 &quantum,exception);
02226 status&=VerticalFilter(resize_filter,filter_image,resize_image,y_factor,
02227 span,&quantum,exception);
02228 }
02229 else
02230 {
02231 span=(MagickSizeType) (filter_image->rows+columns);
02232 status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
02233 &quantum,exception);
02234 status&=HorizontalFilter(resize_filter,filter_image,resize_image,x_factor,
02235 span,&quantum,exception);
02236 }
02237
02238
02239
02240 filter_image=DestroyImage(filter_image);
02241 resize_filter=DestroyResizeFilter(resize_filter);
02242 if ((status == MagickFalse) || (resize_image == (Image *) NULL))
02243 return((Image *) NULL);
02244 resize_image->type=image->type;
02245 return(resize_image);
02246 }
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279 MagickExport Image *SampleImage(const Image *image,const unsigned long columns,
02280 const unsigned long rows,ExceptionInfo *exception)
02281 {
02282 #define SampleImageTag "Sample/Image"
02283
02284 Image
02285 *sample_image;
02286
02287 long
02288 progress,
02289 *x_offset,
02290 y;
02291
02292 MagickBooleanType
02293 status;
02294
02295 register long
02296 x;
02297
02298 CacheView
02299 *image_view,
02300 *sample_view;
02301
02302
02303
02304
02305 assert(image != (const Image *) NULL);
02306 assert(image->signature == MagickSignature);
02307 if (image->debug != MagickFalse)
02308 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02309 assert(exception != (ExceptionInfo *) NULL);
02310 assert(exception->signature == MagickSignature);
02311 if ((columns == 0) || (rows == 0))
02312 ThrowImageException(ImageError,"NegativeOrZeroImageSize");
02313 if ((columns == image->columns) && (rows == image->rows))
02314 return(CloneImage(image,0,0,MagickTrue,exception));
02315 sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
02316 if (sample_image == (Image *) NULL)
02317 return((Image *) NULL);
02318
02319
02320
02321 x_offset=(long *) AcquireQuantumMemory((size_t) sample_image->columns,
02322 sizeof(*x_offset));
02323 if (x_offset == (long *) NULL)
02324 {
02325 sample_image=DestroyImage(sample_image);
02326 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
02327 }
02328 for (x=0; x < (long) sample_image->columns; x++)
02329 x_offset[x]=(long) (((MagickRealType) x+0.5)*image->columns/
02330 sample_image->columns);
02331
02332
02333
02334 status=MagickTrue;
02335 progress=0;
02336 image_view=AcquireCacheView(image);
02337 sample_view=AcquireCacheView(sample_image);
02338 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02339 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
02340 #endif
02341 for (y=0; y < (long) sample_image->rows; y++)
02342 {
02343 long
02344 y_offset;
02345
02346 register const IndexPacket
02347 *__restrict indexes;
02348
02349 register const PixelPacket
02350 *__restrict p;
02351
02352 register IndexPacket
02353 *__restrict sample_indexes;
02354
02355 register long
02356 x;
02357
02358 register PixelPacket
02359 *__restrict q;
02360
02361 if (status == MagickFalse)
02362 continue;
02363 y_offset=(long) (((MagickRealType) y+0.5)*image->rows/sample_image->rows);
02364 p=GetCacheViewVirtualPixels(image_view,0,y_offset,image->columns,1,
02365 exception);
02366 q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
02367 exception);
02368 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
02369 {
02370 status=MagickFalse;
02371 continue;
02372 }
02373 indexes=GetCacheViewAuthenticIndexQueue(image_view);
02374 sample_indexes=GetCacheViewAuthenticIndexQueue(sample_view);
02375
02376
02377
02378 for (x=0; x < (long) sample_image->columns; x++)
02379 *q++=p[x_offset[x]];
02380 if ((image->storage_class == PseudoClass) ||
02381 (image->colorspace == CMYKColorspace))
02382 for (x=0; x < (long) sample_image->columns; x++)
02383 sample_indexes[x]=indexes[x_offset[x]];
02384 if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
02385 status=MagickFalse;
02386 if (image->progress_monitor != (MagickProgressMonitor) NULL)
02387 {
02388 MagickBooleanType
02389 proceed;
02390
02391 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02392 #pragma omp critical (MagickCore_SampleImage)
02393 #endif
02394 proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
02395 if (proceed == MagickFalse)
02396 status=MagickFalse;
02397 }
02398 }
02399 image_view=DestroyCacheView(image_view);
02400 sample_view=DestroyCacheView(sample_view);
02401 x_offset=(long *) RelinquishMagickMemory(x_offset);
02402 sample_image->type=image->type;
02403 return(sample_image);
02404 }
02405
02406
02407
02408
02409
02410
02411
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422
02423
02424
02425
02426
02427
02428
02429
02430
02431
02432
02433
02434
02435 MagickExport Image *ScaleImage(const Image *image,const unsigned long columns,
02436 const unsigned long rows,ExceptionInfo *exception)
02437 {
02438 #define ScaleImageTag "Scale/Image"
02439
02440 Image
02441 *scale_image;
02442
02443 long
02444 number_rows,
02445 y;
02446
02447 MagickBooleanType
02448 next_column,
02449 next_row,
02450 proceed;
02451
02452 MagickPixelPacket
02453 pixel,
02454 *scale_scanline,
02455 *scanline,
02456 *x_vector,
02457 *y_vector,
02458 zero;
02459
02460 PointInfo
02461 scale,
02462 span;
02463
02464 register long
02465 i;
02466
02467
02468
02469
02470 assert(image != (const Image *) NULL);
02471 assert(image->signature == MagickSignature);
02472 if (image->debug != MagickFalse)
02473 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02474 assert(exception != (ExceptionInfo *) NULL);
02475 assert(exception->signature == MagickSignature);
02476 if ((columns == 0) || (rows == 0))
02477 return((Image *) NULL);
02478 if ((columns == image->columns) && (rows == image->rows))
02479 return(CloneImage(image,0,0,MagickTrue,exception));
02480 scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
02481 if (scale_image == (Image *) NULL)
02482 return((Image *) NULL);
02483 if (SetImageStorageClass(scale_image,DirectClass) == MagickFalse)
02484 {
02485 InheritException(exception,&scale_image->exception);
02486 scale_image=DestroyImage(scale_image);
02487 return((Image *) NULL);
02488 }
02489
02490
02491
02492 x_vector=(MagickPixelPacket *) AcquireQuantumMemory((size_t) image->columns,
02493 sizeof(*x_vector));
02494 scanline=x_vector;
02495 if (image->rows != scale_image->rows)
02496 scanline=(MagickPixelPacket *) AcquireQuantumMemory((size_t) image->columns,
02497 sizeof(*scanline));
02498 scale_scanline=(MagickPixelPacket *) AcquireQuantumMemory((size_t)
02499 scale_image->columns,sizeof(*scale_scanline));
02500 y_vector=(MagickPixelPacket *) AcquireQuantumMemory((size_t) image->columns,
02501 sizeof(*y_vector));
02502 if ((scanline == (MagickPixelPacket *) NULL) ||
02503 (scale_scanline == (MagickPixelPacket *) NULL) ||
02504 (x_vector == (MagickPixelPacket *) NULL) ||
02505 (y_vector == (MagickPixelPacket *) NULL))
02506 {
02507 scale_image=DestroyImage(scale_image);
02508 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
02509 }
02510
02511
02512
02513 number_rows=0;
02514 next_row=MagickTrue;
02515 span.y=1.0;
02516 scale.y=(double) scale_image->rows/(double) image->rows;
02517 (void) ResetMagickMemory(y_vector,0,(size_t) image->columns*
02518 sizeof(*y_vector));
02519 GetMagickPixelPacket(image,&pixel);
02520 (void) ResetMagickMemory(&zero,0,sizeof(zero));
02521 i=0;
02522 for (y=0; y < (long) scale_image->rows; y++)
02523 {
02524 register const IndexPacket
02525 *__restrict indexes;
02526
02527 register const PixelPacket
02528 *__restrict p;
02529
02530 register IndexPacket
02531 *__restrict scale_indexes;
02532
02533 register long
02534 x;
02535
02536 register MagickPixelPacket
02537 *__restrict s,
02538 *__restrict t;
02539
02540 register PixelPacket
02541 *__restrict q;
02542
02543 q=QueueAuthenticPixels(scale_image,0,y,scale_image->columns,1,exception);
02544 if (q == (PixelPacket *) NULL)
02545 break;
02546 scale_indexes=GetAuthenticIndexQueue(scale_image);
02547 if (scale_image->rows == image->rows)
02548 {
02549
02550
02551
02552 p=GetVirtualPixels(image,0,i++,image->columns,1,exception);
02553 if (p == (const PixelPacket *) NULL)
02554 break;
02555 indexes=GetVirtualIndexQueue(image);
02556 for (x=0; x < (long) image->columns; x++)
02557 {
02558 x_vector[x].red=(MagickRealType) p->red;
02559 x_vector[x].green=(MagickRealType) p->green;
02560 x_vector[x].blue=(MagickRealType) p->blue;
02561 if (image->matte != MagickFalse)
02562 x_vector[x].opacity=(MagickRealType) p->opacity;
02563 if (indexes != (IndexPacket *) NULL)
02564 x_vector[x].index=(MagickRealType) indexes[x];
02565 p++;
02566 }
02567 }
02568 else
02569 {
02570
02571
02572
02573 while (scale.y < span.y)
02574 {
02575 if ((next_row != MagickFalse) && (number_rows < (long) image->rows))
02576 {
02577
02578
02579
02580 p=GetVirtualPixels(image,0,i++,image->columns,1,exception);
02581 if (p == (const PixelPacket *) NULL)
02582 break;
02583 indexes=GetVirtualIndexQueue(image);
02584 for (x=0; x < (long) image->columns; x++)
02585 {
02586 x_vector[x].red=(MagickRealType) p->red;
02587 x_vector[x].green=(MagickRealType) p->green;
02588 x_vector[x].blue=(MagickRealType) p->blue;
02589 if (image->matte != MagickFalse)
02590 x_vector[x].opacity=(MagickRealType) p->opacity;
02591 if (indexes != (IndexPacket *) NULL)
02592 x_vector[x].index=(MagickRealType) indexes[x];
02593 p++;
02594 }
02595 number_rows++;
02596 }
02597 for (x=0; x < (long) image->columns; x++)
02598 {
02599 y_vector[x].red+=scale.y*x_vector[x].red;
02600 y_vector[x].green+=scale.y*x_vector[x].green;
02601 y_vector[x].blue+=scale.y*x_vector[x].blue;
02602 if (scale_image->matte != MagickFalse)
02603 y_vector[x].opacity+=scale.y*x_vector[x].opacity;
02604 if (scale_indexes != (IndexPacket *) NULL)
02605 y_vector[x].index+=scale.y*x_vector[x].index;
02606 }
02607 span.y-=scale.y;
02608 scale.y=(double) scale_image->rows/(double) image->rows;
02609 next_row=MagickTrue;
02610 }
02611 if ((next_row != MagickFalse) && (number_rows < (long) image->rows))
02612 {
02613
02614
02615
02616 p=GetVirtualPixels(image,0,i++,image->columns,1,exception);
02617 if (p == (const PixelPacket *) NULL)
02618 break;
02619 indexes=GetVirtualIndexQueue(image);
02620 for (x=0; x < (long) image->columns; x++)
02621 {
02622 x_vector[x].red=(MagickRealType) p->red;
02623 x_vector[x].green=(MagickRealType) p->green;
02624 x_vector[x].blue=(MagickRealType) p->blue;
02625 if (image->matte != MagickFalse)
02626 x_vector[x].opacity=(MagickRealType) p->opacity;
02627 if (indexes != (IndexPacket *) NULL)
02628 x_vector[x].index=(MagickRealType) indexes[x];
02629 p++;
02630 }
02631 number_rows++;
02632 next_row=MagickFalse;
02633 }
02634 s=scanline;
02635 for (x=0; x < (long) image->columns; x++)
02636 {
02637 pixel.red=y_vector[x].red+span.y*x_vector[x].red;
02638 pixel.green=y_vector[x].green+span.y*x_vector[x].green;
02639 pixel.blue=y_vector[x].blue+span.y*x_vector[x].blue;
02640 if (image->matte != MagickFalse)
02641 pixel.opacity=y_vector[x].opacity+span.y*x_vector[x].opacity;
02642 if (scale_indexes != (IndexPacket *) NULL)
02643 pixel.index=y_vector[x].index+span.y*x_vector[x].index;
02644 s->red=pixel.red;
02645 s->green=pixel.green;
02646 s->blue=pixel.blue;
02647 if (scale_image->matte != MagickFalse)
02648 s->opacity=pixel.opacity;
02649 if (scale_indexes != (IndexPacket *) NULL)
02650 s->index=pixel.index;
02651 s++;
02652 y_vector[x]=zero;
02653 }
02654 scale.y-=span.y;
02655 if (scale.y <= 0)
02656 {
02657 scale.y=(double) scale_image->rows/(double) image->rows;
02658 next_row=MagickTrue;
02659 }
02660 span.y=1.0;
02661 }
02662 if (scale_image->columns == image->columns)
02663 {
02664
02665
02666
02667 s=scanline;
02668 for (x=0; x < (long) scale_image->columns; x++)
02669 {
02670 q->red=RoundToQuantum(s->red);
02671 q->green=RoundToQuantum(s->green);
02672 q->blue=RoundToQuantum(s->blue);
02673 if (scale_image->matte != MagickFalse)
02674 q->opacity=RoundToQuantum(s->opacity);
02675 if (scale_indexes != (IndexPacket *) NULL)
02676 scale_indexes[x]=(IndexPacket) RoundToQuantum(s->index);
02677 q++;
02678 s++;
02679 }
02680 }
02681 else
02682 {
02683
02684
02685
02686 pixel=zero;
02687 next_column=MagickFalse;
02688 span.x=1.0;
02689 s=scanline;
02690 t=scale_scanline;
02691 for (x=0; x < (long) image->columns; x++)
02692 {
02693 scale.x=(double) scale_image->columns/(double) image->columns;
02694 while (scale.x >= span.x)
02695 {
02696 if (next_column != MagickFalse)
02697 {
02698 pixel=zero;
02699 t++;
02700 }
02701 pixel.red+=span.x*s->red;
02702 pixel.green+=span.x*s->green;
02703 pixel.blue+=span.x*s->blue;
02704 if (image->matte != MagickFalse)
02705 pixel.opacity+=span.x*s->opacity;
02706 if (scale_indexes != (IndexPacket *) NULL)
02707 pixel.index+=span.x*s->index;
02708 t->red=pixel.red;
02709 t->green=pixel.green;
02710 t->blue=pixel.blue;
02711 if (scale_image->matte != MagickFalse)
02712 t->opacity=pixel.opacity;
02713 if (scale_indexes != (IndexPacket *) NULL)
02714 t->index=pixel.index;
02715 scale.x-=span.x;
02716 span.x=1.0;
02717 next_column=MagickTrue;
02718 }
02719 if (scale.x > 0)
02720 {
02721 if (next_column != MagickFalse)
02722 {
02723 pixel=zero;
02724 next_column=MagickFalse;
02725 t++;
02726 }
02727 pixel.red+=scale.x*s->red;
02728 pixel.green+=scale.x*s->green;
02729 pixel.blue+=scale.x*s->blue;
02730 if (scale_image->matte != MagickFalse)
02731 pixel.opacity+=scale.x*s->opacity;
02732 if (scale_indexes != (IndexPacket *) NULL)
02733 pixel.index+=scale.x*s->index;
02734 span.x-=scale.x;
02735 }
02736 s++;
02737 }
02738 if (span.x > 0)
02739 {
02740 s--;
02741 pixel.red+=span.x*s->red;
02742 pixel.green+=span.x*s->green;
02743 pixel.blue+=span.x*s->blue;
02744 if (scale_image->matte != MagickFalse)
02745 pixel.opacity+=span.x*s->opacity;
02746 if (scale_indexes != (IndexPacket *) NULL)
02747 pixel.index+=span.x*s->index;
02748 }
02749 if ((next_column == MagickFalse) &&
02750 ((long) (t-scale_scanline) < (long) scale_image->columns))
02751 {
02752 t->red=pixel.red;
02753 t->green=pixel.green;
02754 t->blue=pixel.blue;
02755 if (scale_image->matte != MagickFalse)
02756 t->opacity=pixel.opacity;
02757 if (scale_indexes != (IndexPacket *) NULL)
02758 t->index=pixel.index;
02759 }
02760
02761
02762
02763 t=scale_scanline;
02764 for (x=0; x < (long) scale_image->columns; x++)
02765 {
02766 q->red=RoundToQuantum(t->red);
02767 q->green=RoundToQuantum(t->green);
02768 q->blue=RoundToQuantum(t->blue);
02769 if (scale_image->matte != MagickFalse)
02770 q->opacity=RoundToQuantum(t->opacity);
02771 if (scale_indexes != (IndexPacket *) NULL)
02772 scale_indexes[x]=(IndexPacket) RoundToQuantum(t->index);
02773 t++;
02774 q++;
02775 }
02776 }
02777 if (SyncAuthenticPixels(scale_image,exception) == MagickFalse)
02778 break;
02779 proceed=SetImageProgress(image,ScaleImageTag,y,image->rows);
02780 if (proceed == MagickFalse)
02781 break;
02782 }
02783
02784
02785
02786 y_vector=(MagickPixelPacket *) RelinquishMagickMemory(y_vector);
02787 scale_scanline=(MagickPixelPacket *) RelinquishMagickMemory(scale_scanline);
02788 if (scale_image->rows != image->rows)
02789 scanline=(MagickPixelPacket *) RelinquishMagickMemory(scanline);
02790 x_vector=(MagickPixelPacket *) RelinquishMagickMemory(x_vector);
02791 scale_image->type=image->type;
02792 return(scale_image);
02793 }
02794
02795
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
02811
02812
02813
02814
02815
02816
02817
02818
02819
02820 MagickExport void SetResizeFilterSupport(ResizeFilter *resize_filter,
02821 const MagickRealType support)
02822 {
02823 assert(resize_filter != (ResizeFilter *) NULL);
02824 assert(resize_filter->signature == MagickSignature);
02825 resize_filter->support=support;
02826 }
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841
02842
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852
02853
02854
02855
02856
02857
02858
02859 MagickExport Image *ThumbnailImage(const Image *image,
02860 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
02861 {
02862 #define SampleFactor 5
02863
02864 char
02865 value[MaxTextExtent];
02866
02867 const char
02868 *name;
02869
02870 Image
02871 *thumbnail_image;
02872
02873 MagickRealType
02874 x_factor,
02875 y_factor;
02876
02877 struct stat
02878 attributes;
02879
02880 unsigned long
02881 version;
02882
02883 assert(image != (Image *) NULL);
02884 assert(image->signature == MagickSignature);
02885 if (image->debug != MagickFalse)
02886 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02887 assert(exception != (ExceptionInfo *) NULL);
02888 assert(exception->signature == MagickSignature);
02889 x_factor=(MagickRealType) columns/(MagickRealType) image->columns;
02890 y_factor=(MagickRealType) rows/(MagickRealType) image->rows;
02891 if ((x_factor*y_factor) > 0.1)
02892 thumbnail_image=ZoomImage(image,columns,rows,exception);
02893 else
02894 if (((SampleFactor*columns) < 128) || ((SampleFactor*rows) < 128))
02895 thumbnail_image=ZoomImage(image,columns,rows,exception);
02896 else
02897 {
02898 Image
02899 *sample_image;
02900
02901 sample_image=SampleImage(image,SampleFactor*columns,SampleFactor*rows,
02902 exception);
02903 if (sample_image == (Image *) NULL)
02904 return((Image *) NULL);
02905 thumbnail_image=ZoomImage(sample_image,columns,rows,exception);
02906 sample_image=DestroyImage(sample_image);
02907 }
02908 if (thumbnail_image == (Image *) NULL)
02909 return(thumbnail_image);
02910 (void) ParseAbsoluteGeometry("0x0+0+0",&thumbnail_image->page);
02911 if (thumbnail_image->matte == MagickFalse)
02912 (void) SetImageAlphaChannel(thumbnail_image,OpaqueAlphaChannel);
02913 thumbnail_image->depth=8;
02914 thumbnail_image->interlace=NoInterlace;
02915
02916
02917
02918 ResetImageProfileIterator(thumbnail_image);
02919 for (name=GetNextImageProfile(thumbnail_image); name != (const char *) NULL; )
02920 {
02921 if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
02922 {
02923 DeleteImageProfile(thumbnail_image,name);
02924 ResetImageProfileIterator(thumbnail_image);
02925 }
02926 name=GetNextImageProfile(thumbnail_image);
02927 }
02928 (void) DeleteImageProperty(thumbnail_image,"comment");
02929 (void) CopyMagickString(value,image->magick_filename,MaxTextExtent);
02930 if (strstr(image->magick_filename,"//") == (char *) NULL)
02931 (void) FormatMagickString(value,MaxTextExtent,"file://%s",
02932 image->magick_filename);
02933 (void) SetImageProperty(thumbnail_image,"Thumb::URI",value);
02934 (void) CopyMagickString(value,image->magick_filename,MaxTextExtent);
02935 if (GetPathAttributes(image->filename,&attributes) != MagickFalse)
02936 {
02937 (void) FormatMagickString(value,MaxTextExtent,"%ld",(long)
02938 attributes.st_mtime);
02939 (void) SetImageProperty(thumbnail_image,"Thumb::MTime",value);
02940 }
02941 (void) FormatMagickString(value,MaxTextExtent,"%ld",(long)
02942 attributes.st_mtime);
02943 (void) FormatMagickSize(GetBlobSize(image),value);
02944 (void) SetImageProperty(thumbnail_image,"Thumb::Size",value);
02945 (void) FormatMagickString(value,MaxTextExtent,"image/%s",image->magick);
02946 LocaleLower(value);
02947 (void) SetImageProperty(thumbnail_image,"Thumb::Mimetype",value);
02948 (void) SetImageProperty(thumbnail_image,"software",
02949 GetMagickVersion(&version));
02950 (void) FormatMagickString(value,MaxTextExtent,"%lu",image->magick_columns);
02951 (void) SetImageProperty(thumbnail_image,"Thumb::Image::Width",value);
02952 (void) FormatMagickString(value,MaxTextExtent,"%lu",image->magick_rows);
02953 (void) SetImageProperty(thumbnail_image,"Thumb::Image::height",value);
02954 (void) FormatMagickString(value,MaxTextExtent,"%lu",
02955 GetImageListLength(image));
02956 (void) SetImageProperty(thumbnail_image,"Thumb::Document::Pages",value);
02957 return(thumbnail_image);
02958 }
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977
02978
02979
02980
02981
02982
02983
02984
02985
02986
02987
02988
02989
02990
02991
02992
02993
02994
02995
02996
02997
02998
02999 MagickExport Image *ZoomImage(const Image *image,const unsigned long columns,
03000 const unsigned long rows,ExceptionInfo *exception)
03001 {
03002 Image
03003 *zoom_image;
03004
03005 assert(image != (const Image *) NULL);
03006 assert(image->signature == MagickSignature);
03007 if (image->debug != MagickFalse)
03008 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03009 assert(exception != (ExceptionInfo *) NULL);
03010 assert(exception->signature == MagickSignature);
03011 zoom_image=ResizeImage(image,columns,rows,image->filter,image->blur,
03012 exception);
03013 return(zoom_image);
03014 }