context: using System;
  using System.IO;
  using System.Net;
  using System.Text;
  using System.Runtime.CompilerServices;
  using System.Collections;
  using System.util;
  using System.Reflection;
  
  using iTextSharp.text.pdf;
  using iTextSharp.text.pdf.codec;
  
  /*
   * $Id: Image.cs,v 1.17 2007/01/24 17:42:16 psoares33 Exp $
   * $Name:  $
   *
   * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie.
   *
   * 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/
   */
  
  namespace iTextSharp.text {
      /// <summary>
      /// An Image is the representation of a graphic element (JPEG, PNG or GIF)
      /// that has to be inserted into the document
      /// </summary>
      /// <seealso cref="T:iTextSharp.text.Element"/>
      /// <seealso cref="T:iTextSharp.text.Rectangle"/>
      public abstract class Image : Rectangle, IElement {
      
          // static membervariables (concerning the presence of borders)
      
          /// <summary> this is a kind of image Element. </summary>
          public const int DEFAULT = 0;
      
          /// <summary> this is a kind of image Element. </summary>
          public const int RIGHT_ALIGN = 2;
      
          /// <summary> this is a kind of image Element. </summary>
          public const int LEFT_ALIGN = 0;
      
          /// <summary> this is a kind of image Element. </summary>
          public const int MIDDLE_ALIGN = 1;
      
          /// <summary> this is a kind of image Element. </summary>
          public const int TEXTWRAP = 4;
      
          /// <summary> this is a kind of image Element. </summary>
          public const int UNDERLYING = 8;
      
          /// <summary> This represents a coordinate in the transformation matrix. </summary>
          public const int AX = 0;
      
          /// <summary> This represents a coordinate in the transformation matrix. </summary>
          public const int AY = 1;
      
          /// <summary> This represents a coordinate in the transformation matrix. </summary>
          public const int BX = 2;
      
          /// <summary> This represents a coordinate in the transformation matrix. </summary>
          public const int BY = 3;
      
          /// <summary> This represents a coordinate in the transformation matrix. </summary>
          public const int CX = 4;
      
          /// <summary> This represents a coordinate in the transformation matrix. </summary>
          public const int CY = 5;
      
          /// <summary> This represents a coordinate in the transformation matrix. </summary>
          public const int DX = 6;
      
          /// <summary> This represents a coordinate in the transformation matrix. </summary>
          public const int DY = 7;
      
          /** type of image */
          public const int ORIGINAL_NONE = 0;
  
          /** type of image */
          public const int ORIGINAL_JPEG = 1;
  
          /** type of image */
          public const int ORIGINAL_PNG = 2;
  
          /** type of image */
          public const int ORIGINAL_GIF = 3;
  
          /** type of image */
          public const int ORIGINAL_BMP = 4;
  
          /** type of image */
          public const int ORIGINAL_TIFF = 5;
  
          /** type of image */
          public const int ORIGINAL_WMF = 6;
  
          /** Image color inversion */
          protected bool invert = false;
      
          /// <summary> The imagetype. </summary>
          protected int type;
      
          /// <summary> The URL of the image. </summary>
          protected Uri url;
      
          /// <summary> The raw data of the image. </summary>
          protected byte[] rawData;
      
          /// <summary> The template to be treated as an image. </summary>
          protected PdfTemplate[] template = new PdfTemplate[1];
      
          /// <summary> The alignment of the Image. </summary>
          protected int alignment;
      
          /// <summary> Text that can be shown instead of the image. </summary>
          protected string alt;
      
          /// <summary> This is the absolute X-position of the image. </summary>
          protected float absoluteX = float.NaN;
      
          /// <summary> This is the absolute Y-position of the image. </summary>
          protected float absoluteY = float.NaN;
      
          /// <summary> This is the width of the image without rotation. </summary>
          protected float plainWidth;
      
          /// <summary> This is the width of the image without rotation. </summary>
          protected float plainHeight;
      
          /// <summary> This is the scaled width of the image taking rotation into account. </summary>
          protected float scaledWidth;
      
          /// <summary> This is the original height of the image taking rotation into account. </summary>
          protected float scaledHeight;
      
          /// <summary> This is the rotation of the image. </summary>
          protected new float rotation;
      
          /// <summary> this is the colorspace of a jpeg-image. </summary>
          protected int colorspace = -1;
      
          /// <summary> this is the bits per component of the raw image. It also flags a CCITT image.</summary>
          protected int bpc = 1;
      
          /// <summary> this is the transparency information of the raw image</summary>
          protected int[] transparency;
      
          // for the moment these variables are only used for Images in class Table
          // code contributed by Pelikan Stephan
          /** the indentation to the left. */
          protected float indentationLeft = 0;
  
          /** the indentation to the right. */
          protected float indentationRight = 0;
          // serial stamping
      
          protected long mySerialId = GetSerialId();
      
          static object serialId = 0L;
  
          /// <summary> Holds value of property dpiX. </summary>
          protected int dpiX = 0;
      
          /// <summary> Holds value of property dpiY. </summary>
          protected int dpiY = 0;
      
          protected bool mask = false;
      
          protected Image imageMask;
      
          /// <summary> Holds value of property interpolation. </summary>
          protected bool interpolation;
      
          /// <summary> if the annotation is not null the image will be clickable. </summary>
          protected Annotation annotation = null;
  
          /// <summary> ICC Profile attached </summary>
          protected ICC_Profile profile = null;
      
          /** Holds value of property deflated. */
          protected bool deflated = false;
  
          private PdfDictionary additional = null;
  
          /** Holds value of property smask. */
          private bool smask;
  
          /** Holds value of property XYRatio. */
          private float xyRatio = 0;
  
          /** Holds value of property originalType. */
          protected int originalType = ORIGINAL_NONE;
  
          /** Holds value of property originalData. */
          protected byte[] originalData;
  
          /** The spacing before the image. */
          protected float spacingBefore;
  
          /** The spacing after the image. */
          protected float spacingAfter;
  
          /**
          * Holds value of property widthPercentage.
          */
          private float widthPercentage = 100;
  
          protected IPdfOCG layer;
  
          private static byte[] skipBuffer = new byte[4096];
  
          /**
          * Holds value of property initialRotation.
          */
          private float initialRotation;
          
          private static String excUri = " <>#%\"{}[]|\\\u005E\u0060";
          private static String[] excUriEsc = {"%20", "%3C", "%3E", "%23", "%25", "%22", "%7B", "%7D", "%5B", "%5D", "%7C", "%5C", "%5E", "%60"};
  
          private PdfIndirectReference directReference;
  
          // constructors
      
          /// <summary>
          /// Constructs an Image-object, using an url.
          /// </summary>
          /// <param name="url">the URL where the image can be found.</param>
          public Image(Uri url) : base(0, 0) {
              this.url = url;
              this.alignment = DEFAULT;
              rotation = 0;
          }
  
          /// <summary>
          /// Constructs an Image-object, using an url.
          /// </summary>
          /// <param name="image">another Image object.</param>
          protected Image(Image image) : base(image) {
              this.type = image.type;
              this.url = image.url;
              this.alignment = image.alignment;
              this.alt = image.alt;
              this.absoluteX = image.absoluteX;
              this.absoluteY = image.absoluteY;
              this.plainWidth = image.plainWidth;
              this.plainHeight = image.plainHeight;
              this.scaledWidth = image.scaledWidth;
              this.scaledHeight = image.scaledHeight;
              this.rotation = image.rotation;
              this.colorspace = image.colorspace;
              this.rawData = image.rawData;
              this.template = image.template;
              this.bpc = image.bpc;
              this.transparency = image.transparency;
              this.mySerialId = image.mySerialId;
              this.invert = image.invert;
              this.dpiX = image.dpiX;
              this.dpiY = image.dpiY;
              this.mask = image.mask;
              this.imageMask = image.imageMask;
              this.interpolation = image.interpolation;
              this.annotation = image.annotation;
              this.profile = image.profile;
              this.deflated = image.deflated;
              this.additional = image.additional;
              this.smask = image.smask;
              this.XYRatio = image.XYRatio;
              this.originalData = image.originalData;
              this.originalType = image.originalType;
              this.spacingAfter = image.spacingAfter;
              this.spacingBefore = image.spacingBefore;
              this.widthPercentage = image.widthPercentage;
              this.layer = image.layer;
              this.initialRotation = image.initialRotation;
              this.directReference = image.directReference;
          }
      
          /// <summary>
          /// Gets an instance of an Image.
          /// </summary>
          /// <param name="image">an Image</param>
          /// <returns>an object of type Gif, Jpeg or Png</returns>
          public static Image GetInstance(Image image) {
              if (image == null)
                  return null;
              return (Image)image.GetType().GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] {typeof(Image)}, null).Invoke(new object[] {image});
          }
  
          /// <summary>
          /// Gets an instance of an Image.
          /// </summary>
          /// <param name="url">an URL</param>
          /// <returns>an object of type Gif, Jpeg or Png</returns>
          public static Image GetInstance(Uri url) {
              Stream istr = null;
              try {
  //NETCF does not know fileWebRequest (file://...)
  #if !NETCF
                  WebRequest w = WebRequest.Create(url);
                  istr = w.GetResponse().GetResponseStream();
  #else
                  istr = new FileStream(url.LocalPath, FileMode.Open);
  #endif
                  int c1 = istr.ReadByte();
                  int c2 = istr.ReadByte();
                  int c3 = istr.ReadByte();
                  int c4 = istr.ReadByte();
                  istr.Close();
  
                  istr = null;
                  if (c1 == 'G' && c2 == 'I' && c3 == 'F') {
                      GifImage gif = new GifImage(url);
                      Image img = gif.GetImage(1);
                      return img;
                  }
                  if (c1 == 0xFF && c2 == 0xD8) {
                      return new Jpeg(url);
                  }
                  if (c1 == PngImage.PNGID[0] && c2 == PngImage.PNGID[1]
                          && c3 == PngImage.PNGID[2] && c4 == PngImage.PNGID[3]) {
                      Image img = PngImage.GetImage(url);
                      return img;
                  }
                  if (c1 == 0xD7 && c2 == 0xCD) {
                      Image img = new ImgWMF(url);
                      return img;
                  }
                  if (c1 == 'B' && c2 == 'M') {
                      Image img = BmpImage.GetImage(url);
                      return img;
                  }
                  if ((c1 == 'M' && c2 == 'M' && c3 == 0 && c4 == 42)
                          || (c1 == 'I' && c2 == 'I' && c3 == 42 && c4 == 0)) {
                      RandomAccessFileOrArray ra = null;
                      try
                      {
                          if (url.IsFile)
                          {
                              String file = url.LocalPath;
                              ra = new RandomAccessFileOrArray(file);
                          }
                          else
                              ra = new RandomAccessFileOrArray(url);
                          Image img = TiffImage.GetTiffImage(ra, 1);
                          img.url = url;
                          return img;
                      }
                      catch (InvalidCastException ix)
                      {
                          System.Diagnostics.Debug.WriteLine("InvalidCastException in TIFF adding: " + ix.Message + ":" + ix.StackTrace);
                      }
                      catch (Exception ex)
                      {
                          System.Diagnostics.Debug.WriteLine("Exception in TIFF adding:" + ex.Message + ":" + ex.InnerException.Message);
                      }
                      finally {
                          if (ra != null)
                              ra.Close();
                      }
  
                  }
                  throw new IOException(url.ToString()
                          + " is not a recognized imageformat.");
              } finally {
                  if (istr != null) {
                      istr.Close();
                  }
              }
          }
  
          /// <summary>
          /// Gets an instance of an Image.
          /// </summary>
          /// <param name="url">an URL</param>
          /// <returns>an object of type Gif, Jpeg or Png</returns>
          public static Image GetLocalInstance(string sFileName)
          {
              Stream istr = null;
              try
              {
  #if !NETCF
                  WebRequest w = WebRequest.Create(url);
                  istr = w.GetResponse().GetResponseStream();
  #else
                  istr = new FileStream(sFileName, FileMode.Open);
  #endif
                  //istr = w.GetResponse().GetResponseStream();
                  int c1 = istr.ReadByte();
                  int c2 = istr.ReadByte();
                  int c3 = istr.ReadByte();
                  int c4 = istr.ReadByte();
                  istr.Close();
  
                  istr = null;
                  if (c1 == 'G' && c2 == 'I' && c3 == 'F')
                  {
                      GifImage gif = new GifImage(sFileName);
                      Image img = gif.GetImage(1);
                      return img;
                  }
                  if (c1 == 0xFF && c2 == 0xD8)
                  {
                      return new Jpeg(sFileName);
                  }
                  if (c1 == PngImage.PNGID[0] && c2 == PngImage.PNGID[1]
                          && c3 == PngImage.PNGID[2] && c4 == PngImage.PNGID[3])
                  {
                      Image img = PngImage.GetImage(sFileName);
                      return img;
                  }
                  if (c1 == 0xD7 && c2 == 0xCD)
                  {
                      Image img = new ImgWMF(sFileName);
                      return img;
                  }
                  if (c1 == 'B' && c2 == 'M')
                  {
                      Image img = BmpImage.GetImage(sFileName);
                      return img;
                  }
                  if ((c1 == 'M' && c2 == 'M' && c3 == 0 && c4 == 42)
                          || (c1 == 'I' && c2 == 'I' && c3 == 42 && c4 == 0))
                  {
                      RandomAccessFileOrArray ra = null;
                      try
                      {
                              ra = new RandomAccessFileOrArray(sFileName);
                          Image img = TiffImage.GetTiffImage(ra, 1);
                          img.url = new Uri(sFileName);
                          return img;
                      }
                      finally
                      {
                          if (ra != null)
                              ra.Close();
                      }
  
                  }
                  throw new IOException(sFileName.ToString()
                          + " is not a recognized imageformat.");
              }
              finally
              {
                  if (istr != null)
                  {
                      istr.Close();
                  }
              }
          }
  
          public static Image GetInstance(Stream s) {
              byte[] a = RandomAccessFileOrArray.InputStreamToArray(s);
              s.Close();
              return GetInstance(a);
          }
  
          /// <summary>
          /// Gets an instance of an Image.
          /// </summary>
          /// <param name="img">a byte array</param>
          /// <returns>an object of type Gif, Jpeg or Png</returns>
          public static Image GetInstance(byte[] imgb) {
              int c1 = imgb[0];
              int c2 = imgb[1];
              int c3 = imgb[2];
              int c4 = imgb[3];
  
              if (c1 == 'G' && c2 == 'I' && c3 == 'F') {
                  GifImage gif = new GifImage(imgb);
                  return gif.GetImage(1);
              }
              if (c1 == 0xFF && c2 == 0xD8) {
                  return new Jpeg(imgb);
              }
              if (c1 == PngImage.PNGID[0] && c2 == PngImage.PNGID[1]
                      && c3 == PngImage.PNGID[2] && c4 == PngImage.PNGID[3]) {
                  return PngImage.GetImage(imgb);
              }
              if (c1 == 0xD7 && c2 == 0xCD) {
                  return new ImgWMF(imgb);
              }
              if (c1 == 'B' && c2 == 'M') {
                  return BmpImage.GetImage(imgb);
              }
              if ((c1 == 'M' && c2 == 'M' && c3 == 0 && c4 == 42)
                      || (c1 == 'I' && c2 == 'I' && c3 == 42 && c4 == 0)) {
                  RandomAccessFileOrArray ra = null;
                  try {
                      ra = new RandomAccessFileOrArray(imgb);
                      Image img = TiffImage.GetTiffImage(ra, 1);
                      if (img.OriginalData == null)
                          img.OriginalData = imgb;
  
                      return img;
                  } finally {
                      if (ra != null)
                          ra.Close();
                  }
  
              }
              throw new IOException("The byte array is not a recognized imageformat.");
          }
          /// <summary>
          /// Converts a .NET image to a Native(PNG, JPG, GIF, WMF) image
          /// </summary>
          /// <param name="image"></param>
          /// <param name="?"></param>
          /// <returns></returns>
          public static Image GetInstance(System.Drawing.Image image, System.Drawing.Imaging.ImageFormat format) {
              MemoryStream ms = new MemoryStream();
              image.Save(ms, format);
              return GetInstance(ms.ToArray());
          }
      
          /// <summary>
          /// Gets an instance of an Image from a System.Drwaing.Image.
          /// </summary>
          /// <param name="image">the System.Drawing.Image to convert</param>
          /// <param name="color">
          /// if different from null the transparency
          /// pixels are replaced by this color
          /// </param>
          /// <param name="forceBW">if true the image is treated as black and white</param>
          /// <returns>an object of type ImgRaw</returns>
          public static Image GetInstance(System.Drawing.Image image, Color color, bool forceBW) {
              System.Drawing.Bitmap bm = (System.Drawing.Bitmap)image;
              int w = bm.Width;
              int h = bm.Height;
              int pxv = 0;
              if (forceBW) {
                  int byteWidth = (w / 8) + ((w & 7) != 0 ? 1 : 0);
                  byte[] pixelsByte = new byte[byteWidth * h];
              
                  int index = 0;
                  int size = h * w;
                  int transColor = 1;
                  if (color != null) {
                      transColor = (color.R + color.G + color.B < 384) ? 0 : 1;
                  }
                  int[] transparency = null;
                  int cbyte = 0x80;
                  int wMarker = 0;
                  int currByte = 0;
                  if (color != null) {
                      for (int j = 0; j < h; j++) {
                          for (int i = 0; i < w; i++) {
                              int alpha = bm.GetPixel(i, j).A;
                              if (alpha < 250) {
                                  if (transColor == 1)
                                      currByte |= cbyte;
                              }
                              else {
                                  if ((bm.GetPixel(i, j).ToArgb() & 0x888) != 0)
                                      currByte |= cbyte;
                              }
                              cbyte >>= 1;
                              if (cbyte == 0 || wMarker + 1 >= w) {
                                  pixelsByte[index++] = (byte)currByte;
                                  cbyte = 0x80;
                                  currByte = 0;
                              }
                              ++wMarker;
                              if (wMarker >= w)
                                  wMarker = 0;
                          }
                      }
                  }
                  else {
                      for (int j = 0; j < h; j++) {
                          for (int i = 0; i < w; i++) {
                              if (transparency == null) {
                                  int alpha = bm.GetPixel(i, j).A;
                                  if (alpha == 0) {
                                      transparency = new int[2];
                                      transparency[0] = transparency[1] = ((bm.GetPixel(i, j).ToArgb() & 0x888) != 0) ? 1 : 0;
                                  }
                              }
                              if ((bm.GetPixel(i, j).ToArgb() & 0x888) != 0)
                                  currByte |= cbyte;
                              cbyte >>= 1;
                              if (cbyte == 0 || wMarker + 1 >= w) {
                                  pixelsByte[index++] = (byte)currByte;
                                  cbyte = 0x80;
                                  currByte = 0;
                              }
                              ++wMarker;
                              if (wMarker >= w)
                                  wMarker = 0;
                          }
                      }
                  }
                  return Image.GetInstance(w, h, 1, 1, pixelsByte, transparency);
              }
              else {
                  byte[] pixelsByte = new byte[w * h * 3];
                  byte[] smask = null;
              
                  int index = 0;
                  int size = h * w;
                  int red = 255;
                  int green = 255;
                  int blue = 255;
                  if (color != null) {
                      red = color.R;
                      green = color.G;
                      blue = color.B;
                  }
                  int[] transparency = null;
                  if (color != null) {
                      for (int j = 0; j < h; j++) {
                          for (int i = 0; i < w; i++) {
                              int alpha = (bm.GetPixel(i, j).ToArgb() >> 24) & 0xff;
  
gt:                             if (alpha < 250) {