001 002 package railo.runtime.img; 003 import java.awt.image.BufferedImage; 004 import java.awt.image.ColorModel; 005 006 import railo.runtime.exp.ExpressionException; 007 import railo.runtime.img.interpolation.Bessel; 008 import railo.runtime.img.interpolation.Blackman; 009 import railo.runtime.img.interpolation.Hamming; 010 import railo.runtime.img.interpolation.Hanning; 011 import railo.runtime.img.interpolation.Hermite; 012 import railo.runtime.img.interpolation.Interpolation; 013 import railo.runtime.img.interpolation.Lanczos; 014 import railo.runtime.img.interpolation.Mitchell; 015 import railo.runtime.img.interpolation.Quadratic; 016 import railo.runtime.img.interpolation.Triangle; 017 018 019 public class ImageResizer { 020 021 private static class ContributionInfo { 022 int pixel; 023 double weight; 024 025 026 public void setPixel(int pixel) { 027 this.pixel = pixel; 028 } 029 030 public int getPixel() { 031 return pixel; 032 } 033 034 public void setWeight(double weight) { 035 this.weight = weight; 036 } 037 038 public double getWeight() { 039 return weight; 040 } 041 } 042 043 private static int horizontal(BufferedImage source, BufferedImage destination, double xFactor,Interpolation ip, double blur, ContributionInfo[] contribution) { 044 if (source.getWidth() == destination.getWidth() 045 && source.getHeight() == destination.getHeight()) { 046 destination.setData(source.getData()); 047 return destination.getWidth(); 048 } 049 double scale = blur * Math.max(1.0 / xFactor, 1.0); 050 double support = Math.max(scale * ip.getSupport(), 0.5); 051 if (support <= 0.5) { 052 support = 0.500000000001; 053 scale = 1.0; 054 } 055 ColorModel cm = ColorModel.getRGBdefault(); 056 for (int x = 0; x < destination.getWidth(); x++) { 057 double center = x / xFactor; 058 int start = (int) Math.max(center - support + 0.5, 0.0); 059 int end = (int) Math.min(center + support + 0.5, 060 source.getWidth()); 061 int n = setContributionWeight(start, end, contribution, ip, 062 center, scale); 063 int sourceWidth = (contribution[n - 1].getPixel() 064 - contribution[0].getPixel() + 1); 065 int[] sourcePixels = new int[sourceWidth * source.getHeight()]; 066 int[] destPixels = new int[destination.getHeight()]; 067 sourcePixels = source.getRGB(contribution[0].getPixel(), 0, 068 sourceWidth, source.getHeight(), 069 sourcePixels, 0, sourceWidth); 070 int destIndex = 0; 071 for (int y = 0; y < destination.getHeight(); y++) { 072 double blue = 0.0; 073 double green = 0.0; 074 double red = 0.0; 075 double opacity = 0.0; 076 int[] c = new int[4]; 077 for (int i = 0; i < n; i++) { 078 int j = (y * (contribution[n - 1].getPixel() 079 - contribution[0].getPixel() + 1) 080 + (contribution[i].getPixel() 081 - contribution[0].getPixel())); 082 c = cm.getComponents(sourcePixels[j], c, 0); 083 red += contribution[i].getWeight() * c[0]; 084 green += contribution[i].getWeight() * c[1]; 085 blue += contribution[i].getWeight() * c[2]; 086 opacity += contribution[i].getWeight() * c[3]; 087 } 088 red = red < 0.0 ? 0.0 : red > 255.0 ? 255.0 : red + 0.5; 089 green 090 = green < 0.0 ? 0.0 : green > 255.0 ? 255.0 : green + 0.5; 091 blue = blue < 0.0 ? 0.0 : blue > 255.0 ? 255.0 : blue + 0.5; 092 opacity = (opacity < 0.0 ? 0.0 : opacity > 255.0 ? 255.0 093 : opacity + 0.5); 094 destPixels[destIndex] 095 = cm.getDataElement(new int[] { (int) red, (int) green, 096 (int) blue, 097 (int) opacity }, 098 0); 099 destIndex++; 100 } 101 destination.setRGB(x, 0, 1, destination.getHeight(), destPixels, 0, 102 1); 103 } 104 return destination.getWidth(); 105 } 106 107 private static int setContributionWeight(int start, int end, ContributionInfo[] contribution, Interpolation interpolation, double center, double scale) { 108 int n = 0; 109 double density = 0.0; 110 for (int i = start; i < end; i++) { 111 contribution[n].setPixel(i); 112 contribution[n].setWeight(interpolation.f((i - center + 0.5D) 113 / scale) / scale); 114 density += contribution[n].getWeight(); 115 n++; 116 } 117 density = density == 0.0 ? 1.0 : 1.0 / density; 118 for (int i = 0; i < n; i++) 119 contribution[i].setWeight(contribution[i].getWeight() * density); 120 return n; 121 } 122 123 private static int vertical(BufferedImage source, BufferedImage destination, double y_factor, Interpolation ip, double blur, ContributionInfo[] contribution) { 124 /*if (source.getWidth() == destination.getWidth() 125 && source.getHeight() == destination.getHeight()) { 126 destination.setData(source.getData()); 127 return destination.getWidth(); 128 }*/ 129 double scale = blur * Math.max(1.0 / y_factor, 1.0); 130 double support = Math.max(scale * ip.getSupport(), 0.5); 131 if (support <= 0.5) { 132 support = 0.500000000001; 133 scale = 1.0; 134 } 135 ColorModel cm = ColorModel.getRGBdefault(); 136 for (int y = 0; y < destination.getHeight(); y++) { 137 double center = y / y_factor; 138 int start = (int) Math.max(center - support + 0.5, 0.0); 139 int end = (int) Math.min(center + support + 0.5, 140 source.getHeight()); 141 int n = setContributionWeight(start, end, contribution, ip, 142 center, scale); 143 int sourceHeight = (contribution[n - 1].getPixel() 144 - contribution[0].getPixel() + 1); 145 int[] sourcePixels = new int[source.getWidth() * sourceHeight]; 146 int[] destPixels = new int[destination.getWidth()]; 147 sourcePixels = source.getRGB(0, contribution[0].getPixel(), 148 source.getWidth(), sourceHeight, 149 sourcePixels, 0, source.getWidth()); 150 int destIndex = 0; 151 for (int x = 0; x < destination.getWidth(); x++) { 152 double blue = 0.0; 153 double green = 0.0; 154 double red = 0.0; 155 double opacity = 0.0; 156 int[] c = new int[4]; 157 for (int i = 0; i < n; i++) { 158 int j = ((contribution[i].getPixel() 159 - contribution[0].getPixel()) * source.getWidth() 160 + x); 161 c = cm.getComponents(sourcePixels[j], c, 0); 162 red += contribution[i].getWeight() * c[0]; 163 green += contribution[i].getWeight() * c[1]; 164 blue += contribution[i].getWeight() * c[2]; 165 opacity += contribution[i].getWeight() * c[3]; 166 } 167 red = red < 0.0 ? 0.0 : red > 255.0 ? 255.0 : red + 0.5; 168 green 169 = green < 0.0 ? 0.0 : green > 255.0 ? 255.0 : green + 0.5; 170 blue = blue < 0.0 ? 0.0 : blue > 255.0 ? 255.0 : blue + 0.5; 171 opacity = (opacity < 0.0 ? 0.0 : opacity > 255.0 ? 255.0 172 : opacity + 0.5); 173 destPixels[destIndex] 174 = cm.getDataElement(new int[] { (int) red, (int) green, 175 (int) blue, 176 (int) opacity }, 177 0); 178 destIndex++; 179 } 180 destination.setRGB(0, y, destination.getWidth(), 1, destPixels, 0, 181 destination.getWidth()); 182 } 183 return destination.getHeight(); 184 } 185 186 187 188 public static BufferedImage resize(BufferedImage image, int columns, int rows, int interpolation, double blur) throws ExpressionException { 189 if (columns == 0 || rows == 0) 190 throw new ExpressionException("invalid size for image"); 191 192 BufferedImage resizeImage = ImageUtil.createBufferedImage(image, columns, rows); 193 194 Interpolation inter = getInterpolation(interpolation); 195 double xFactor = (double) columns / (double) image.getWidth(); 196 double scale = blur * Math.max(1.0 / xFactor, 1.0); 197 double xSupport = Math.max(scale * inter.getSupport(), 0.5); 198 double yFactor = (double) rows / (double) image.getHeight(); 199 scale = blur * Math.max(1.0 / yFactor, 1.0); 200 double ySupport = Math.max(scale * inter.getSupport(), 0.5); 201 double support = Math.max(xSupport, ySupport); 202 if (support < inter.getSupport()) 203 support = inter.getSupport(); 204 ContributionInfo[] contribution = new ContributionInfo[(int) support * 2 + 3]; 205 206 for (int cloop = 0; cloop < (int) support * 2 + 3; cloop++) 207 contribution[cloop] = new ContributionInfo(); 208 209 int status; 210 if (columns * (image.getHeight() + rows) < rows * (image.getWidth() + columns)) { 211 BufferedImage sourceImage = ImageUtil.createBufferedImage(image, columns, image.getHeight()); 212 status = horizontal(image, sourceImage, xFactor, inter, blur, contribution); 213 status |= vertical(sourceImage, resizeImage, yFactor,inter, blur, contribution); 214 } 215 else { 216 BufferedImage sourceImage = ImageUtil.createBufferedImage(image, image.getWidth(), rows); 217 status = vertical(image, sourceImage, yFactor, inter, blur, contribution); 218 status |= horizontal(sourceImage, resizeImage, xFactor, inter, blur, contribution); 219 } 220 221 if (status == 0) throw new ExpressionException("can't resize image"); 222 return resizeImage; 223 } 224 225 226 227 228 229 private static Interpolation getInterpolation(int interpolation) throws ExpressionException { 230 switch (interpolation) { 231 232 case 0: return new Triangle(); 233 case Image.IP_HERMITE: return new Hermite(); 234 case Image.IP_HANNING: return new Hanning(); 235 case Image.IP_MEDIUMQUALITY: 236 case Image.IP_HIGHPERFORMANCE: 237 case Image.IP_HAMMING: return new Hamming(); 238 case Image.IP_BLACKMAN: return new Blackman(); 239 case Image.IP_QUADRATIC:return new Quadratic(); 240 case Image.IP_HIGHQUALITY: 241 case Image.IP_MEDIUMPERFORMANCE: 242 case Image.IP_MITCHELL: return new Mitchell(); 243 case Image.IP_HIGHESTQUALITY: 244 case Image.IP_LANCZOS: return new Lanczos(); 245 case Image.IP_BESSEL: return new Bessel(); 246 default: throw new ExpressionException("invalid interpolation definition"); 247 } 248 } 249 250 251 }