Adding IPTC to JPEG file using markers and segments

Started by yosh, October 16, 2012, 09:03:26 AM

Previous topic - Next topic

yosh

Hello, for a while I've been working with metadata and now I'm trying to write my own code to add/edit IPTC (only) in JPEG files, without the use of ExifTool. I was hoping you could help me here or guide me in the right direction.

I'm currently able to display IPTC tags by finding their HEX markers in file (find App13, find each 0x1C02XX, read length). Knowing the IPTC tag place I'm also able to edit the field by expanding the App13 and IPTC segments by the size of data added to that field.

However, I find it difficult to add App13 to clean image, straight from camera. I have checked some sample images from multiple different cameras and noticed that JPEG headers differ a lot. Some have thumbnail, some don't. Some have EXIF information about the image and thumbnail and some don't. My question is - how does one find a place to insert the entire IPTC segment? I can't really look for 0xFFDB marker (image data) to insert IPTC in front of it, since many times I'm not able to tell if it's the start of main picture or thumbnail data in Exif.

The IPTC segment I'd like to insert would have formatting like:
FF ED SS SS Photoshop 3.0 00
8BIM 04 04 00 00 00 00 SS SS
1C 02 00
1C 02 XX SS SS ...
1C 02 YY SS SS ...


It's probably a big question, but even though there is some documentation about IPTC, I couldn't really find an answer for it. Thanks in advance for any help.

Phil Harvey

I suggest putting APP13 after all of the other APP segments (if they exist).  Otherwise, put it after the SOI (FF D8).

To do this you'll need to parse all of the JPEG segments up to the SOS (FF DA).  Read the JPEG/JFIF spec for more information.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

yosh

Thanks for fast reply, I will try that. I don't know how did I miss the SOS (FF DA) marker. I thought FF DB is the start of image data.

Not sure if it's only me, but all documents about JPEG/JFIF are some kind of nightmare to read, when all I need is correct way to edit IPTC :-)

Phil Harvey

Quote from: yosh on October 18, 2012, 05:46:58 AM
Not sure if it's only me, but all documents about JPEG/JFIF are some kind of nightmare to read, when all I need is correct way to edit IPTC :-)

Yes. The JPEG spec mostly ignores the application segments.

IPTC is straightforward unless you have to deal with special (non-ASCII) characters, then it becomes a nightmare.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

yosh

Well, I'm actually working with CP-1250 IPTC encoding... and I've already seen multiple IPTC blocks in 1 JPEG, IPTC at the end of the image, incomplete or broken segments - it's when you get images from hundreds of photographers around the World, edited with many different applications.

I've encountered a simple problem with image that already has metadata. I have found FFDA as a part of thumbnail in Exif. So the 1st SOS maker I found, wasn't really SOS after all. I know I've asked about adding metadata to "clean" image, but I hoped there might be some universal solution like "IPTC is supposed to be between marker X and Y in every kind of JPEG image, and those X and Y are unique in a file". It's so frustrating, you must be extremely patient ;)

Am I supposed to track every single FFE0, FFE1 etc. marker and one by one count their lengths to omit the data that they might contain and look for FFDA outside the range of these markers?

Phil Harvey

Quote from: yosh on October 19, 2012, 07:05:55 AM
Well, I'm actually working with CP-1250 IPTC encoding... and I've already seen multiple IPTC blocks in 1 JPEG, IPTC at the end of the image, incomplete or broken segments - it's when you get images from hundreds of photographers around the World, edited with many different applications.

If you're dealing with images from many sources you will have more work to do.  IPTC may be located in many non-standard places, and it sounds like you will have to deal with these too.

QuoteAm I supposed to track every single FFE0, FFE1 etc. marker and one by one count their lengths to omit the data that they might contain and look for FFDA outside the range of these markers?

Absolutely.  The segments (not just application segments, but other segments too) may contain arbitrary data, so they must be parsed properly by determining their length and skipping over the arbitrary data.  This is more of a pain for IPTC in a trailer (ie. after the JPEG EOI) because then you must parse through the entire JPEG image data.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

yosh

I guess for now I'll concentrate on images that have IPTC in front of the image data.

From your experience, in case of "healthy" images, do you think it's safe to just check 3rd and 4th byte (should be either FFE0 or FFE1), follow the length, check what is the next marker and then do it again for next markers? Searching this way for APP13 or stopping when SOS is found. Or are there any specific markers I should scan the image data for that might shorten the process?

Thanks again :) It's unfortunate that you confirm my worst assumptions, but I guess I can't escape it then...

Phil Harvey

#7
You should definitely parse the JPEG properly.  It isn't too hard, but there are a few peculiarities:

1) Scan for the first 0xff byte

2) Skip over any extra 0xff bytes to the first non-0xff byte

3) Determine the length of this segment.  The length depends on the segment type from step 2:

    0xd8 - Start Of Image (segment length is 0)
    0xc0-0xc3,0xc5-0xc7,0xc9-0xcb,0xcd-0xcf: Start Of Frame (segment length is 7)
    0x00, 0x01, 0xd0-0xd7: stand alone markers (segment length is 0)
    0xda: Start Of Scan (length 0) there shouldn't be any application segments after this
    0xd9: End Of Image (length 0) anything after this is the JPEG trailer, not part of the spec
    For everything else the next 2 bytes give the length of data in this segment (including the 2-byte length word).  The things you are interested in are:
    0xe0-0xef: APPlication segments
    0xfe: COMment

4) Read the segment data.

For application segments, you must parse the data at the start of the segment to determine the type of information it contains.  (Just because it is APP13, doesn't mean it is always the Photoshop segment.)

5) Go to step 1.  Repeat.

- Phil

Edit: The SOF segments also contain a length word
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

yosh

Back from holidays, back to work :) I'll definitely try to rewrite my "parser" according to your guidelines. I didn't really know about all these segments. Till now I've been using a different approach - looking for 0xFFED marker that has 8BIM 0x0404 ITPC Tags segment. That gave me access to both length markers (APP13 length and IPTCTags length).

Ad 4. You're saying it's possible that there are multiple correct APP13 markers? I thought there's only one 0xFFED, but can contain multiple 8BIMs - even two 0x0404 segments in case some metadata exceeds it's max length. So I should check if APP13 length marker is followed by "Photoshop 3.0" and if yes, then find the segment with 0x0404 marker.. and here are my IPTC records.

Thanks again for very practical information!

Phil Harvey

Some information may span multiple APP segments, but they all must begin with an identifying signature.  See this table for a list of segments -- the multi-segment types are noted in the descriptions.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

yosh

Quote0xd8 - Start Of Image (segment length is 0)
    0xc0-0xc3,0xc5-0xc7,0xc9-0xcb,0xcd-0xcf: Start Of Frame (segment length is 7)
    0x00, 0x01, 0xd0-0xd7: stand alone markers (segment length is 0)
    0xda: Start Of Scan (length 0) there shouldn't be any application segments after this
    0xd9: End Of Image (length 0) anything after this is the JPEG trailer, not part of the spec
    For everything else the next 2 bytes give the length of data in this segment (including the 2-byte length word).  The things you are interested in are:
    0xe0-0xef: APPlication segments
    0xfe: COMment

I thought the length means that it's a constant-length segment, but markers like FFC0, FFC4 are followed by 2 length bytes (FFC0 always seems to have length of 0x11). Overall algorithm seems really good, but can you explain what did you mean by segment lengths here?

Quote from: Canon camera image sample...
FF C0 00 11 08 00 08 00 08 03 01 22 00 02 11 01 03 11 01
FF C4 00 4B 00 01 01 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 06 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 10 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 11 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 FF DA ...

Phil Harvey

#11
Interesting.  You're right.  I am just skipping 7 bytes of the SOF segments, then scanning for the next 0xff, but it does look like they contain a length word too.  Perhaps I should re-read the specification.

- Phil

Edit: I read the spec and yes, the SOF segments do contain a length word.
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

yosh

It works perfectly, thank you. I got IPTC and I skipped all other segments. You don't mind if I ask some more questions?

How would you advise to edit/insert data? I think that editing each IPTC field, one by one, might be a bit too slow and wondered if it would be better to cut out the entire 0x0404 IPTCData segment, execute changes and then insert it again with new lengths and additional fields, also changing the sizes (length words) of both 0x0404 and APP13 segments.

Do you think it's safe to remove all Photoshop Tags from APP13 and insert only the 0x0404 IPTCData segment. Image properties and XMP data should be in EXIF anyway. What I'm aiming at is to avoid parsing other Photoshop segments than 0x0404 and make it just a little faster. Else I have to parse each 8BIM\x#### marker, right?

Phil Harvey

I can't answer the question about whether it is OK to throw out the rest of the Photoshop IRB information.  This depends entirely on your requirements.

Also, I don't know what you mean about editing each IPTC field one by one.  If you want to keep any existing IPTC you would need to read the existing IPTC first.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

yosh

Ah, I meant what kind of workflow would be optimal for editing IPTC. Should I only overwrite edited IPTC fields or read the entire IPTCData to array/map and then substitute the whole segment in file. I guess I have to take the 2nd option to make less operations on file.

About Photoshop IRB I only wondered if the information is duplicated in EXIF or JFIF segments or is there anything very specific that might damage or decrease the informational value of file if deleted.