package yi.iu.processor.resample;

import java.awt.*;
import yi.iu.ui.*;
import yi.iu.processor.*;
import yi.iu.processor.channel.*;
import yi.iu.processor.resample.*;
import yi.iu.SImage;
import yi.util.io.*;

// Credits:
// The algorithms and methods used in this class are based on the article
// "General Filtered Image Rescaling" by Dale Schumacher which appeared in the
// book Graphics Gems III, published by Academic Press, Inc.

abstract public class Resampler extends ImageProcessor
{
    public static int BELL_RESAMPLER = 0;
    public static int BSPLINE_RESAMPLER = 1;
    public static int HERMITE_RESAMPLER = 2;
    public static int LANCZOS3_RESAMPLER = 3;
    public static int LINEAR_RESAMPLER = 4;
    public static int MITCHELL_RESAMPLER = 5;
    public static int NEAREST_RESAMPLER = 6;
    public static int SIMPLE_RESAMPLER = 7;
    public static String RESIZED_FILE_SUFFIX = ".s";

    abstract public double filter(double value);

    //the width and height of the destination image
    int dstWidth=160;
    int dstHeight=120;
    double fwidth=1.0;     //Relative sample radius

    public Resampler () {
        fwidth=1.0;
    }

    public Resampler(int w, int h) {
        dstWidth=w; dstHeight=h; fwidth=1.0;
    }

    public int[] getProcessed(int source[], Dimension d)
    {
        SImage src= new SImage(d.width, d.height, SImage.GRAY, source);
        SImage dst= strecth(src);
        return dst.data;
    }

    public int[] getProcessedPseudoColor(int source[], Dimension d)
    {
        int rst[]= getProcessed(source,d);
        DisplayFrame f= new DisplayFrame(this, rst, dstWidth, dstHeight);
        f.show();
        return source;
    }

    class Weighter {
        int pixel[];
        double weight[];
        int n;
        public Weighter (int size) {
            pixel= new int[size];
            weight= new double[size];
            n=0;
        }

        void normalized() {
          // sum
          double sum = 0;
          for (int i=0; i<n; i++) sum += weight[i];
          for (int i=0; i<n; i++) weight[i] /= sum;
        }
    }
// -----------------------------------------------------------------------------
//
//			Interpolator
//
// -----------------------------------------------------------------------------
    SImage strecth(SImage src)
    {
        int i,j,k,n;
        double center, weight;
        int left,right;
        double rgb_r, rgb_g, rgb_b;
        int color_r, color_g, color_b;
        double width;
        double fscale;

        int red[]= (new RedChannelMaker()).getProcessed(src).data;
        int green[]= (new GreenChannelMaker()).getProcessed(src).data;
        int blue[]= (new BlueChannelMaker()).getProcessed(src).data;

        // Create the result Image
        SImage dst=new SImage(dstWidth, dstHeight, src.type);

        int srcWidth = src.width;
        int srcHeight = src.height;

        // Create intermediate image to hold horizontal zoom
        int work_red[]= new int[dstWidth*srcHeight];
        int work_green[]= new int[dstWidth*srcHeight];
        int work_blue[]= new int[dstWidth*srcHeight];

        double xscale= (double)dstWidth / srcWidth;
        double yscale= (double)dstHeight / srcHeight;

        // --------------------------------------------
        // Pre-calculate filter contributions for a row
        // -----------------------------------------------
        // contrib stores the weight functions for every pixel in a row.
        Weighter contrib[]= new Weighter[dstWidth];
        // Horizontal sub-sampling
        // Scales from bigger to smaller width
        if (xscale < 1.0) {
            width= fwidth / xscale;
            fscale= 1.0 / xscale;

            for (i=0; i<dstWidth; i++) {
                contrib[i]= new Weighter((int)Math.floor(width*2.0+1));
                center= i / xscale;
                left= (int)Math.floor(center - width);
                right= (int)Math.ceil(center + width);

                // construct the weight vector for column i on every row
                for (j= left; j<=right; j++) {
                    weight = filter((center - j) / fscale) / fscale;
                    if (weight== 0.0) continue;

                    if (j < 0) n= -j;
                    else if (j >= srcWidth) n= srcWidth - j + srcWidth - 1;
                    else n= j;

                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }

        else
        // Horizontal super-sampling
        // Scales from smaller to bigger width
        {
            for (i=0; i<dstWidth; i++) {
                contrib[i]= new Weighter((int)Math.floor(fwidth*2.0+1));
                center = i / xscale;
                left = (int)Math.floor(center - fwidth);
                right = (int)Math.ceil(center + fwidth);
                for (j=left; j<=right; j++) {
                    weight = filter(center - j);
                    if (weight == 0.0) continue;
                    if (j < 0) n= -j;
                    else if (j >= srcWidth) n= srcWidth - j + srcWidth - 1;
                    else n= j;

                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }

        // normalize the weights so that the sum = 1 (10/20/2002)
        for (i=0; i<dstWidth; i++) contrib[i].normalized();

        // ----------------------------------------------------
        // Apply filter to sample horizontally from Src to Work
        // ----------------------------------------------------
        int ptr=0,row_ptr=0,pixel;
        for (k=0; k<srcHeight; k++, row_ptr+=srcWidth) {
            for (i=0; i<dstWidth; i++, ptr++) {
                rgb_r = 0.0;
                rgb_g = 0.0;
                rgb_b = 0.0;
                for (j=0; j<contrib[i].n; j++) {
                    weight = contrib[i].weight[j];
                    if (weight == 0.0) continue;
                    pixel= row_ptr+contrib[i].pixel[j];
                    color_r= red[pixel]; color_g= green[pixel]; color_b= blue[pixel];
                    rgb_r = rgb_r + color_r * weight;
                    rgb_g = rgb_g + color_g * weight;
                    rgb_b = rgb_b + color_b * weight;
                }

                if (rgb_r > 255.0) color_r = 255;
                else if (rgb_r < 0.0) color_r = 0;
                else  color_r = (int)Math.round(rgb_r);

                if (rgb_g > 255.0) color_g = 255;
                else if (rgb_g < 0.0) color_g = 0;
                else color_g = (int)Math.round(rgb_g);

                if (rgb_b > 255.0) color_b = 255;
                else if (rgb_b < 0.0) color_b = 0;
                else color_b = (int)Math.round(rgb_b);

                work_red[ptr]= color_r;
                work_green[ptr]= color_g;
                work_blue[ptr]= color_b;
            }
        }

        // -----------------------------------------------
        // Pre-calculate filter contributions for a column
        // -----------------------------------------------
        contrib= new Weighter[dstHeight];

        // Vertical sub-sampling
        // Scales from bigger to smaller height
        if (yscale < 1.0) {
            width = fwidth / yscale;
            fscale = 1.0 / yscale;

            for (i=0; i<dstHeight; i++) {
                contrib[i]= new Weighter((int)Math.floor(width*2.0+1));
                center = i / yscale;
                left = (int)Math.floor(center - width);
                right = (int)Math.ceil(center + width);
                for ( j= left; j<=right; j++) {
                    weight = filter((center - j) / fscale) / fscale;
                    if (weight == 0.0) continue;
                    if (j < 0) n= -j;
                    else if (j >= srcHeight) n= srcHeight - j + srcHeight - 1;
                    else n= j;
                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }
        else
        // Vertical super-sampling
        // Scales from smaller to bigger height
        {
            for (i= 0; i<dstHeight; i++) {
                contrib[i]= new Weighter((int)Math.floor(fwidth*2.0+1));
                center = i / yscale;
                left = (int)Math.floor(center - fwidth);
                right = (int)Math.ceil(center + fwidth);
                for (j= left; j<=right; j++) {
                    weight = filter(center - j);
                    if (weight == 0.0) continue;
                    if (j < 0) n= -j;
                    else if (j >= srcHeight) n= srcHeight - j + srcHeight - 1;
                    else n= j;
                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }

        // normalize the weights so that the sum = 1 (10/20/2002)
        for (i=0; i<dstHeight; i++) contrib[i].normalized();

        // --------------------------------------------------
        // Apply filter to sample vertically from Work to Dst
        // --------------------------------------------------
        ptr=0;
        for (k= 0;k<dstWidth;k++) {
            for (i=0; i<dstHeight; i++) {
                rgb_r = 0;
                rgb_g = 0;
                rgb_b = 0;
                // weight = 0.0;
                for (j=0; j<contrib[i].n; j++, ptr++) {
                    weight = contrib[i].weight[j];
                    if (weight == 0.0) continue;
                    pixel= contrib[i].pixel[j]*dstWidth+k;
                    color_r= work_red[pixel]; color_g= work_green[pixel]; color_b= work_blue[pixel];

                    rgb_r = rgb_r + color_r * weight;
                    rgb_g = rgb_g + color_g * weight;
                    rgb_b = rgb_b + color_b * weight;
                }
                if (rgb_r > 255.0) color_r = 255;
                else if (rgb_r < 0.0) color_r = 0;
                else color_r = (int)Math.round(rgb_r);

                if (rgb_g > 255.0) color_g = 255;
                else if (rgb_g < 0.0) color_g = 0;
                else color_g = (int)Math.round(rgb_g);

                if (rgb_b > 255.0) color_b = 255;
                else if (rgb_b < 0.0) color_b = 0;
                else color_b = (int)Math.round(rgb_b);

                dst.data[i*dstWidth+k]=0xff000000|color_r<<16|color_g<<8|color_b;
            }
        }

        contrib=null;
        work_red=work_green=work_blue=null;
        System.gc();

        return dst;
    }


    /**
     * Strech one channel of data only.  Don't consider the color information
     * @param data
     * @param width
     * @param height
     * @return
     */
    public int[] strecth(int[] data, int srcWidth, int srcHeight)
    {
        int i,j,k,n;
        double center, weight;
        int left,right;
        double rgb_r;
        int color_r;
        double width;
        double fscale;

        int red[]= data;
        int dst[] = new int[dstWidth*dstHeight];//data.length];

        // Create intermediate image to hold horizontal zoom
        int work_red[]= new int[dstWidth*srcHeight];

        double xscale= (double)dstWidth / srcWidth;
        double yscale= (double)dstHeight / srcHeight;

        // --------------------------------------------
        // Pre-calculate filter contributions for a row
        // -----------------------------------------------
        // contrib stores the weight functions for every pixel in a row.
        Weighter contrib[]= new Weighter[dstWidth];
        // Horizontal sub-sampling
        // Scales from bigger to smaller width
        if (xscale < 1.0) {
            width= fwidth / xscale;
            fscale= 1.0 / xscale;

            for (i=0; i<dstWidth; i++) {
                contrib[i]= new Weighter((int)Math.floor(width*2.0+1));
                center= i / xscale;
                left= (int)Math.floor(center - width);
                right= (int)Math.ceil(center + width);

                // construct the weight vector for column i on every row
                for (j= left; j<=right; j++) {
                    weight = filter((center - j) / fscale) / fscale;
                    if (weight== 0.0) continue;

                    if (j < 0) n= -j;
                    else if (j >= srcWidth) n= srcWidth - j + srcWidth - 1;
                    else n= j;

                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }

        else
        // Horizontal super-sampling
        // Scales from smaller to bigger width
        {
            for (i=0; i<dstWidth; i++) {
                contrib[i]= new Weighter((int)Math.floor(fwidth*2.0+1));
                center = i / xscale;
                left = (int)Math.floor(center - fwidth);
                right = (int)Math.ceil(center + fwidth);
                for (j=left; j<=right; j++) {
                    weight = filter(center - j);
                    if (weight == 0.0) continue;
                    if (j < 0) n= -j;
                    else if (j >= srcWidth) n= srcWidth - j + srcWidth - 1;
                    else n= j;

                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }

        // normalize the weights so that the sum = 1 (10/20/2002)
        for (i=0; i<dstWidth; i++) contrib[i].normalized();

        // ----------------------------------------------------
        // Apply filter to sample horizontally from Src to Work
        // ----------------------------------------------------
        int ptr=0,row_ptr=0,pixel;
        for (k=0; k<srcHeight; k++, row_ptr+=srcWidth) {
            for (i=0; i<dstWidth; i++, ptr++) {
                rgb_r = 0.0;
                for (j=0; j<contrib[i].n; j++) {
                    weight = contrib[i].weight[j];
                    if (weight == 0.0) continue;
                    pixel= row_ptr+contrib[i].pixel[j];
                    color_r= red[pixel];
                    rgb_r = rgb_r + color_r * weight;
                }

                color_r = (int)Math.round(rgb_r);


                work_red[ptr]= color_r;
            }
        }

        // -----------------------------------------------
        // Pre-calculate filter contributions for a column
        // -----------------------------------------------
        contrib= new Weighter[dstHeight];

        // Vertical sub-sampling
        // Scales from bigger to smaller height
        if (yscale < 1.0) {
            width = fwidth / yscale;
            fscale = 1.0 / yscale;

            for (i=0; i<dstHeight; i++) {
                contrib[i]= new Weighter((int)Math.floor(width*2.0+1));
                center = i / yscale;
                left = (int)Math.floor(center - width);
                right = (int)Math.ceil(center + width);
                for ( j= left; j<=right; j++) {
                    weight = filter((center - j) / fscale) / fscale;
                    if (weight == 0.0) continue;
                    if (j < 0) n= -j;
                    else if (j >= srcHeight) n= srcHeight - j + srcHeight - 1;
                    else n= j;
                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }
        else
        // Vertical super-sampling
        // Scales from smaller to bigger height
        {
            for (i= 0; i<dstHeight; i++) {
                contrib[i]= new Weighter((int)Math.floor(fwidth*2.0+1));
                center = i / yscale;
                left = (int)Math.floor(center - fwidth);
                right = (int)Math.ceil(center + fwidth);
                for (j= left; j<=right; j++) {
                    weight = filter(center - j);
                    if (weight == 0.0) continue;
                    if (j < 0) n= -j;
                    else if (j >= srcHeight) n= srcHeight - j + srcHeight - 1;
                    else n= j;
                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }

        // normalize the weights so that the sum = 1 (10/20/2002)
        for (i=0; i<dstHeight; i++) contrib[i].normalized();

        // --------------------------------------------------
        // Apply filter to sample vertically from Work to Dst
        // --------------------------------------------------
        ptr=0;
        for (k= 0;k<dstWidth;k++) {
            for (i=0; i<dstHeight; i++) {
                rgb_r = 0;
                // weight = 0.0;
                for (j=0; j<contrib[i].n; j++, ptr++) {
                    weight = contrib[i].weight[j];
                    if (weight == 0.0) continue;
                    pixel= contrib[i].pixel[j]*dstWidth+k;
                    color_r= work_red[pixel];

                    rgb_r = rgb_r + color_r * weight;
                }
                color_r = (int)Math.round(rgb_r);

                dst[i*dstWidth+k]=color_r;
            }
        }

        contrib=null;
        work_red=null;
        System.gc();

        return dst;
    }


    public double[] strecth(double[] data, int srcWidth, int srcHeight)
    {
        int i,j,k,n;
        double center, weight;
        int left,right;
        double rgb_r;
        double color_r;
        double width;
        double fscale;

        double red[]= data;
        double dst[] = new double[dstWidth*dstHeight];//data.length];

        // Create intermediate image to hold horizontal zoom
        double work_red[]= new double[dstWidth*srcHeight];

        double xscale= (double)dstWidth / srcWidth;
        double yscale= (double)dstHeight / srcHeight;

        // --------------------------------------------
        // Pre-calculate filter contributions for a row
        // -----------------------------------------------
        // contrib stores the weight functions for every pixel in a row.
        Weighter contrib[]= new Weighter[dstWidth];
        // Horizontal sub-sampling
        // Scales from bigger to smaller width
        if (xscale < 1.0) {
            width= fwidth / xscale;
            fscale= 1.0 / xscale;

            for (i=0; i<dstWidth; i++) {
                contrib[i]= new Weighter((int)Math.floor(width*2.0+1));
                center= i / xscale;
                left= (int)Math.floor(center - width);
                right= (int)Math.ceil(center + width);

                // construct the weight vector for column i on every row
                for (j= left; j<=right; j++) {
                    weight = filter((center - j) / fscale) / fscale;
                    if (weight== 0.0) continue;

                    if (j < 0) n= -j;
                    else if (j >= srcWidth) n= srcWidth - j + srcWidth - 1;
                    else n= j;

                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }

        else
        // Horizontal super-sampling
        // Scales from smaller to bigger width
        {
            for (i=0; i<dstWidth; i++) {
                contrib[i]= new Weighter((int)Math.floor(fwidth*2.0+1));
                center = i / xscale;
                left = (int)Math.floor(center - fwidth);
                right = (int)Math.ceil(center + fwidth);
                for (j=left; j<=right; j++) {
                    weight = filter(center - j);
                    if (weight == 0.0) continue;
                    if (j < 0) n= -j;
                    else if (j >= srcWidth) n= srcWidth - j + srcWidth - 1;
                    else n= j;

                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }

        // normalize the weights so that the sum = 1 (10/20/2002)
        for (i=0; i<dstWidth; i++) contrib[i].normalized();

        // ----------------------------------------------------
        // Apply filter to sample horizontally from Src to Work
        // ----------------------------------------------------
        int ptr=0,row_ptr=0,pixel;
        for (k=0; k<srcHeight; k++, row_ptr+=srcWidth) {
            for (i=0; i<dstWidth; i++, ptr++) {
                rgb_r = 0.0;
                for (j=0; j<contrib[i].n; j++) {
                    weight = contrib[i].weight[j];
                    if (weight == 0.0) continue;
                    pixel= row_ptr+contrib[i].pixel[j];
                    color_r= red[pixel];
                    rgb_r = rgb_r + color_r * weight;
                }

                color_r = rgb_r;


                work_red[ptr]= color_r;
            }
        }

        // -----------------------------------------------
        // Pre-calculate filter contributions for a column
        // -----------------------------------------------
        contrib= new Weighter[dstHeight];

        // Vertical sub-sampling
        // Scales from bigger to smaller height
        if (yscale < 1.0) {
            width = fwidth / yscale;
            fscale = 1.0 / yscale;

            for (i=0; i<dstHeight; i++) {
                contrib[i]= new Weighter((int)Math.floor(width*2.0+1));
                center = i / yscale;
                left = (int)Math.floor(center - width);
                right = (int)Math.ceil(center + width);
                for ( j= left; j<=right; j++) {
                    weight = filter((center - j) / fscale) / fscale;
                    if (weight == 0.0) continue;
                    if (j < 0) n= -j;
                    else if (j >= srcHeight) n= srcHeight - j + srcHeight - 1;
                    else n= j;
                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }
        else
        // Vertical super-sampling
        // Scales from smaller to bigger height
        {
            for (i= 0; i<dstHeight; i++) {
                contrib[i]= new Weighter((int)Math.floor(fwidth*2.0+1));
                center = i / yscale;
                left = (int)Math.floor(center - fwidth);
                right = (int)Math.ceil(center + fwidth);
                for (j= left; j<=right; j++) {
                    weight = filter(center - j);
                    if (weight == 0.0) continue;
                    if (j < 0) n= -j;
                    else if (j >= srcHeight) n= srcHeight - j + srcHeight - 1;
                    else n= j;
                    k = contrib[i].n;
                    contrib[i].n = contrib[i].n + 1;
                    contrib[i].pixel[k] = n;
                    contrib[i].weight[k] = weight;
                }
            }
        }

        // normalize the weights so that the sum = 1 (10/20/2002)
        for (i=0; i<dstHeight; i++) contrib[i].normalized();

        // --------------------------------------------------
        // Apply filter to sample vertically from Work to Dst
        // --------------------------------------------------
        ptr=0;
        for (k= 0;k<dstWidth;k++) {
            for (i=0; i<dstHeight; i++) {
                rgb_r = 0;
                // weight = 0.0;
                for (j=0; j<contrib[i].n; j++, ptr++) {
                    weight = contrib[i].weight[j];
                    if (weight == 0.0) continue;
                    pixel= contrib[i].pixel[j]*dstWidth+k;
                    color_r= work_red[pixel];

                    rgb_r = rgb_r + color_r * weight;
                }
                color_r = rgb_r;

                dst[i*dstWidth+k]=color_r;
            }
        }

        contrib=null;
        work_red=null;
        System.gc();

        return dst;
    }


    public int getArguNum() { return 2;}
    public void setArgument(int i, String st) {
        if (st.length()==0) return;
        if (i==0) dstWidth= Integer.valueOf(st).intValue();
        else if (i==1) dstHeight= Integer.valueOf(st).intValue();
    };
    public String getArgument(int i) {
        if (i==0) return (new Integer(dstWidth)).toString();
        else if (i==1) return (new Integer(dstHeight)).toString();
        return null;
    };
    public String getArguName(int i) {
        if (i==0) return "width";
        else if (i==1) return "height";
        return null;
    };

    /**
     * getDestSize is to return the destination image size while maintain the
     * aspect ratio of the original image.  For example, if a 648*480 image is
     * scaled down to 160*160, the real size will be 160*120 if the ascpect ratio
     * is kept.  User will provide the boundary of the destination image.
     * @param img_width original image width
     * @param img_height original image height
     * @param boundary_width width of the destination image boundary
     * @param boundary_height height of the destination image boundary
     * @return the real dimension of the destination image
     */
    public static Dimension getDestSize(int img_width, int img_height,
      int boundary_width, int boundary_height) {
        // boundary_width/img_width < boundary_height/img_height
        if (boundary_width * img_height < boundary_height * img_width) {
          return new Dimension(boundary_width, boundary_width * img_height / img_width);
        }
        else return new Dimension(boundary_height * img_width / img_height, boundary_height);
    }

    /**
     * Resample using the specified method.  The maximum of the returned image
     * width and height is less than the given max_size.
     * @param pixels pass null if only want the rescaled dimension
     * @param d used to pass in the dimension of the image and return size of
     *          the processed image.
     * @param resample_method
     * @param max_size
     * @return
     */
    public static ResampledDescriptor scaleDown(int[] pixels, Dimension d, int resample_method, int max_size)
    {

        double x_scale = (double)max_size / d.width;
        double y_scale = (double)max_size / d.height;

        // scale the image so that the max (width, height) <= max_size
        double the_scale = Math.min(x_scale, y_scale);
        if (the_scale < 1) {
          int target_w = (int)Math.round(d.width * the_scale);
          int target_h = (int)Math.round(d.height * the_scale);
          if (pixels == null) return new ResampledDescriptor(null, new Dimension(target_w, target_h), the_scale);

          int[] scaled = scaleDown(pixels, d, resample_method, target_w, target_h);

          return new ResampledDescriptor(scaled, new Dimension(target_w, target_h), the_scale);
        }
        return null;
    }

    /**
     * Resample using the specified method.  The maximum of the returned image
     * width and height is less than the given max_size.
     * @param pixels
     * @param d used to pass in the dimension of the image and return size of
     *          the processed image.
     * @param resample_method
     * @param max_size
     * @return
     */
    public static int[] scaleDown(int[] pixels, Dimension d, int resample_method, int target_w, int target_h)
    {

        if (target_w < d.width || target_h < d.height) {
          Resampler resampler = null;
          switch (resample_method) {
            case 0: resampler = new BellResampler(target_w, target_h); break;
            case 1: resampler = new BSplineResampler(target_w, target_h); break;
            case 2: resampler = new HermiteResampler(target_w, target_h); break;
            case 3: resampler = new Lanczos3Resampler(target_w, target_h); break;
            case 4: resampler = new LinearResampler(target_w, target_h); break;
            case 5: resampler = new MitchellResampler(target_w, target_h); break;
            case 6: resampler = new NearestResampler(target_w, target_h); break;
            default: resampler = new SimpleResampler(target_w, target_h);
          }

          return resampler.getProcessed(pixels, d);
        }
        return pixels;
    }

    /**
     * Scale the image to either 192x128 or 128x192
     * @param pixels
     * @param d
     * @return
     */
    public static int[] scale4Blobworld(int[] pixels, Dimension d) {
      // rescale the image if necessary
      if (d.width > d.height) {
        pixels = Resampler.scaleDown(pixels, d,
            Resampler.BELL_RESAMPLER, 192, 128);
        d.width = 192;
        d.height = 128;
      } else {
        pixels = Resampler.scaleDown(pixels, d,
            Resampler.BELL_RESAMPLER, 128, 192);
        d.width = 128;
        d.height = 192;
      }
      return pixels;
    }

    /**
     * The images will be scaled to 192x128 or 128x192
     */
    public static class Scale4Blobworld {
      public final static String USAGE = "Usage: -f from_path -t dest_path -i image_name";

      public static void main(String[] args)
      {
        // get the image name
        String img_name = ReadArgu.getOption('i', args);
        if (img_name == null) {
          System.err.println("Usage: -i image_name");
          System.exit(1);
        }

        String from_path = ReadArgu.getOption('f', args, "");
        String to_path = ReadArgu.getOption('t', args, "");

        // read in image
        System.out.println("resample " + from_path + img_name);
        Image image = yi.util.io.ImageReader.JAIReadImage(from_path + img_name);
        Dimension d = new Dimension();
        int[] pixels = yi.util.io.ImageReader.getPixels(image, d);

        // rescale the image if necessary
        pixels = scale4Blobworld(pixels, d) ;

        img_name = img_name + Resampler.RESIZED_FILE_SUFFIX + "192.ppm";
        System.out.println("write to " + to_path + img_name);
        boolean madedir = yi.util.io.File.makeDirectory(to_path + img_name, true);
        if (!madedir) {
          System.err.println("Can't make directory for " + to_path);
          System.exit(1);
        }
        yi.util.io.OutputResult.outputColorImage(to_path + img_name, pixels, d.width,
                                     d.height);
//        try {
//          yi.util.io.ImageIOUtil.write(to_path + img_name, "png", pixels, d.width, d.height);
//        } catch (Exception e) {
//          e.printStackTrace();
//        }
      }

    }

    public final static String USAGE = "Usage: -f from_path -t dest_path -i image_name -s max_of_dest_image_width_and_height";

    public static void main(String[] args)
    {
      // get the image name
      String img_name = ReadArgu.getOption('i', args);
      if (img_name == null) {
        System.err.println("Usage: -i image_name");
        System.exit(1);
      }

      String from_path = ReadArgu.getOption('f', args, "");
      String to_path = ReadArgu.getOption('t', args, "");

      // get the scale
      String scale_str = ReadArgu.getOption('s', args);
      int scale = 1;
      if (scale_str != null) {
        scale = Integer.parseInt(scale_str);
      }

      // read in image
      System.out.println("resample " + from_path + img_name);
      Image image = yi.util.io.ImageReader.JAIReadImage(from_path + img_name);
      Dimension d = new Dimension();
      int[] pixels = yi.util.io.ImageReader.getPixels(image, d);

      // rescale the image if necessary
      double the_scale = 1.0;
      if (scale != 1) {
          ResampledDescriptor resampled = Resampler.scaleDown(pixels, d,
              Resampler.BELL_RESAMPLER, scale);
          if (resampled != null) {
            pixels = resampled.m_resampled;
            d = resampled.m_newDimension;
            the_scale = resampled.m_scale;
            img_name = img_name + Resampler.RESIZED_FILE_SUFFIX + scale + ".ppm";
            System.out.println("write to " + to_path + img_name);
            boolean madedir = yi.util.io.File.makeDirectory(to_path + img_name, true);
            if (!madedir) {
              System.err.println("Can't make directory for " + to_path);
              System.exit(1);
            }

            yi.util.io.OutputResult.outputColorImage(to_path + img_name, pixels, d.width,
                                         d.height);
          }
      }
    }

}


