Page 1 of 1

Profile Tag Broken

Posted: 2012-06-26T12:07:20-07:00
by docjones2
Hello,

For a project I am extensively using MSL to alter images on the fly in a web based environment. It is desirable to be able to optimize the file size of an image as losslessly as possible, something like `convert file -strip file` or `convert file +profile "*" file` from within MSL.

MSL does not have a "strip" tag, however it does have a "profile" tag which is broken as far removing profiles is concerned.

Code: Select all

              /*
              From msl.c, line 4314
              */

              keyword=(const char *) attributes[i++];
              attribute=InterpretImageProperties(msl_info->image_info[n],
                msl_info->attributes[n],(const char *) attributes[i]);
              CloneString(&value,attribute);
              if (*keyword == '+')
                {
                  /*
                    Remove a profile from the image.
                  */
                  (void) ProfileImage(msl_info->image[n],keyword,
                    (const unsigned char *) NULL,0,MagickTrue);
                  continue;
                }
This iterates over the attributes of a given <profile/> tag and looks for one with '+' as the first character and then removes it. So for this to work, a tag could look like:

Code: Select all

<profile +remove="arbitrary" />
However this is impossible because it is malformed XML. Because of this, it is impossible to remove profiles in MSL at this time.

possible solutions:
  • Have an add_profile and a remove_profile tag which work like <add_profile profile="whatever" /> and <remove_profile profile="*" />
  • Retool the profile tag to work like <profile some_profile="-" some_other="+" ... /> where "+" and "-" represent add or remove and a special attribute "all" exists which is equivalent to "*"
  • Have attributes "add" and "remove" which accept comma-separated profiles to add or remove like <profile add="a,b,c" /> and <profile remove="*" />
  • Leave profile adding functionality as is and implement a "remove" attribute which removes a given profile or comma-separated list of profiles
The last possible solution I listed is the simplest to implement and maintains backwards compatibility, so I went ahead and fixed it (without support for csv input)

Code: Select all

              /*
              msl.c, line 4314
              */

              keyword=(const char *) attributes[i++];
              attribute=InterpretImageProperties(msl_info->image_info[n],
                msl_info->attributes[n],(const char *) attributes[i]);
              CloneString(&value,attribute);
 
              if (LocaleCompare(keyword, "remove") == 0)
                {
                  /*
                    Remove a profile from the image.
                  */
                  (void) ProfileImage(msl_info->image[n],attribute,
                    (const unsigned char *) NULL,0,MagickTrue);
                  continue;
                }
The code has been tested and the following MSL works as expected under this patch

Code: Select all

<profile remove="*" />
Whatever solution is decided upon for profile, it would also be nice to have a simple "strip" tag, like <strip />, which does what the command line argument does. This would be convenient for my use case -- and others surely -- and would provide the functionality to remove profiles in the mean time that the profile tag is not fixed to handle removals.

Please consider using my patch or implementing a way to remove profiles in MSL.

Thank you.

Re: Profile Tag Broken

Posted: 2012-06-26T17:56:25-07:00
by magick
We'll add a patch to support profile remove in the next point release of ImageMagick. To remove a specified profile use "!" as the filename eg.:

<profile icm="!" iptc="profile.iptc" />

We'll also add a strip tag.