1 /* 2 * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.imageio.plugins.png; 27 28 public class RowFilter { 29 abs(int x)30 private static final int abs(int x) { 31 return (x < 0) ? -x : x; 32 } 33 34 // Returns the sum of absolute differences subFilter(byte[] currRow, byte[] subFilteredRow, int bytesPerPixel, int bytesPerRow)35 protected static int subFilter(byte[] currRow, 36 byte[] subFilteredRow, 37 int bytesPerPixel, 38 int bytesPerRow) { 39 int badness = 0; 40 for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { 41 int curr = currRow[i] & 0xff; 42 int left = currRow[i - bytesPerPixel] & 0xff; 43 int difference = curr - left; 44 subFilteredRow[i] = (byte)difference; 45 46 badness += abs(difference); 47 } 48 49 return badness; 50 } 51 52 // Returns the sum of absolute differences upFilter(byte[] currRow, byte[] prevRow, byte[] upFilteredRow, int bytesPerPixel, int bytesPerRow)53 protected static int upFilter(byte[] currRow, 54 byte[] prevRow, 55 byte[] upFilteredRow, 56 int bytesPerPixel, 57 int bytesPerRow) { 58 int badness = 0; 59 for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { 60 int curr = currRow[i] & 0xff; 61 int up = prevRow[i] & 0xff; 62 int difference = curr - up; 63 upFilteredRow[i] = (byte)difference; 64 65 badness += abs(difference); 66 } 67 68 return badness; 69 } 70 paethPredictor(int a, int b, int c)71 protected final int paethPredictor(int a, int b, int c) { 72 int p = a + b - c; 73 int pa = abs(p - a); 74 int pb = abs(p - b); 75 int pc = abs(p - c); 76 77 if ((pa <= pb) && (pa <= pc)) { 78 return a; 79 } else if (pb <= pc) { 80 return b; 81 } else { 82 return c; 83 } 84 } 85 filterRow(int colorType, byte[] currRow, byte[] prevRow, byte[][] scratchRows, int bytesPerRow, int bytesPerPixel)86 public int filterRow(int colorType, 87 byte[] currRow, 88 byte[] prevRow, 89 byte[][] scratchRows, 90 int bytesPerRow, 91 int bytesPerPixel) { 92 93 // Use type 0 for palette images 94 if (colorType != PNGImageReader.PNG_COLOR_PALETTE) { 95 System.arraycopy(currRow, bytesPerPixel, 96 scratchRows[0], bytesPerPixel, 97 bytesPerRow); 98 return 0; 99 } 100 101 int[] filterBadness = new int[5]; 102 for (int i = 0; i < 5; i++) { 103 filterBadness[i] = Integer.MAX_VALUE; 104 } 105 106 { 107 int badness = 0; 108 109 for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { 110 int curr = currRow[i] & 0xff; 111 badness += curr; 112 } 113 114 filterBadness[0] = badness; 115 } 116 117 { 118 byte[] subFilteredRow = scratchRows[1]; 119 int badness = subFilter(currRow, 120 subFilteredRow, 121 bytesPerPixel, 122 bytesPerRow); 123 124 filterBadness[1] = badness; 125 } 126 127 { 128 byte[] upFilteredRow = scratchRows[2]; 129 int badness = upFilter(currRow, 130 prevRow, 131 upFilteredRow, 132 bytesPerPixel, 133 bytesPerRow); 134 135 filterBadness[2] = badness; 136 } 137 138 { 139 byte[] averageFilteredRow = scratchRows[3]; 140 int badness = 0; 141 142 for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { 143 int curr = currRow[i] & 0xff; 144 int left = currRow[i - bytesPerPixel] & 0xff; 145 int up = prevRow[i] & 0xff; 146 int difference = curr - (left + up)/2;; 147 averageFilteredRow[i] = (byte)difference; 148 149 badness += abs(difference); 150 } 151 152 filterBadness[3] = badness; 153 } 154 155 { 156 byte[] paethFilteredRow = scratchRows[4]; 157 int badness = 0; 158 159 for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { 160 int curr = currRow[i] & 0xff; 161 int left = currRow[i - bytesPerPixel] & 0xff; 162 int up = prevRow[i] & 0xff; 163 int upleft = prevRow[i - bytesPerPixel] & 0xff; 164 int predictor = paethPredictor(left, up, upleft); 165 int difference = curr - predictor; 166 paethFilteredRow[i] = (byte)difference; 167 168 badness += abs(difference); 169 } 170 171 filterBadness[4] = badness; 172 } 173 174 int minBadness = filterBadness[0]; 175 int filterType = 0; 176 177 for (int i = 1; i < 5; i++) { 178 if (filterBadness[i] < minBadness) { 179 minBadness = filterBadness[i]; 180 filterType = i; 181 } 182 } 183 184 if (filterType == 0) { 185 System.arraycopy(currRow, bytesPerPixel, 186 scratchRows[0], bytesPerPixel, 187 bytesPerRow); 188 } 189 190 return filterType; 191 } 192 } 193