Source for gnu.javax.imageio.png.PNGFilter

   1: /* PNGFilter.java -- PNG image filters.
   2:    Copyright (C) 2006 Free Software Foundation
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package gnu.javax.imageio.png;
  39: 
  40: /**
  41:  * A utility class of static methods implementing the PNG filtering algorithms.
  42:  */
  43: public class PNGFilter
  44: {
  45: 
  46:   public static final byte FILTER_NONE = 0;
  47:   public static final byte FILTER_SUB = 1;
  48:   public static final byte FILTER_UP = 2;
  49:   public static final byte FILTER_AVERAGE = 3;
  50:   public static final byte FILTER_PAETH = 4;
  51: 
  52:   /**
  53:    * Return whether a filter should be used or FILTER_NONE,
  54:    * following the recommendations in the PNG spec.
  55:    */
  56:   public static boolean useFilter( PNGHeader header )
  57:   {
  58:     switch( header.getColorType() )
  59:       {
  60:       case PNGHeader.INDEXED:
  61:         return false;
  62: 
  63:       case PNGHeader.GRAYSCALE:
  64:       case PNGHeader.RGB:
  65:         if( header.bytesPerPixel() <= 1 )
  66:           return false;
  67:       case PNGHeader.GRAYSCALE_WITH_ALPHA:
  68:       case PNGHeader.RGB_WITH_ALPHA:
  69:       default:
  70:         return true;
  71:       }
  72:   }
  73: 
  74:   /**
  75:    * Heuristic for adaptively choosing a filter, following the scheme
  76:    * suggested in the PNG spec.
  77:    * @return a fiter type.
  78:    */
  79:   public static byte chooseFilter( byte[] scanline, byte[] lastScanline,
  80:                                   int bpp)
  81: 
  82:   {
  83:     long[] values = new long[5];
  84:     int idx = 0;
  85:     for( int i = 0; i < 5; i++ )
  86:       {
  87:         byte[] filtered = filterScanline((byte)i, scanline, lastScanline, bpp);
  88:         values[i] = 0;
  89:         for(int j = 0; j < filtered.length; j++ )
  90:           values[i] += (int)(filtered[j] & 0xFF);
  91:         if( values[ idx ] > values[i] )
  92:           idx = i;
  93:       }
  94:     return (byte)idx;
  95:   }
  96: 
  97:   /**
  98:    * Filter a scanline.
  99:    */
 100:   public static byte[] filterScanline( byte filtertype, byte[] scanline,
 101:                                        byte[] lastScanline, int bpp)
 102:   {
 103:     int stride = scanline.length;
 104:     byte[] out = new byte[ stride ];
 105:     switch( filtertype )
 106:       {
 107:       case FILTER_SUB:
 108:         for( int i = 0; i < bpp; i++)
 109:           out[ i ] = scanline[ i ];
 110: 
 111:         for( int i = bpp; i < stride; i++ )
 112:           out[i] = (byte)(scanline[ i ] -
 113:                           scanline[ i - bpp ]);
 114:         break;
 115: 
 116:       case FILTER_UP:
 117:         for( int i = 0; i < stride; i++ )
 118:           out[ i ] = (byte)(scanline[ i ] - lastScanline[ i ]);
 119:         break;
 120: 
 121:       case FILTER_AVERAGE:
 122:         for( int i = 0; i < bpp; i++)
 123:           out[ i ] = (byte)((scanline[ i ] & 0xFF) - ((lastScanline[ i ] & 0xFF) >> 1));
 124:         for( int i = bpp; i < stride; i++ )
 125:           out[ i ] = (byte)((scanline[ i ] & 0xFF) -
 126:                             (((scanline[ i - bpp ] & 0xFF) +
 127:                               (lastScanline[ i ] & 0xFF)) >> 1));
 128:         break;
 129: 
 130:       case FILTER_PAETH:
 131:         for( int i = 0; i < stride; i++ )
 132:           {
 133:             int x;
 134:             {
 135:               int a, b, c;
 136:               if( i >= bpp )
 137:                 {
 138:                   a = (scanline[ i - bpp ] & 0xFF); // left
 139:                   c = (lastScanline[ i - bpp ] & 0xFF); // upper-left
 140:                 }
 141:               else
 142:                 a = c = 0;
 143:               b = (lastScanline[ i ] & 0xFF); // up
 144: 
 145:               int p = (a + b - c);        // initial estimate
 146:               // distances to a, b, c
 147:               int pa = (p > a) ? p - a : a - p;
 148:               int pb = (p > b) ? p - b : b - p;
 149:               int pc = (p > c) ? p - c : c - p;
 150:               // return nearest of a,b,c,
 151:               // breaking ties in order a,b,c.
 152:               if( pa <= pb && pa <= pc ) x = a;
 153:               else { if( pb <= pc ) x = b;
 154:                 else x = c;
 155:               }
 156:             }
 157:             out[ i ] = (byte)(scanline[ i ] - x);
 158:           }
 159:         break;
 160:       default:
 161:       case FILTER_NONE:
 162:         return scanline;
 163:       }
 164:     return out;
 165:   }
 166: 
 167:   /**
 168:    * Unfilter a scanline.
 169:    */
 170:   public static byte[] unFilterScanline( int filtertype, byte[] scanline,
 171:                                          byte[] lastScanline, int bpp)
 172:   {
 173:     int stride = scanline.length;
 174:     byte[] out = new byte[ stride ];
 175:     switch( filtertype )
 176:       {
 177: 
 178:       case FILTER_NONE:
 179:         System.arraycopy( scanline, 0, out, 0, stride );
 180:         break;
 181: 
 182:       case FILTER_SUB:
 183:         for( int i = 0; i < bpp; i++)
 184:           out[ i ] = scanline[ i ];
 185: 
 186:         for( int i = bpp; i < stride; i++ )
 187:           out[ i ] = (byte)(scanline[ i ] +
 188:                             out[ i - bpp ]);
 189:         break;
 190: 
 191:       case FILTER_UP:
 192:         for( int i = 0; i < stride; i++ )
 193:           out[ i ] = (byte)(scanline[ i ] + lastScanline[ i ]);
 194:         break;
 195: 
 196:       case FILTER_AVERAGE:
 197:         for( int i = 0; i < bpp; i++)
 198:           out[ i ] = (byte)((scanline[ i ] & 0xFF) + ((lastScanline[ i ] & 0xFF) >> 1));
 199:         for( int i = bpp; i < stride; i++ )
 200:           out[ i ] = (byte)((scanline[ i ] & 0xFF) +
 201:                             (((out[ i - bpp ] & 0xFF) + (lastScanline[ i ] & 0xFF)) >> 1));
 202:         break;
 203: 
 204:       case FILTER_PAETH:
 205:         for( int i = 0; i < stride; i++ )
 206:           {
 207:             int x;
 208:             {
 209:               int a, b, c;
 210:               if( i >= bpp )
 211:                 {
 212:                   a = (out[ i - bpp ] & 0xFF); // left
 213:                   c = (lastScanline[ i - bpp ] & 0xFF); // upper-left
 214:                 }
 215:               else
 216:                 a = c = 0;
 217:               b = (lastScanline[ i ] & 0xFF); // up
 218: 
 219:               int p = (a + b - c);        // initial estimate
 220:               // distances to a, b, c
 221:               int pa = (p > a) ? p - a : a - p;
 222:               int pb = (p > b) ? p - b : b - p;
 223:               int pc = (p > c) ? p - c : c - p;
 224:               // return nearest of a,b,c,
 225:               // breaking ties in order a,b,c.
 226:               if( pa <= pb && pa <= pc ) x = a;
 227:               else { if( pb <= pc ) x = b;
 228:                 else x = c;
 229:               }
 230:             }
 231:             out[ i ] = (byte)(scanline[ i ] + x);
 232:           }
 233:         break;
 234:       }
 235:     return out;
 236:   }
 237: }