001    /*
002     * ScaleReplication
003     * 
004     * Copyright (c) 2001, 2002 Marco Schmidt <marcoschmidt@users.sourceforge.net>
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.geometry;
009    
010    import net.sourceforge.jiu.data.PixelImage;
011    import net.sourceforge.jiu.data.IntegerImage;
012    import net.sourceforge.jiu.ops.ImageToImageOperation;
013    import net.sourceforge.jiu.ops.MissingParameterException;
014    import net.sourceforge.jiu.ops.WrongParameterException;
015    
016    /**
017     * Changes the pixel resolution of an image by replicating (or dropping) pixels.
018     * A fast but low quality scaling algorithm that works with all kinds
019     * of image types.
020     * {@link Resample} provides better quality, but is slower and works with
021     * intensity-based image data types only.
022     *
023     * <h3>Usage example</h3>
024     *
025     * The input image will be scaled to an image that is twice as wide as
026     * itself and three times as high.
027     *
028     * <pre>
029     * ScaleReplication scale = new ScaleReplication();
030     * scale.setInputImage(image); // something implementing IntegerImage
031     * scale.setSize(image.getWidth() * 2, image.getHeight() * 2);
032     * scale.process();
033     * PixelImage scaledImage = scale.getOutputImage();
034     * </pre>
035     * @author Marco Schmidt
036     */
037    public class ScaleReplication extends ImageToImageOperation
038    {
039            private Integer outWidth;
040            private Integer outHeight;
041    
042            private void process(IntegerImage in, IntegerImage out)
043            {
044                    if (out == null)
045                    {
046                            out = (IntegerImage)in.createCompatibleImage(outWidth.intValue(), outHeight.intValue());
047                            setOutputImage(out);
048                    }
049                    int IN_MAX_X = in.getWidth() - 1;
050                    int IN_MAX_Y = in.getHeight() - 1;
051                    int OUT_WIDTH = outWidth.intValue();
052                    int OUT_HEIGHT = outHeight.intValue();
053                    int totalItems = in.getNumChannels() * in.getHeight();
054                    int processedItems = 0;
055                    for (int y = 0; y < OUT_HEIGHT; y++)
056                    {
057                            final int SRC_Y = (int)(IN_MAX_Y * (y + 1) / OUT_HEIGHT);
058                            for (int x = 0; x < OUT_WIDTH; x++)
059                            {
060                                    final int SRC_X = (int)(IN_MAX_X * (x + 1) / OUT_WIDTH);
061                                    for (int c = 0; c < in.getNumChannels(); c++)
062                                    {
063                                            out.putSample(c, x, y, in.getSample(c, SRC_X, SRC_Y));
064                                    }
065                            }
066                            setProgress(y, OUT_HEIGHT);
067                    }
068            }
069    
070            public void process() throws
071                    MissingParameterException,
072                    WrongParameterException
073            {
074                    PixelImage pin = getInputImage();
075                    if (pin == null)
076                    {
077                            throw new MissingParameterException("Input image object missing.");
078                    }
079                    if (!(pin instanceof IntegerImage))
080                    {
081                            throw new WrongParameterException("ScaleReplication only works on IntegerImage objects.");
082                    }
083                    if (outWidth == null)
084                    {
085                            throw new MissingParameterException("Output width value missing.");
086                    }
087                    if (outHeight == null)
088                    {
089                            throw new MissingParameterException("Output height value missing.");
090                    }
091                    ensureImagesHaveSameResolution();
092                    process((IntegerImage)pin, (IntegerImage)getOutputImage());
093            }
094    
095            /**
096             * Specify the resolution to be used for the image to be created.
097             * @param width horizontal resolution of the new image
098             * @param height vertical resolution of the new image
099             * @throws IllegalArgumentException if any of the arguments is smaller than 1
100             */
101            public void setSize(int width, int height)
102            {
103                    if (width < 1)
104                    {
105                            throw new IllegalArgumentException("Output width must be larger than 0.");
106                    }
107                    if (height < 1)
108                    {
109                            throw new IllegalArgumentException("Output height must be larger than 0.");
110                    }
111                    outWidth = new Integer(width);
112                    outHeight = new Integer(height);
113            }
114    }