/common/common-image/src/main/java/com/twelvemonkeys/image/BrightnessContrastFilter.java

https://github.com/conceptboard/TwelveMonkeys · Java · 167 lines · 44 code · 20 blank · 103 comment · 5 complexity · 20b6388fe1313b6da53b2f0e12f8d203 MD5 · raw file

  1. /*
  2. * Copyright (c) 2008, Harald Kuhr
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name "TwelveMonkeys" nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  19. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  20. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  21. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  22. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  23. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  24. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  25. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. package com.twelvemonkeys.image;
  29. import java.awt.image.RGBImageFilter;
  30. /**
  31. * Adjusts the contrast and brightness of an image.
  32. * <p/>
  33. * For brightness, the valid range is {@code -2.0,..,0.0,..,2.0}.
  34. * A value of {@code 0.0} means no change.
  35. * Negative values will make the pixels darker.
  36. * Maximum negative value ({@code -2}) will make all filtered pixels black.
  37. * Positive values will make the pixels brighter.
  38. * Maximum positive value ({@code 2}) will make all filtered pixels white.
  39. * <p/>
  40. * For contrast, the valid range is {@code -1.0,..,0.0,..,1.0}.
  41. * A value of {@code 0.0} means no change.
  42. * Negative values will reduce contrast.
  43. * Maximum negative value ({@code -1}) will make all filtered pixels grey
  44. * (no contrast).
  45. * Positive values will increase contrast.
  46. * Maximum positive value ({@code 1}) will make all filtered pixels primary
  47. * colors (either black, white, cyan, magenta, yellow, red, blue or green).
  48. *
  49. * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
  50. * @author last modified by $Author: haku $
  51. *
  52. * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/BrightnessContrastFilter.java#1 $
  53. *
  54. * @todo consider doing something similar to http://archives.java.sun.com/cgi-bin/wa?A2=ind0302&L=jai-interest&F=&S=&P=15947
  55. */
  56. public class BrightnessContrastFilter extends RGBImageFilter {
  57. // This filter can filter IndexColorModel, as it is does not depend on
  58. // the pixels' location
  59. {
  60. canFilterIndexColorModel = true;
  61. }
  62. // Use a precalculated lookup table for performace
  63. private final int[] LUT;
  64. /**
  65. * Creates a BrightnessContrastFilter with default values
  66. * ({@code brightness=0.3, contrast=0.3}).
  67. * <p/>
  68. * This will slightly increase both brightness and contrast.
  69. */
  70. public BrightnessContrastFilter() {
  71. this(0.3f, 0.3f);
  72. }
  73. /**
  74. * Creates a BrightnessContrastFilter with the given values for brightness
  75. * and contrast.
  76. * <p/>
  77. * For brightness, the valid range is {@code -2.0,..,0.0,..,2.0}.
  78. * A value of {@code 0.0} means no change.
  79. * Negative values will make the pixels darker.
  80. * Maximum negative value ({@code -2}) will make all filtered pixels black.
  81. * Positive values will make the pixels brighter.
  82. * Maximum positive value ({@code 2}) will make all filtered pixels white.
  83. * <p/>
  84. * For contrast, the valid range is {@code -1.0,..,0.0,..,1.0}.
  85. * A value of {@code 0.0} means no change.
  86. * Negative values will reduce contrast.
  87. * Maximum negative value ({@code -1}) will make all filtered pixels grey
  88. * (no contrast).
  89. * Positive values will increase contrast.
  90. * Maximum positive value ({@code 1}) will make all filtered pixels primary
  91. * colors (either black, white, cyan, magenta, yellow, red, blue or green).
  92. *
  93. * @param pBrightness adjust the brightness of the image, in the range
  94. * {@code -2.0,..,0.0,..,2.0}.
  95. * @param pContrast adjust the contrast of the image, in the range
  96. * {@code -1.0,..,0.0,..,1.0}.
  97. */
  98. public BrightnessContrastFilter(float pBrightness, float pContrast) {
  99. LUT = createLUT(pBrightness, pContrast);
  100. }
  101. private static int[] createLUT(float pBrightness, float pContrast) {
  102. int[] lut = new int[256];
  103. // Hmmm.. This approximates Photoshop values.. Not good though..
  104. double contrast = pContrast > 0 ? Math.pow(pContrast, 7.0) * 127.0 : pContrast;
  105. // Convert range [-1,..,0,..,1] -> [0,..,1,..,2]
  106. double brightness = pBrightness + 1.0;
  107. for (int i = 0; i < 256; i++) {
  108. lut[i] = clamp((int) (127.5 * brightness + (i - 127) * (contrast + 1.0)));
  109. }
  110. // Special case, to ensure only primary colors for max contrast
  111. if (pContrast == 1f) {
  112. lut[127] = lut[126];
  113. }
  114. return lut;
  115. }
  116. private static int clamp(int i) {
  117. if (i < 0) {
  118. return 0;
  119. }
  120. if (i > 255) {
  121. return 255;
  122. }
  123. return i;
  124. }
  125. /**
  126. * Filters one pixel, adjusting brightness and contrast according to this
  127. * filter.
  128. *
  129. * @param pX x
  130. * @param pY y
  131. * @param pARGB pixel value in default color space
  132. *
  133. * @return the filtered pixel value in the default color space
  134. */
  135. public int filterRGB(int pX, int pY, int pARGB) {
  136. // Get color components
  137. int r = pARGB >> 16 & 0xFF;
  138. int g = pARGB >> 8 & 0xFF;
  139. int b = pARGB & 0xFF;
  140. // Scale to new contrast
  141. r = LUT[r];
  142. g = LUT[g];
  143. b = LUT[b];
  144. // Return ARGB pixel, leave transparency as is
  145. return (pARGB & 0xFF000000) | (r << 16) | (g << 8) | b;
  146. }
  147. }