import java.awt.*;
import java.awt.event.*;
import java.awt.Image.*;
import java.awt.image.*;
//import GE;              //for gif
import java.io.*;               //for gif
import java.awt.Graphics.*;
import java.lang.*;
import java.applet.*;
import java.applet.Applet.*;
import java.net.*;
import java.util.*;
import java.awt.image.BufferedImage;
//import com.sun.image.codec.jpeg.*;
//import com.sun.image.codec.jpeg.*;
import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
public class Img extends BufferedImage
 {
  int pixa[];
  Img img;
  private static final Component comp = new Component() {};
  private static final MediaTracker tracker = new MediaTracker(comp);
  private static int trackerID = 0;
  Rec rec;
  String name;
  static M parent;
  public Img(ColorModel cm,WritableRaster raster,boolean b,Hashtable h) 
   {
    super(cm,raster,b,h);
   }
  public Img(int w,int h,int type) 
   {
    super(w,h,type);
   }
  public Img(String n,int w,int h,int type) 
   {
    super(w,h,type); 
    name=n;
   }
  public static void tta(String s) { parent.tta(s); }
  public static void tta1(String s) { parent.tta1(s); }
  public void jpgEncode(String fn,double d) { jpgEncode(this,fn,d); }
  public static void jpgEncode(Image im,String fn,double d) { jpgEncode(mkImgforjpg(im),fn,d); }
  public static void jpgEncode(Image im,String fn) { jpgEncode(mkImgforjpg(im),fn,1.0); }
  public static void jpgEncode(BufferedImage img,String fn) { jpgEncode(img,fn,1.0); }
  public static void jpgEncode(BufferedImage img,String fn,double d)
   {
    if(fn.indexOf("/") ==-1) fn="images/"+fn;
    FileOutputStream fos;
    /*    try
     {
      fos = new FileOutputStream(fn);
      JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(fos);
      JPEGEncodeParam param=encoder.getDefaultJPEGEncodeParam(img);
      param.setQuality((float)d,true);
      encoder.encode(img,param);
      //encoder.encode(img);
      fos.flush();
      fos.close();
     }
    catch(FileNotFoundException e) { System.out.println(e); }
    catch(IOException ioe) { System.out.println(ioe); }
    */
   }
  public static Img mkImg(Image im) { return mkImg(im,BufferedImage.TYPE_INT_ARGB); }
  public static Img mkImgforjpg(Image im) { return mkImg(im,BufferedImage.TYPE_INT_RGB); }
  public static Img mkImg(Image im,int type)
   {
    if (waitForImage(im) == false) return null;
    if(im==null) tta("Img.mkImg im is null");
    Img img = new Img(im.getWidth(null),im.getHeight(null),type);
    img.rec= new Rec(0,0,im.getWidth(null),im.getHeight(null));
    Graphics2D g2 = img.createGraphics();
    g2.drawImage(im,null,null);
    g2.dispose();
    img.rec=setRec(img);
    return img;
   }
  public static Img mkImggy(int w,int h,int[] ia)
   {
    long[] la=new long[ia.length];
    for (int i=0;i<ia.length;i++) la[i]=ia[i];
    //for (int i=0;i<ia.length;i++) la[i] &= ;
    return mkImg(w,h,la);
   }
  public static Img mkImg(int w,int h,long[] la)
   {
    Img imga=new Img(w,h,BufferedImage.TYPE_INT_ARGB);
    int[] ia=new int[la.length];
    for (int i=0;i<la.length;i++) ia[i]=(int)la[i];
    imga.setRGB(0,0,w,h,ia,0,w);
    imga.rec= new Rec(0,0,w,h);
    return imga;
   }
  public static Img mkImg(int w,int h,int[] ia)
   {
    Img imga=new Img(w,h,BufferedImage.TYPE_INT_ARGB);
    imga.setRGB(0,0,w,h,ia,0,w);
    imga.rec= new Rec(0,0,w,h);
    return imga; 
   }
  static Rec setRec(Img im,dP dp) { return new Rec(dp,im.getWidth(null),im.getHeight(null)); }
  static Rec setRec(Img im) { return new Rec(0,0,im.getWidth(null),im.getHeight(null)); }
  public static int gopix (Img img,int x,int y)
   {
    if(img ==null) 
     {
      System.out.println("img is null");
      tta("Img.gopix  img is null");
      return 0;
     }
    return img.getRGB(x,y);
   }
  public static int[] gspix(Img img,int x,int y,int w,int h)
   {
    int[] rgbs=new int[w*h];
    img.getRGB(x,y,w,h,rgbs,0,w);
    return rgbs;
   }
  public static int[] gspix(Image im,int x,int y,int w,int h)
   {
    int[] rgbs=new int[w*h];
    mkImg(im).getRGB(x,y,w,h,rgbs,0,w);
    return rgbs;
   }
  int[] gapix(Img img)
   {
    // Get all the pixels.
    int w=img.getWidth(null);
    int h=img.getHeight(null);
    int[] rgbs=new int[w*h];
    img.getRGB(0,0,w,h,rgbs,0,w);
    return rgbs;
   }
  public static void sopix(Img img,int x, int y,int i) { img.setRGB(x,y,i); }
  public static void sopix(Img img,int x, int y,K k) 
   {
    if(img ==null)
     {
      System.out.println("libm is null");
      return;
     }
    img.setRGB(x,y,k.i);
   }
  public static void sspix(Img img,int x, int y,int w,int h,int[] ia)
   {
    img.setRGB(x,y,w,h,ia,0,w);
   }
  public static boolean waitForImage(Image im)
   {
    int id;
    synchronized(comp) { id = trackerID++; }
    tracker.addImage(im, id);
    try { tracker.waitForID(id); }
    catch (InterruptedException ie) { return false; }
    if (tracker.isErrorID(id)) return false;
    return true;
   }
  public static Img scalelib(Img imga, double scx,double scy)
   {
    if(scx ==0 || scy==0) return null;
    int w=(int)((imga.getWidth()*scx)/100);
    int h=(int)((imga.getHeight()*scy)/100);
    if (w==0 ) w=1;
    if(h==0) h=1;
    return mkImg(imga.getScaledInstance(w,h,1));
   }
  public static BufferedImage scalelib(BufferedImage imga, double scx,double scy)
   {
    int w=(int)((imga.getWidth()*scx)/100);
    int h=(int)((imga.getHeight()*scy)/100);
    //MediaTracker tracker = new MediaTracker(null);
    MediaTracker trkr = new MediaTracker(null);
    BufferedImage imgb=mkImg(imga.getScaledInstance(w,h,1));
    try
     {
      trkr.addImage(imgb,0);
      trkr.waitForID(0);
     }
    catch(InterruptedException e) { e.printStackTrace(); }
    return imgb;
   }
  public static void pngEncode(Image im,String filename)
   {
    if(filename.indexOf("/") ==-1  && filename.indexOf("\\") ==-1)
     {
      tta("Img.pngEncode adding images/");
      filename="images/"+filename;
     }
    tta("Img.pngEncode  fn:"+filename);
    byte[] pngbytes;
    //boolean encodeAlpha=false;
    boolean encodeAlpha=true;
    int filter=0;
    int pixelDepth=24;
    int compressionLevel=1;
    // Png png=new Png(im,(encodeAlpha) ? Png.ENCODE_ALPHA : Png.NO_ALPHA,filter, compressionLevel);
    Png png=new Png(im,true,filter, compressionLevel);
    try
     {
      FileOutputStream outfile = new FileOutputStream( filename );
      pngbytes = png.pngEncode();
      if (pngbytes == null) System.out.println("Null image");
      else outfile.write( pngbytes );
      outfile.flush();
      outfile.close();
     }
    catch (IOException e) { e.printStackTrace(); }
   }
  public static void gifEncode(Image im,String fn)
   {
    gifEncode(im,fn,-1,false);
   }
  public static void gifEncode(Image im,String fn,int transindex,boolean inter)
   {
    //  fn="/C:/webroot/ajlogo/html/ajlogo/version3beta/images"+fn;
    fn="/webroot/ajlogo/html/ajlogo/version3beta/images"+fn;
    //  fn="images/"+fn;
    try 
     {
      FileOutputStream fos = new FileOutputStream(fn); 
      try
       {
        GE gifen=new GE(im,fos,transindex,inter);
        gifen.encode();
       }
      catch( IOException e) { tta("Error encoding gif"); }
     }
    catch( IOException e) { tta("Error creating FileOutputStream for:"+fn); }
   }
  public static Img loadpng(String fn)
   {
    PNGReader pr = new PNGReader();
    //pr.setVerbose(true);
    // fn="/C:/webroot/ajlogo/html/ajlogo/version3beta/images"+fn;
    fn="/webroot/ajlogo/html/ajlogo/version3beta/images"+fn;
    tta("Img.loadpng   fn:"+fn);
    pr.setImageFile(fn);
    return mkImg(pr.getImage());
   }
  void ed(String name)
   {
    tta1(name+".x "+Te.Svo(rec.bl.x));
    tta1(name+".y "+Te.Svo(rec.bl.y));
    tta1(name+".bl "+Te.Svo(rec.bl));
    tta1(name+".cp "+Te.Svo(rec.cp));
   }
  // public void dofin() { this.flush(); try { finalize(); } catch (Throwable e) { } }
 }
class PNGReader extends PIV
 {
  public PNGReader()
   {
    hdrIsRead = false;
    verbose = false;
    useAlpha = false;
   }
  public int getWidth()
   {
    if(!hdrIsRead)
    getFrame();
    return width;
   }
  public int getHeight()
   {
    if(!hdrIsRead)
    getFrame();
    return height;
   }
  public Image getImage()
   {
    if(pngImage == null)
    readPNGFile();
    return pngImage;
   }
  public void playIt(Graphics g, Component component)
   {
    drawGraphics = g;
    drawComponent = component;
    if(readPNGFile() && pngImage != null)
    drawGraphics.drawImage(pngImage, 0, 0, drawComponent);
   }
  public int checkImage()
   {
    return 32;
   }
  public void setImageFile(String s)
   {
    pictureFile = new File(s);
    hdrIsRead = false;
   }
  public void setVerbose(boolean flag)
   {
    verbose = flag;
   }
  public boolean isVerbose(boolean flag)
   {
    return verbose;
   }
  public boolean readPNGFile()
   {
    if(!getInputStreams())
    return false;
    if(!readHeader(pictureBIS))
     {
      if(verbose)
      System.out.println("Error parsing file!");
      closeInputStreams();
      return false;
     }
    if(!readChunks(pictureBIS))
     {
      closeInputStreams();
      if(verbose)
      System.out.println("Error parsing file!");
      return false;
     }
    closeInputStreams();
    if(verbose)
    System.out.println("Finished reading file!");
    return true;
   }
  private boolean getFrame()
   {
    if(!getInputStreams())
    return false;
    if(!readHeader(pictureBIS))
     {
      if(verbose)
      System.out.println("Error parsing file!");
      closeInputStreams();
      return false;
     }
    else
     {
      closeInputStreams();
      return true;
     }
   }
  private boolean getInputStreams()
   {
    if(pictureFile == null || !pictureFile.exists())
    return false;
    try
     {
      pictureFIS = new FileInputStream(pictureFile);
      pictureBIS = new BufferedInputStream(pictureFIS);
     }
    catch(IOException _ex)
     {
      return false;
     }
    return true;
   }
  private void closeInputStreams()
   {
    try
     {
      if(pictureBIS != null)
      pictureBIS.close();
      if(pictureFIS != null)
       {
        pictureFIS.close();
        return;
       }
     }
    catch(IOException _ex) { }
   }
  private boolean readHeader(BufferedInputStream bufferedinputstream)
   {
    byte abyte1[] = new byte[25];
    if(bufferedinputstream == null)
    return false;
    try
     {
      byte abyte0[] = new byte[PNG_IDENTIFICATION_BYTES.length];
      fillByteBuf(bufferedinputstream, abyte0, 0, abyte0.length);
      for(int i = 0; i < abyte0.length && i < PNG_IDENTIFICATION_BYTES.length; i++)
      if(abyte0[i] != PNG_IDENTIFICATION_BYTES[i])
       {
        if(verbose)
        System.out.println("Not valid PNG file identifier!");
        return false;
       }
      fillByteBuf(bufferedinputstream, abyte1, 0, abyte1.length);
      int k = BCA.bytesLEasUINT(abyte1, 0, 4);
      if(k != 13)
       {
        if(verbose)
        System.out.println("Wrong IHDR data size!");
        return false;
       }
      for(int j = 0; j < 4; j++)
      if(abyte1[j + 4] != IHDR_CHUNK_TYPE[j])
       {
        if(verbose)
        System.out.println("File does not begin with an IHDR chunk!");
        return false;
       }
      width = BCA.bytesLEasUINT(abyte1, 8, 12);
      height = BCA.bytesLEasUINT(abyte1, 12, 16);
      bitDepth = BCA.bytesLEasUINT(abyte1, 16, 17);
      colorType = BCA.bytesLEasUINT(abyte1, 17, 18);
      compressionMethod = BCA.bytesLEasUINT(abyte1, 18, 19);
      filterMethod = BCA.bytesLEasUINT(abyte1, 19, 20);
      interlaceMethod = BCA.bytesLEasUINT(abyte1, 20, 21);
      if(verbose)
      System.out.println("IHDR, width: " + width + ", height: " + height + ", bitDepth: " + bitDepth + ", colorType: " + colorType + ", compressionMethod: " + compressionMethod + ", filterMethod: " + filterMethod + ", interlaceMethod: " + interlaceMethod);
      bytesPerPixel = 3;
      if((colorType & 0x4) > 0)
       {
        bytesPerPixel = 4;
        useAlpha = true;
       }
     }
    catch(IOException _ex)
     {
      closeInputStreams();
      return false;
     }
    hdrIsRead = true;
    return true;
   }
  private boolean readChunks(BufferedInputStream bufferedinputstream)
   {
    byte abyte0[] = new byte[8];
    byte abyte1[] = new byte[4];
    byte abyte2[] = new byte[512];
    byte abyte3[] = new byte[512];
    boolean flag = false;
    boolean flag1 = true;
    Inflater inflater = new Inflater();
    if(bufferedinputstream == null)
    return false;
    rawPixmap = new byte[width * height * bytesPerPixel];
    pixmapX = pixmapY = 0;
    int k1 = 0;
    int l2 = 0;
    byte byte0 = 0;
    try
     {
      while(!flag) 
       {
        fillByteBuf(bufferedinputstream, abyte0, 0, abyte0.length);
        int l = BCA.bytesLEasUINT(abyte0, 0, 4);
        if(verbose)
        System.out.println("Chunk data length: " + l);
        switch(abyte0[4])
         {
          case 73: // 'I'
            if(abyte0[5] == IDAT_CHUNK_TYPE[1] && abyte0[6] == IDAT_CHUNK_TYPE[2] && abyte0[7] == IDAT_CHUNK_TYPE[3])
             {
              if(verbose)
              System.out.println("IDAT chunk.");
              for(int i1 = 0; i1 < l; i1 += 512)
               {
                fillByteBuf(bufferedinputstream, abyte2, 0, Math.min(abyte2.length, l - i1));
                inflater.setInput(abyte2, 0, Math.min(abyte2.length, l - i1));
                while(!inflater.needsInput()) 
                try
                 {
                  int j1 = inflater.inflate(abyte3);
                  for(int i = 0; i < j1; i++)
                  if(flag1)
                   {
                    byte0 = abyte3[i];
                    flag1 = false;
                   }
                  else
                  if(k1 == width * bytesPerPixel)
                   {
                    pixmapX = 0;
                    pixmapY++;
                    byte0 = abyte3[i];
                    k1 = 0;
                   }
                  else
                   {
                    switch(k1 % bytesPerPixel)
                     {
                      case 0: // '\0'
                        int l1 = getFltrValue(byte0, abyte3[i] & 0xff, rawPixmap, l2);
                        rawPixmap[l2++] = (byte)(l1 & 0xff);
                      break;
                      case 1: // '\001'
                        int i2 = getFltrValue(byte0, abyte3[i] & 0xff, rawPixmap, l2);
                        rawPixmap[l2++] = (byte)(i2 & 0xff);
                      break;
                      case 2: // '\002'
                        int j2 = getFltrValue(byte0, abyte3[i] & 0xff, rawPixmap, l2);
                        rawPixmap[l2++] = (byte)(j2 & 0xff);
                      break;
                      case 3: // '\003'
                        int k2 = getFltrValue(byte0, abyte3[i] & 0xff, rawPixmap, l2);
                        rawPixmap[l2++] = (byte)(k2 & 0xff);
                      break;
                     }
                    if(k1 % bytesPerPixel == bytesPerPixel - 1)
                    pixmapX++;
                    k1++;
                   }
                 }
                catch(DataFormatException dataformatexception)
                 {
                  if(verbose)
                  System.out.println("DataFormatException: " + dataformatexception);
                  return false;
                 }
               }
              break;
             }
            if(abyte0[5] != IEND_CHUNK_TYPE[1] || abyte0[6] != IEND_CHUNK_TYPE[2] || abyte0[7] != IEND_CHUNK_TYPE[3])
            break;
            if(verbose)
            System.out.println("IEND chunk.");
            flag = true;
            break;
            default:
              fillByteBuf(bufferedinputstream, new byte[l], 0, l);
              if(verbose)
              System.out.println("Unknown chunk: " + new String(abyte0, 4, 4));
            break;
           }
          fillByteBuf(bufferedinputstream, abyte1, 0, abyte1.length);
         }
       }
      catch(IOException ioexception)
       {
        if(verbose)
        System.out.println("IOException: " + ioexception);
        closeInputStreams();
        return false;
       }
      int ai[] = new int[width * height];
      int j = 0;
      for(int k = 0; j < width * height; k += bytesPerPixel)
       {
        if(useAlpha)
        ai[j] = (rawPixmap[k] & 0xff) << 16 | (rawPixmap[k + 1] & 0xff) << 8 | rawPixmap[k + 2] & 0xff | (rawPixmap[k + 3] & 0xff) << 24;
        else
        ai[j] = 0xff000000 | (rawPixmap[k] & 0xff) << 16 | (rawPixmap[k + 1] & 0xff) << 8 | rawPixmap[k + 2] & 0xff;
        j++;
       }
      pngImage = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(width, height, ai, 0, width));
      return true;
     }
    private int getFltrValue(int i, int j, byte abyte0[], int k)
     {
      int k1 = k - bytesPerPixel;
      int l;
      if(pixmapX <= 0)
      l = 0;
      else
      l = abyte0[k1] & 0xff;
      k1 = k - bytesPerPixel * width;
      int j1;
      if(pixmapY <= 0)
      j1 = 0;
      else
      j1 = abyte0[k1] & 0xff;
      k1 -= bytesPerPixel;
      int i1;
      if(pixmapX <= 0 || pixmapY <= 0)
      i1 = 0;
      else
      i1 = abyte0[k1] & 0xff;
      switch(i)
       {
        case 0: // '\0'
          return j;
        case 1: // '\001'
          return (j & 0xff) + l & 0xff;
        case 2: // '\002'
          return (j & 0xff) + j1 & 0xff;
        case 3: // '\003'
          return (j & 0xff) + (l + j1) / 2 & 0xff & 0xff;
        case 4: // '\004'
          return (j & 0xff) + paethPredictor(l, j1, i1) & 0xff & 0xff;
         }
        return j;
       }
      private int paethPredictor(int i, int j, int k)
       {
        int l = (i + j) - k;
        int i1 = Math.abs(l - i);
        int j1 = Math.abs(l - j);
        int k1 = Math.abs(l - k);
        if(i1 <= j1 && i1 <= k1)
        return i;
        if(j1 <= k1)
        return j;
        else
        return k;
       }
      private void fillByteBuf(InputStream inputstream, byte abyte0[], int i, int j)
      throws IOException
       {
        int k;
        for(; j > 0; j -= k)
         {
          if((k = inputstream.read(abyte0, i, j)) == -1)
          throw new IOException("Unexpected EOF");
          i += k;
         }
       }
      private final byte PNG_IDENTIFICATION_BYTES[] = 
       {
        -119, 80, 78, 71, 13, 10, 26, 10
       }
      ;
      private final static int CHUNK_LENGTH_SIZE = 4;
      private final static int CHUNK_TYPE_SIZE = 4;
      private final static int CHUNK_CRC_SIZE = 4;
      private final static int IHDR_DATA_SIZE = 13;
      private final static int INFLATE_BUF_SIZE = 512;
      private final static byte COLOR_TYPE_USE_ALPHA_CHANNEL = 4;
      private final static byte NO_FILTERING = 0;
      private final static byte SUB_FILTER = 1;
      private final static byte UP_FILTER = 2;
      private final static byte AVERAGE_FILTER = 3;
      private final static byte PAETH_FILTER = 4;
      private final static byte IHDR_CHUNK_TYPE[] = 
       {
        73, 72, 68, 82
       }
      ;
      private final byte IDAT_CHUNK_TYPE[] = 
       {
        73, 68, 65, 84
       }
      ;
      private final byte IEND_CHUNK_TYPE[] = 
       {
        73, 69, 78, 68
       }
      ;
      private File pictureFile;
      private FileInputStream pictureFIS;
      private BufferedInputStream pictureBIS;
      private Image pngImage;
      private boolean verbose;
      private int width;
      private int height;
      private int bitDepth;
      private int colorType;
      private int compressionMethod;
      private int filterMethod;
      private int interlaceMethod;
      private int version;
      private Graphics drawGraphics;
      private Component drawComponent;
      private boolean hdrIsRead;
      private byte rawPixmap[];
      private int pixmapX;
      private int pixmapY;
      private int bytesPerPixel;
      private boolean useAlpha;
     }
    class BCA
     {
      public static int bytesLEasUINT(byte abyte0[], int i, int j)
       {
        int l = abyte0[i] & 0xff;
        for(int k = i + 1; k < abyte0.length && k < j; k++)
        l = l << 8 | abyte0[k] & 0xff;
        return l;
       }
      public static int bytesLEasINT(byte abyte0[], int i, int j)
       {
        boolean flag = false;
        if((abyte0[i] & 0x80) != 0)
        flag = true;
        abyte0[i] &= 0x7f;
        int k = bytesLEasUINT(abyte0, i, j);
        if(flag)
         {
          int l = (int)Math.pow(2D, (j - i) * 8 - 1);
          k -= l;
         }
        return k;
       }
      public static void ulongAsBytesBE(long l, byte abyte0[], int i, int j)
       {
        int k = j - 1;
        for(int i1 = 0; k >= i; i1 += 8)
         {
          abyte0[k] = (byte)(int)(l >> i1 & 255L);
          k--;
         }
       }
      public static void uintAsBytesBE(int i, byte abyte0[], int j, int k)
       {
        ulongAsBytesBE(i, abyte0, j, k);
       }
      public static void uintAsBytesLE(int i, byte abyte0[], int j, int k)
       {
        int l = j;
        for(int i1 = 0; l < k; i1 += 8)
         {
          abyte0[l] = (byte)(i >> i1 & 0xff);
          l++;
         }
       }
      public static void intAsBytesLE(int i, byte abyte0[], int j, int k)
       {
        if(i < 0)
         {
          int l = -i;
          int i1 = (int)Math.pow(2D, (k - j) * 8 - 1);
          uintAsBytesLE(i1 - l, abyte0, j, k);
          abyte0[k - 1] |= 0x80;
          return;
         }
        else
         {
          uintAsBytesLE(i, abyte0, j, k);
          return;
         }
       }
      public BCA()
       {
       }
     }
    abstract class PIV
     {
      public abstract int getWidth();
      public abstract int getHeight();
      public void playIt(Graphics g)
       {
        playIt(g, null);
       }
      public abstract void playIt(Graphics g, Component component);
      public void playIt(Image image, Component component)
       {
        playIt(image.getGraphics(), component);
       }
      public abstract int checkImage();
      public PIV()
       {
       }
     }
