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:   }