1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
//--------------------------------------------------------------------------
// Process IPTC data and XMP data.
//--------------------------------------------------------------------------
#include "jhead.h"
// IPTC entry types known to Jhead (there's many more defined)
#define IPTC_RECORD_VERSION 0x00
#define IPTC_SUPLEMENTAL_CATEGORIES 0x14
#define IPTC_KEYWORDS 0x19
#define IPTC_CAPTION 0x78
#define IPTC_AUTHOR 0x7A
#define IPTC_HEADLINE 0x69
#define IPTC_SPECIAL_INSTRUCTIONS 0x28
#define IPTC_CATEGORY 0x0F
#define IPTC_BYLINE 0x50
#define IPTC_BYLINE_TITLE 0x55
#define IPTC_CREDIT 0x6E
#define IPTC_SOURCE 0x73
#define IPTC_COPYRIGHT_NOTICE 0x74
#define IPTC_OBJECT_NAME 0x05
#define IPTC_CITY 0x5A
#define IPTC_STATE 0x5F
#define IPTC_COUNTRY 0x65
#define IPTC_TRANSMISSION_REFERENCE 0x67
#define IPTC_DATE 0x37
#define IPTC_COPYRIGHT 0x0A
#define IPTC_COUNTRY_CODE 0x64
#define IPTC_REFERENCE_SERVICE 0x2D
#define IPTC_TIME_CREATED 0x3C
#define IPTC_SUB_LOCATION 0x5C
#define IPTC_IMAGE_TYPE 0x82
//--------------------------------------------------------------------------
// Process and display IPTC marker.
//
// IPTC block consists of:
// - Marker: 1 byte (0xED)
// - Block length: 2 bytes
// - IPTC Signature: 14 bytes ("Photoshop 3.0\0")
// - 8BIM Signature 4 bytes ("8BIM")
// - IPTC Block start 2 bytes (0x04, 0x04)
// - IPTC Header length 1 byte
// - IPTC header Header is padded to even length, counting the length byte
// - Length 4 bytes
// - IPTC Data which consists of a number of entries, each of which has the following format:
// - Signature 2 bytes (0x1C02)
// - Entry type 1 byte (for defined entry types, see #defines above)
// - entry length 2 bytes
// - entry data 'entry length' bytes
//
//--------------------------------------------------------------------------
void show_IPTC (unsigned char* Data, unsigned int itemlen)
{
const char IptcSig1[] = "Photoshop 3.0";
const char IptcSig2[] = "8BIM";
const char IptcSig3[] = {0x04, 0x04};
unsigned char * pos = Data + sizeof(short); // position data pointer after length field
unsigned char * maxpos = Data+itemlen;
unsigned char headerLen = 0;
unsigned char dataLen = 0;
if (itemlen < 25) goto corrupt;
// Check IPTC signatures
if (memcmp(pos, IptcSig1, sizeof(IptcSig1)-1) != 0) goto badsig;
pos += sizeof(IptcSig1); // move data pointer to the next field
if (memcmp(pos, IptcSig2, sizeof(IptcSig2)-1) != 0) goto badsig;
pos += sizeof(IptcSig2)-1; // move data pointer to the next field
while (memcmp(pos, IptcSig3, sizeof(IptcSig3)) != 0) { // loop on valid Photoshop blocks
pos += sizeof(IptcSig3); // move data pointer to the Header Length
// Skip header
headerLen = *pos; // get header length and move data pointer to the next field
pos += (headerLen & 0xfe) + 2; // move data pointer to the next field (Header is padded to even length, counting the length byte)
if (pos+16 > maxpos) goto corrupt;
pos += 3; // move data pointer to length, assume only one byte, TODO: use all 4 bytes
dataLen = *pos++;
pos += dataLen; // skip data section
if (pos+16 > maxpos) goto corrupt;
if (memcmp(pos, IptcSig2, sizeof(IptcSig2) - 1) != 0) {
badsig: if (ShowTags) {
ErrNonfatal("IPTC type signature mismatch\n", 0, 0);
}
return;
}
pos += sizeof(IptcSig2) - 1; // move data pointer to the next field
}
pos += sizeof(IptcSig3); // move data pointer to the next field
if (pos+16 >= maxpos) goto corrupt;
// IPTC section found
// Skip header
headerLen = *pos++; // get header length and move data pointer to the next field
pos += headerLen + 1 - (headerLen % 2); // move data pointer to the next field (Header is padded to even length, counting the length byte)
if (pos+8 >= maxpos) goto corrupt;
// Get length (from motorola format)
//length = (*pos << 24) | (*(pos+1) << 16) | (*(pos+2) << 8) | *(pos+3);
pos += 4; // move data pointer to the next field
printf("======= IPTC data: =======\n");
// Now read IPTC data
while (pos+5 < maxpos) {
short signature;
unsigned char type = 0;
short length = 0;
const char * description = NULL;
if (pos+5 > maxpos) goto corrupt;
signature = (*pos << 8) + (*(pos+1));
pos += 2;
if (signature != 0x1C01 && signature != 0x1c02) break;
type = *pos++;
length = (*pos << 8) + (*(pos+1));
if (length < 1) goto corrupt;
pos += 2; // Skip tag length
if (pos+length > maxpos) goto corrupt;
// Process tag here
switch (type) {
case IPTC_RECORD_VERSION:
printf("Record vers. : %d\n", (*pos << 8) + (*(pos+1)));
break;
case IPTC_SUPLEMENTAL_CATEGORIES: description = "SuplementalCategories"; break;
case IPTC_KEYWORDS: description = "Keywords"; break;
case IPTC_CAPTION: description = "Caption"; break;
case IPTC_AUTHOR: description = "Author"; break;
case IPTC_HEADLINE: description = "Headline"; break;
case IPTC_SPECIAL_INSTRUCTIONS: description = "Spec. Instr."; break;
case IPTC_CATEGORY: description = "Category"; break;
case IPTC_BYLINE: description = "Byline"; break;
case IPTC_BYLINE_TITLE: description = "Byline Title"; break;
case IPTC_CREDIT: description = "Credit"; break;
case IPTC_SOURCE: description = "Source"; break;
case IPTC_COPYRIGHT_NOTICE: description = "(C)Notice"; break;
case IPTC_OBJECT_NAME: description = "Object Name"; break;
case IPTC_CITY: description = "City"; break;
case IPTC_STATE: description = "State"; break;
case IPTC_COUNTRY: description = "Country"; break;
case IPTC_TRANSMISSION_REFERENCE: description = "OriginalTransmissionReference"; break;
case IPTC_DATE: description = "DateCreated"; break;
case IPTC_COPYRIGHT: description = "(C)Flag"; break;
case IPTC_REFERENCE_SERVICE: description = "Country Code"; break;
case IPTC_COUNTRY_CODE: description = "Ref. Service"; break;
case IPTC_TIME_CREATED: description = "Time Created"; break;
case IPTC_SUB_LOCATION: description = "Sub Location"; break;
case IPTC_IMAGE_TYPE: description = "Image type"; break;
default:
if (ShowTags){
printf("Unrecognised IPTC tag: %d\n", type );
}
break;
}
if (description != NULL) {
char TempBuf[32];
memset(TempBuf, 0, sizeof(TempBuf));
memset(TempBuf, ' ', 14);
memcpy(TempBuf, description, strlen(description));
strcat(TempBuf, ":");
printf("%s %*.*s\n", TempBuf, length, length, pos);
}
pos += length;
}
return;
corrupt:
ErrNonfatal("Pointer corruption in IPTC\n",0,0);
}
//--------------------------------------------------------------------------
// Dump contents of XMP section
//--------------------------------------------------------------------------
void ShowXmp(Section_t XmpSection)
{
unsigned char * Data;
char OutLine[101];
int OutLineChars;
int NonBlank;
unsigned a;
NonBlank = 0;
Data = XmpSection.Data;
OutLineChars = 0;
for (a=0;a<XmpSection.Size;a++){
if (Data[a] >= 32 && Data[a] < 128){
OutLine[OutLineChars++] = Data[a];
if (Data[a] != ' ') NonBlank |= 1;
}else{
if (Data[a] != '\n'){
OutLine[OutLineChars++] = '?';
}
}
if (Data[a] == '\n' || OutLineChars >= 100){
OutLine[OutLineChars] = 0;
if (NonBlank){
puts(OutLine);
}
NonBlank = (NonBlank & 1) << 1;
OutLineChars = 0;
}
}
}
|