home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / image / LookupOp.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  16.8 KB  |  464 lines

  1. /*
  2.  * @(#)LookupOp.java    1.37 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15.  
  16. package java.awt.image;
  17.  
  18. import java.awt.GraphicsEnvironment;
  19. import java.awt.color.ColorSpace;
  20. import java.awt.geom.Rectangle2D;
  21. import java.awt.Rectangle;
  22. import java.awt.geom.Point2D;
  23.  
  24. /**
  25.  * This class implements a lookup operation from the source
  26.  * to the destination.  The LookupTable object may contain a single array
  27.  * or multiple arrays, subject to the restrictions below.
  28.  * <p>
  29.  * For Rasters, the lookup operates on channel elements.  The number of
  30.  * lookup arrays may be one, in which case the same array is
  31.  * applied to all channels, or it must equal the number of Source
  32.  * Raster channels.
  33.  * <p>
  34.  * For BufferedImages, the lookup operates on color and alpha components.
  35.  * The number of lookup arrays may be one, in which case the
  36.  * same array is applied to all color and alpha components, or it
  37.  * must equal the number of Source color components, in which case no
  38.  * lookup of the alpha component (if present) is performed, or it
  39.  * must equal the number of Source color components plus alpha components,
  40.  * in which case lookup is performed for all color and alpha components.
  41.  * This allows non-uniform rescaling of multi-channelled BufferedImages.
  42.  *
  43.  * Images with an IndexColorModel cannot be used.
  44.  * <p>
  45.  * This class allows the Source to be the same as Destination.
  46.  * 
  47.  * @version 10 Feb 1997
  48.  * @see LookupTable
  49.  */
  50.  
  51. public class LookupOp implements BufferedImageOp, RasterOp {
  52.     private LookupTable ltable;
  53.  
  54.     /**
  55.      * Constructs a LookupOp object given the lookup table.
  56.      */
  57.     public LookupOp(LookupTable lookup) {
  58.         this.ltable = lookup;
  59.     }
  60.  
  61.     /**
  62.      * Returns the LookupTable.
  63.      */
  64.     public final LookupTable getLookupTable() {
  65.         return ltable;
  66.     }
  67.  
  68.     /**
  69.      * Performs a lookup operation on a BufferedImage.  
  70.      * If the color model in the source image is not the same as that
  71.      * in the destination image, the pixels will be converted
  72.      * in the destination.  If the destination image is null,
  73.      * a BufferedImage will be created with the source ColorModel.
  74.      * The IllegalArgumentException may be thrown if the number of
  75.      * arrays in the LookupTable does not meet the restrictions
  76.      * stated in the class comment above.
  77.      */
  78.     public BufferedImage filter (BufferedImage src, BufferedImage dst) {
  79.         ColorModel srcCM = src.getColorModel();
  80.         int numBands = srcCM.getNumColorComponents();
  81.         if (srcCM instanceof IndexColorModel) {
  82.             throw new
  83.                 IllegalArgumentException("LookupOp cannot be "+
  84.                                          "performed on an indexed image");
  85.         }
  86.         boolean needToConvert = false;
  87.         
  88.         int width = src.getWidth();
  89.         int height = src.getHeight();
  90.  
  91.         if (dst == null) {
  92.             dst = createCompatibleDestImage(src, null);
  93.         }
  94.         else {
  95.             if (width != dst.getWidth()) {
  96.                 throw new
  97.                     IllegalArgumentException("Src width ("+width+
  98.                                              ") not equal to dst width ("+
  99.                                              dst.getWidth()+")");
  100.             }
  101.             if (height != dst.getHeight()) {
  102.                 throw new
  103.                     IllegalArgumentException("Src height ("+height+
  104.                                              ") not equal to dst height ("+
  105.                                              dst.getHeight()+")");
  106.             }
  107.  
  108.             ColorModel dstCM = dst.getColorModel();
  109.             if (srcCM.getColorSpace().getType() !=
  110.                 dstCM.getColorSpace().getType())
  111.             {
  112.                 needToConvert = true;
  113.                 dst = createCompatibleDestImage(src, null);
  114.             }
  115.  
  116.         }
  117.         
  118.         BufferedImage origDst = dst;
  119.         GraphicsEnvironment ge =
  120.             GraphicsEnvironment.getLocalGraphicsEnvironment();
  121.         ImagingLib imlib = ge.getImagingLib();
  122.  
  123.         if (imlib.filter(this, src, dst) == null) {
  124.             if (srcCM instanceof ComponentColorModel) {
  125.                 filter(src.getRaster(), dst.getRaster());
  126.             }
  127.             else {
  128.                 // Do it the slow way
  129.                 WritableRaster srcRaster = src.getRaster();
  130.                 WritableRaster dstRaster = dst.getRaster();
  131.                 int[] data = null;
  132.                 int[] components = null;
  133.  
  134.                 int sminX = src.getMinXCoord();
  135.                 int sX;
  136.                 int sY = src.getMinYCoord();
  137.                 int dminX = dst.getMinXCoord();
  138.                 int dX;
  139.                 int dY = dst.getMinYCoord();
  140.                 for (int y=0; y < height; y++, sY++, dY++) {
  141.                     sX = sminX;
  142.                     dX = dminX;
  143.                     for (int x = 0; x < width; x++, sX++, dX++) {
  144.                         data = srcRaster.getPixel(sX, sY, data);
  145.                         // Lookup the data for all bands at this x,y position
  146.                         ltable.lookupPixel(data, data);
  147.                         
  148.                         dstRaster.setPixel(dX, dY, data);
  149.                     }
  150.                 }
  151.             }
  152.         }
  153.         
  154.         if (needToConvert) {
  155.             // ColorModels are not the same
  156.             ColorConvertOp ccop = new ColorConvertOp();
  157.             ccop.filter(dst, origDst);
  158.         }
  159.  
  160.         return origDst;
  161.     }
  162.  
  163.     /**
  164.      * Performs a lookup operation on a Raster.  If the destination Raster is
  165.      * null, a new Raster will be created.
  166.      * The IllegalArgumentException may be thrown if the source and
  167.      * destination Rasters have different number of channels or if
  168.      * the number of arrays in the LookupTable does not meet the
  169.      * restrictions stated in the class comment above.
  170.      */
  171.     public WritableRaster filter (Raster src, WritableRaster dst) {
  172.         int x, y, band;
  173.         int numBands  = src.getNumBands();
  174.         int dstLength = dst.getNumBands();
  175.         int height    = src.getHeight();
  176.         int width     = src.getWidth();
  177.         int srcPix[]  = new int[width];
  178.         
  179.         // Create a new destination Raster, if needed
  180.         if (dst == null) {
  181.             dst = createCompatibleDestRaster(src);
  182.         }
  183.         else if (height != dst.getHeight() || width != dst.getWidth()) {
  184.             throw new
  185.                 IllegalArgumentException ("Width or height of Rasters do not "+
  186.                                           "match");
  187.         }
  188.         dstLength = dst.getNumBands();
  189.         
  190.         if (numBands != dstLength) {
  191.             throw new
  192.                 IllegalArgumentException ("Number of channels in the src ("
  193.                                           + numBands +
  194.                                           ") does not match number of channels"
  195.                                           + " in the destination ("
  196.                                           + dstLength + ")");
  197.         }
  198.  
  199.         // Optimize for cases we know about
  200.         if (ltable instanceof ByteLookupTable) {
  201.             byteFilter ((ByteLookupTable) ltable, src, dst,
  202.                         width, height, numBands);
  203.         }
  204.         else if (ltable instanceof ShortLookupTable) {
  205.             shortFilter ((ShortLookupTable) ltable, src, dst, width,
  206.                          height, numBands);
  207.         }
  208.         else {
  209.             // Not one we recognize so do it slowly
  210.             int sminX = src.getMinX();
  211.             int sX;
  212.             int sY = src.getMinY();
  213.             int dminX = dst.getMinX();
  214.             int dX;
  215.             int dY = dst.getMinY();
  216.             for (y=0; y < height; y++, sY++, dY++) {
  217.                 sX = sminX;
  218.                 dX = dminX;
  219.                 for (x=0; x < width; x++, sX++, dX++) {
  220.                     // Find data for all bands at this x,y position
  221.                     src.getPixel(sX, sY, srcPix);
  222.  
  223.                     // Lookup the data for all bands at this x,y position
  224.                     ltable.lookupPixel(srcPix, srcPix);
  225.  
  226.                     // Put it back for all bands
  227.                     dst.setPixel(dX, dY, srcPix);
  228.                 }
  229.             }
  230.         }
  231.  
  232.         return dst;
  233.     }
  234.  
  235.     /**
  236.      * Returns the bounding box of the destination.  Since
  237.      * this is not a geometric operation, the bounding box does not
  238.      * change.
  239.      * The IllegalArgumentException may be thrown if the number of
  240.      * arrays in the LookupTable does not meet the restrictions
  241.      * stated in the class comment above.
  242.      */
  243.     public Rectangle2D getDestBounds (BufferedImage src) {
  244.         return getDestBounds(src.getRaster());
  245.     }
  246.  
  247.     /**
  248.      * Returns the bounding box of the destination.  Since
  249.      * this is not a geometric operation, the bounding box does not
  250.      * change.
  251.      * The IllegalArgumentException may be thrown if the number of
  252.      * arrays in the LookupTable does not meet the restrictions
  253.      * stated in the class comment above.
  254.      */
  255.     public Rectangle2D getDestBounds (Raster src) {
  256.     /*        return new Rectangle (src.getXOffset(),
  257.                   src.getYOffset(),
  258.                   src.getWidth(), src.getHeight()); */
  259.     return src.getBounds();
  260.                   
  261.     }
  262.  
  263.     /**
  264.      * Creates an empty destination image with the correct size and number of
  265.      * channels.
  266.      * The IllegalArgumentException may be thrown if the number of
  267.      * arrays in the LookupTable does not meet the restrictions
  268.      * stated in the class comment above.
  269.      * @param src       Source image for the filter operation.
  270.      * @param destCM    ColorModel of the destination.  If null, the
  271.      *                  ColorModel of the source will be used.
  272.      */
  273.     public BufferedImage createCompatibleDestImage (BufferedImage src,
  274.                                                     ColorModel destCM) {
  275.         BufferedImage image;
  276.         int w = src.getWidth();
  277.         int h = src.getHeight();
  278.         if (destCM == null) {
  279.             ColorModel cm = src.getColorModel();
  280.             Raster raster = src.getRaster();
  281.             if (cm instanceof ComponentColorModel) {
  282.                 DataBuffer db = raster.getDataBuffer();
  283.                 boolean hasAlpha = cm.hasAlpha();
  284.                 boolean isPre    = cm.isAlphaPremultiplied();
  285.                 int trans        = cm.getTransparency();
  286.                 int[] nbits = null;
  287.                 if (ltable instanceof ByteLookupTable) {
  288.                     if (db.getDataType() == db.SHORT_DATA) {
  289.                         // Dst raster should be of type byte
  290.                         if (hasAlpha) {
  291.                             nbits = new int[2];
  292.                             if (trans == cm.BITMASK) {
  293.                                 nbits[1] = 1;
  294.                             }
  295.                             else {
  296.                                 nbits[1] = 8;
  297.                             }
  298.                         }
  299.                         else {
  300.                             nbits = new int[1];
  301.                         }
  302.                         nbits[0] = 8;
  303.                     }
  304.                     // For byte, no need to change the cm
  305.                 }
  306.                 else if (ltable instanceof ShortLookupTable) {
  307.                     if (db.getDataType() == db.BYTE_DATA) {
  308.                         if (hasAlpha) {
  309.                             nbits = new int[2];
  310.                             if (trans == cm.BITMASK) {
  311.                                 nbits[1] = 1;
  312.                             }
  313.                             else {
  314.                                 nbits[1] = 16;
  315.                             }
  316.                         }
  317.                         else {
  318.                             nbits = new int[1];
  319.                         }
  320.                         nbits[0] = 16;
  321.                     }
  322.                 }
  323.                 if (nbits != null) {
  324.                     cm = new ComponentColorModel(cm.getColorSpace(),
  325.                                                  nbits, hasAlpha, isPre,
  326.                                                  trans);
  327.                 }
  328.             }
  329.             image = new BufferedImage(cm,
  330.                                       cm.createCompatibleWritableRaster(w, h),
  331.                                       cm.isAlphaPremultiplied());
  332.         }
  333.         else {
  334.             image = new BufferedImage(destCM,
  335.                                       destCM.createCompatibleWritableRaster(w,
  336.                                                                             h),
  337.                                       destCM.isAlphaPremultiplied());
  338.         }
  339.  
  340.         return image;
  341.     }
  342.     
  343.     /**
  344.      * Creates an empty destination Raster with the correct size and number of
  345.      * channels.
  346.      * The IllegalArgumentException may be thrown if the number of
  347.      * arrays in the LookupTable does not meet the restrictions
  348.      * stated in the class comment above.
  349.      */
  350.     public WritableRaster createCompatibleDestRaster (Raster src) {
  351.         return src.createCompatibleWritableRaster();
  352.     }
  353.     
  354.     /**
  355.      * Returns the location of the destination point given a
  356.      * point in the source image.  If dstPt is non-null, it will
  357.      * be used to hold the return value.  Since this is not a geometric
  358.      * operation, the srcPt will equal the dstPt.
  359.      */
  360.     public Point2D getDestPoint (Point2D srcPt, Point2D dstPt) {
  361.         if (dstPt == null) {
  362.             dstPt = new Point2D.Float();
  363.         }
  364.     dstPt.setLocation(srcPt.getX(), srcPt.getY());
  365.  
  366.         return dstPt;
  367.     }
  368.     
  369.     private final void byteFilter(ByteLookupTable lookup, Raster src,
  370.                                   WritableRaster dst,
  371.                                   int width, int height, int numBands) {
  372.         int[] srcPix = null;
  373.  
  374.         // Find the ref to the table and the offset
  375.         byte[][] table = lookup.getDataStorage();
  376.         int offset = lookup.getOffset();
  377.         int tidx;
  378.         int step=1;
  379.  
  380.         // Check if it is one lookup applied to all bands
  381.         if (table.length == 1) {
  382.             step=0;
  383.         }
  384.  
  385.         int x;
  386.         int y;
  387.         int band;
  388.         int len = table[0].length;
  389.         
  390.         // Loop through the data
  391.         for ( y=0; y < height; y++) {
  392.             tidx = 0;
  393.             for ( band=0; band < numBands; band++, tidx+=step) {
  394.                 // Find data for this band, scanline
  395.                 srcPix = src.getSample(0, y, width, 1, band, srcPix);
  396.  
  397.                 for ( x=0; x < width; x++) {
  398.                     int index = srcPix[x]-offset;
  399.                     if (index < 0 || index > len) {
  400.                         throw new
  401.                             IllegalArgumentException("index ("+index+
  402.                                                      "(out of range: "+
  403.                                                      " srcPix["+x+
  404.                                                      "]="+ srcPix[x]+
  405.                                                      " offset="+ offset);
  406.                     }
  407.                     // Do the lookup
  408.                     srcPix[x] = table[tidx][index];
  409.                 }
  410.                 // Put it back
  411.                 dst.setSample(0, y, width, 1, band, srcPix);
  412.             }
  413.         }
  414.     }
  415.     
  416.     private final void shortFilter(ShortLookupTable lookup, Raster src,
  417.                                    WritableRaster dst,
  418.                                    int width, int height, int numBands) {
  419.         int band;
  420.         int[] srcPix = null;
  421.  
  422.         // Find the ref to the table and the offset
  423.         short[][] table = lookup.getDataStorage();
  424.         int offset = lookup.getOffset();
  425.         int tidx;
  426.         int step=1;
  427.         
  428.         // Check if it is one lookup applied to all bands
  429.         if (table.length == 1) {
  430.             step=0;
  431.         }
  432.  
  433.         int x = 0;
  434.         int y = 0;
  435.         int index;
  436.         int maxShort = (1<<16)-1;
  437.         // Loop through the data
  438.         for (y=0; y < height; y++) {
  439.             tidx = 0;
  440.             for ( band=0; band < numBands; band++, tidx+=step) {
  441.                 // Find data for this band, scanline
  442.                 srcPix = src.getSample(0, y, width, 1, band, srcPix);
  443.  
  444.                 for ( x=0; x < width; x++) {
  445.                     index = srcPix[x]-offset;
  446.                     if (index < 0 || index > maxShort) {
  447.                         throw new
  448.                             IllegalArgumentException("index out of range "+
  449.                                                      index+" x is "+x+
  450.                                                      "srcPix[x]="+srcPix[x]
  451.                                                      +" offset="+ offset);
  452.                     }
  453.                     // Do the lookup
  454.                     srcPix[x] = table[tidx][index];
  455.                 }
  456.                 // Put it back
  457.                 dst.setSample(0, y, width, 1, band, srcPix);
  458.             }
  459.         }
  460.     }
  461. }
  462.  
  463.  
  464.