Package org.apache.sanselan.formats.icns

Source Code of org.apache.sanselan.formats.icns.IcnsDecoder

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sanselan.formats.icns;

import java.io.IOException;
import java.util.ArrayList;

import org.apache.sanselan.ImageReadException;

import com.jgraph.gaeawt.java.awt.image.BufferedImage;

public class IcnsDecoder
{
  private static final int[] palette_4bpp =
  {
    0xffffffff,
    0xfffcf305,
    0xffff6402,
    0xffdd0806,
    0xfff20884,
    0xff4600a5,
    0xff0000d4,
    0xff02abea,
    0xff1fb714,
    0xff006411,
    0xff562c05,
    0xff90713a,
    0xffc0c0c0,
    0xff808080,
    0xff404040,
    0xff000000
  };

  private static final int[] palette_8bpp =
  {
    0xFFFFFFFF,
    0xFFFFFFCC,
    0xFFFFFF99,
    0xFFFFFF66,
    0xFFFFFF33,
    0xFFFFFF00,
    0xFFFFCCFF,
    0xFFFFCCCC,
    0xFFFFCC99,
    0xFFFFCC66,
    0xFFFFCC33,
    0xFFFFCC00,
    0xFFFF99FF,
    0xFFFF99CC,
    0xFFFF9999,
    0xFFFF9966,
    0xFFFF9933,
    0xFFFF9900,
    0xFFFF66FF,
    0xFFFF66CC,
    0xFFFF6699,
    0xFFFF6666,
    0xFFFF6633,
    0xFFFF6600,
    0xFFFF33FF,
    0xFFFF33CC,
    0xFFFF3399,
    0xFFFF3366,
    0xFFFF3333,
    0xFFFF3300,
    0xFFFF00FF,
    0xFFFF00CC,
    0xFFFF0099,
    0xFFFF0066,
    0xFFFF0033,
    0xFFFF0000,
    0xFFCCFFFF,
    0xFFCCFFCC,
    0xFFCCFF99,
    0xFFCCFF66,
    0xFFCCFF33,
    0xFFCCFF00,
    0xFFCCCCFF,
    0xFFCCCCCC,
    0xFFCCCC99,
    0xFFCCCC66,
    0xFFCCCC33,
    0xFFCCCC00,
    0xFFCC99FF,
    0xFFCC99CC,
    0xFFCC9999,
    0xFFCC9966,
    0xFFCC9933,
    0xFFCC9900,
    0xFFCC66FF,
    0xFFCC66CC,
    0xFFCC6699,
    0xFFCC6666,
    0xFFCC6633,
    0xFFCC6600,
    0xFFCC33FF,
    0xFFCC33CC,
    0xFFCC3399,
    0xFFCC3366,
    0xFFCC3333,
    0xFFCC3300,
    0xFFCC00FF,
    0xFFCC00CC,
    0xFFCC0099,
    0xFFCC0066,
    0xFFCC0033,
    0xFFCC0000,
    0xFF99FFFF,
    0xFF99FFCC,
    0xFF99FF99,
    0xFF99FF66,
    0xFF99FF33,
    0xFF99FF00,
    0xFF99CCFF,
    0xFF99CCCC,
    0xFF99CC99,
    0xFF99CC66,
    0xFF99CC33,
    0xFF99CC00,
    0xFF9999FF,
    0xFF9999CC,
    0xFF999999,
    0xFF999966,
    0xFF999933,
    0xFF999900,
    0xFF9966FF,
    0xFF9966CC,
    0xFF996699,
    0xFF996666,
    0xFF996633,
    0xFF996600,
    0xFF9933FF,
    0xFF9933CC,
    0xFF993399,
    0xFF993366,
    0xFF993333,
    0xFF993300,
    0xFF9900FF,
    0xFF9900CC,
    0xFF990099,
    0xFF990066,
    0xFF990033,
    0xFF990000,
    0xFF66FFFF,
    0xFF66FFCC,
    0xFF66FF99,
    0xFF66FF66,
    0xFF66FF33,
    0xFF66FF00,
    0xFF66CCFF,
    0xFF66CCCC,
    0xFF66CC99,
    0xFF66CC66,
    0xFF66CC33,
    0xFF66CC00,
    0xFF6699FF,
    0xFF6699CC,
    0xFF669999,
    0xFF669966,
    0xFF669933,
    0xFF669900,
    0xFF6666FF,
    0xFF6666CC,
    0xFF666699,
    0xFF666666,
    0xFF666633,
    0xFF666600,
    0xFF6633FF,
    0xFF6633CC,
    0xFF663399,
    0xFF663366,
    0xFF663333,
    0xFF663300,
    0xFF6600FF,
    0xFF6600CC,
    0xFF660099,
    0xFF660066,
    0xFF660033,
    0xFF660000,
    0xFF33FFFF,
    0xFF33FFCC,
    0xFF33FF99,
    0xFF33FF66,
    0xFF33FF33,
    0xFF33FF00,
    0xFF33CCFF,
    0xFF33CCCC,
    0xFF33CC99,
    0xFF33CC66,
    0xFF33CC33,
    0xFF33CC00,
    0xFF3399FF,
    0xFF3399CC,
    0xFF339999,
    0xFF339966,
    0xFF339933,
    0xFF339900,
    0xFF3366FF,
    0xFF3366CC,
    0xFF336699,
    0xFF336666,
    0xFF336633,
    0xFF336600,
    0xFF3333FF,
    0xFF3333CC,
    0xFF333399,
    0xFF333366,
    0xFF333333,
    0xFF333300,
    0xFF3300FF,
    0xFF3300CC,
    0xFF330099,
    0xFF330066,
    0xFF330033,
    0xFF330000,
    0xFF00FFFF,
    0xFF00FFCC,
    0xFF00FF99,
    0xFF00FF66,
    0xFF00FF33,
    0xFF00FF00,
    0xFF00CCFF,
    0xFF00CCCC,
    0xFF00CC99,
    0xFF00CC66,
    0xFF00CC33,
    0xFF00CC00,
    0xFF0099FF,
    0xFF0099CC,
    0xFF009999,
    0xFF009966,
    0xFF009933,
    0xFF009900,
    0xFF0066FF,
    0xFF0066CC,
    0xFF006699,
    0xFF006666,
    0xFF006633,
    0xFF006600,
    0xFF0033FF,
    0xFF0033CC,
    0xFF003399,
    0xFF003366,
    0xFF003333,
    0xFF003300,
    0xFF0000FF,
    0xFF0000CC,
    0xFF000099,
    0xFF000066,
    0xFF000033,
    0xFFEE0000,
    0xFFDD0000,
    0xFFBB0000,
    0xFFAA0000,
    0xFF880000,
    0xFF770000,
    0xFF550000,
    0xFF440000,
    0xFF220000,
    0xFF110000,
    0xFF00EE00,
    0xFF00DD00,
    0xFF00BB00,
    0xFF00AA00,
    0xFF008800,
    0xFF007700,
    0xFF005500,
    0xFF004400,
    0xFF002200,
    0xFF001100,
    0xFF0000EE,
    0xFF0000DD,
    0xFF0000BB,
    0xFF0000AA,
    0xFF000088,
    0xFF000077,
    0xFF000055,
    0xFF000044,
    0xFF000022,
    0xFF000011,
    0xFFEEEEEE,
    0xFFDDDDDD,
    0xFFBBBBBB,
    0xFFAAAAAA,
    0xFF888888,
    0xFF777777,
    0xFF555555,
    0xFF444444,
    0xFF222222,
    0xFF111111,
    0xFF000000
  };

  private static void decode1BPPImage(IcnsType imageType, byte[] imageData,
      BufferedImage bufferedImage)
  {
    int position = 0;
    int bitsLeft = 0;
    int value = 0;
    for (int y = 0; y < imageType.getHeight(); y++)
    {
      for (int x = 0; x < imageType.getWidth(); x++)
      {
        if (bitsLeft == 0)
        {
          value = 0xff & imageData[position++];
          bitsLeft = 8;
        }
        int argb;
        if ((value & 0x80) != 0)
          argb = 0xff000000;
        else
          argb = 0xffffffff;
        value <<= 1;
        bitsLeft--;
        bufferedImage.setRGB(x, y, argb);
      }
    }
  }

  private static void decode4BPPImage(IcnsType imageType, byte[] imageData,
      BufferedImage bufferedImage)
  {
    int i = 0;
    boolean visited = false;
    for (int y = 0; y < imageType.getHeight(); y++)
    {
      for (int x = 0; x < imageType.getWidth(); x++)
      {
        int index;
        if (!visited)
          index = 0xf & (imageData[i] >> 4);
        else
          index = 0xf & imageData[i++];
        visited = !visited;
        bufferedImage.setRGB(x, y, palette_4bpp[index]);
      }
    }
  }

  private static void decode8BPPImage(IcnsType imageType, byte[] imageData,
      BufferedImage bufferedImage)
  {
    for (int y = 0; y < imageType.getHeight(); y++)
    {
      for (int x = 0; x < imageType.getWidth(); x++)
      {
        int index = 0xff & imageData[y*imageType.getWidth() + x];
        bufferedImage.setRGB(x, y, palette_8bpp[index]);
      }
    }
  }

  private static void decode32BPPImage(IcnsType imageType, byte[] imageData,
      BufferedImage bufferedImage)
  {
    for (int y = 0; y < imageType.getHeight(); y++)
    {
      for (int x = 0; x < imageType.getWidth(); x++)
      {
        int argb = 0xff000000 /* the "alpha" is ignored */ |
            ((0xff & imageData[4*(y*imageType.getWidth() + x) + 1]) << 16) |
            ((0xff & imageData[4*(y*imageType.getWidth() + x) + 2]) << 8) |
            (0xff & imageData[4*(y*imageType.getWidth() + x) + 3]);
        bufferedImage.setRGB(x, y, argb);
      }
    }
  }

  private static void apply1BPPMask(byte[] maskData, BufferedImage bufferedImage) throws ImageReadException
  {
    int position = 0;
    int bitsLeft = 0;
    int value = 0;

    // 1 bit icon types have image data followed by mask data in the same entry
    int totalBytes = (bufferedImage.getWidth() * bufferedImage.getHeight() + 7) / 8;
    if (maskData.length >= 2*totalBytes)
      position = totalBytes;
    else
      throw new ImageReadException("1 BPP mask underrun parsing ICNS file");

    for (int y = 0; y < bufferedImage.getHeight(); y++)
    {
      for (int x = 0; x < bufferedImage.getWidth(); x++)
      {
        if (bitsLeft == 0)
        {
          value = 0xff & maskData[position++];
          bitsLeft = 8;
        }
        int alpha;
        if ((value & 0x80) != 0)
          alpha = 0xff;
        else
          alpha = 0x00;
        value <<= 1;
        bitsLeft--;
        bufferedImage.setRGB(x, y, (alpha << 24) |
          (0xffffff & bufferedImage.getRGB(x, y)));
      }
    }
  }

  private static void apply8BPPMask(byte[] maskData, BufferedImage bufferedImage)
  {
    for (int y = 0; y < bufferedImage.getHeight(); y++)
    {
      for (int x = 0; x < bufferedImage.getWidth(); x++)
      {
        int alpha = 0xff & maskData[y*bufferedImage.getWidth() + x];
        bufferedImage.setRGB(x, y, (alpha << 24) |
          (0xffffff & bufferedImage.getRGB(x, y)));
      }
    }
  }

  public static ArrayList decodeAllImages(IcnsImageParser.IcnsElement[] icnsElements)
      throws ImageReadException, IOException
  {
    ArrayList result = new ArrayList();
    for (int i = 0; i < icnsElements.length; i++)
    {
      IcnsImageParser.IcnsElement imageElement = icnsElements[i];
      IcnsType imageType = IcnsType.findImageType(imageElement.type);
      if (imageType == null)
        continue;

      IcnsType maskType = null;
      IcnsImageParser.IcnsElement maskElement = null;
      if (imageType.hasMask())
      {
        maskType = imageType;
        maskElement = imageElement;
      }
      else
      {
        maskType = IcnsType.find8BPPMaskType(imageType);
        if (maskType != null)
        {
          for (int j = 0; j < icnsElements.length; j++)
          {
            if (icnsElements[j].type == maskType.getType())
            {
              maskElement = icnsElements[j];
              break;
            }
          }
        }
        if (maskElement == null)
        {
          maskType = IcnsType.find1BPPMaskType(imageType);
          if (maskType != null)
          {
            for (int j = 0; j < icnsElements.length; j++)
            {
              if (icnsElements[j].type == maskType.getType())
              {
                maskElement = icnsElements[j];
                break;
              }
            }
          }
        }
      }

      // FIXME: don't skip these when JPEG 2000 support is added:
      if (imageType == IcnsType.ICNS_256x256_32BIT_ARGB_IMAGE ||
        imageType == IcnsType.ICNS_512x512_32BIT_ARGB_IMAGE)
        continue;

      int expectedSize = (imageType.getWidth()*imageType.getHeight()*
          imageType.getBitsPerPixel() + 7) / 8;
      byte[] imageData;
      if (imageElement.data.length < expectedSize)
      {
        if (imageType.getBitsPerPixel() == 32)
        {
          imageData = Rle24Compression.decompress(imageType.getWidth(),
              imageType.getHeight(), imageElement.data);
        }
        else
          throw new ImageReadException(
              "Short image data but not a 32 bit compressed type");
      }
      else
        imageData = imageElement.data;

      BufferedImage bufferedImage = new BufferedImage(imageType.getWidth(),
          imageType.getHeight(), BufferedImage.TYPE_INT_ARGB);
      switch (imageType.getBitsPerPixel())
      {
        case 1:
          decode1BPPImage(imageType, imageData, bufferedImage);
          break;
        case 4:
          decode4BPPImage(imageType, imageData, bufferedImage);
          break;
        case 8:
          decode8BPPImage(imageType, imageData, bufferedImage);
          break;
        case 32:
          decode32BPPImage(imageType, imageData, bufferedImage);
          break;
        default:
          throw new ImageReadException(
            "Unsupported bit depth " + imageType.getBitsPerPixel());
      }

      if (maskElement != null)
      {
        if (maskType.getBitsPerPixel() == 1)
          apply1BPPMask(maskElement.data, bufferedImage);
        else if (maskType.getBitsPerPixel() == 8)
          apply8BPPMask(maskElement.data, bufferedImage);
        else
          throw new ImageReadException("Unsupport mask bit depth " +
              maskType.getBitsPerPixel());
      }

      result.add(bufferedImage);
    }
    return result;
  }
}
TOP

Related Classes of org.apache.sanselan.formats.icns.IcnsDecoder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.