Commit 02a8cbcc9 for imagemagick.org
commit 02a8cbcc99393cb9984f9f39f4b6da06b8139da4
Author: Cristy <urban-warrior@imagemagick.org>
Date: Thu Oct 15 20:22:36 2026 -0400
support -shuffle operator
diff --git a/MagickCore/list.c b/MagickCore/list.c
index 3491de5ec..584f99b5a 100644
--- a/MagickCore/list.c
+++ b/MagickCore/list.c
@@ -1337,24 +1337,24 @@ MagickExport void ReverseImageList(Image **images)
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% ShuffleImages() randomly shuffles the positions of the images in an image
-% list.
+% ShuffleImages() reorders the sequence of images in an image list based on
+% ascending, descending, or random criteria.
%
% The format of the ShuffleImages method is:
%
-% Image *ShuffleImages(Image **images,const ShuffleType shuffle_type,
+% Image *ShuffleImages(Image **images,const ShuffleStrategy strategy,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o images: the image list.
%
-% o shuffle_type: the shuffle type (Ascending, descending, random).
+% o strategy: the shuffle strategy (ascending, descending, random).
%
% o exception: return any errors or warnings in this structure.
%
*/
-MagickExport Image *ShuffleImages(Image **images,const ShuffleType shuffle_type,
+MagickExport Image *ShuffleImages(Image **images,const ShuffleStrategy strategy,
ExceptionInfo *exception)
{
Image
@@ -1369,50 +1369,115 @@ MagickExport Image *ShuffleImages(Image **images,const ShuffleType shuffle_type,
ssize_t
i;
- /*
- Ensure the image list is valid.
- */
- (void) shuffle_type;
assert(images != (Image **) NULL);
if (*images == (Image *) NULL)
return((Image *) NULL);
- if ((*images)->previous != (Image *) NULL)
- *images=GetFirstImageInList(*images);
- number_images=GetImageListLength(*images);
- if (number_images <= 1)
+ if ((*images)->next == (Image *) NULL)
return(*images);
- /*
- Convert the image list into a temporary array of image pointers.
- */
- image_array=ImageListToArray(*images,exception);
- if (image_array == (Image **) NULL)
+ number_images=GetImageListLength(*images);
+ if (number_images == 0)
return((Image *) NULL);
- /*
- Shuffle the array using the Fisher-Yates algorithm.
- */
- random_info=AcquireRandomInfo();
- for (i=(ssize_t) number_images-1; i > 0; i--)
+ image_array=(Image **) AcquireQuantumMemory(number_images,
+ sizeof(*image_array));
+ if (image_array == (Image **) NULL)
+ {
+ ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
+ "MemoryAllocationFailed","%s",exception->reason);
+ return((Image *) NULL);
+ }
{
- ssize_t
+ Image
+ *image;
+
+ register ssize_t
j;
- Image *temp = image_array[i];
- j=(ssize_t) (GetPseudoRandomValue(random_info)*(i+1));
- if (j > i)
- j=i;
- image_array[i]=image_array[j];
- image_array[j]=temp;
+ image=(*images);
+ for (j=0; j < (ssize_t) number_images; j++)
+ {
+ image_array[j]=image;
+ image=image->next;
+ }
+ }
+ switch (strategy)
+ {
+ case AscendingShuffle:
+ {
+ register ssize_t
+ j;
+
+ for (i=0; i < (ssize_t) (number_images-1); i++)
+ {
+ for (j=i+1; j < (ssize_t) number_images; j++)
+ {
+ if (LocaleCompare(image_array[j]->filename,image_array[i]->filename) < 0)
+ {
+ Image
+ *swap;
+
+ swap=image_array[i];
+ image_array[i]=image_array[j];
+ image_array[j]=swap;
+ }
+ }
+ }
+ break;
+ }
+ case DescendingShuffle:
+ {
+ register ssize_t
+ j;
+
+ for (i=0; i < (ssize_t) (number_images-1); i++)
+ {
+ for (j=i+1; j < (ssize_t) number_images; j++)
+ {
+ if (LocaleCompare(image_array[j]->filename,image_array[i]->filename) > 0)
+ {
+ Image
+ *swap;
+
+ swap=image_array[i];
+ image_array[i]=image_array[j];
+ image_array[j]=swap;
+ }
+ }
+ }
+ break;
+ }
+ case RandomShuffle:
+ {
+ random_info=AcquireRandomInfo();
+ for (i=(ssize_t) number_images-1; i > 0; i--)
+ {
+ ssize_t
+ j;
+
+ j=(ssize_t) (GetPseudoRandomValue(random_info)*(i+1));
+ if (j > i)
+ j=i;
+ {
+ Image
+ *swap;
+
+ swap=image_array[i];
+ image_array[i]=image_array[j];
+ image_array[j]=swap;
+ }
+ }
+ random_info=DestroyRandomInfo(random_info);
+ break;
+ }
+ case UndefinedShuffle:
+ default:
+ break;
}
- random_info=DestroyRandomInfo(random_info);
- /*
- Re-link the image list based on the shuffled order.
- */
*images=image_array[0];
(*images)->previous=(Image *) NULL;
for (i=0; i < (ssize_t) number_images; i++)
{
- image_array[i]->next=(i+1 < (ssize_t) number_images) ? image_array[i+1] :
- (Image *) NULL;
+ image_array[i]->next=(i < (ssize_t) number_images-1) ?
+ image_array[i+1] : (Image *) NULL;
image_array[i]->previous=(i > 0) ? image_array[i-1] : (Image *) NULL;
}
image_array=(Image **) RelinquishMagickMemory(image_array);
diff --git a/MagickCore/list.h b/MagickCore/list.h
index 8133f0b2e..5327cd50b 100644
--- a/MagickCore/list.h
+++ b/MagickCore/list.h
@@ -28,7 +28,7 @@ typedef enum
RandomShuffle,
AscendingShuffle,
DescendingShuffle
-} ShuffleType;
+} ShuffleStrategy;
extern MagickExport Image
*CloneImageList(const Image *,ExceptionInfo *),
@@ -45,7 +45,7 @@ extern MagickExport Image
*RemoveImageFromList(Image **),
*RemoveLastImageFromList(Image **),
*RemoveFirstImageFromList(Image **),
- *ShuffleImages(Image **,const ShuffleType,ExceptionInfo *),
+ *ShuffleImages(Image **,const ShuffleStrategy,ExceptionInfo *),
*SpliceImageIntoList(Image **,const size_t,const Image *),
*SplitImageList(Image *),
*SyncNextImageInList(const Image *);
diff --git a/MagickCore/option.c b/MagickCore/option.c
index 23cfa4ee0..ebf24a120 100644
--- a/MagickCore/option.c
+++ b/MagickCore/option.c
@@ -1128,7 +1128,7 @@ static const OptionInfo
{ "-shave", 1L, SimpleOperatorFlag, MagickFalse },
{ "+shear", 1L, DeprecateOptionFlag, MagickTrue },
{ "-shear", 1L, SimpleOperatorFlag, MagickFalse },
- { "+shuffle", 0L, DeprecateOptionFlag | FireOptionFlag, MagickTrue },
+ { "+shuffle", 1L, DeprecateOptionFlag | FireOptionFlag, MagickTrue },
{ "-shuffle", 1L, ListOperatorFlag | FireOptionFlag, MagickFalse },
{ "-sigmoidal-contrast", 1L, SimpleOperatorFlag, MagickFalse },
{ "+sigmoidal-contrast", 1L, SimpleOperatorFlag, MagickFalse },
diff --git a/MagickWand/magick-cli.c b/MagickWand/magick-cli.c
index 62ce1859a..146a05b54 100644
--- a/MagickWand/magick-cli.c
+++ b/MagickWand/magick-cli.c
@@ -1018,6 +1018,7 @@ static MagickBooleanType MagickCommandUsage(void)
" terms (coefficients and degree pairs).\n"
" -print string interpret string and print to console\n"
" -process arguments process the image with a custom image filter\n"
+ " -shuffle strategy reorders the sequence of images\n"
" -smush geometry smush an image sequence together\n"
" -write filename write images to this file",
settings[] =
diff --git a/MagickWand/mogrify.c b/MagickWand/mogrify.c
index 96ad00430..331a4d3fc 100644
--- a/MagickWand/mogrify.c
+++ b/MagickWand/mogrify.c
@@ -3580,6 +3580,7 @@ static MagickBooleanType MogrifyUsage(void)
" terms (coefficients and degree pairs).\n"
" -print string interpret string and print to console\n"
" -process arguments process the image with a custom image filter\n"
+ " -shuffle strategy reorders the sequence of images\n"
" -smush geometry smush an image sequence together\n"
" -write filename write images to this file",
settings[] =
@@ -6131,6 +6132,24 @@ WandExport MagickBooleanType MogrifyImageCommand(ImageInfo *image_info,
ThrowMogrifyInvalidArgumentException(option,argv[i]);
break;
}
+ if (LocaleCompare("shuffle",option+1) == 0)
+ {
+ ssize_t
+ strategy;
+
+ strategy=UndefinedShuffle;
+ if (*option == '+')
+ break;
+ i++;
+ if (i == (ssize_t) argc)
+ ThrowMogrifyException(OptionError,"MissingArgument",option);
+ strategy=ParseCommandOption(MagickShuffleOptions,MagickFalse,
+ argv[i]);
+ if (strategy < 0)
+ ThrowMogrifyException(OptionError,"UnrecognizedImageOrientation",
+ argv[i]);
+ break;
+ }
if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
{
i++;
@@ -8922,6 +8941,17 @@ WandExport MagickBooleanType MogrifyImageList(ImageInfo *image_info,
}
case 's':
{
+ if (LocaleCompare("shuffle",option+1) == 0)
+ {
+ ShuffleStrategy
+ shuffle_type;
+
+ (void) SyncImagesSettings(mogrify_info,*images,exception);
+ shuffle_type=(ShuffleStrategy) ParseCommandOption(
+ MagickShuffleOptions,MagickFalse,argv[i+1]);
+ (void) ShuffleImages(&(*images),shuffle_type,exception);
+ break;
+ }
if (LocaleCompare("smush",option+1) == 0)
{
Image
diff --git a/MagickWand/operation.c b/MagickWand/operation.c
index f5e9fb3d0..e251e0315 100644
--- a/MagickWand/operation.c
+++ b/MagickWand/operation.c
@@ -4287,20 +4287,6 @@ static MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
{
if (LocaleCompare("fft",option+1) == 0)
{
- new_images=ForwardFourierTransformImage(_images,IsNormalOp,
- _exception);
- break;
- }
- if (LocaleCompare("flatten",option+1) == 0)
- {
- /* REDIRECTED to use -layers flatten instead */
- (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
- break;
- }
- if (LocaleCompare("fx",option+1) == 0)
- {
- new_images=FxImage(_images,arg1,_exception);
- break;
}
CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
}
@@ -4691,6 +4677,15 @@ static MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
}
case 's':
{
+ if (LocaleCompare("shuffle",option+1) == 0)
+ {
+ parse=ParseCommandOption(MagickShuffleOptions,MagickFalse,arg1);
+ if ( parse < 0 )
+ CLIWandExceptArgBreak(OptionError,"UnrecognizedShuffleStrategy",
+ option,arg1);
+ (void) ShuffleImages(&_images,(ShuffleStrategy) parse,_exception);
+ break;
+ }
if (LocaleCompare("smush",option+1) == 0)
{
/* FUTURE: this option needs more work to make better */