Package org.apache.sanselan.formats.bmp

Source Code of org.apache.sanselan.formats.bmp.BmpImageParser

/*
* 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.bmp;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.apache.sanselan.FormatCompliance;
import org.apache.sanselan.ImageFormat;
import org.apache.sanselan.ImageInfo;
import org.apache.sanselan.ImageParser;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.ImageWriteException;
import org.apache.sanselan.common.BinaryOutputStream;
import org.apache.sanselan.common.IImageMetadata;
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.formats.bmp.pixelparsers.PixelParser;
import org.apache.sanselan.formats.bmp.pixelparsers.PixelParserBitFields;
import org.apache.sanselan.formats.bmp.pixelparsers.PixelParserRgb;
import org.apache.sanselan.formats.bmp.pixelparsers.PixelParserRle;
import org.apache.sanselan.formats.bmp.writers.BMPWriter;
import org.apache.sanselan.formats.bmp.writers.BMPWriterPalette;
import org.apache.sanselan.formats.bmp.writers.BMPWriterRGB;
import org.apache.sanselan.palette.PaletteFactory;
import org.apache.sanselan.palette.SimplePalette;
import org.apache.sanselan.util.Debug;
import org.apache.sanselan.util.ParamMap;

public class BmpImageParser extends ImageParser
{

  public BmpImageParser()
  {
    super.setByteOrder(BYTE_ORDER_INTEL);
  }

  public String getName()
  {
    return "Bmp-Custom";
  }

  public String getDefaultExtension()
  {
    return DEFAULT_EXTENSION;
  }

  private static final String DEFAULT_EXTENSION = ".bmp";

  private static final String ACCEPTED_EXTENSIONS[] = { DEFAULT_EXTENSION, };

  protected String[] getAcceptedExtensions()
  {
    return ACCEPTED_EXTENSIONS;
  }

  protected ImageFormat[] getAcceptedTypes()
  {
    return new ImageFormat[] { ImageFormat.IMAGE_FORMAT_BMP, //
    };
  }

  private static final byte BMP_HEADER_SIGNATURE[] = { 0x42, 0x4d, };

  private BmpHeaderInfo readBmpHeaderInfo(InputStream is,
      FormatCompliance formatCompliance, boolean verbose)
      throws ImageReadException, IOException
  {
    byte identifier1 = readByte("Identifier1", is, "Not a Valid BMP File");
    byte identifier2 = readByte("Identifier2", is, "Not a Valid BMP File");

    if (formatCompliance != null)
    {
      formatCompliance.compare_bytes("Signature", BMP_HEADER_SIGNATURE,
          new byte[] { identifier1, identifier2, });
    }

    int fileSize = read4Bytes("File Size", is, "Not a Valid BMP File");
    int reserved = read4Bytes("Reserved", is, "Not a Valid BMP File");
    int bitmapDataOffset = read4Bytes("Bitmap Data Offset", is,
        "Not a Valid BMP File");

    int bitmapHeaderSize = read4Bytes("Bitmap Header Size", is,
        "Not a Valid BMP File");
    int width = read4Bytes("Width", is, "Not a Valid BMP File");
    int height = read4Bytes("Height", is, "Not a Valid BMP File");
    int planes = read2Bytes("Planes", is, "Not a Valid BMP File");
    int bitsPerPixel = read2Bytes("Bits Per Pixel", is,
        "Not a Valid BMP File");
    int compression = read4Bytes("Compression", is, "Not a Valid BMP File");
    int bitmapDataSize = read4Bytes("Bitmap Data Size", is,
        "Not a Valid BMP File");
    int hResolution = read4Bytes("HResolution", is, "Not a Valid BMP File");
    int vResolution = read4Bytes("VResolution", is, "Not a Valid BMP File");
    int colorsUsed = read4Bytes("ColorsUsed", is, "Not a Valid BMP File");
    int colorsImportant = read4Bytes("ColorsImportant", is,
        "Not a Valid BMP File");

    if (verbose)
    {
      this.debugNumber("identifier1", identifier1, 1);
      this.debugNumber("identifier2", identifier2, 1);
      this.debugNumber("fileSize", fileSize, 4);
      this.debugNumber("reserved", reserved, 4);
      this.debugNumber("bitmapDataOffset", bitmapDataOffset, 4);
      this.debugNumber("bitmapHeaderSize", bitmapHeaderSize, 4);
      this.debugNumber("width", width, 4);
      this.debugNumber("height", height, 4);
      this.debugNumber("planes", planes, 2);
      this.debugNumber("bitsPerPixel", bitsPerPixel, 2);
      this.debugNumber("compression", compression, 4);
      this.debugNumber("bitmapDataSize", bitmapDataSize, 4);
      this.debugNumber("hResolution", hResolution, 4);
      this.debugNumber("vResolution", vResolution, 4);
      this.debugNumber("colorsUsed", colorsUsed, 4);
      this.debugNumber("colorsImportant", colorsImportant, 4);
    }

    BmpHeaderInfo result = new BmpHeaderInfo(identifier1, identifier2,
        fileSize, reserved, bitmapDataOffset, bitmapHeaderSize, width,
        height, planes, bitsPerPixel, compression, bitmapDataSize,
        hResolution, vResolution, colorsUsed, colorsImportant);
    return result;
  }

  private static final int BI_RGB = 0;
  private static final int BI_RLE4 = 2;
  private static final int BI_RLE8 = 1;
  private static final int BI_BITFIELDS = 3;

  private byte[] getRLEBytes(InputStream is, int RLESamplesPerByte)
      throws ImageReadException, IOException
  {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    // this.setDebug(true);

    boolean done = false;
    while (!done)
    {
      int a = 0xff & this.readByte("RLE a", is, "BMP: Bad RLE");
      baos.write(a);
      int b = 0xff & this.readByte("RLE b", is, "BMP: Bad RLE");
      baos.write(b);

      if (a == 0)
      {
        switch (b)
        {
        case 0: // EOL
          break;
        case 1: // EOF
          // System.out.println("xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
          // );
          done = true;
          break;
        case 2: {
          // System.out.println("xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
          // );
          int c = 0xff & this.readByte("RLE c", is, "BMP: Bad RLE");
          baos.write(c);
          int d = 0xff & this.readByte("RLE d", is, "BMP: Bad RLE");
          baos.write(d);

        }
          break;
        default: {
          int size = b / RLESamplesPerByte;
          if ((b % RLESamplesPerByte) > 0)
            size++;
          if ((size % 2) != 0)
            size++;

          // System.out.println("b: " + b);
          // System.out.println("size: " + size);
          // System.out.println("RLESamplesPerByte: " +
          // RLESamplesPerByte);
          // System.out.println("xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
          // );
          byte bytes[] = this.readByteArray("bytes", size, is,
              "RLE: Absolute Mode");
          baos.write(bytes);
        }
          break;
        }
      }
    }

    return baos.toByteArray();
  }

  private ImageContents readImageContents(InputStream is,
      FormatCompliance formatCompliance, boolean verbose)
      throws ImageReadException, IOException
  {
    BmpHeaderInfo bhi = readBmpHeaderInfo(is, formatCompliance, verbose);

    int colorTableSize = bhi.colorsUsed;
    if (colorTableSize == 0)
      colorTableSize = (1 << bhi.bitsPerPixel);

    if (verbose)
    {
      this.debugNumber("ColorsUsed", bhi.colorsUsed, 4);
      this.debugNumber("BitsPerPixel", bhi.bitsPerPixel, 4);
      this.debugNumber("ColorTableSize", colorTableSize, 4);
      this.debugNumber("bhi.colorsUsed", bhi.colorsUsed, 4);
      this.debugNumber("Compression", bhi.compression, 4);
    }

    int paletteLength;
    int rleSamplesPerByte = 0;
    boolean rle = false;

    switch (bhi.compression)
    {
    case BI_RGB:
      if (verbose)
        System.out.println("Compression: BI_RGB");
      if (bhi.bitsPerPixel <= 8)
        paletteLength = 4 * colorTableSize;
      else
        paletteLength = 0;
      // BytesPerPaletteEntry = 0;
      // System.out.println("Compression: BI_RGBx2: " + bhi.BitsPerPixel);
      // System.out.println("Compression: BI_RGBx2: " + (bhi.BitsPerPixel
      // <= 16));
      break;

    case BI_RLE4:
      if (verbose)
        System.out.println("Compression: BI_RLE4");
      paletteLength = 4 * colorTableSize;
      rleSamplesPerByte = 2;
      // ExtraBitsPerPixel = 4;
      rle = true;
      // // BytesPerPixel = 2;
      // // BytesPerPaletteEntry = 0;
      break;
    //
    case BI_RLE8:
      if (verbose)
        System.out.println("Compression: BI_RLE8");
      paletteLength = 4 * colorTableSize;
      rleSamplesPerByte = 1;
      // ExtraBitsPerPixel = 8;
      rle = true;
      // BytesPerPixel = 2;
      // BytesPerPaletteEntry = 0;
      break;
    //
    case BI_BITFIELDS:
      if (verbose)
        System.out.println("Compression: BI_BITFIELDS");
      paletteLength = 3 * 4; // TODO: is this right? are the masks always
      // LONGs?
      // BytesPerPixel = 2;
      // BytesPerPaletteEntry = 4;
      break;

    default:
      throw new ImageReadException("BMP: Unknown Compression: "
          + bhi.compression);
    }

    byte colorTable[] = null;
    if (paletteLength > 0)
      colorTable = this.readByteArray("ColorTable", paletteLength, is,
          "Not a Valid BMP File");

    if (verbose)
    {
      this.debugNumber("paletteLength", paletteLength, 4);
      System.out.println("ColorTable: "
          + ((colorTable == null) ? "null" : "" + colorTable.length));
    }

    int pixelCount = bhi.width * bhi.height;

    int imageLineLength = ((((bhi.bitsPerPixel) * bhi.width) + 7) / 8);

    if (verbose)
    {
      // this.debugNumber("Total BitsPerPixel",
      // (ExtraBitsPerPixel + bhi.BitsPerPixel), 4);
      // this.debugNumber("Total Bit Per Line",
      // ((ExtraBitsPerPixel + bhi.BitsPerPixel) * bhi.Width), 4);
      // this.debugNumber("ExtraBitsPerPixel", ExtraBitsPerPixel, 4);
      this.debugNumber("bhi.Width", bhi.width, 4);
      this.debugNumber("bhi.Height", bhi.height, 4);
      this.debugNumber("ImageLineLength", imageLineLength, 4);
      // this.debugNumber("imageDataSize", imageDataSize, 4);
      this.debugNumber("PixelCount", pixelCount, 4);
    }
    // int ImageLineLength = BytesPerPixel * bhi.Width;
    while ((imageLineLength % 4) != 0)
      imageLineLength++;

    final int headerSize = BITMAP_FILE_HEADER_SIZE
        + BITMAP_INFO_HEADER_SIZE;
    int expectedDataOffset = headerSize + paletteLength;

    if (verbose)
    {
      this.debugNumber("bhi.BitmapDataOffset", bhi.bitmapDataOffset, 4);
      this.debugNumber("expectedDataOffset", expectedDataOffset, 4);
    }
    int extraBytes = bhi.bitmapDataOffset - expectedDataOffset;
    if (extraBytes < 0)
      throw new ImageReadException("BMP has invalid image data offset: "
          + bhi.bitmapDataOffset + " (expected: "
          + expectedDataOffset + ", paletteLength: " + paletteLength
          + ", headerSize: " + headerSize + ")");
    else if (extraBytes > 0)
      this.readByteArray("BitmapDataOffset", extraBytes, is,
          "Not a Valid BMP File");

    int imageDataSize = bhi.height * imageLineLength;

    if (verbose)
      this.debugNumber("imageDataSize", imageDataSize, 4);

    byte imageData[];
    if (rle)
      imageData = getRLEBytes(is, rleSamplesPerByte);
    else
      imageData = this.readByteArray("ImageData", imageDataSize, is,
          "Not a Valid BMP File");

    if (verbose)
      this.debugNumber("ImageData.length", imageData.length, 4);

    PixelParser pixelParser;

    switch (bhi.compression)
    {
    case BI_RLE4:
    case BI_RLE8:
      pixelParser = new PixelParserRle(bhi, colorTable, imageData);
      break;
    case BI_RGB:
      pixelParser = new PixelParserRgb(bhi, colorTable, imageData);
      break;
    case BI_BITFIELDS:
      pixelParser = new PixelParserBitFields(bhi, colorTable, imageData);
      break;
    default:
      throw new ImageReadException("BMP: Unknown Compression: "
          + bhi.compression);
    }

    return new ImageContents(bhi, colorTable, imageData, pixelParser);
  }

  private BmpHeaderInfo readBmpHeaderInfo(ByteSource byteSource,
      boolean verbose) throws ImageReadException, IOException
  {
    InputStream is = null;
    try
    {
      is = byteSource.getInputStream();

      // readSignature(is);
      return readBmpHeaderInfo(is, null, verbose);
    } finally
    {
      try
      {
        is.close();
      } catch (Exception e)
      {
        Debug.debug(e);
      }

    }
  }

  public byte[] getICCProfileBytes(ByteSource byteSource, Map params)
      throws ImageReadException, IOException
  {
    return null;
  }

  public Dimension getImageSize(ByteSource byteSource, Map params)
      throws ImageReadException, IOException
  {
    // make copy of params; we'll clear keys as we consume them.
    params = (params == null) ? new HashMap() : new HashMap(params);

    boolean verbose = ParamMap.getParamBoolean(params, PARAM_KEY_VERBOSE,
        false);

    if (params.containsKey(PARAM_KEY_VERBOSE))
      params.remove(PARAM_KEY_VERBOSE);

    if (params.size() > 0)
    {
      Object firstKey = params.keySet().iterator().next();
      throw new ImageReadException("Unknown parameter: " + firstKey);
    }

    BmpHeaderInfo bhi = readBmpHeaderInfo(byteSource, verbose);

    if (bhi == null)
      throw new ImageReadException("BMP: couldn't read header");

    return new Dimension(bhi.width, bhi.height);

  }

  public byte[] embedICCProfile(byte image[], byte profile[])
  {
    return null;
  }

  public boolean embedICCProfile(File src, File dst, byte profile[])
  {
    return false;
  }

  public IImageMetadata getMetadata(ByteSource byteSource, Map params)
      throws ImageReadException, IOException
  {
    return null;
  }

  private String getBmpTypeDescription(int Identifier1, int Identifier2)
  {
    if ((Identifier1 == 'B') && (Identifier2 == 'M'))
      return "Windows 3.1x, 95, NT,";
    if ((Identifier1 == 'B') && (Identifier2 == 'A'))
      return "OS/2 Bitmap Array";
    if ((Identifier1 == 'C') && (Identifier2 == 'I'))
      return "OS/2 Color Icon";
    if ((Identifier1 == 'C') && (Identifier2 == 'P'))
      return "OS/2 Color Pointer";
    if ((Identifier1 == 'I') && (Identifier2 == 'C'))
      return "OS/2 Icon";
    if ((Identifier1 == 'P') && (Identifier2 == 'T'))
      return "OS/2 Pointer";

    return "Unknown";
  }

  public ImageInfo getImageInfo(ByteSource byteSource, Map params)
      throws ImageReadException, IOException
  {
    // make copy of params; we'll clear keys as we consume them.
    params = (params == null) ? new HashMap() : new HashMap(params);

    boolean verbose = ParamMap.getParamBoolean(params, PARAM_KEY_VERBOSE,
        false);

    if (params.containsKey(PARAM_KEY_VERBOSE))
      params.remove(PARAM_KEY_VERBOSE);

    if (params.size() > 0)
    {
      Object firstKey = params.keySet().iterator().next();
      throw new ImageReadException("Unknown parameter: " + firstKey);
    }

    ImageContents ic = readImageContents(byteSource.getInputStream(),
        FormatCompliance.getDefault(), verbose);

    if (ic == null)
      throw new ImageReadException("Couldn't read BMP Data");

    BmpHeaderInfo bhi = ic.bhi;
    byte colorTable[] = ic.colorTable;

    if (bhi == null)
      throw new ImageReadException("BMP: couldn't read header");

    int height = bhi.height;
    int width = bhi.width;

    ArrayList comments = new ArrayList();
    // TODO: comments...

    int bitsPerPixel = bhi.bitsPerPixel;
    ImageFormat format = ImageFormat.IMAGE_FORMAT_BMP;
    String name = "BMP Windows Bitmap";
    String mimeType = "image/x-ms-bmp";
    // we ought to count images, but don't yet.
    int numberOfImages = -1;
    // not accurate ... only reflects first
    boolean isProgressive = false;
    // boolean isProgressive = (fPNGChunkIHDR.InterlaceMethod != 0);
    //
    // pixels per meter
    int physicalWidthDpi = (int) ((double) bhi.hResolution * 1000.0 / 2.54);
    float physicalWidthInch = (float) ((double) width / (double) physicalWidthDpi);
    // int physicalHeightDpi = 72;
    int physicalHeightDpi = (int) ((double) bhi.vResolution * 1000.0 / 2.54);
    float physicalHeightInch = (float) ((double) height / (double) physicalHeightDpi);

    String formatDetails = "Bmp (" + (char) bhi.identifier1
        + (char) bhi.identifier2 + ": "
        + getBmpTypeDescription(bhi.identifier1, bhi.identifier2) + ")";

    boolean isTransparent = false;

    boolean usesPalette = colorTable != null;
    int colorType = ImageInfo.COLOR_TYPE_RGB;
    String compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_RLE;

    ImageInfo result = new ImageInfo(formatDetails, bitsPerPixel, comments,
        format, name, height, mimeType, numberOfImages,
        physicalHeightDpi, physicalHeightInch, physicalWidthDpi,
        physicalWidthInch, width, isProgressive, isTransparent,
        usesPalette, colorType, compressionAlgorithm);

    return result;
  }

  public boolean dumpImageFile(PrintWriter pw, ByteSource byteSource)
      throws ImageReadException, IOException
  {
    pw.println("bmp.dumpImageFile");

    ImageInfo imageData = getImageInfo(byteSource, null);
    if (imageData == null)
      return false;

    imageData.toString(pw, "");

    pw.println("");

    return true;
  }

  public FormatCompliance getFormatCompliance(ByteSource byteSource)
      throws ImageReadException, IOException
  {
    boolean verbose = false;

    FormatCompliance result = new FormatCompliance(byteSource
        .getDescription());

    readImageContents(byteSource.getInputStream(), result, verbose);

    return result;
  }

  public BufferedImage getBufferedImage(ByteSource byteSource, Map params)
      throws ImageReadException, IOException
  {
    // make copy of params; we'll clear keys as we consume them.
    params = (params == null) ? new HashMap() : new HashMap(params);

    boolean verbose = ParamMap.getParamBoolean(params, PARAM_KEY_VERBOSE,
        false);

    if (params.containsKey(PARAM_KEY_VERBOSE))
      params.remove(PARAM_KEY_VERBOSE);
    if (params.containsKey(BUFFERED_IMAGE_FACTORY))
      params.remove(BUFFERED_IMAGE_FACTORY);

    if (params.size() > 0)
    {
      Object firstKey = params.keySet().iterator().next();
      throw new ImageReadException("Unknown parameter: " + firstKey);
    }

    ImageContents ic = readImageContents(byteSource.getInputStream(),
        FormatCompliance.getDefault(), verbose);
    if (ic == null)
      throw new ImageReadException("Couldn't read BMP Data");

    BmpHeaderInfo bhi = ic.bhi;
    // byte colorTable[] = ic.colorTable;
    // byte imageData[] = ic.imageData;

    int width = bhi.width;
    int height = bhi.height;

    boolean hasAlpha = false;
    BufferedImage result = getBufferedImageFactory(params)
        .getColorBufferedImage(width, height, hasAlpha);

    if (verbose)
    {
      System.out.println("width: " + width);
      System.out.println("height: " + height);
      System.out.println("width*height: " + width * height);
      System.out.println("width*height*4: " + width * height * 4);
    }

    PixelParser pixelParser = ic.pixelParser;

    pixelParser.processImage(result);

    return result;

  }

  private static final int BITMAP_FILE_HEADER_SIZE = 14;
  private static final int BITMAP_INFO_HEADER_SIZE = 40;

  public void writeImage(BufferedImage src, OutputStream os, Map params)
      throws ImageWriteException, IOException
  {
    // make copy of params; we'll clear keys as we consume them.
    params = (params == null) ? new HashMap() : new HashMap(params);

    // clear format key.
    if (params.containsKey(PARAM_KEY_FORMAT))
      params.remove(PARAM_KEY_FORMAT);

    if (params.size() > 0)
    {
      Object firstKey = params.keySet().iterator().next();
      throw new ImageWriteException("Unknown parameter: " + firstKey);
    }

    final SimplePalette palette = new PaletteFactory().makePaletteSimple(
        src, 256);

    BMPWriter writer = null;
    if (palette == null)
      writer = new BMPWriterRGB();
    else
      writer = new BMPWriterPalette(palette);

    byte imagedata[] = writer.getImageData(src);
    BinaryOutputStream bos = new BinaryOutputStream(os, BYTE_ORDER_INTEL);

    {
      // write BitmapFileHeader
      os.write(0x42); // B, Windows 3.1x, 95, NT, Bitmap
      os.write(0x4d); // M

      int filesize = BITMAP_FILE_HEADER_SIZE + BITMAP_INFO_HEADER_SIZE + // header
          // size
          4 * writer.getPaletteSize() + // palette size in bytes
          imagedata.length;
      bos.write4Bytes(filesize);

      bos.write4Bytes(0); // reserved
      bos.write4Bytes(BITMAP_FILE_HEADER_SIZE + BITMAP_INFO_HEADER_SIZE
          + 4 * writer.getPaletteSize()); // Bitmap Data Offset
    }

    int width = src.getWidth();
    int height = src.getHeight();

    { // write BitmapInfoHeader
      bos.write4Bytes(BITMAP_INFO_HEADER_SIZE); // Bitmap Info Header Size
      bos.write4Bytes(width); // width
      bos.write4Bytes(height); // height
      bos.write2Bytes(1); // Number of Planes
      bos.write2Bytes(writer.getBitsPerPixel()); // Bits Per Pixel

      bos.write4Bytes(BI_RGB); // Compression
      bos.write4Bytes(imagedata.length); // Bitmap Data Size
      bos.write4Bytes(0); // HResolution
      bos.write4Bytes(0); // VResolution
      if (palette == null)
        bos.write4Bytes(0); // Colors
      else
        bos.write4Bytes(palette.length()); // Colors
      bos.write4Bytes(0); // Important Colors
      // bos.write_4_bytes(0); // Compression
    }

    { // write Palette
      writer.writePalette(bos);
    }
    { // write Image Data
      bos.writeByteArray(imagedata);
    }
  }

  /**
   * Extracts embedded XML metadata as XML string.
   * <p>
   *
   * @param file
   *            File containing image data.
   * @param params
   *            Map of optional parameters, defined in SanselanConstants.
   * @return Xmp Xml as String, if present. Otherwise, returns null..
   */
  public String getXmpXml(ByteSource byteSource, Map params)
      throws ImageReadException, IOException
  {
    return null;
  }

}
TOP

Related Classes of org.apache.sanselan.formats.bmp.BmpImageParser

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.