001 /* 002 * Contrast 003 * 004 * Copyright (c) 2001, 2002, 2003 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.color.adjustment; 009 010 import net.sourceforge.jiu.data.GrayIntegerImage; 011 import net.sourceforge.jiu.data.IntegerImage; 012 import net.sourceforge.jiu.data.Palette; 013 import net.sourceforge.jiu.data.Paletted8Image; 014 import net.sourceforge.jiu.data.RGBIntegerImage; 015 import net.sourceforge.jiu.ops.LookupTableOperation; 016 import net.sourceforge.jiu.ops.MissingParameterException; 017 import net.sourceforge.jiu.ops.WrongParameterException; 018 019 /** 020 * Adjusts the contrast of an image. 021 * The amount of adjustment is given to the constructor as a percentage value between -100 and 100. 022 * -100 will make the resulting image middle-gray, 0 will leave it unchanged, 100 will map it to 023 * the eight corners of the color cube. 024 * <h3>Usage example</h3> 025 * This code snippet will reduce <code>image</code>'s contrast by 40 percent. 026 * <pre> 027 * Contrast contrast = new Contrast(); 028 * contrast.setInputImage(image); 029 * contrast.setContrast(-40); 030 * contrast.process(); 031 * PixelImage adjustedImage = contrast.getOutputImage(); 032 * </pre> 033 * @author Marco Schmidt 034 */ 035 public class Contrast extends LookupTableOperation 036 { 037 private int contrast; 038 039 private int[] createLookupTable(int numSamples, int contrast) 040 { 041 int[] result = new int[numSamples]; 042 final int MAX = numSamples - 1; 043 final float MID = MAX / 2.0f; 044 for (int i = 0; i < numSamples; i++) 045 { 046 if (contrast < 0) 047 { 048 if (i < MID) 049 { 050 result[i] = (int)(i + (MID - i) * (- contrast) / 100.0f); 051 } 052 else 053 { 054 result[i] = (int)(MID + (i - MID) * (100.0f + contrast) / 100.0f); 055 } 056 } 057 else 058 { 059 if (i < MID) 060 { 061 result[i] = (int)(i * (100.0f - contrast) / 100.0f); 062 } 063 else 064 { 065 result[i] = (int)(i + (MAX - i) * contrast / 100.0f); 066 } 067 } 068 } 069 return result; 070 } 071 072 /** 073 * Returns the contrast adjustment value associated with this opperation. 074 * The value lies between -100 and 100 (including both values). 075 * @return contrast adjustment 076 * @see #setContrast 077 */ 078 public int getContrast() 079 { 080 return contrast; 081 } 082 083 private void process(Paletted8Image in, Paletted8Image out) 084 { 085 if (out == null) 086 { 087 out = (Paletted8Image)in.createCompatibleImage(in.getWidth(), in.getHeight()); 088 } 089 Palette palette = out.getPalette(); 090 int numSamples = palette.getMaxValue() + 1; 091 final int[] LUT = createLookupTable(numSamples, contrast); 092 for (int c = 0; c < 3; c++) 093 { 094 for (int i = 0; i < palette.getNumEntries(); i++) 095 { 096 palette.putSample(c, i, LUT[palette.getSample(c, i)]); 097 } 098 } 099 for (int y = 0; y < in.getHeight(); y++) 100 { 101 for (int x = 0; x < in.getWidth(); x++) 102 { 103 out.putSample(0, x, y, in.getSample(0, x, y)); 104 } 105 setProgress(y, in.getHeight()); 106 } 107 setOutputImage(out); 108 } 109 110 public void process() throws 111 MissingParameterException, 112 WrongParameterException 113 { 114 prepareImages(); 115 IntegerImage in = (IntegerImage)getInputImage(); 116 if (in instanceof GrayIntegerImage || in instanceof RGBIntegerImage) 117 { 118 setNumTables(in.getNumChannels()); 119 for (int channelIndex = 0; channelIndex < in.getNumChannels(); channelIndex++) 120 { 121 setTable(channelIndex, createLookupTable(in.getMaxSample(channelIndex) + 1, getContrast())); 122 } 123 super.process(); 124 } 125 else 126 if (in instanceof Paletted8Image) 127 { 128 process((Paletted8Image)in, (Paletted8Image)getOutputImage()); 129 } 130 else 131 { 132 throw new WrongParameterException("Contrast operation cannot operate on input image type: " + in.getClass()); 133 } 134 } 135 136 /** 137 * Sets the value for contrast adjustment to be used within this operation. 138 * @param newContrast new contrast, between -100 and 100 (including both values) 139 * @throws IllegalArgumentException if the new contrast value is not in the above mentioned interval 140 * @see #getContrast 141 */ 142 public void setContrast(int newContrast) 143 { 144 if (newContrast < -100) 145 { 146 throw new IllegalArgumentException("Contrast must be at least -100: " + newContrast); 147 } 148 if (newContrast > 100) 149 { 150 throw new IllegalArgumentException("Contrast must be at most 100: " + newContrast); 151 } 152 contrast = newContrast; 153 } 154 }