예제 #1
0
 /**
  * Calculate the size of this IPTC directory if if were to be encoded inside a JPEG image.
  *
  * @return Returns the size in bytes.
  */
 private int calcEncodedIPTCSize() {
   int size = 0;
   for (Iterator<Map.Entry<Integer, ImageMetaValue>> i = iterator(); i.hasNext(); ) {
     final Map.Entry<Integer, ImageMetaValue> me = i.next();
     final ImageMetaValue imValue = me.getValue();
     switch (imValue.getType()) {
       case META_SBYTE:
       case META_UBYTE:
         size += IPTC_ENTRY_HEADER_SIZE + 1;
         break;
       case META_DATE:
         size += IPTC_ENTRY_HEADER_SIZE + IPTC_DATE_SIZE;
         break;
       case META_SSHORT:
       case META_USHORT:
         size += IPTC_ENTRY_HEADER_SIZE + IPTC_SHORT_SIZE;
         break;
       case META_STRING:
         for (String s : imValue.getValues()) {
           try {
             final byte[] b = s.getBytes("ISO-8859-1");
             size += IPTC_ENTRY_HEADER_SIZE + b.length;
           } catch (UnsupportedEncodingException e) {
             throw new IllegalStateException(e);
           }
         }
         break;
       default:
         throw new IllegalStateException();
     }
   }
   return size;
 }
예제 #2
0
 /** {@inheritDoc} */
 public RenderedImage getPreviewImage(ImageInfo imageInfo, int maxWidth, int maxHeight)
     throws BadImageFileException, IOException, UnknownImageTypeException {
   final ImageMetadata metadata = imageInfo.getMetadata();
   final ImageMetadataDirectory dir = metadata.getDirectoryFor(CIFFDirectory.class);
   if (dir != null) {
     final ImageMetaValue colorSpace = dir.getValue(CIFF_COLOR_SPACE);
     ColorSpace cs = JAIContext.sRGBColorSpace;
     if (colorSpace != null)
       switch (colorSpace.getIntValue()) {
         case CIFF_COLOR_SPACE_ADOBE_RGB:
           cs = JAIContext.adobeRGBColorSpace;
           break;
       }
     final RenderedImage image =
         JPEGImageType.getImageFromBuffer(
             imageInfo.getByteBuffer(),
             dir.getValue(CIFF_PREVIEW_IMAGE_OFFSET),
             0,
             dir.getValue(CIFF_PREVIEW_IMAGE_LENGTH),
             cs,
             maxWidth,
             maxHeight);
     if (image != null) return image;
   }
   return super.getPreviewImage(imageInfo, maxWidth, maxHeight);
 }
예제 #3
0
 /**
  * Puts a key/value pair into this directory. For a Olympus tag that has subfields, expands the
  * values into multiple key/value pairs.
  *
  * @param tagID The metadata tag ID (the key).
  * @param value The value to put.
  * @see #valueToString(ImageMetaValue)
  */
 public void putValue(Integer tagID, ImageMetaValue value) {
   switch (tagID) {
     case OLYMPUS_CAMERA_SETTINGS:
     case OLYMPUS_CAMERA_SETTINGS_OLD:
       explodeSubfields(tagID, 0, value, true);
       break;
     case OLYMPUS_ISO:
       {
         final float n = value.getFloatValue();
         value = new UnsignedShortMetaValue((int) (100 * Math.pow(2, n - 5)));
         break;
       }
     case OLYMPUS_WHITE_BALANCE_MODE:
       final long[] v = ((LongMetaValue) value).getLongValues();
       final int n;
       switch (v.length) {
         case 1:
           n = (int) v[0];
           break;
         case 2:
           n = (int) (v[0] * 10 + v[1]);
           break;
         default:
           return;
       }
       value = new UnsignedShortMetaValue(n);
       break;
   }
   super.putValue(tagID, value);
 }
예제 #4
0
  /**
   * Merges the given {@link DateMetaValue} and a time into a new {@link DateMetaValue}.
   *
   * @param date The starting {@link DateMetaValue}. It is not modified.
   * @param timeTagID The ID of the tag of the {@link ImageMetaValue} that contains a time in the
   *     form HHMMSS+HHMM. (This is the form of all IPTC time values.)
   * @return Returns a new {@link DateMetaValue} that is the date of the old {@link DateMetaValue}
   *     plus the time.
   */
  private ImageMetaValue mergeDateTime(ImageMetaValue date, int timeTagID) {
    final ImageMetaValue timeValue = getValue(timeTagID);
    if (timeValue == null) return date;
    final String timeString = timeValue.getStringValue();
    if (timeString.length() != 11) return date;

    try {
      final int hh = Integer.parseInt(timeString.substring(0, 2));
      final int mm = Integer.parseInt(timeString.substring(2, 4));
      final int ss = Integer.parseInt(timeString.substring(4, 6));

      int zh = Integer.parseInt(timeString.substring(7, 9));
      int zm = Integer.parseInt(timeString.substring(9, 11));
      //
      // We have to adjust the hour and minute by the timezone offset and
      // we need to do this based on GMT.
      //
      // For an offset like -08:00 (i.e., somewhere on the west coast of
      // the USA), we need to add 8 hours so midnight on the west coast
      // is 8am GMT.  To get this result, we don't have to do anything to
      // the sign of zh and zm.
      //
      // For an offset like +08:00 (i.e., somewhere on the west coast of
      // Australia), we need to substract 8 hours.  To get this result,
      // we negate zh and zm.
      //
      switch (timeString.charAt(6)) {
        case '+':
          zh = -zh;
          zm = -zm;
          break;
        case '-':
          break;
        default:
          return date;
      }

      final int delta = ((hh + zh) * 60 * 60 + (mm + zm) * 60 + ss) * 1000;

      final DateMetaValue newDateValue = (DateMetaValue) date.clone();
      final Date newDate = newDateValue.getDateValue();
      newDate.setTime(newDate.getTime() + delta);
      return newDateValue;
    } catch (NumberFormatException e) {
      return date;
    }
  }
예제 #5
0
 /** {@inheritDoc} */
 public String valueToString(ImageMetaValue value) {
   switch (value.getOwningTagID()) {
     case IPTC_DATE_CREATED:
     case IPTC_DATE_SENT:
     case IPTC_DIGITAL_CREATION_DATE:
     case IPTC_EXPIRATION_DATE:
     case IPTC_RELEASE_DATE:
       {
         //
         // IPTC dates don't have times (those are stored seperately --
         // see below), so we chop off the "00:00:00" from the Date
         // value.
         //
         final String s = value.getStringValue();
         if (s.length() != 19) // YYYY:MM:DD 00:00:00
         break;
         if (!s.endsWith("00:00:00")) break;
         return s.substring(0, 11);
       }
     case IPTC_DIGITAL_CREATION_TIME:
     case IPTC_EXPIRATION_TIME:
     case IPTC_RELEASE_TIME:
     case IPTC_TIME_CREATED:
     case IPTC_TIME_SENT:
       {
         final String s = value.getStringValue();
         if (s.length() != 11) // HHMMSS+HHMM
         break;
         return s.substring(0, 2)
             + ':'
             + // HH
             s.substring(2, 4)
             + ':'
             + // MM
             s.substring(4, 6)
             + ' '
             + // SS
             s.substring(6); // GMT offset
       }
   }
   return super.valueToString(value);
 }
예제 #6
0
 /** {@inheritDoc} */
 public String valueToString(ImageMetaValue value) {
   switch (value.getOwningTagID()) {
     case OLYMPUS_BLUE_BALANCE:
     case OLYMPUS_RED_BALANCE:
       return TextUtil.tenths(value.getFloatValue() / 256);
     case OLYMPUS_CS_CUSTOM_SATURATION:
       {
         final String model = getOwningMetadata().getCameraMake(true);
         if (model != null && model.contains("E-1")) {
           final long[] n = ((LongMetaValue) value).getLongValues();
           n[0] -= n[1];
           n[2] -= n[1];
           return n[0] + " (0," + n[2] + ')';
         }
         // no break;
       }
     case OLYMPUS_CS_CONTRAST_SETTING:
     case OLYMPUS_CS_PM_CONTRAST:
     case OLYMPUS_CS_PM_SATURATION:
     case OLYMPUS_CS_PM_SHARPNESS:
     case OLYMPUS_CS_SHARPNESS_SETTING:
       {
         final String[] values = value.getValues();
         if (values.length != 3) return null;
         return values[0] + " (" + values[1] + ',' + values[2] + ')';
       }
     case OLYMPUS_CS_PANORAMA_MODE:
       {
         if (value.getValueCount() != 2) break;
         final int tagID = value.getOwningTagID();
         return getTagValueLabelFor(tagID, value.getIntValue()) + ", " + value.getValues()[1];
       }
     case OLYMPUS_FOCAL_PLANE_DIAGONAL:
       return value.getStringValue() + "mm"; // TODO: localize
   }
   return super.valueToString(value);
 }
예제 #7
0
 /** {@inheritDoc} */
 public String getTitle() {
   final ImageMetaValue value = getValue(IPTC_OBJECT_NAME);
   return value != null ? value.getStringValue() : null;
 }
예제 #8
0
 /** {@inheritDoc} */
 public String getCopyright() {
   final ImageMetaValue value = getValue(IPTC_COPYRIGHT_NOTICE);
   return value != null ? value.getStringValue() : null;
 }
예제 #9
0
 /** {@inheritDoc} */
 public String getArtist() {
   final ImageMetaValue value = getValue(IPTC_CREATOR);
   return value != null ? value.getStringValue() : null;
 }
예제 #10
0
  /**
   * Encode an {@link IPTCDirectory}'s values into a {@link ByteBuffer} suitable for writing into a
   * JPEG image file.
   *
   * @param includePhotoshopHeader If <code>true</code>, encode the Photoshop header as is needed in
   *     JPEG files.
   * @return Returns said {@link ByteBuffer}.
   */
  private ByteBuffer encodeImpl(boolean includePhotoshopHeader) {
    final int encodedIPTCSize = calcEncodedIPTCSize();
    int bufSize = encodedIPTCSize;

    ////////// Encode Photoshop IPTC header, if wanted ////////////////////

    if (includePhotoshopHeader) bufSize += IPTC_JPEG_HEADER_SIZE;

    //
    // Ensure the buffer size is padded to be an even number of bytes.
    //
    final ByteBuffer buf = ByteBuffer.allocate(bufSize + (bufSize & 1));

    if (includePhotoshopHeader) {
      ByteBufferUtil.put(buf, PHOTOSHOP_3_IDENT, "ASCII");
      buf.put((byte) 0);
      ByteBufferUtil.put(buf, PHOTOSHOP_CREATOR_CODE, "ASCII");
      buf.putShort(PHOTOSHOP_IPTC_RESOURCE_ID);
      buf.putShort((short) 0); // resource name (empty)
      buf.putInt(encodedIPTCSize);
    }

    ////////// Now encode all the IPTC tags ///////////////////////////////

    final Integer[] tagIDs = getTagIDSet(false).toArray(new Integer[] {null});
    Arrays.sort(tagIDs);

    for (int tagID : tagIDs) {
      if (!tagIsIIM(tagID)) {
        //
        // Non-IIM tags can't be encoded into binary form.
        //
        continue;
      }
      final ImageMetaValue imValue = getValue(tagID);
      switch (imValue.getType()) {
        case META_SBYTE:
        case META_UBYTE:
          {
            encodeTag(buf, tagID);
            buf.putShort((short) 1);
            buf.put(imValue.getStringValue().getBytes()[0]);
            break;
          }
        case META_DATE:
          {
            encodeTag(buf, tagID);
            String date = imValue.getStringValue();
            date =
                date.substring(0, 4)
                    + // YYYY
                    date.substring(5, 7)
                    + // MM
                    date.substring(8, 10); // DD
            encodeString(buf, date);
            break;
          }
        case META_SSHORT:
        case META_USHORT:
          {
            encodeTag(buf, tagID);
            buf.putShort((short) 2);
            buf.putShort(imValue.getShortValue());
            break;
          }
        case META_STRING:
          {
            for (String s : imValue.getValues()) {
              encodeTag(buf, tagID);
              encodeString(buf, s);
            }
            break;
          }
        default:
          throw new IllegalStateException();
      }
    }

    if ((bufSize & 1) != 0) {
      //
      // The number of encoded bytes is odd: pad to make even.
      //
      buf.put((byte) 0);
    }

    return buf;
  }
예제 #11
0
  /** {@inheritDoc} */
  protected Collection<Element> toXMP(Document xmpDoc, String nsURI, String prefix) {
    Element rdfDescElement = null;
    //
    // First we have to scan through all the metadata values to see if at
    // least one of them is one of the Creator Contact Info values because
    // they need special handling.
    //
    Element cciElement = null;
    for (Iterator<Map.Entry<Integer, ImageMetaValue>> i = iterator(); i.hasNext(); ) {
      final Map.Entry<Integer, ImageMetaValue> me = i.next();
      final int tagID = me.getKey();
      if (tagIsCreatorContactInfo(tagID)) {
        rdfDescElement = XMPUtil.createRDFDescription(xmpDoc, nsURI, prefix);
        cciElement =
            XMLUtil.addElementChildTo(rdfDescElement, nsURI, prefix + ':' + "CreatorContactInfo");
        cciElement.setAttribute(XMP_RDF_PREFIX + ":parseType", "Resource");
        rdfDescElement.appendChild(cciElement);
        break;
      }
    }

    //
    // Now go through the metadata values for real and convert them to XMP.
    // If a given metadata value is one of the Creator Contact Info values,
    // make its parent the Creator Contact Info element rather than the
    // given parent.
    //
    for (Iterator<Map.Entry<Integer, ImageMetaValue>> i = iterator(); i.hasNext(); ) {
      final Map.Entry<Integer, ImageMetaValue> me = i.next();
      final int tagID = me.getKey();
      ImageMetaValue value = me.getValue();

      //
      // Only these tags are encoded as part of IPTC for XMP Core.
      //
      switch (tagID) {
        case IPTC_COUNTRY_CODE:
        case IPTC_INTELLECTUAL_GENRE:
        case IPTC_LOCATION:
        case IPTC_SCENE:
        case IPTC_SUBJECT_CODE:
          break;
        default:
          if (!tagIsCreatorContactInfo(tagID)) continue;
      }

      /*
                  //
                  // In XMP, IPTC time fields are merged into the corresponding date
                  // field.
                  //
                  switch ( tagID ) {
                      case IPTC_DATE_CREATED:
                          value = mergeDateTime( value, IPTC_TIME_CREATED );
                          break;
                      case IPTC_DATE_SENT:
                          value = mergeDateTime( value, IPTC_TIME_SENT );
                          break;
                      case IPTC_DIGITAL_CREATION_DATE:
                          value = mergeDateTime( value, IPTC_DIGITAL_CREATION_TIME );
                          break;
                      case IPTC_EXPIRATION_DATE:
                          value = mergeDateTime( value, IPTC_EXPIRATION_TIME );
                          break;
                      case IPTC_RELEASE_DATE:
                          value = mergeDateTime( value, IPTC_RELEASE_TIME );
                          break;
                      case IPTC_DIGITAL_CREATION_TIME:
                      case IPTC_EXPIRATION_TIME:
                      case IPTC_RELEASE_TIME:
                      case IPTC_TIME_CREATED:
                      case IPTC_TIME_SENT:
                          continue;
                  }

      */
      final Element valueElement = value.toXMP(xmpDoc, nsURI, prefix);
      if (valueElement != null) {
        final Element parent;
        if (tagIsCreatorContactInfo(tagID)) parent = cciElement;
        else {
          if (rdfDescElement == null)
            rdfDescElement = XMPUtil.createRDFDescription(xmpDoc, nsURI, prefix);
          parent = rdfDescElement;
        }
        //noinspection ConstantConditions
        parent.appendChild(valueElement);
      }
    }
    if (rdfDescElement != null) {
      final Collection<Element> elements = new ArrayList<Element>(1);
      elements.add(rdfDescElement);
      return elements;
    }
    return null;
  }