using System; using System.Collections; using System.IO; using System.Net; using System.util; using iTextSharp.text; /* * Copyright 2003-2008 by Paulo Soares. * * The contents of this file are subject to the Mozilla Public License Version 1.1 * (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the License. * * The Original Code is 'iText, a free JAVA-PDF library'. * * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. * All Rights Reserved. * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. * * Contributor(s): all the names of the contributors are added in the source code * where applicable. * * Alternatively, the contents of this file may be used under the terms of the * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the * provisions of LGPL are applicable instead of those above. If you wish to * allow use of your version of this file only under the terms of the LGPL * License and not to allow others to use your version of this file under * the MPL, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the LGPL. * If you do not delete the provisions above, a recipient may use your version * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. * * This library is free software; you can redistribute it and/or modify it * under the terms of the MPL as stated above or under the terms of the GNU * Library General Public License as published by the Free Software Foundation; * either version 2 of the License, or any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more * details. * * If you didn't download this code from the following link, you should check if * you aren't using an obsolete version: * http://www.lowagie.com/iText/ * * This code was originally released in 2001 by SUN (see class * com.sun.media.imageioimpl.plugins.bmp.BMPImageReader.java) * using the BSD license in a specific wording. In a mail dating from * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission * to use the code under the following version of the BSD license: * * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for * use in the design, construction, operation or maintenance of any * nuclear facility. */ namespace iTextSharp.text.pdf.codec { /** Reads a BMP image. All types of BMP can be read. *
* It is based in the JAI codec.
*
* @author Paulo Soares (psoares@consiste.pt)
*/
public class BmpImage {
// BMP variables
private Stream inputStream;
private long bitmapFileSize;
private long bitmapOffset;
private long compression;
private long imageSize;
private byte[] palette;
private int imageType;
private int numBands;
private bool isBottomUp;
private int bitsPerPixel;
private int redMask, greenMask, blueMask, alphaMask;
public Hashtable properties = new Hashtable();
private long xPelsPerMeter;
private long yPelsPerMeter;
// BMP Image types
private const int VERSION_2_1_BIT = 0;
private const int VERSION_2_4_BIT = 1;
private const int VERSION_2_8_BIT = 2;
private const int VERSION_2_24_BIT = 3;
private const int VERSION_3_1_BIT = 4;
private const int VERSION_3_4_BIT = 5;
private const int VERSION_3_8_BIT = 6;
private const int VERSION_3_24_BIT = 7;
private const int VERSION_3_NT_16_BIT = 8;
private const int VERSION_3_NT_32_BIT = 9;
private const int VERSION_4_1_BIT = 10;
private const int VERSION_4_4_BIT = 11;
private const int VERSION_4_8_BIT = 12;
private const int VERSION_4_16_BIT = 13;
private const int VERSION_4_24_BIT = 14;
private const int VERSION_4_32_BIT = 15;
// Color space types
private const int LCS_CALIBRATED_RGB = 0;
private const int LCS_sRGB = 1;
private const int LCS_CMYK = 2;
// Compression Types
private const int BI_RGB = 0;
private const int BI_RLE8 = 1;
private const int BI_RLE4 = 2;
private const int BI_BITFIELDS = 3;
int width;
int height;
internal BmpImage(Stream isp, bool noHeader, int size) {
bitmapFileSize = size;
bitmapOffset = 0;
Process(isp, noHeader);
}
/** Reads a BMP from an url.
* @param url the url
* @throws IOException on error
* @return the image
*/
public static Image GetImage(Uri url) {
Stream isp = null;
try {
isp = WebRequest.Create(url).GetResponse().GetResponseStream();
Image img = GetImage(isp);
img.Url = url;
return img;
}
finally {
if (isp != null) {
isp.Close();
}
}
}
/** Reads a BMP from a stream. The stream is not closed.
* @param is the stream
* @throws IOException on error
* @return the image
*/
public static Image GetImage(Stream isp) {
return GetImage(isp, false, 0);
}
/** Reads a BMP from a stream. The stream is not closed.
* The BMP may not have a header and be considered as a plain DIB.
* @param is the stream
* @param noHeader true to process a plain DIB
* @param size the size of the DIB. Not used for a BMP
* @throws IOException on error
* @return the image
*/
public static Image GetImage(Stream isp, bool noHeader, int size) {
BmpImage bmp = new BmpImage(isp, noHeader, size);
Image img = bmp.GetImage();
img.SetDpi((int)((double)bmp.xPelsPerMeter * 0.0254 + 0.5), (int)((double)bmp.yPelsPerMeter * 0.0254 + 0.5));
img.OriginalType = Image.ORIGINAL_BMP;
return img;
}
/** Reads a BMP from a file.
* @param file the file
* @throws IOException on error
* @return the image
*/
public static Image GetImage(String file) {
return GetImage(Utilities.ToURL(file));
}
/** Reads a BMP from a byte array.
* @param data the byte array
* @throws IOException on error
* @return the image
*/
public static Image GetImage(byte[] data) {
Stream isp = new MemoryStream(data);
Image img = GetImage(isp);
img.OriginalData = data;
return img;
}
protected void Process(Stream stream, bool noHeader) {
if (noHeader || stream is BufferedStream) {
inputStream = stream;
} else {
inputStream = new BufferedStream(stream);
}
if (!noHeader) {
// Start File Header
if (!(ReadUnsignedByte(inputStream) == 'B' &&
ReadUnsignedByte(inputStream) == 'M')) {
throw new Exception("Invalid magic value for BMP file.");
}
// Read file size
bitmapFileSize = ReadDWord(inputStream);
// Read the two reserved fields
ReadWord(inputStream);
ReadWord(inputStream);
// Offset to the bitmap from the beginning
bitmapOffset = ReadDWord(inputStream);
// End File Header
}
// Start BitmapCoreHeader
long size = ReadDWord(inputStream);
if (size == 12) {
width = ReadWord(inputStream);
height = ReadWord(inputStream);
} else {
width = ReadLong(inputStream);
height = ReadLong(inputStream);
}
int planes = ReadWord(inputStream);
bitsPerPixel = ReadWord(inputStream);
properties["color_planes"] = planes;
properties["bits_per_pixel"] = bitsPerPixel;
// As BMP always has 3 rgb bands, except for Version 5,
// which is bgra
numBands = 3;
if (bitmapOffset == 0)
bitmapOffset = size;
if (size == 12) {
// Windows 2.x and OS/2 1.x
properties["bmp_version"] = "BMP v. 2.x";
// Classify the image type
if (bitsPerPixel == 1) {
imageType = VERSION_2_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_2_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_2_8_BIT;
} else if (bitsPerPixel == 24) {
imageType = VERSION_2_24_BIT;
}
// Read in the palette
int numberOfEntries = (int)((bitmapOffset-14-size) / 3);
int sizeOfPalette = numberOfEntries*3;
if (bitmapOffset == size) {
switch (imageType) {
case VERSION_2_1_BIT:
sizeOfPalette = 2 * 3;
break;
case VERSION_2_4_BIT:
sizeOfPalette = 16 * 3;
break;
case VERSION_2_8_BIT:
sizeOfPalette = 256 * 3;
break;
case VERSION_2_24_BIT:
sizeOfPalette = 0;
break;
}
bitmapOffset = size + sizeOfPalette;
}
ReadPalette(sizeOfPalette);
} else {
compression = ReadDWord(inputStream);
imageSize = ReadDWord(inputStream);
xPelsPerMeter = ReadLong(inputStream);
yPelsPerMeter = ReadLong(inputStream);
long colorsUsed = ReadDWord(inputStream);
long colorsImportant = ReadDWord(inputStream);
switch ((int)compression) {
case BI_RGB:
properties["compression"] = "BI_RGB";
break;
case BI_RLE8:
properties["compression"] = "BI_RLE8";
break;
case BI_RLE4:
properties["compression"] = "BI_RLE4";
break;
case BI_BITFIELDS:
properties["compression"] = "BI_BITFIELDS";
break;
}
properties["x_pixels_per_meter"] = xPelsPerMeter;
properties["y_pixels_per_meter"] = yPelsPerMeter;
properties["colors_used"] = colorsUsed;
properties["colors_important"] = colorsImportant;
if (size == 40) {
// Windows 3.x and Windows NT
switch ((int)compression) {
case BI_RGB: // No compression
case BI_RLE8: // 8-bit RLE compression
case BI_RLE4: // 4-bit RLE compression
if (bitsPerPixel == 1) {
imageType = VERSION_3_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_3_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_3_8_BIT;
} else if (bitsPerPixel == 24) {
imageType = VERSION_3_24_BIT;
} else if (bitsPerPixel == 16) {
imageType = VERSION_3_NT_16_BIT;
redMask = 0x7C00;
greenMask = 0x3E0;
blueMask = 0x1F;
properties["red_mask"] = redMask;
properties["green_mask"] = greenMask;
properties["blue_mask"] = blueMask;
} else if (bitsPerPixel == 32) {
imageType = VERSION_3_NT_32_BIT;
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
properties["red_mask"] = redMask;
properties["green_mask"] = greenMask;
properties["blue_mask"] = blueMask;
}
// Read in the palette
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries*4;
if (bitmapOffset == size) {
switch (imageType) {
case VERSION_3_1_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4;
break;
case VERSION_3_4_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4;
break;
case VERSION_3_8_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4;
break;
default:
sizeOfPalette = 0;
break;
}
bitmapOffset = size + sizeOfPalette;
}
ReadPalette(sizeOfPalette);
properties["bmp_version"] = "BMP v. 3.x";
break;
case BI_BITFIELDS:
if (bitsPerPixel == 16) {
imageType = VERSION_3_NT_16_BIT;
} else if (bitsPerPixel == 32) {
imageType = VERSION_3_NT_32_BIT;
}
// BitsField encoding
redMask = (int)ReadDWord(inputStream);
greenMask = (int)ReadDWord(inputStream);
blueMask = (int)ReadDWord(inputStream);
properties["red_mask"] = redMask;
properties["green_mask"] = greenMask;
properties["blue_mask"] = blueMask;
if (colorsUsed != 0) {
// there is a palette
sizeOfPalette = (int)colorsUsed*4;
ReadPalette(sizeOfPalette);
}
properties["bmp_version"] = "BMP v. 3.x NT";
break;
default:
throw new
Exception("Invalid compression specified in BMP file.");
}
} else if (size == 108) {
// Windows 4.x BMP
properties["bmp_version"] = "BMP v. 4.x";
// rgb masks, valid only if comp is BI_BITFIELDS
redMask = (int)ReadDWord(inputStream);
greenMask = (int)ReadDWord(inputStream);
blueMask = (int)ReadDWord(inputStream);
// Only supported for 32bpp BI_RGB argb
alphaMask = (int)ReadDWord(inputStream);
long csType = ReadDWord(inputStream);
int redX = ReadLong(inputStream);
int redY = ReadLong(inputStream);
int redZ = ReadLong(inputStream);
int greenX = ReadLong(inputStream);
int greenY = ReadLong(inputStream);
int greenZ = ReadLong(inputStream);
int blueX = ReadLong(inputStream);
int blueY = ReadLong(inputStream);
int blueZ = ReadLong(inputStream);
long gammaRed = ReadDWord(inputStream);
long gammaGreen = ReadDWord(inputStream);
long gammaBlue = ReadDWord(inputStream);
if (bitsPerPixel == 1) {
imageType = VERSION_4_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_4_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_4_8_BIT;
} else if (bitsPerPixel == 16) {
imageType = VERSION_4_16_BIT;
if ((int)compression == BI_RGB) {
redMask = 0x7C00;
greenMask = 0x3E0;
blueMask = 0x1F;
}
} else if (bitsPerPixel == 24) {
imageType = VERSION_4_24_BIT;
} else if (bitsPerPixel == 32) {
imageType = VERSION_4_32_BIT;
if ((int)compression == BI_RGB) {
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
}
}
properties["red_mask"] = redMask;
properties["green_mask"] = greenMask;
properties["blue_mask"] = blueMask;
properties["alpha_mask"] = alphaMask;
// Read in the palette
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries*4;
if (bitmapOffset == size) {
switch (imageType) {
case VERSION_4_1_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4;
break;
case VERSION_4_4_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4;
break;
case VERSION_4_8_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4;
break;
default:
sizeOfPalette = 0;
break;
}
bitmapOffset = size + sizeOfPalette;
}
ReadPalette(sizeOfPalette);
switch ((int)csType) {
case LCS_CALIBRATED_RGB:
// All the new fields are valid only for this case
properties["color_space"] = "LCS_CALIBRATED_RGB";
properties["redX"] = redX;
properties["redY"] = redY;
properties["redZ"] = redZ;
properties["greenX"] = greenX;
properties["greenY"] = greenY;
properties["greenZ"] = greenZ;
properties["blueX"] = blueX;
properties["blueY"] = blueY;
properties["blueZ"] = blueZ;
properties["gamma_red"] = gammaRed;
properties["gamma_green"] = gammaGreen;
properties["gamma_blue"] = gammaBlue;
// break;
throw new
Exception("Not implemented yet.");
case LCS_sRGB:
// Default Windows color space
properties["color_space"] = "LCS_sRGB";
break;
case LCS_CMYK:
properties["color_space"] = "LCS_CMYK";
// break;
throw new
Exception("Not implemented yet.");
}
} else {
properties["bmp_version"] = "BMP v. 5.x";
throw new
Exception("BMP version 5 not implemented yet.");
}
}
if (height > 0) {
// bottom up image
isBottomUp = true;
} else {
// top down image
isBottomUp = false;
height = Math.Abs(height);
}
// When number of bitsPerPixel is <= 8, we use IndexColorModel.
if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
numBands = 1;
// Create IndexColorModel from the palette.
byte[] r;
byte[] g;
byte[] b;
int sizep;
if (imageType == VERSION_2_1_BIT ||
imageType == VERSION_2_4_BIT ||
imageType == VERSION_2_8_BIT) {
sizep = palette.Length/3;
if (sizep > 256) {
sizep = 256;
}
int off;
r = new byte[sizep];
g = new byte[sizep];
b = new byte[sizep];
for (int i=0; i