PixelUtils.java 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. ** Copyright 2005 Huxtable.com. All rights reserved.
  3. */
  4. package com.cvte.blurfilter;
  5. import java.awt.Color;
  6. import java.util.Random;
  7. /**
  8. * Some more useful math functions for image processing.
  9. * These are becoming obsolete as we move to Java2D. Use MiscComposite instead.
  10. */
  11. public class PixelUtils {
  12. public final static int REPLACE = 0;
  13. public final static int NORMAL = 1;
  14. public final static int MIN = 2;
  15. public final static int MAX = 3;
  16. public final static int ADD = 4;
  17. public final static int SUBTRACT = 5;
  18. public final static int DIFFERENCE = 6;
  19. public final static int MULTIPLY = 7;
  20. public final static int HUE = 8;
  21. public final static int SATURATION = 9;
  22. public final static int VALUE = 10;
  23. public final static int COLOR = 11;
  24. public final static int SCREEN = 12;
  25. public final static int AVERAGE = 13;
  26. public final static int OVERLAY = 14;
  27. public final static int CLEAR = 15;
  28. public final static int EXCHANGE = 16;
  29. public final static int DISSOLVE = 17;
  30. public final static int DST_IN = 18;
  31. public final static int ALPHA = 19;
  32. public final static int ALPHA_TO_GRAY = 20;
  33. private static Random randomGenerator = new Random();
  34. /**
  35. * Clamp a value to the range 0..255
  36. */
  37. public static int clamp(int c) {
  38. if (c < 0)
  39. return 0;
  40. if (c > 255)
  41. return 255;
  42. return c;
  43. }
  44. public static int interpolate(int v1, int v2, float f) {
  45. return clamp((int)(v1+f*(v2-v1)));
  46. }
  47. public static int brightness(int rgb) {
  48. int r = (rgb >> 16) & 0xff;
  49. int g = (rgb >> 8) & 0xff;
  50. int b = rgb & 0xff;
  51. return (r+g+b)/3;
  52. }
  53. public static boolean nearColors(int rgb1, int rgb2, int tolerance) {
  54. int r1 = (rgb1 >> 16) & 0xff;
  55. int g1 = (rgb1 >> 8) & 0xff;
  56. int b1 = rgb1 & 0xff;
  57. int r2 = (rgb2 >> 16) & 0xff;
  58. int g2 = (rgb2 >> 8) & 0xff;
  59. int b2 = rgb2 & 0xff;
  60. return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance;
  61. }
  62. private final static float hsb1[] = new float[3];//FIXME-not thread safe
  63. private final static float hsb2[] = new float[3];//FIXME-not thread safe
  64. // Return rgb1 painted onto rgb2
  65. public static int combinePixels(int rgb1, int rgb2, int op) {
  66. return combinePixels(rgb1, rgb2, op, 0xff);
  67. }
  68. public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha, int channelMask) {
  69. return (rgb2 & ~channelMask) | combinePixels(rgb1 & channelMask, rgb2, op, extraAlpha);
  70. }
  71. public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha) {
  72. if (op == REPLACE)
  73. return rgb1;
  74. int a1 = (rgb1 >> 24) & 0xff;
  75. int r1 = (rgb1 >> 16) & 0xff;
  76. int g1 = (rgb1 >> 8) & 0xff;
  77. int b1 = rgb1 & 0xff;
  78. int a2 = (rgb2 >> 24) & 0xff;
  79. int r2 = (rgb2 >> 16) & 0xff;
  80. int g2 = (rgb2 >> 8) & 0xff;
  81. int b2 = rgb2 & 0xff;
  82. switch (op) {
  83. case NORMAL:
  84. break;
  85. case MIN:
  86. r1 = Math.min(r1, r2);
  87. g1 = Math.min(g1, g2);
  88. b1 = Math.min(b1, b2);
  89. break;
  90. case MAX:
  91. r1 = Math.max(r1, r2);
  92. g1 = Math.max(g1, g2);
  93. b1 = Math.max(b1, b2);
  94. break;
  95. case ADD:
  96. r1 = clamp(r1+r2);
  97. g1 = clamp(g1+g2);
  98. b1 = clamp(b1+b2);
  99. break;
  100. case SUBTRACT:
  101. r1 = clamp(r2-r1);
  102. g1 = clamp(g2-g1);
  103. b1 = clamp(b2-b1);
  104. break;
  105. case DIFFERENCE:
  106. r1 = clamp(Math.abs(r1-r2));
  107. g1 = clamp(Math.abs(g1-g2));
  108. b1 = clamp(Math.abs(b1-b2));
  109. break;
  110. case MULTIPLY:
  111. r1 = clamp(r1*r2/255);
  112. g1 = clamp(g1*g2/255);
  113. b1 = clamp(b1*b2/255);
  114. break;
  115. case DISSOLVE:
  116. if ((randomGenerator.nextInt() & 0xff) <= a1) {
  117. r1 = r2;
  118. g1 = g2;
  119. b1 = b2;
  120. }
  121. break;
  122. case AVERAGE:
  123. r1 = (r1+r2)/2;
  124. g1 = (g1+g2)/2;
  125. b1 = (b1+b2)/2;
  126. break;
  127. case HUE:
  128. case SATURATION:
  129. case VALUE:
  130. case COLOR:
  131. java.awt.Color.RGBtoHSB(r1, g1, b1, hsb1);
  132. Color.RGBtoHSB(r2, g2, b2, hsb2);
  133. switch (op) {
  134. case HUE:
  135. hsb2[0] = hsb1[0];
  136. break;
  137. case SATURATION:
  138. hsb2[1] = hsb1[1];
  139. break;
  140. case VALUE:
  141. hsb2[2] = hsb1[2];
  142. break;
  143. case COLOR:
  144. hsb2[0] = hsb1[0];
  145. hsb2[1] = hsb1[1];
  146. break;
  147. }
  148. rgb1 = Color.HSBtoRGB(hsb2[0], hsb2[1], hsb2[2]);
  149. r1 = (rgb1 >> 16) & 0xff;
  150. g1 = (rgb1 >> 8) & 0xff;
  151. b1 = rgb1 & 0xff;
  152. break;
  153. case SCREEN:
  154. r1 = 255 - ((255 - r1) * (255 - r2)) / 255;
  155. g1 = 255 - ((255 - g1) * (255 - g2)) / 255;
  156. b1 = 255 - ((255 - b1) * (255 - b2)) / 255;
  157. break;
  158. case OVERLAY:
  159. int m, s;
  160. s = 255 - ((255 - r1) * (255 - r2)) / 255;
  161. m = r1 * r2 / 255;
  162. r1 = (s * r1 + m * (255 - r1)) / 255;
  163. s = 255 - ((255 - g1) * (255 - g2)) / 255;
  164. m = g1 * g2 / 255;
  165. g1 = (s * g1 + m * (255 - g1)) / 255;
  166. s = 255 - ((255 - b1) * (255 - b2)) / 255;
  167. m = b1 * b2 / 255;
  168. b1 = (s * b1 + m * (255 - b1)) / 255;
  169. break;
  170. case CLEAR:
  171. r1 = g1 = b1 = 0xff;
  172. break;
  173. case DST_IN:
  174. r1 = clamp((r2*a1)/255);
  175. g1 = clamp((g2*a1)/255);
  176. b1 = clamp((b2*a1)/255);
  177. a1 = clamp((a2*a1)/255);
  178. return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
  179. case ALPHA:
  180. a1 = a1*a2/255;
  181. return (a1 << 24) | (r2 << 16) | (g2 << 8) | b2;
  182. case ALPHA_TO_GRAY:
  183. int na = 255-a1;
  184. return (a1 << 24) | (na << 16) | (na << 8) | na;
  185. }
  186. if (extraAlpha != 0xff || a1 != 0xff) {
  187. a1 = a1*extraAlpha/255;
  188. int a3 = (255-a1)*a2/255;
  189. r1 = clamp((r1*a1+r2*a3)/255);
  190. g1 = clamp((g1*a1+g2*a3)/255);
  191. b1 = clamp((b1*a1+b2*a3)/255);
  192. a1 = clamp(a1+a3);
  193. }
  194. return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
  195. }
  196. }