public void read() throws IOException {
    if (!isDataRead) {
      int expectedLen = 9;
      int offset = 0;

      if (data.length >= expectedLen) {
        majorVersion = data[offset++] & 0xff;
        minorVersion = data[offset++] & 0xff;
        densityUnit = data[offset++] & 0xff;
        xDensity = IOUtils.readUnsignedShortMM(data, offset);
        offset += 2;
        yDensity = IOUtils.readUnsignedShortMM(data, offset);
        offset += 2;
        thumbnailWidth = data[offset++] & 0xff;
        thumbnailHeight = data[offset] & 0xff;
        if (thumbnailWidth != 0 && thumbnailHeight != 0) {
          containsThumbnail = true;
          // Extract the thumbnail
          // Create a Bitmap
          int size = 3 * thumbnailWidth * thumbnailHeight;
          int[] colors = MetadataUtils.toARGB(ArrayUtils.subArray(data, expectedLen, size));
          thumbnail =
              new JFIFThumbnail(
                  Bitmap.createBitmap(
                      colors, thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888));
        }
      }

      isDataRead = true;
    }
  }
  /**
   * Wraps a BufferedImage inside a Photoshop _8BIM
   *
   * @param thumbnail input thumbnail image
   * @return a Photoshop _8BMI
   * @throws IOException
   */
  public static _8BIM createThumbnail8BIM(Bitmap thumbnail) throws IOException {
    // Create memory buffer to write data
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    // Compress the thumbnail
    try {
      thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, bout);
    } catch (Exception e) {
      e.printStackTrace();
    }
    byte[] data = bout.toByteArray();
    bout.reset();
    // Write thumbnail format
    IOUtils.writeIntMM(bout, 1); // 1 = kJpegRGB. We are going to write JPEG format thumbnail
    // Write thumbnail dimension
    int width = thumbnail.getWidth();
    int height = thumbnail.getHeight();
    IOUtils.writeIntMM(bout, width);
    IOUtils.writeIntMM(bout, height);
    // Padded row bytes = (width * bits per pixel + 31) / 32 * 4.
    int bitsPerPixel = 24;
    int planes = 1;
    int widthBytes = (width * bitsPerPixel + 31) / 32 * 4;
    IOUtils.writeIntMM(bout, widthBytes);
    // Total size = widthbytes * height * planes
    IOUtils.writeIntMM(bout, widthBytes * height * planes);
    // Size after compression. Used for consistency check.
    IOUtils.writeIntMM(bout, data.length);
    IOUtils.writeShortMM(bout, bitsPerPixel);
    IOUtils.writeShortMM(bout, planes);
    bout.write(data);
    // Create 8BIM
    _8BIM bim = new _8BIM(ImageResourceID.THUMBNAIL_RESOURCE_PS5, "thumbnail", bout.toByteArray());

    return bim;
  }
 public void write(OutputStream os) throws IOException {
   ensureDataRead();
   IOUtils.write(os, majorVersion);
   IOUtils.write(os, minorVersion);
   IOUtils.write(os, densityUnit);
   IOUtils.writeShortMM(os, getXDensity());
   IOUtils.writeShortMM(os, getYDensity());
   IOUtils.write(os, thumbnailWidth);
   IOUtils.write(os, thumbnailHeight);
   if (containsThumbnail) thumbnail.write(os);
 }