Initial Contribution
diff --git a/awt/javax/imageio/ImageIO.java b/awt/javax/imageio/ImageIO.java
new file mode 100644
index 0000000..d4cd1dd
--- /dev/null
+++ b/awt/javax/imageio/ImageIO.java
@@ -0,0 +1,777 @@
+/*
+ *  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.
+ */
+/**
+ * @author Rustem V. Rafikov
+ * @version $Revision: 1.3 $
+ */
+package javax.imageio;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.spi.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.net.URL;
+
+/**
+ * The ImageIO class provides static methods to perfom 
+ * reading and writing operations using registered
+ * ImageReader and ImageWriter objects.
+ */
+public final class ImageIO {
+
+    /** The Constant registry. */
+    private static final IIORegistry registry = IIORegistry.getDefaultInstance();
+
+    /**
+     * Instantiates a new image io.
+     */
+    private ImageIO() {}
+    
+
+    /**
+     * Scans for plug-ins in the class path, 
+     * loads spi classes, and registers them with the IIORegistry.
+     */
+    public static void scanForPlugins() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Sets flag which indicates whether a cache file is used when 
+     * creating ImageInputStreams and ImageOutputStreams or not.
+     * 
+     * @param useCache the use cache flag.
+     */
+    public static void setUseCache(boolean useCache) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the flag which indicates whether a cache file is used when 
+     * creating ImageInputStreams and ImageOutputStreams or not.
+     * This method returns the current value which is set by setUseCache
+     * method.
+     * 
+     * @return the use cache flag.
+     */
+    public static boolean getUseCache() {
+        // TODO implement
+        return false;
+    }
+
+    /**
+     * Sets the cache directory.
+     * 
+     * @param cacheDirectory the File which specifies a cache directory.
+     */
+    public static void setCacheDirectory(File cacheDirectory) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the directory where cache files are created, returned
+     * the file which is set by setCacheDirectory method, or null.
+     * 
+     * @return the File object which is set by setCacheDirectory method, 
+     * or null.
+     */
+    public static File getCacheDirectory() {
+        // TODO implement
+        //-- null indicates system-dep default temporary directory
+        return null;
+    }
+
+    /**
+     * Creates an ImageInputStream from the specified Object.
+     * The specified Object should obtain the input source
+     * such as File, or InputStream.   
+     * 
+     * @param input the input Object such as File, or InputStream.   
+     * 
+     * @return the ImageInputStream object, or null.
+     * 
+     * @throws IOException signals that an I/O exception has occurred.
+     */
+    public static ImageInputStream createImageInputStream(Object input)
+            throws IOException {
+
+        if (input == null) {
+            throw new IllegalArgumentException("input source cannot be NULL");
+        }
+
+        Iterator<ImageInputStreamSpi> it = registry.getServiceProviders(ImageInputStreamSpi.class, true);
+
+        while (it.hasNext()) {
+            ImageInputStreamSpi spi = it.next();
+            if (spi.getInputClass().isInstance(input)) {
+                return spi.createInputStreamInstance(input);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Creates an ImageOutputStream using the specified Object.
+     * The specified Object should obtain the output source
+     * such as File, or OutputStream.   
+     * 
+     * @param output the output Object such as File, or OutputStream.   
+     * 
+     * @return the ImageOutputStream object, or null.
+     * 
+     * @throws IOException signals that an I/O exception has occurred.
+     */
+    public static ImageOutputStream createImageOutputStream(Object output)
+            throws IOException {
+        if (output == null) {
+            throw new IllegalArgumentException("output destination cannot be NULL");
+        }
+
+        Iterator<ImageOutputStreamSpi> it = registry.getServiceProviders(ImageOutputStreamSpi.class, true);
+
+        while (it.hasNext()) {
+            ImageOutputStreamSpi spi = it.next();
+            if (spi.getOutputClass().isInstance(output)) {
+                // todo - use getUseCache and getCacheDir here
+                return spi.createOutputStreamInstance(output);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the array of format names as String which can be 
+     * decoded by registered ImageReader objects.
+     * 
+     * @return the array of format names.
+     */
+    public static String[] getReaderFormatNames() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the array of MIME types as String which can be 
+     * decoded by registered ImageReader objects.
+     * 
+     * @return the array of MIME types.
+     */
+    public static String[] getReaderMIMETypes() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the Iterator of registered ImageReader which are able to 
+     * decode an imput data specified by input Object.
+     * 
+     * @param input the input Object with encoded data such as 
+     * ImageInputStream object.
+     * 
+     * @return the Iterator of registered ImageReader. 
+     */
+    public static Iterator<ImageReader> getImageReaders(Object input) {
+        if (input == null) {
+            throw new NullPointerException("input cannot be NULL");
+        }
+
+        Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+                new CanReadFilter(input), true);
+
+        return new SpiIteratorToReadersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator of registered ImageReader which are able to 
+     * decode the specified format.
+     * 
+     * @param formatName the format name such as "jpeg", or "gif".
+     * 
+     * @return the Iterator of registered ImageReader.
+     */
+    public static Iterator<ImageReader> getImageReadersByFormatName(String formatName) {
+        if (formatName == null) {
+            throw new NullPointerException("format name cannot be NULL");
+        }
+
+        Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+                new FormatFilter(formatName), true);
+
+        return new SpiIteratorToReadersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator which lists the registered ImageReader objects that
+     * are able to decode files with the specified suffix.
+     * 
+     * @param fileSuffix the file suffix such as "jpg".
+     * 
+     * @return the Iterator of registered ImageReaders.
+     */
+    public static Iterator<ImageReader> getImageReadersBySuffix(String fileSuffix) {
+        if (fileSuffix == null) {
+            throw new NullPointerException("suffix cannot be NULL");
+        }
+        Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
+                new SuffixFilter(fileSuffix), true);
+
+        return new SpiIteratorToReadersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator of registered ImageReader objects that
+     * are able to decode files with the specified MIME type.
+     * 
+     * @param MIMEType the MIME type such as "image/jpeg".
+     * 
+     * @return the Iterator of registered ImageReaders.
+     */
+    public static Iterator<ImageReader> getImageReadersByMIMEType(String MIMEType) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an array of Strings giving the names of the formats supported 
+     * by registered ImageWriter objects.
+     * 
+     * @return the array of format names.
+     */
+    public static String[] getWriterFormatNames() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an array of Strings giving the MIME types of the formats supported 
+     * by registered ImageWriter objects.
+     * 
+     * @return the array of MIME types.
+     */
+    public static String[] getWriterMIMETypes() {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the Iterator which lists the registered ImageReader objects that
+     * are able to encode the specified image format.
+     * 
+     * @param formatName the image format name such as "jpeg".
+     * 
+     * @return the Iterator of registered ImageWriter.
+     */
+    public static Iterator<ImageWriter> getImageWritersByFormatName(String formatName) {
+        if (formatName == null) {
+            throw new NullPointerException("format name cannot be NULL");
+        }
+
+        Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+                new FormatFilter(formatName), true);
+
+        return new SpiIteratorToWritersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator which lists the registered ImageReader objects that
+     * are able to encode the specified suffix.
+     * 
+     * @param fileSuffix the file suffix such as "jpg".
+     * 
+     * @return the Iterator of registered ImageWriter.
+     */
+    public static Iterator<ImageWriter> getImageWritersBySuffix(String fileSuffix) {
+        if (fileSuffix == null) {
+            throw new NullPointerException("suffix cannot be NULL");
+        }
+        Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+                new SuffixFilter(fileSuffix), true);
+        return new SpiIteratorToWritersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator which lists the registered ImageReader objects that
+     * are able to encode the specified MIME type.
+     * 
+     * @param MIMEType the MIME type such as "image/jpeg".
+     * 
+     * @return the Iterator of registered ImageWriter.
+     */
+    public static Iterator<ImageWriter> getImageWritersByMIMEType(String MIMEType) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an ImageWriter object which corresponds to the 
+     * specified ImageReader, or returns null if the specified
+     * ImageReader is not registered. 
+     * 
+     * @param reader the specified ImageReader.
+     * 
+     * @return the ImageWriter, or null.
+     */
+    public static ImageWriter getImageWriter(ImageReader reader) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets an ImageReader object which corresponds to the 
+     * specified ImageWriter, or returns null if the specified
+     * ImageWriter is not registered. 
+     * 
+     * @param writer the registered ImageWriter object.
+     * 
+     * @return the ImageReader.
+     */
+    public static ImageReader getImageReader(ImageWriter writer) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Gets the Iterator of ImageWriter objects which are able to
+     * encode images with the specified ImageTypeSpecifier and
+     * format.
+     * 
+     * @param type the ImageTypeSpecifier, which defines layout.
+     * @param formatName the format name.
+     * 
+     * @return the Iterator of ImageWriter objects.
+     */
+    public static Iterator<ImageWriter> getImageWriters(ImageTypeSpecifier type,
+                                           String formatName) {
+        if (type == null) {
+            throw new NullPointerException("type cannot be NULL");
+        }
+
+        if (formatName == null) {
+            throw new NullPointerException("format name cannot be NULL");
+        }
+
+        Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
+                new FormatAndEncodeFilter(type, formatName), true);
+
+        return new SpiIteratorToWritersIteratorWrapper(it);
+    }
+
+    /**
+     * Gets the Iterator of registered ImageTranscoders which 
+     * are able to transcode the metadata of the specified
+     * ImageReader object to a suitable object for encoding 
+     * by the specified ImageWriter.
+     * 
+     * @param reader the specified ImageReader.
+     * @param writer the specified ImageWriter.
+     * 
+     * @return the Iterator of registered ImageTranscoders.
+     */
+    public static Iterator<ImageTranscoder> getImageTranscoders(ImageReader reader,
+                                               ImageWriter writer) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    /**
+     * Reads image data from the specified File and decodes it using 
+     * the appropriate registered ImageReader object. 
+     * The File is wrapped in an ImageInputStream.
+     * 
+     * @param input the File to be read.
+     * 
+     * @return the BufferedImage decoded from the specified File, or null.
+     * 
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    public static BufferedImage read(File input) throws IOException {
+        if (input == null) {
+            throw new IllegalArgumentException("input == null!");
+        }
+
+        ImageInputStream stream = createImageInputStream(input);
+        return read(stream);
+    }
+
+    /**
+     * Reads image data from the specified InputStream and decodes it 
+     * using an appropriate registered an ImageReader object.
+     * 
+     * @param input the InputStream.
+     * 
+     * @return the BufferedImage decoded from the specified InputStream,
+     * or null.
+     * 
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    public static BufferedImage read(InputStream input) throws IOException {
+        if (input == null) {
+            throw new IllegalArgumentException("input == null!");
+        }
+
+        ImageInputStream stream = createImageInputStream(input);
+        return read(stream);
+    }
+
+    /**
+     * Reads image data from the specified URL and decodes it using 
+     * the appropriate registered ImageReader object. 
+     *  
+     * @param input the URL to be read.
+     * 
+     * @return the BufferedImage decoded from the specified URL, or null.
+     * 
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    public static BufferedImage read(URL input) throws IOException {
+        if (input == null) {
+            throw new IllegalArgumentException("input == null!");
+        }
+
+        InputStream stream = input.openStream();
+        BufferedImage res = read(stream);
+        stream.close();
+        
+        return res;
+    }
+
+    /**
+     * Reads image data from the specified ImageInputStream and decodes it 
+     * using appropriate registered an ImageReader object.
+     * 
+     * @param stream the ImageInputStream.
+     * 
+     * @return the BufferedImage decoded from the specified ImageInputStream,
+     * or null.
+     * 
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    public static BufferedImage read(ImageInputStream stream) throws IOException {
+        if (stream == null) {
+            throw new IllegalArgumentException("stream == null!");
+        }
+
+        Iterator<ImageReader> imageReaders = getImageReaders(stream);
+        if (!imageReaders.hasNext()) {
+            return null;
+        }
+
+        ImageReader reader = imageReaders.next();
+        reader.setInput(stream, false, true);
+        BufferedImage res = reader.read(0);
+        reader.dispose();
+
+        try {
+            stream.close();
+        } catch (IOException e) {
+            // Stream could be already closed, proceed silently in this case
+        }
+        
+        return res;
+    }
+
+    /**
+     * Writes the specified image in the specified format (using an 
+     * appropriate ImageWriter) to the specified ImageOutputStream.
+     * 
+     * @param im the RenderedImage.
+     * @param formatName the format name.
+     * @param output the ImageOutputStream where Image to be written.
+     * 
+     * @return true, if Image is written successfully, false otherwise.
+     * 
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    public static boolean write(RenderedImage im,
+                                String formatName,
+                                ImageOutputStream output)
+            throws IOException {
+
+        if (im == null) {
+            throw new IllegalArgumentException("image cannot be NULL");
+        }
+        if (formatName == null) {
+            throw new IllegalArgumentException("format name cannot be NULL");
+        }
+        if (output == null) {
+            throw new IllegalArgumentException("output cannot be NULL");
+        }
+
+        Iterator<ImageWriter> it = getImageWriters(ImageTypeSpecifier.createFromRenderedImage(im), formatName);
+        if (it.hasNext()) {
+            ImageWriter writer = it.next();
+            writer.setOutput(output);
+            writer.write(im);
+            output.flush();
+            writer.dispose();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Writes the specified image in the specified format (using an 
+     * appropriate ImageWriter) to the specified File.
+     * 
+     * @param im the RenderedImage.
+     * @param formatName the format name.
+     * @param output the output File where Image to be written.
+     * 
+     * @return true, if Image is written successfully, false otherwise.
+     * 
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    public static boolean write(RenderedImage im,
+                                String formatName,
+                                File output)
+            throws IOException {
+
+        if (output == null) {
+            throw new IllegalArgumentException("output cannot be NULL");
+        }
+
+        if (output.exists()) {
+            output.delete();
+        }
+
+        ImageOutputStream ios = createImageOutputStream(output);
+        boolean rt = write(im, formatName, ios);
+        ios.close();
+        return rt;
+    }
+
+    /**
+     * Writes the specified image in the specified format (using an 
+     * appropriate ImageWriter) to the specified OutputStream.
+     * 
+     * @param im the RenderedImage.
+     * @param formatName the format name.
+     * @param output the OutputStream where Image is to be written.
+     * 
+     * @return true, if Image is written successfully, false otherwise.
+     * 
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    public static boolean write(RenderedImage im,
+                                String formatName,
+                                OutputStream output)
+            throws IOException {
+
+        if (output == null) {
+            throw new IllegalArgumentException("output cannot be NULL");
+        }
+
+        ImageOutputStream ios = createImageOutputStream(output);
+        boolean rt = write(im, formatName, ios);
+        ios.close();
+        return rt;
+    }
+
+
+    /**
+     * Filter to match spi by format name.
+     */
+    static class FormatFilter implements ServiceRegistry.Filter {
+        
+        /** The name. */
+        private String name;
+
+        /**
+         * Instantiates a new format filter.
+         * 
+         * @param name the name
+         */
+        public FormatFilter(String name) {
+            this.name = name;
+        }
+
+        public boolean filter(Object provider) {
+            ImageReaderWriterSpi spi = (ImageReaderWriterSpi) provider;
+            return Arrays.asList(spi.getFormatNames()).contains(name);
+        }
+    }
+
+    /**
+     * Filter to match spi by format name and encoding possibility.
+     */
+    static class FormatAndEncodeFilter extends FormatFilter {
+
+        /** The type. */
+        private ImageTypeSpecifier type;
+
+        /**
+         * Instantiates a new format and encode filter.
+         * 
+         * @param type the type
+         * @param name the name
+         */
+        public FormatAndEncodeFilter(ImageTypeSpecifier type, String name) {
+            super(name);
+            this.type = type;
+        }
+
+        @Override
+        public boolean filter(Object provider) {
+            ImageWriterSpi spi = (ImageWriterSpi) provider;
+            return super.filter(provider) && spi.canEncodeImage(type);
+        }
+    }
+
+    /**
+     * Filter to match spi by suffix.
+     */
+    static class SuffixFilter implements ServiceRegistry.Filter {
+        
+        /** The suf. */
+        private String suf;
+
+        /**
+         * Instantiates a new suffix filter.
+         * 
+         * @param suf the suf
+         */
+        public SuffixFilter(String suf) {
+            this.suf = suf;
+        }
+
+        public boolean filter(Object provider) {
+            ImageReaderWriterSpi spi = (ImageReaderWriterSpi) provider;
+            return Arrays.asList(spi.getFileSuffixes()).contains(suf);
+        }
+    }
+
+    /**
+     * Filter to match spi by decoding possibility.
+     */
+    static class CanReadFilter implements ServiceRegistry.Filter {
+        
+        /** The input. */
+        private Object input;
+
+        /**
+         * Instantiates a new can read filter.
+         * 
+         * @param input the input
+         */
+        public CanReadFilter(Object input) {
+            this.input = input;
+        }
+
+        public boolean filter(Object provider) {
+            ImageReaderSpi spi = (ImageReaderSpi) provider;
+            try {
+                return spi.canDecodeInput(input);
+            } catch (IOException e) {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Wraps Spi's iterator to ImageWriter iterator.
+     */
+    static class SpiIteratorToWritersIteratorWrapper implements Iterator<ImageWriter> {
+
+        /** The backend. */
+        private Iterator<ImageWriterSpi> backend;
+
+        /**
+         * Instantiates a new spi iterator to writers iterator wrapper.
+         * 
+         * @param backend the backend
+         */
+        public SpiIteratorToWritersIteratorWrapper(Iterator<ImageWriterSpi> backend) {
+            this.backend = backend;
+        }
+
+        /**
+         * Next.
+         * 
+         * @return the image writer
+         */
+        public ImageWriter next() {
+            try {
+                return backend.next().createWriterInstance();
+            } catch (IOException e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+
+        /**
+         * Checks for next.
+         * 
+         * @return true, if successful
+         */
+        public boolean hasNext() {
+            return backend.hasNext();
+        }
+
+        /**
+         * Removes the.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException("Use deregisterServiceprovider instead of Iterator.remove()");
+        }
+    }
+
+    /**
+     * Wraps spi's iterator to ImageReader iterator.
+     */
+    static class SpiIteratorToReadersIteratorWrapper implements Iterator<ImageReader> {
+        
+        /** The backend. */
+        private Iterator<ImageReaderSpi> backend;
+
+        /**
+         * Instantiates a new spi iterator to readers iterator wrapper.
+         * 
+         * @param backend the backend
+         */
+        public SpiIteratorToReadersIteratorWrapper(Iterator<ImageReaderSpi> backend) {
+            this.backend = backend;
+        }
+
+        /**
+         * Next.
+         * 
+         * @return the image reader
+         */
+        public ImageReader next() {
+            try {
+                return backend.next().createReaderInstance();
+            } catch (IOException e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+
+        /**
+         * Checks for next.
+         * 
+         * @return true, if successful
+         */
+        public boolean hasNext() {
+            return backend.hasNext();
+        }
+
+        /**
+         * Removes the.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException("Use deregisterServiceprovider instead of Iterator.remove()");
+        }
+    }
+}