/* * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package com.sun.imageio.plugins.png; public class RowFilter { private static final int abs(int x) { return (x < 0) ? -x : x; } // Returns the sum of absolute differences protected static int subFilter(byte[] currRow, byte[] subFilteredRow, int bytesPerPixel, int bytesPerRow) { int badness = 0; for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { int curr = currRow[i] & 0xff; int left = currRow[i - bytesPerPixel] & 0xff; int difference = curr - left; subFilteredRow[i] = (byte)difference; badness += abs(difference); } return badness; } // Returns the sum of absolute differences protected static int upFilter(byte[] currRow, byte[] prevRow, byte[] upFilteredRow, int bytesPerPixel, int bytesPerRow) { int badness = 0; for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { int curr = currRow[i] & 0xff; int up = prevRow[i] & 0xff; int difference = curr - up; upFilteredRow[i] = (byte)difference; badness += abs(difference); } return badness; } protected final int paethPredictor(int a, int b, int c) { int p = a + b - c; int pa = abs(p - a); int pb = abs(p - b); int pc = abs(p - c); if ((pa <= pb) && (pa <= pc)) { return a; } else if (pb <= pc) { return b; } else { return c; } } public int filterRow(int colorType, byte[] currRow, byte[] prevRow, byte[][] scratchRows, int bytesPerRow, int bytesPerPixel) { // Use type 0 for palette images if (colorType != PNGImageReader.PNG_COLOR_PALETTE) { System.arraycopy(currRow, bytesPerPixel, scratchRows[0], bytesPerPixel, bytesPerRow); return 0; } int[] filterBadness = new int[5]; for (int i = 0; i < 5; i++) { filterBadness[i] = Integer.MAX_VALUE; } { int badness = 0; for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { int curr = currRow[i] & 0xff; badness += curr; } filterBadness[0] = badness; } { byte[] subFilteredRow = scratchRows[1]; int badness = subFilter(currRow, subFilteredRow, bytesPerPixel, bytesPerRow); filterBadness[1] = badness; } { byte[] upFilteredRow = scratchRows[2]; int badness = upFilter(currRow, prevRow, upFilteredRow, bytesPerPixel, bytesPerRow); filterBadness[2] = badness; } { byte[] averageFilteredRow = scratchRows[3]; int badness = 0; for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { int curr = currRow[i] & 0xff; int left = currRow[i - bytesPerPixel] & 0xff; int up = prevRow[i] & 0xff; int difference = curr - (left + up)/2;; averageFilteredRow[i] = (byte)difference; badness += abs(difference); } filterBadness[3] = badness; } { byte[] paethFilteredRow = scratchRows[4]; int badness = 0; for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { int curr = currRow[i] & 0xff; int left = currRow[i - bytesPerPixel] & 0xff; int up = prevRow[i] & 0xff; int upleft = prevRow[i - bytesPerPixel] & 0xff; int predictor = paethPredictor(left, up, upleft); int difference = curr - predictor; paethFilteredRow[i] = (byte)difference; badness += abs(difference); } filterBadness[4] = badness; } int minBadness = filterBadness[0]; int filterType = 0; for (int i = 1; i < 5; i++) { if (filterBadness[i] < minBadness) { minBadness = filterBadness[i]; filterType = i; } } if (filterType == 0) { System.arraycopy(currRow, bytesPerPixel, scratchRows[0], bytesPerPixel, bytesPerRow); } return filterType; } }