package kussmaulUtils; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DataBufferInt; import java.awt.image.WritableRaster; import java.io.IOException; import java.util.List; import javax.imageio.ImageIO; enum ImageHandling{FITWIDTH, FITHEIGHT, FITBOTH, ACTUALSIZE, CUSTOM} public class ImageTools { public static BufferedImage toBufferedImage(Image img) { if(img instanceof BufferedImage) return (BufferedImage)img; BufferedImage imgb=new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics2D g=imgb.createGraphics(); g.drawImage(img,0, 0, null); g.dispose(); return imgb; } public static BufferedImage resize(BufferedImage img, int width, int height, boolean fast){ if(img.getWidth()==width && img.getHeight()==height) return deepCopy(img); width = Math.max(width, 1); height = Math.max(height, 1); Image resizedImg = img.getScaledInstance(width, height, fast ? Image.SCALE_FAST : Image.SCALE_SMOOTH); if(resizedImg instanceof BufferedImage) return (BufferedImage)resizedImg; BufferedImage imgb=new BufferedImage(width, height, img.getType()); Graphics2D g=imgb.createGraphics(); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, fast ? RenderingHints.VALUE_INTERPOLATION_BILINEAR: RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); g.drawImage(resizedImg,0, 0, null); g.dispose(); return imgb; } public static BufferedImage fitBoth(BufferedImage img, int width, int height, Object interpolation){ if(img.getWidth()==width && img.getHeight()==height) return deepCopy(img); if (interpolation.equals(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) return fitBoth(img, width, height, false); width = Math.max(width, 1); height = Math.max(height, 1); BufferedImage imgb=new BufferedImage(width, height, img.getType()); Graphics2D g=imgb.createGraphics(); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation); g.drawImage(img, 0, 0, imgb.getWidth(), imgb.getHeight(), null); g.dispose(); return imgb; } public static BufferedImage fitWidth(BufferedImage img, int width, int height, boolean fast){ img=resize(img, width, (int)(img.getHeight()*(width/(double)img.getWidth())), fast); if(img.getHeight()>height) img=img.getSubimage(0, (img.getHeight()-height)/2, img.getWidth(), height); BufferedImage fullImage=new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g=(Graphics2D)fullImage.getGraphics(); if(!fast){ g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); } g.drawImage(img, 0, (height-img.getHeight())/2, null); g.dispose(); return fullImage; } public static BufferedImage fitHeight(BufferedImage img, int width, int height, boolean fast){ img=resize(img, (int)(img.getWidth()*(height/(double)img.getHeight())), height, fast); if(img.getHeight()>height){ img=img.getSubimage((img.getWidth()-width)/2, 0, width, img.getHeight()); } BufferedImage fullImage=new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g=(Graphics2D)fullImage.getGraphics(); if(!fast){ g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); } g.drawImage(img, (width-img.getWidth())/2, 0, null); g.dispose(); return fullImage; } public static BufferedImage doNotScale(BufferedImage img, int width, int height, boolean fast){ width = Math.max(width, 1); height = Math.max(height, 1); BufferedImage fullImage=new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g=(Graphics2D)fullImage.getGraphics(); if(!fast){ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); } g.drawImage(img, (fullImage.getWidth()-img.getWidth())/2, (height-img.getHeight())/2, null); g.dispose(); return fullImage; } public static BufferedImage fitBoth(BufferedImage img, int width, int height, boolean fast){ return resize(img, width, height, fast); } public static BufferedImage customFit(BufferedImage img, int width, int height, double scalex, double scaley, boolean fast){ img = resize(img, (int) Math.round(img.getWidth()*scalex), (int) Math.round(img.getHeight()*scaley), fast); return doNotScale(img, width, height, fast); } public static BufferedImage scale(BufferedImage img, double factor, boolean fast){ return resize(img, (int) Math.round(img.getWidth()*factor), (int) Math.round(img.getHeight()*factor), fast); } public static BufferedImage fit(BufferedImage img, int width, int height, ImageHandling ih, double scalex, double scaley, boolean fast){ if(ih.equals(ImageHandling.ACTUALSIZE)) return doNotScale(img, width, height, fast); if(ih.equals(ImageHandling.CUSTOM)) return customFit(img, width, height, scalex, scaley, fast); if(ih.equals(ImageHandling.FITBOTH)) return fitBoth(img, width, height, fast); if(ih.equals(ImageHandling.FITHEIGHT)) return fitHeight(img, width, height, fast); if(ih.equals(ImageHandling.FITWIDTH)) return fitWidth(img, width, height, fast); return null; } public static BufferedImage addEmptyBorder(BufferedImage img, int Pixels, boolean fast){ return doNotScale(img, img.getWidth()+2*Pixels, img.getHeight()+2*Pixels, fast); } public static BufferedImage scaleToHeight(BufferedImage img, int height, boolean fast){ return resize(img, (int) Math.round(img.getWidth()*(height/(double)img.getHeight())), height, fast); } public static BufferedImage scaleToWidth(BufferedImage img, int width, boolean fast){ return resize(img, width, (int) Math.round(img.getHeight()*(width/(double)img.getWidth())), fast); } public static BufferedImage limitToSize(BufferedImage img, int maxw, int maxh, boolean fast) { //return new BufferedImage(maxw, maxh, BufferedImage.TYPE_3BYTE_BGR); float ratio = img.getWidth()/(float)img.getHeight(); float maxRatio = maxw/(float)maxh; if(ratio < maxRatio) return scaleToHeight(img, maxh, fast); else return scaleToWidth(img, maxw, fast); } public static BufferedImage rotate(BufferedImage img, double angle, boolean fast) { angle = angle % 360; if(angle == 0) return ImageTools.deepCopy(img); angle = Math.toRadians(angle); double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle)); int w = img.getWidth(), h = img.getHeight(); double neww = (int) (w*cos + h*sin), newh = (int) (h*cos + w*sin); BufferedImage bimg = new BufferedImage((int) Math.round(neww), (int) Math.round(newh), BufferedImage.TYPE_INT_ARGB); //alpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_3BYTE_BGR); Graphics2D g = bimg.createGraphics(); g.setRenderingHint(RenderingHints.KEY_RENDERING, fast ? RenderingHints.VALUE_RENDER_SPEED : RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.translate((neww - w)/2, (newh - h)/2); g.rotate(angle, w/2.0, h/2.0); g.drawImage(img, null, null); g.dispose(); return bimg; } public static BufferedImage unrotate(BufferedImage img, double angle, int origw, int origh, boolean subpixel, boolean fast) { img = rotate(img, 360 - (angle % 360), fast); int startx = (img.getWidth()-origw)/2; int starty = (img.getHeight()-origh)/2; int extra = (img.getWidth() - origw) >2 ? 1 : 0; img = img.getSubimage(startx, starty, origw + extra, origh + extra); AffineTransform t = new AffineTransform(); if(subpixel) { double xerr = 0, yerr = 0; for(int x = 0; x < img.getWidth(); x++) xerr += ImageTools.getAlpha(img.getRGB(x, 0)); for(int y = 0; y < img.getHeight(); y++) yerr += ImageTools.getAlpha(img.getRGB(0, y)); xerr /= (img.getWidth() * 255); xerr = 1 - xerr; yerr /= (img.getHeight() * 255); yerr = 1 - yerr; t.translate(-yerr, -xerr); } BufferedImage ret = new BufferedImage(origw, origh, BufferedImage.TYPE_INT_ARGB); Graphics2D g = ret.createGraphics(); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.drawImage(img, t, null); g.dispose(); return ret; } public static BufferedImage rotate(BufferedImage img, double angle, Object interpolation) { if(angle % 360 == 0) return ImageTools.deepCopy(img); angle = Math.toRadians(angle); double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle)); int w = img.getWidth(), h = img.getHeight(); double neww = (int) (w*cos + h*sin), newh = (int) (h*cos + w*sin); BufferedImage bimg = new BufferedImage((int) Math.round(neww), (int) Math.round(newh), BufferedImage.TYPE_INT_ARGB); //alpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_3BYTE_BGR); Graphics2D g = bimg.createGraphics(); if(interpolation.equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); else g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation); g.translate((neww - w)/2, (newh - h)/2); g.rotate(angle, w/2.0, h/2.0); g.drawImage(img, null, null); g.dispose(); return bimg; } public static BufferedImage unrotate(BufferedImage img, double angle, int origw, int origh, boolean subpixel, Object interpolation) { img = rotate(img, 360 - angle, interpolation); int startx = (img.getWidth()-origw)/2; int starty = (img.getHeight()-origh)/2; int extra = (img.getWidth() - origw) >2 ? 1 : 0; img = img.getSubimage(startx, starty, origw + extra, origh + extra); AffineTransform t = new AffineTransform(); if(subpixel) { double xerr = 0, yerr =0; for(int x = 0; x < img.getWidth(); x++) xerr += ImageTools.getAlpha(img.getRGB(x, 0)); for(int y = 0; y < img.getHeight(); y++) yerr += ImageTools.getAlpha(img.getRGB(0, y)); xerr /= (img.getWidth() * 255); xerr = 1 - xerr; yerr /= (img.getHeight() * 255); yerr = 1 - yerr; t.translate(-yerr, -xerr); } BufferedImage ret = new BufferedImage(origw, origh, BufferedImage.TYPE_INT_ARGB); Graphics2D g = ret.createGraphics(); if(interpolation.equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); else g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation); g.drawImage(img, t, null); g.dispose(); return ret; } public static BufferedImage deepCopy(BufferedImage img) { ColorModel cm = img.getColorModel(); boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); WritableRaster raster = img.copyData(null); return new BufferedImage(cm, raster, isAlphaPremultiplied, null); } public static BufferedImage getResourceImage(String name){ try { return ImageIO.read(ClassLoader.getSystemResource(name)); } catch (IOException e) { e.printStackTrace(); return null; } } public static BufferedImage getBestIconForSize(BufferedImage[] imgs, int size) { BufferedImage bestSoFar = null; for(BufferedImage img : imgs) { if(bestSoFar == null) bestSoFar = img; else if(isSquareish(img) && !isSquareish(bestSoFar)) bestSoFar = img; else if(!(!isSquareish(img) && isSquareish(bestSoFar))) { if(bestSoFar.getWidth() < size && img.getWidth() > bestSoFar.getWidth()) bestSoFar = img; else if(bestSoFar.getWidth() > size && img.getWidth() < bestSoFar.getWidth() && img.getWidth() >= size) bestSoFar = img; } } return bestSoFar; } public static BufferedImage getBestIconForSize(List<BufferedImage> imgs, int size) { return getBestIconForSize(imgs.toArray(new BufferedImage[imgs.size()]), size); } public static boolean isSquareish(BufferedImage img) { return Math.abs(img.getWidth()-img.getHeight()) < 5 ; } public static int getAlpha(int c) { return c >>> 24; } public static int getRed(int c) { return (c >> 16) & 255; } public static int getGreen(int c) { return (c >> 8) & 255; } public static int getBlue(int c) { return c & 255; } public static int getTotalRGB(int c) { return ((c >> 16) & 255) + ((c >> 8) & 255) + (c & 255); } public static float getMaxRGB(int color) { return Math.max(Math.max((color >> 16) & 255, (color >> 8) & 255), color & 255); } public static float[] getHSB(int c) { float[] hsbVals = new float[3]; Color.RGBtoHSB((c >> 16) & 255, (c >> 8) & 255, c & 255, hsbVals); return hsbVals; } public static int gradientRGB(int c0, int c1, float level) { float comp = 1-level; int a = (int) (level * ((c0 >> 24) & 255) + comp * ((c1 >> 24) & 255)); int r = (int) (level * ((c0 >> 16) & 255) + comp * ((c1 >> 16) & 255)); int g = (int) (level * ((c0 >> 8) & 255) + comp * ((c1 >> 8) & 255)); int b = (int) (level * (c0 & 255) + comp * (c1 & 255)); return (a << 24 | r << 16 | g << 8 | b); } public static int toRGB(int a, int r, int g, int b) { return (a << 24 | r << 16 | g << 8 | b); } public static int toRGB(int r, int g, int b) { return (0xFF000000 | r << 16 | g << 8 | b); } // public static BufferedImage[] getRGBChannels(BufferedImage img) { // // BufferedImage[] channels = new BufferedImage[3]; // // for(int i = 0; i < 3; i++) // channels[i] = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB); // // return channels; // // } private static BufferedImage getChannel1(BufferedImage img, int channel) { // BufferedImage img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB); // for(int y = 0; y < img.getHeight(); y++) //slow // for(int x = 0; x < img.getWidth(); x++) // img2.setRGB(x, y, img.getRGB(x, y) & channel); BufferedImage img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE); int[] rgb = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth()); for(int i = 0; i < rgb.length; i ++) rgb[i] = rgb[i] & channel; img2.setRGB(0, 0, img.getWidth(), img.getHeight(), rgb, 0, img.getWidth()); return img2; } public static BufferedImage getChannel(BufferedImage img, int channel) { if(channel == 0xFFFF0000) channel = 0; else if(channel == 0xFF00FF00) channel = 1; else if(channel == 0xFF0000FF) channel = 2; WritableRaster r = img.getRaster(); BufferedImage img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB); int[] nullArray = null; img2.getRaster().setSamples(0, 0, r.getWidth(), r.getHeight(), channel, r.getSamples(0, 0, r.getWidth(), r.getHeight(), channel, nullArray)); return img2; } public static BufferedImage getChannel2(BufferedImage img, int channel) { BufferedImage img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB); int[] oldd = ((DataBufferInt)img.getRaster().getDataBuffer()).getData(); int[] newd = ((DataBufferInt)img.getRaster().getDataBuffer()).getData(); for(int i = 0; i < newd.length; i++) { newd[i] = oldd[i] & channel; } return img2; } public static BufferedImage getRedChannel(BufferedImage img) { return getChannel(img, 0xFFFF0000); } public static BufferedImage getGreenChannel(BufferedImage img) { return getChannel(img, 0xFF00FF00); } public static BufferedImage getBlueChannel(BufferedImage img) { return getChannel(img, 0xFF0000FF); } public static BufferedImage getAlphaChannel(BufferedImage img) { return getChannel(img, 0xFF000000); } public static BufferedImage combine(BufferedImage a, BufferedImage r, BufferedImage g, BufferedImage b) { // BufferedImage img = new BufferedImage(r.getWidth(), r.getHeight(), BufferedImage.TYPE_INT_ARGB); // // for(int y = 0; y < r.getHeight(); y++) // for(int x = 0; x < r.getWidth(); x++) // img.setRGB(x, y, r.getRGB(x, y) | g.getRGB(x, y) | b.getRGB(x, y)); // //img.setRGB(x, y, 0xFF000000 + (r.getRGB(x, y) & 0x00FF0000) + (g.getRGB(x, y) & 0x0000FF00) + (b.getRGB(x, y) & 0x000000FF)); // return img; //slower // int[] nullArray = null; // // r.getRaster().setSamples(0, 0, g.getRaster().getWidth(), g.getRaster().getHeight(), 1, g.getRaster().getSamples(0, 0, g.getWidth(), g.getHeight(), 1, nullArray)); // r.getRaster().setSamples(0, 0, b.getRaster().getWidth(), b.getRaster().getHeight(), 2, b.getRaster().getSamples(0, 0, b.getWidth(), b.getHeight(), 2, nullArray)); // // return r; int w = r.getWidth(), h = r.getHeight(); int[] rarr = r.getRGB(0, 0, w, h, null, 0, w); int[] garr = g.getRGB(0, 0, w, h, null, 0, w); int[] barr = b.getRGB(0, 0, w, h, null, 0, w); for(int i = 0; i < rarr.length; i ++) rarr[i] = (rarr[i] & 0xFFFF0000) | (garr[i] & 0x0000FF00) | (barr[i]& 0x000000FF); r.setRGB(0, 0, w, h, rarr, 0, w); return r; } } /*g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); */