Clipping paths in JPG files are truncated

Post any defects you find in the released or beta versions of the ImageMagick software here. Include the ImageMagick version, OS, and any command-line required to reproduce the problem. Got a patch for a bug? Post it here.
Post Reply
jn0101
Posts: 40
Joined: 2007-06-16T01:36:07-07:00

Clipping paths in JPG files are truncated

Post by jn0101 »

It seems long clipping path in JPG files are truncated when read from ImageMagick.

Please look at this image, saved from PhotoShop as JPG and TIFF:
http://javabog.dk/filer/5827_original.jpg and http://javabog.dk/filer/5827_original.tif

If I do
identify -verbose 5827_original.tif
I get a clipping path of 1857 lines.

However, if I do
identify -verbose 5827_original.jpg
I get a clipping path of only the first 1008 lines. The rest of the SVG data is gone.


I have tried with ImageMagick 6.2.6, 6.3.2 and 6.3.4 on Linux and
with ImageMagick 6.3.4 on Windows. The result is always the same.


This is a boildown of a very big problem I am having with clipping paths, so
I on beforehand would like to thank you very much for looking on this!

Jacob Nordfalk
jn0101
Posts: 40
Joined: 2007-06-16T01:36:07-07:00

Re: Clipping paths in JPG files are truncated

Post by jn0101 »

It seems that PhotoShop inserts the text 'Photoshop 3.0' in the middle of the binary clipping path-data of JPG-files!!

If I change magick/property.c and just before line
path=TraceSVGClippath((unsigned char *) attribute,(size_t) count,
image->columns,image->rows);

insert

char* pspos = NULL;
for (i = 0; i<count-14; i++) {
if (
attribute[i+0]=='P' &&
attribute[i+1]=='h' &&
attribute[i+2]=='o' &&
attribute[i+3]=='t' &&
attribute[i+4]=='o' &&
attribute[i+5]=='s' &&
attribute[i+6]=='h' &&
attribute[i+7]=='o' &&
attribute[i+8]=='p')
{
pspos = (char *) (attribute + i) ;
break;
}
}

if (pspos != NULL) {
printf ("\n\n") ;
printf ("XXX Photoshop 3.0=%u\n\n",(int)(pspos-attribute)) ;
printf ("XXX memmove(%u, %u, %u)\n\n",(int)pspos, (int)pspos+14, (int)((size_t) count-(pspos-attribute)-14));
memmove(pspos, pspos+14, (size_t) count-(pspos-attribute)-14);
memset(attribute+count-14,0,14);


(sorry for the puny C code - its been a long time since my last C program)
then the Clippath becomes correct, apart from the last line, which gets scrambled (becaurse of the duplicated 14 bytes in the end).
I have tried to decrease count by 14, but that makes IM crash.




Could anybody please comment on this?

Jacob
jn0101
Posts: 40
Joined: 2007-06-16T01:36:07-07:00

Patch - Please comment!!

Post by jn0101 »

I have managed to make ImageMagick parse JPG files correct by changing a line in coders/jpeg.c line 453.

Here is my perception of the problem. Please comment!!


The problem is that IM does only remove the 'Photoshop 3.0' string from the first IPTC segment.
The string is not removed from the subsequent segments, and thus some IPTC data are scrambled.

As all IPTC often can be fitted into just one segment (Photoshop makes them 32000 bytes large), this error seldom appears. The only way I have seen it is when there is a big clipping path.




static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
{
...
length=(size_t) ((unsigned long) GetCharacter(jpeg_info) << 8);
length+=(size_t) GetCharacter(jpeg_info);
if (length <= 2)
return(MagickTrue);
length-=2;
tag_length=0;
iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");

/////// THE FOLLOWING IF-STATEMENT SHOULD BE REMOVED //////
// NOT ONLY FIRST (where iptc_profile==NULL)
// BUT ALSO SUBSEQUENT (where iptc_profile!=NULL)
// SEGMENTS SHOULD HAVE THE 'Photoshop 3.0' REMOVED

if (iptc_profile == (StringInfo *) NULL)
{
/*
Validate that this was written as a Photoshop resource format slug.
*/
for (i=0; i < 10; i++)
magick=(char) GetCharacter(jpeg_info);
magick[10]='\0';
if (length <= 10)
return(MagickTrue);
length-=10;
if (LocaleCompare(magick,"Photoshop ") != 0)
{
/*
Not a IPTC profile, return.
*/
for (i=0; i < (long) length; i++)
(void) GetCharacter(jpeg_info);
return(MagickTrue);
}
/*
Remove the version number.
*/
for (i=0; i < 4; i++)
(void) GetCharacter(jpeg_info);
if (length <= 4)
return(MagickTrue);
length-=4;
tag_length=0;
}

profile=AcquireStringInfo(length);
p=GetStringInfoDatum(profile);
for (i=(long) GetStringInfoLength(profile)-1; i >= 0; i--)
*p++=(unsigned char) GetCharacter(jpeg_info);

iptc_profile=(StringInfo *) GetImageProfile(image,"8bim");
if (iptc_profile != (StringInfo *) NULL)
{
ConcatenateStringInfo(iptc_profile,profile);
profile=DestroyStringInfo(profile);
}
else
{
status=SetImageProfile(image,"8bim",profile);
profile=DestroyStringInfo(profile);
}




Im in doubt whether some subsequent IPTC segments does not begin
with the 'Photoshop 3.0' string. In this case they would be ignored if you implement my patch.

I dont know what to do, Im not an expert on this.

Could someone that knows a little about JPEG please comment??

Could this please be patched in the next version of ImageMagick?

Jacob
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Clipping paths in JPG files are truncated

Post by magick »

We have a patch in ImageMagick 6.3.4-10 Beta to fix the problem you reported. The patch will be available sometime tomorrow.
jn0101
Posts: 40
Joined: 2007-06-16T01:36:07-07:00

Re: Clipping paths in JPG files are truncated

Post by jn0101 »

Thank you very much, you are quick!

Im awaiting eagerly for
https://www.imagemagick.org/subversion/ ... ers/jpeg.c
to update.

When would a Windows binary be available?

I need to test this on Windows within a couple of days, but I dont have the tools and have never made a Windows binary.

The questions is whether I should install the tools and give it a try, or I can rely on you to make a Windows beta binary ?

Jacob
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Clipping paths in JPG files are truncated

Post by magick »

Your patch did make it in the ImageMagick 6.3.4-10 source release uploading now but it did not make it in the Windows binaries which were built two days ago. We will update the Windows binaries in a few days.
jn0101
Posts: 40
Joined: 2007-06-16T01:36:07-07:00

Re: Clipping paths in JPG files are truncated

Post by jn0101 »

Thank you
jn0101
Posts: 40
Joined: 2007-06-16T01:36:07-07:00

Re: Clipping paths in JPG files are truncated

Post by jn0101 »

Taking a closer look at coders/jpeg.c, it seems IM will only put the Photoshop 3.0
text in the start of the first block of the IPTC profile:


static void WriteProfile(j_compress_ptr jpeg_info,Image *image)
{
...
if (LocaleCompare(name,"IPTC") == 0)
{
unsigned long
roundup;

tag_length=26;
(void) CopyMagickMemory(custom_profile->datum,
"Photoshop 3.0 8BIM\04\04\0\0\0\0",24);
custom_profile->datum[13]=0x00;
custom_profile->datum[24]=profile->length >> 8;
custom_profile->datum[25]=profile->length & 0xff;
for (i=0; i < (long) profile->length; i+=65500L)
{
length=Min(profile->length-i,65500L);
roundup=(unsigned long) (length & 0x01);
(void) CopyMagickMemory(custom_profile->datum+tag_length,
profile->datum+i,length);
if (roundup != 0)
custom_profile->datum[length+tag_length]='\0';
jpeg_write_marker(jpeg_info,IPTC_MARKER,custom_profile->datum,
(unsigned int) (length+tag_length+roundup));
}
}


Therefore, if IM assumes this Photoshop 3.0 text is in every block, it
will fail to load its own files!



What do you think? (I havent tested this)

Jacob
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Clipping paths in JPG files are truncated

Post by magick »

ImageMagick 6.3.4-10, the current release appears to have the correct logic:

Code: Select all

       p=GetStringInfoDatum(custom_profile);
        if (LocaleNCompare((char *) GetStringInfoDatum(profile),"8BIM",4) == 0)
          {
            (void) CopyMagickMemory(p,"Photoshop 3.0\0",14);
            tag_length=14;
          }
        else
          {
            (void) CopyMagickMemory(p,"Photoshop 3.0\08BIM\04\04\0\0\0\0",24);
            p[13]=0x00;
            p[24]=(unsigned char) (GetStringInfoLength(profile) >> 8);
            p[25]=(unsigned char) (GetStringInfoLength(profile) & 0xff);
            tag_length=26;
          }
        for (i=0; i < (long) GetStringInfoLength(profile); i+=65500L)
Post Reply