package org.lateralgm.file.iconio;
import java.awt.Image;
import java.io.IOException;
import org.lateralgm.file.StreamDecoder;
import org.lateralgm.file.StreamEncoder;
/**
* <p>
* ICO file entry descriptor. Describes an embedded bitmap, and points to the header/bitmap pair. I
* found that the descriptor often "lies" about size, number of colors etc., hence the bitmap header
* should be used for reference.
* </p>
*
* @author © Christian Treber, ct@ctreber.com
*/
public class BitmapDescriptor
{
//See note in constructor: the ICO format's width/height are broken and ignored.
//private int width;
//private int height;
private int colorCount;
private int reserved;
private int planes;
private int bpp;
private long size;
private long offset;
/** For convenience, not part of an entry: The header the entry refers to. */
private BitmapHeader header;
/** For convenience, not part of an entry: The bitmap the entry refers to. */
private AbstractBitmap bitmap;
/**
* Read the descriptor with the decoder (16 Bytes in total).
*
* @param pDec The decoder.
* @throws IOException
*/
// @PMD:REVIEWED:CallSuperInConstructor: by Chris on 06.03.06 10:32
public BitmapDescriptor(final StreamDecoder pDec) throws IOException
{
// The ICO format's width/height fields are universally ignored
// (Windows and Linux will both ignore them even if they are clearly set wrong).
// Instead, you have to use the internal bitmap/png's width/height.
/*int ignoredWidth =*/ pDec.read();
/*int ignoredHeight =*/ pDec.read();
colorCount = pDec.read();
reserved = pDec.read();
planes = pDec.read2();
bpp = pDec.read2();
size = pDec.read4();
offset = pDec.read4();
}
/**
* @return Provides some information on the descriptor.
*/
public String toString()
{
return "width: " + getWidth() + ", height: " + getHeight() + ", colorCount: " + colorCount + " ("
+ getColorCount() + ")" + ", planes: " + planes + ", BPP: " + bpp + ", size: " + size
+ ", offset: " + offset;
}
/**
* Image with indexed colors. Returns null if an indexed image can't be created (like, from an RGB
* icon - color mapping and dithering is a bit much for the time being). Transparency information
* that might be present in the ICO file is lost. See {@link #getImageRGB}.
*
* @return Image.
*/
public Image getImageIndexed()
{
if (!(bitmap instanceof AbstractBitmapIndexed))
{
// Can't create indexed image from RGB icon.
return null;
}
return ((AbstractBitmapIndexed) bitmap).createImageIndexed();
}
/**
* Bits per pixel. If the bit count of the entry is 0, the bit count of the header is returned.
* See {@link #getBPPRaw}.
*
* @return Bits per pixel (fudged).
*/
public int getBPP()
{
if (bpp != 0)
{
return bpp;
}
return header.getBPP();
}
/**
* The original bits per pixel count. See {@link #getBPP()}.
*
* @return Bits per pixel (raw).
*/
public int getBPPRaw()
{
return bpp;
}
/**
* Image with ARGB colors. This method works for indexed color and RGB ICO files. Transparency
* information that might be present in the ICO is used. See {@link #getImageIndexed}.
*
* @return Image created from the bitmap.
*/
public Image getImageRGB()
{
return bitmap.createImageRGB();
}
/**
* The original color count (note "0" means "256"). See {@link #getColorCount}.
*
* @return Color count (raw).
*/
public int getColorCountRaw()
{
return colorCount;
}
/**
* The actual color count. See {@link #getColorCountRaw}.
*
* @return Color count (cooked).
*/
public int getColorCount()
{
return colorCount == 0 ? 256 : colorCount;
}
/**
* Bitmap height.
*
* @return Height.
*/
public int getHeight()
{
return (header==null || header.getHeight()>Integer.MAX_VALUE) ? 0 : ((int)header.getHeight());
}
/**
* Offset of header in ICO file.
*
* @return Offset.
*/
public long getOffset()
{
return offset;
}
public void setOffset(long offset)
{
this.offset = offset;
}
/**
* Number of planes ("1" for bitmaps, as far as I know).
*
* @return Planes.
*/
public int getPlanes()
{
return planes;
}
/**
* Reserved value in the descriptor.
*
* @return Reserved value.
*/
public int getReserved()
{
return reserved;
}
/**
* Hm - the size of the header and bitmap maybe?
*
* @return Size.
*/
public long getSize()
{
return size;
}
public void setSize(long size)
{
this.size = size;
}
/**
* Bitmap width.
*
* @return Width.
*/
public int getWidth()
{
return (header==null || header.getWidth()>Integer.MAX_VALUE) ? 0 : ((int)header.getWidth());
}
/**
* The header of the bitmap this descriptor refers to.
*
* @return Header.
*/
public BitmapHeader getHeader()
{
return header;
}
/**
* @param pHeader
*/
void setHeader(final BitmapHeader pHeader)
{
header = pHeader;
}
/**
* Bitmap this descriptor refers to.
*
* @return Bitmap.
*/
public AbstractBitmap getBitmap()
{
return bitmap;
}
void setBitmap(final AbstractBitmap pBitmap)
{
bitmap = pBitmap;
}
void write(StreamEncoder out) throws IOException
{
out.write(getWidth());
out.write(getHeight());
out.write(colorCount);
out.write(reserved);
out.write2(planes);
out.write2(bpp);
out.write4((int) size);
out.write4((int) offset);
}
}