Changeset 6127 in josm for trunk/src/com/drew/metadata/iptc/IptcReader.java
- Timestamp:
- 2013-08-09T18:05:11+02:00 (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/com/drew/metadata/iptc/IptcReader.java
r4231 r6127 1 1 /* 2 * This is public domain software - that is, you can do whatever you want 3 * with it, and include it software that is licensed under the GNU or the 4 * BSD license, or whatever other licence you choose, including proprietary 5 * closed source licenses. I do ask that you leave this header in tact. 2 * Copyright 2002-2012 Drew Noakes 6 3 * 7 * If you make modifications to this code that you think would benefit the 8 * wider community, please send me a copy and I'll post it on my site. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 9 7 * 10 * If you make use of this code, I'd appreciate hearing about it. 11 * drew@drewnoakes.com 12 * Latest version of this software kept at 13 * http://drewnoakes.com/ 8 * http://www.apache.org/licenses/LICENSE-2.0 14 9 * 15 * Created by dnoakes on 12-Nov-2002 19:00:03 using IntelliJ IDEA. 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * More information about this project is available at: 17 * 18 * http://drewnoakes.com/code/exif/ 19 * http://code.google.com/p/metadata-extractor/ 16 20 */ 17 21 package com.drew.metadata.iptc; 18 22 19 import com.drew.imaging.jpeg.JpegProcessingException; 20 import com.drew.imaging.jpeg.JpegSegmentReader; 23 import com.drew.lang.BufferBoundsException; 24 import com.drew.lang.BufferReader; 25 import com.drew.lang.annotations.NotNull; 21 26 import com.drew.metadata.Directory; 22 27 import com.drew.metadata.Metadata; 23 import com.drew.metadata.MetadataException;24 28 import com.drew.metadata.MetadataReader; 25 29 26 import java.io.File;27 import java.io.InputStream;28 30 import java.util.Date; 29 31 30 32 /** 33 * Decodes IPTC binary data, populating a <code>Metadata</code> object with tag values in an <code>IptcDirectory</code>. 31 34 * 35 * @author Drew Noakes http://drewnoakes.com 32 36 */ 33 37 public class IptcReader implements MetadataReader 34 38 { 39 // TODO consider breaking the IPTC section up into multiple directories and providing segregation of each IPTC directory 35 40 /* 36 41 public static final int DIRECTORY_IPTC = 2; … … 46 51 public static final int POST_DATA_RECORD = 9; 47 52 */ 48 /**49 * The Iptc data segment.50 */51 private final byte[] _data;52 53 53 /** 54 * Creates a new IptcReader for the specified Jpeg jpegFile. 55 */ 56 public IptcReader(File jpegFile) throws JpegProcessingException 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) 57 56 { 58 this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_APPD)); 59 } 57 IptcDirectory directory = metadata.getOrCreateDirectory(IptcDirectory.class); 60 58 61 /** Creates an IptcReader for a JPEG stream. 62 * 63 * @param is JPEG stream. Stream will be closed. 64 */ 65 public IptcReader(InputStream is) throws JpegProcessingException 66 { 67 this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD)); 68 } 59 int offset = 0; 69 60 70 public IptcReader(byte[] data) 71 { 72 _data = data; 73 } 74 75 /** 76 * Performs the Exif data extraction, returning a new instance of <code>Metadata</code>. 77 */ 78 public Metadata extract() 79 { 80 return extract(new Metadata()); 81 } 82 83 /** 84 * Performs the Exif data extraction, adding found values to the specified 85 * instance of <code>Metadata</code>. 86 */ 87 public Metadata extract(Metadata metadata) 88 { 89 if (_data == null) { 90 return metadata; 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; 91 69 } 92 93 Directory directory = metadata.getDirectory(IptcDirectory.class); 94 95 // find start of data 96 int offset = 0; 97 try { 98 while (offset < _data.length - 1 && get32Bits(offset) != 0x1c02) { 99 offset++; 100 } 101 } catch (MetadataException e) { 102 directory.addError("Couldn't find start of Iptc data (invalid segment)"); 103 return metadata; 104 } 70 */ 105 71 106 72 // for each tag 107 while (offset < _data.length) { 73 while (offset < reader.getLength()) { 74 108 75 // identifies start of a tag 109 if (_data[offset] != 0x1c) { 76 short startByte; 77 try { 78 startByte = reader.getUInt8(offset); 79 } catch (BufferBoundsException e) { 80 directory.addError("Unable to read starting byte of IPTC tag"); 110 81 break; 111 82 } 83 84 if (startByte != 0x1c) { 85 directory.addError("Invalid start to IPTC tag"); 86 break; 87 } 88 112 89 // we need at least five bytes left to read a tag 113 if ((offset + 5) >= _data.length) { 90 if (offset + 5 >= reader.getLength()) { 91 directory.addError("Too few bytes remain for a valid IPTC tag"); 114 92 break; 115 93 } … … 121 99 int tagByteCount; 122 100 try { 123 directoryType = _data[offset++]; 124 tagType = _data[offset++]; 125 tagByteCount = get32Bits(offset); 126 } catch (MetadataException e) { 127 directory.addError("Iptc data segment ended mid-way through tag descriptor"); 128 return metadata; 101 directoryType = reader.getUInt8(offset++); 102 tagType = reader.getUInt8(offset++); 103 tagByteCount = reader.getUInt16(offset); 104 offset += 2; 105 } catch (BufferBoundsException e) { 106 directory.addError("IPTC data segment ended mid-way through tag descriptor"); 107 return; 129 108 } 130 offset += 2; 131 if ( (offset + tagByteCount) > _data.length) {132 directory.addError(" data for tag extends beyond end of iptcsegment");109 110 if (offset + tagByteCount > reader.getLength()) { 111 directory.addError("Data for tag extends beyond end of IPTC segment"); 133 112 break; 134 113 } 135 114 136 processTag(directory, directoryType, tagType, offset, tagByteCount); 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 137 122 offset += tagByteCount; 138 123 } 139 140 return metadata;141 124 } 142 125 143 /** 144 * Returns an int calculated from two bytes of data at the specified offset (MSB, LSB). 145 * @param offset position within the data buffer to read first byte 146 * @return the 32 bit int value, between 0x0000 and 0xFFFF 147 */ 148 private int get32Bits(int offset) throws MetadataException 149 { 150 if (offset >= _data.length) { 151 throw new MetadataException("Attempt to read bytes from outside Iptc data buffer"); 152 } 153 return ((_data[offset] & 255) << 8) | (_data[offset + 1] & 255); 154 } 155 156 /** 157 * This method serves as marsheller of objects for dataset. It converts from IPTC 158 * octets to relevant java object. 159 */ 160 private void processTag(Directory directory, int directoryType, int tagType, int offset, int tagByteCount) 126 private void processTag(@NotNull BufferReader reader, @NotNull Directory directory, int directoryType, int tagType, int offset, int tagByteCount) throws BufferBoundsException 161 127 { 162 128 int tagIdentifier = tagType | (directoryType << 8); 163 129 164 130 switch (tagIdentifier) { 165 case IptcDirectory.TAG_ RECORD_VERSION:131 case IptcDirectory.TAG_APPLICATION_RECORD_VERSION: 166 132 // short 167 short shortValue = (short)((_data[offset] << 8) | _data[offset + 1]);133 int shortValue = reader.getUInt16(offset); 168 134 directory.setInt(tagIdentifier, shortValue); 169 135 return; 170 136 case IptcDirectory.TAG_URGENCY: 171 137 // byte 172 directory.setInt(tagIdentifier, _data[offset]);138 directory.setInt(tagIdentifier, reader.getUInt8(offset)); 173 139 return; 174 140 case IptcDirectory.TAG_RELEASE_DATE: … … 176 142 // Date object 177 143 if (tagByteCount >= 8) { 178 String dateStr = new String(_data,offset, tagByteCount);144 String dateStr = reader.getString(offset, tagByteCount); 179 145 try { 180 146 int year = Integer.parseInt(dateStr.substring(0, 4)); 181 147 int month = Integer.parseInt(dateStr.substring(4, 6)) - 1; 182 148 int day = Integer.parseInt(dateStr.substring(6, 8)); 183 Date date = (new java.util.GregorianCalendar(year, month, day)).getTime();149 Date date = new java.util.GregorianCalendar(year, month, day).getTime(); 184 150 directory.setDate(tagIdentifier, date); 185 151 return; … … 194 160 // fall through 195 161 } 196 // If no special handling by now, treat it as a string 162 163 // If we haven't returned yet, treat it as a string 197 164 String str; 198 165 if (tagByteCount < 1) { 199 166 str = ""; 200 167 } else { 201 str = new String(_data, offset, tagByteCount);168 str = reader.getString(offset, tagByteCount, System.getProperty("file.encoding")); // "ISO-8859-1" 202 169 } 170 203 171 if (directory.containsTag(tagIdentifier)) { 204 String[] oldStrings; 172 // this fancy string[] business avoids using an ArrayList for performance reasons 173 String[] oldStrings = directory.getStringArray(tagIdentifier); 205 174 String[] newStrings; 206 try {207 oldStrings = directory.getStringArray(tagIdentifier);208 } catch (MetadataException e) {209 oldStrings = null;210 }211 175 if (oldStrings == null) { 212 176 newStrings = new String[1]; 213 177 } else { 214 178 newStrings = new String[oldStrings.length + 1]; 215 for (int i = 0; i < oldStrings.length; i++) { 216 newStrings[i] = oldStrings[i]; 217 } 179 System.arraycopy(oldStrings, 0, newStrings, 0, oldStrings.length); 218 180 } 219 181 newStrings[newStrings.length - 1] = str;
Note:
See TracChangeset
for help on using the changeset viewer.