1. /*
  2. * @(#)RowFilter.java 1.8 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.imageio.plugins.png;
  8. /**
  9. * @version 0.5
  10. */
  11. public class RowFilter {
  12. private static final int abs(int x) {
  13. return (x < 0) ? -x : x;
  14. }
  15. // Returns the sum of absolute differences
  16. protected static int subFilter(byte[] currRow,
  17. byte[] subFilteredRow,
  18. int bytesPerPixel,
  19. int bytesPerRow) {
  20. int badness = 0;
  21. for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
  22. int curr = currRow[i] & 0xff;
  23. int left = currRow[i - bytesPerPixel] & 0xff;
  24. int difference = curr - left;
  25. subFilteredRow[i] = (byte)difference;
  26. badness += abs(difference);
  27. }
  28. return badness;
  29. }
  30. // Returns the sum of absolute differences
  31. protected static int upFilter(byte[] currRow,
  32. byte[] prevRow,
  33. byte[] upFilteredRow,
  34. int bytesPerPixel,
  35. int bytesPerRow) {
  36. int badness = 0;
  37. for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
  38. int curr = currRow[i] & 0xff;
  39. int up = prevRow[i] & 0xff;
  40. int difference = curr - up;
  41. upFilteredRow[i] = (byte)difference;
  42. badness += abs(difference);
  43. }
  44. return badness;
  45. }
  46. protected final int paethPredictor(int a, int b, int c) {
  47. int p = a + b - c;
  48. int pa = abs(p - a);
  49. int pb = abs(p - b);
  50. int pc = abs(p - c);
  51. if ((pa <= pb) && (pa <= pc)) {
  52. return a;
  53. } else if (pb <= pc) {
  54. return b;
  55. } else {
  56. return c;
  57. }
  58. }
  59. public int filterRow(int colorType,
  60. byte[] currRow,
  61. byte[] prevRow,
  62. byte[][] scratchRows,
  63. int bytesPerRow,
  64. int bytesPerPixel) {
  65. // Use type 0 for palette images
  66. if (colorType != PNGImageReader.PNG_COLOR_PALETTE) {
  67. System.arraycopy(currRow, bytesPerPixel,
  68. scratchRows[0], bytesPerPixel,
  69. bytesPerRow);
  70. return 0;
  71. }
  72. int[] filterBadness = new int[5];
  73. for (int i = 0; i < 5; i++) {
  74. filterBadness[i] = Integer.MAX_VALUE;
  75. }
  76. {
  77. int badness = 0;
  78. for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
  79. int curr = currRow[i] & 0xff;
  80. badness += curr;
  81. }
  82. filterBadness[0] = badness;
  83. }
  84. {
  85. byte[] subFilteredRow = scratchRows[1];
  86. int badness = subFilter(currRow,
  87. subFilteredRow,
  88. bytesPerPixel,
  89. bytesPerRow);
  90. filterBadness[1] = badness;
  91. }
  92. {
  93. byte[] upFilteredRow = scratchRows[2];
  94. int badness = upFilter(currRow,
  95. prevRow,
  96. upFilteredRow,
  97. bytesPerPixel,
  98. bytesPerRow);
  99. filterBadness[2] = badness;
  100. }
  101. {
  102. byte[] averageFilteredRow = scratchRows[3];
  103. int badness = 0;
  104. for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
  105. int curr = currRow[i] & 0xff;
  106. int left = currRow[i - bytesPerPixel] & 0xff;
  107. int up = prevRow[i] & 0xff;
  108. int difference = curr - (left + up)/2;;
  109. averageFilteredRow[i] = (byte)difference;
  110. badness += abs(difference);
  111. }
  112. filterBadness[3] = badness;
  113. }
  114. {
  115. byte[] paethFilteredRow = scratchRows[4];
  116. int badness = 0;
  117. for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
  118. int curr = currRow[i] & 0xff;
  119. int left = currRow[i - bytesPerPixel] & 0xff;
  120. int up = prevRow[i] & 0xff;
  121. int upleft = prevRow[i - bytesPerPixel] & 0xff;
  122. int predictor = paethPredictor(left, up, upleft);
  123. int difference = curr - predictor;
  124. paethFilteredRow[i] = (byte)difference;
  125. badness += abs(difference);
  126. }
  127. filterBadness[4] = badness;
  128. }
  129. int minBadness = filterBadness[0];
  130. int filterType = 0;
  131. for (int i = 1; i < 5; i++) {
  132. if (filterBadness[i] < minBadness) {
  133. minBadness = filterBadness[i];
  134. filterType = i;
  135. }
  136. }
  137. if (filterType == 0) {
  138. System.arraycopy(currRow, bytesPerPixel,
  139. scratchRows[0], bytesPerPixel,
  140. bytesPerRow);
  141. }
  142. return filterType;
  143. }
  144. }