Changeset 8132 in josm for trunk/src/com/drew/metadata/iptc
- Timestamp:
- 2015-03-10T01:17:39+01:00 (10 years ago)
- Location:
- trunk/src/com/drew/metadata/iptc
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/com/drew/metadata/iptc/IptcDescriptor.java
r6127 r8132 1 1 /* 2 * Copyright 2002-201 2Drew Noakes2 * Copyright 2002-2015 Drew Noakes 3 3 * 4 4 * Licensed under the Apache License, Version 2.0 (the "License"); … … 16 16 * More information about this project is available at: 17 17 * 18 * http ://drewnoakes.com/code/exif/19 * http ://code.google.com/p/metadata-extractor/18 * https://drewnoakes.com/code/exif/ 19 * https://github.com/drewnoakes/metadata-extractor 20 20 */ 21 21 package com.drew.metadata.iptc; … … 27 27 28 28 /** 29 * Provides human-readable string representations of tag values stored in a <code>IptcDirectory</code>.30 * <p />29 * Provides human-readable string representations of tag values stored in a {@link IptcDirectory}. 30 * <p> 31 31 * As the IPTC directory already stores values as strings, this class simply returns the tag's value. 32 32 * 33 * @author Drew Noakes http ://drewnoakes.com33 * @author Drew Noakes https://drewnoakes.com 34 34 */ 35 35 public class IptcDescriptor extends TagDescriptor<IptcDirectory> … … 40 40 } 41 41 42 @Override 42 43 @Nullable 43 44 public String getDescription(int tagType) -
trunk/src/com/drew/metadata/iptc/IptcDirectory.java
r6127 r8132 1 1 /* 2 * Copyright 2002-201 2Drew Noakes2 * Copyright 2002-2015 Drew Noakes 3 3 * 4 4 * Licensed under the Apache License, Version 2.0 (the "License"); … … 16 16 * More information about this project is available at: 17 17 * 18 * http ://drewnoakes.com/code/exif/19 * http ://code.google.com/p/metadata-extractor/18 * https://drewnoakes.com/code/exif/ 19 * https://github.com/drewnoakes/metadata-extractor 20 20 */ 21 21 package com.drew.metadata.iptc; … … 32 32 * Describes tags used by the International Press Telecommunications Council (IPTC) metadata format. 33 33 * 34 * @author Drew Noakes http ://drewnoakes.com34 * @author Drew Noakes https://drewnoakes.com 35 35 */ 36 36 public class IptcDirectory extends Directory … … 211 211 } 212 212 213 @Override 213 214 @NotNull 214 215 public String getName() 215 216 { 216 return "Iptc"; 217 } 218 217 return "IPTC"; 218 } 219 220 @Override 219 221 @NotNull 220 222 protected HashMap<Integer, String> getTagNameMap() -
trunk/src/com/drew/metadata/iptc/IptcReader.java
r6127 r8132 1 1 /* 2 * Copyright 2002-201 2Drew Noakes2 * Copyright 2002-2015 Drew Noakes 3 3 * 4 4 * Licensed under the Apache License, Version 2.0 (the "License"); … … 16 16 * More information about this project is available at: 17 17 * 18 * http ://drewnoakes.com/code/exif/19 * http ://code.google.com/p/metadata-extractor/18 * https://drewnoakes.com/code/exif/ 19 * https://github.com/drewnoakes/metadata-extractor 20 20 */ 21 21 package com.drew.metadata.iptc; 22 22 23 import com.drew.lang.BufferBoundsException; 24 import com.drew.lang.BufferReader; 23 import com.drew.imaging.jpeg.JpegSegmentMetadataReader; 24 import com.drew.imaging.jpeg.JpegSegmentType; 25 import com.drew.lang.SequentialByteArrayReader; 26 import com.drew.lang.SequentialReader; 25 27 import com.drew.lang.annotations.NotNull; 26 28 import com.drew.metadata.Directory; 27 29 import com.drew.metadata.Metadata; 28 import com.drew.metadata.MetadataReader; 29 30 31 import java.io.IOException; 32 import java.util.Arrays; 30 33 import java.util.Date; 31 34 32 35 /** 33 * Decodes IPTC binary data, populating a <code>Metadata</code> object with tag values in an <code>IptcDirectory</code>. 34 * 35 * @author Drew Noakes http://drewnoakes.com 36 * Decodes IPTC binary data, populating a {@link Metadata} object with tag values in an {@link IptcDirectory}. 37 * <p> 38 * http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf 39 * 40 * @author Drew Noakes https://drewnoakes.com 36 41 */ 37 public class IptcReader implements MetadataReader42 public class IptcReader implements JpegSegmentMetadataReader 38 43 { 39 44 // TODO consider breaking the IPTC section up into multiple directories and providing segregation of each IPTC directory … … 52 57 */ 53 58 54 /** Performs the IPTC data extraction, adding found values to the specified instance of <code>Metadata</code>. */ 55 public void extract(@NotNull final BufferReader reader, @NotNull final Metadata metadata) 59 @NotNull 60 public Iterable<JpegSegmentType> getSegmentTypes() 61 { 62 return Arrays.asList(JpegSegmentType.APPD); 63 } 64 65 public boolean canProcess(@NotNull byte[] segmentBytes, @NotNull JpegSegmentType segmentType) 66 { 67 // Check whether the first byte resembles 68 return segmentBytes.length != 0 && segmentBytes[0] == 0x1c; 69 } 70 71 public void extract(@NotNull byte[] segmentBytes, @NotNull Metadata metadata, @NotNull JpegSegmentType segmentType) 72 { 73 extract(new SequentialByteArrayReader(segmentBytes), metadata, segmentBytes.length); 74 } 75 76 /** 77 * Performs the IPTC data extraction, adding found values to the specified instance of {@link Metadata}. 78 */ 79 public void extract(@NotNull final SequentialReader reader, @NotNull final Metadata metadata, long length) 56 80 { 57 81 IptcDirectory directory = metadata.getOrCreateDirectory(IptcDirectory.class); … … 59 83 int offset = 0; 60 84 61 /*62 // find start-of-segment marker (potentially need to skip some ASCII photoshop header info)63 try {64 while (offset < data.length - 1 && reader.getUInt16(offset) != 0x1c01 && reader.getUInt16(offset) != 0x1c02)65 offset++;66 } catch (BufferBoundsException e) {67 directory.addError("Couldn't find start of IPTC data (invalid segment)");68 return;69 }70 */71 72 85 // for each tag 73 while (offset < reader.getLength()) {86 while (offset < length) { 74 87 75 88 // identifies start of a tag 76 89 short startByte; 77 90 try { 78 startByte = reader.getUInt8(offset); 79 } catch (BufferBoundsException e) { 91 startByte = reader.getUInt8(); 92 offset++; 93 } catch (IOException e) { 80 94 directory.addError("Unable to read starting byte of IPTC tag"); 81 break;95 return; 82 96 } 83 97 84 98 if (startByte != 0x1c) { 85 directory.addError("Invalid start to IPTC tag"); 86 break; 99 // NOTE have seen images where there was one extra byte at the end, giving 100 // offset==length at this point, which is not worth logging as an error. 101 if (offset != length) 102 directory.addError("Invalid IPTC tag marker at offset " + (offset - 1) + ". Expected '0x1c' but got '0x" + Integer.toHexString(startByte) + "'."); 103 return; 87 104 } 88 105 89 106 // we need at least five bytes left to read a tag 90 if (offset + 5 >= reader.getLength()) {107 if (offset + 5 >= length) { 91 108 directory.addError("Too few bytes remain for a valid IPTC tag"); 92 break; 93 } 94 95 offset++; 109 return; 110 } 96 111 97 112 int directoryType; … … 99 114 int tagByteCount; 100 115 try { 101 directoryType = reader.getUInt8(offset++); 102 tagType = reader.getUInt8(offset++); 103 tagByteCount = reader.getUInt16(offset); 104 offset += 2; 105 } catch (BufferBoundsException e) { 116 directoryType = reader.getUInt8(); 117 tagType = reader.getUInt8(); 118 // TODO support Extended DataSet Tag (see 1.5(c), p14, IPTC-IIMV4.2.pdf) 119 tagByteCount = reader.getUInt16(); 120 offset += 4; 121 } catch (IOException e) { 106 122 directory.addError("IPTC data segment ended mid-way through tag descriptor"); 107 123 return; 108 124 } 109 125 110 if (offset + tagByteCount > reader.getLength()) {126 if (offset + tagByteCount > length) { 111 127 directory.addError("Data for tag extends beyond end of IPTC segment"); 128 return; 129 } 130 131 try { 132 processTag(reader, directory, directoryType, tagType, tagByteCount); 133 } catch (IOException e) { 134 directory.addError("Error processing IPTC tag"); 135 return; 136 } 137 138 offset += tagByteCount; 139 } 140 } 141 142 private void processTag(@NotNull SequentialReader reader, @NotNull Directory directory, int directoryType, int tagType, int tagByteCount) throws IOException 143 { 144 int tagIdentifier = tagType | (directoryType << 8); 145 146 // Some images have been seen that specify a zero byte tag, which cannot be of much use. 147 // We elect here to completely ignore the tag. The IPTC specification doesn't mention 148 // anything about the interpretation of this situation. 149 // https://raw.githubusercontent.com/wiki/drewnoakes/metadata-extractor/docs/IPTC-IIMV4.2.pdf 150 if (tagByteCount == 0) { 151 directory.setString(tagIdentifier, ""); 152 return; 153 } 154 155 String string = null; 156 157 switch (tagIdentifier) { 158 case IptcDirectory.TAG_CODED_CHARACTER_SET: 159 byte[] bytes = reader.getBytes(tagByteCount); 160 String charset = Iso2022Converter.convertISO2022CharsetToJavaCharset(bytes); 161 if (charset == null) { 162 // Unable to determine the charset, so fall through and treat tag as a regular string 163 string = new String(bytes); 164 break; 165 } 166 directory.setString(tagIdentifier, charset); 167 return; 168 case IptcDirectory.TAG_ENVELOPE_RECORD_VERSION: 169 case IptcDirectory.TAG_APPLICATION_RECORD_VERSION: 170 case IptcDirectory.TAG_FILE_VERSION: 171 case IptcDirectory.TAG_ARM_VERSION: 172 case IptcDirectory.TAG_PROGRAM_VERSION: 173 // short 174 if (tagByteCount >= 2) { 175 int shortValue = reader.getUInt16(); 176 reader.skip(tagByteCount - 2); 177 directory.setInt(tagIdentifier, shortValue); 178 return; 179 } 112 180 break; 113 }114 115 try {116 processTag(reader, directory, directoryType, tagType, offset, tagByteCount);117 } catch (BufferBoundsException e) {118 directory.addError("Error processing IPTC tag");119 break;120 }121 122 offset += tagByteCount;123 }124 }125 126 private void processTag(@NotNull BufferReader reader, @NotNull Directory directory, int directoryType, int tagType, int offset, int tagByteCount) throws BufferBoundsException127 {128 int tagIdentifier = tagType | (directoryType << 8);129 130 switch (tagIdentifier) {131 case IptcDirectory.TAG_APPLICATION_RECORD_VERSION:132 // short133 int shortValue = reader.getUInt16(offset);134 directory.setInt(tagIdentifier, shortValue);135 return;136 181 case IptcDirectory.TAG_URGENCY: 137 182 // byte 138 directory.setInt(tagIdentifier, reader.getUInt8(offset)); 183 directory.setInt(tagIdentifier, reader.getUInt8()); 184 reader.skip(tagByteCount - 1); 139 185 return; 140 186 case IptcDirectory.TAG_RELEASE_DATE: … … 142 188 // Date object 143 189 if (tagByteCount >= 8) { 144 String dateStr = reader.getString(offset,tagByteCount);190 string = reader.getString(tagByteCount); 145 191 try { 146 int year = Integer.parseInt( dateStr.substring(0, 4));147 int month = Integer.parseInt( dateStr.substring(4, 6)) - 1;148 int day = Integer.parseInt( dateStr.substring(6, 8));192 int year = Integer.parseInt(string.substring(0, 4)); 193 int month = Integer.parseInt(string.substring(4, 6)) - 1; 194 int day = Integer.parseInt(string.substring(6, 8)); 149 195 Date date = new java.util.GregorianCalendar(year, month, day).getTime(); 150 196 directory.setDate(tagIdentifier, date); 151 197 return; 152 198 } catch (NumberFormatException e) { 153 // fall through and we'll store whatever was there as a String199 // fall through and we'll process the 'string' value below 154 200 } 201 } else { 202 reader.skip(tagByteCount); 155 203 } 156 204 case IptcDirectory.TAG_RELEASE_TIME: … … 162 210 163 211 // If we haven't returned yet, treat it as a string 164 String str; 165 if (tagByteCount < 1) { 166 str = ""; 167 } else { 168 str = reader.getString(offset, tagByteCount, System.getProperty("file.encoding")); // "ISO-8859-1" 212 // NOTE that there's a chance we've already loaded the value as a string above, but failed to parse the value 213 if (string == null) { 214 String encoding = directory.getString(IptcDirectory.TAG_CODED_CHARACTER_SET); 215 if (encoding != null) { 216 string = reader.getString(tagByteCount, encoding); 217 } else { 218 byte[] bytes = reader.getBytes(tagByteCount); 219 encoding = Iso2022Converter.guessEncoding(bytes); 220 string = encoding != null ? new String(bytes, encoding) : new String(bytes); 221 } 169 222 } 170 223 … … 179 232 System.arraycopy(oldStrings, 0, newStrings, 0, oldStrings.length); 180 233 } 181 newStrings[newStrings.length - 1] = str ;234 newStrings[newStrings.length - 1] = string; 182 235 directory.setStringArray(tagIdentifier, newStrings); 183 236 } else { 184 directory.setString(tagIdentifier, str );237 directory.setString(tagIdentifier, string); 185 238 } 186 239 }
Note:
See TracChangeset
for help on using the changeset viewer.