Ebben a témában rengeteg bejegyzés található a neten, én személy szerint mégsem találtam elfogadható megoldás, ami egyben megoldaná minden problémámat, kivéve a Java Advanced Imaging-ot. Utóbbival elég nagy problémám volt, hogy nincsen agyondokumentálva, vannak ugyan példák, de azokon eligazodni is felér egy rém-álommal. A rossz tapasztalatok sarkalltak arra, hogy belekezdjek egy, az én igényeimet kielégítő, eszköz megírásába, mely az alapvető webes környezetben előforduló problémákat orvosolja. A projekt elérkezett az első "mérföld-kőhöz", így gondoltam szánok rá pár sort.
Jelenlegi stádiumban képes átméretezni jpg, png, gif, anim gif formátumokat, alkalmazza az élsimítás technológiát, viszont a transzparens képekbe még beletörik a foga. A művelet pilléreit szeretném itt bemutatni, a teljes forráskódot elérhetővé teszem, de mivel felhasználtam pár osztályt, amit letöltöttem és javítottam, ezek pontos liszenszelését még egyeztetem.
Első esetben nézzük az egyszerűbb oldalát a dolognak, amikor nem animált gif-et kell átméretezni. Mivel a legtöbb példa csak a Graphics2D beépített élsimítását használta fel, aminek minősége finoman szólva is vacak, így átméretezés előtt egy blur effektet húzok a képre. A példa csak a kicsinyítés problémájával foglalkozik, mivel a jelentős minőség-romlás ilyen esetben érzékelhető igazán, és a gyakorlatban is ritkán kell nagyítani egy felhasználó által feltöltött képet.OutputStream out; BufferedImage bufferedImage; String extension; //... if (!extension.equals("gif")) { //Első lépésként, amenniyben jpg-a forrás kép, át kell állítanunk a típusát, mivel az alapértelmezett típus nem támogatja a blur készítését, minden más esetben, kompatibilissé tesszük a képet, szintén a blur-ozhatóság érdekében. if (mimeType.equals("image/jpeg") || mimeType.equals("image/pjpeg")) { bufferedImage = convert(bufferedImage, BufferedImage.TYPE_INT_RGB); } else { bufferedImage = createCompatibleImage(bufferedImage); } //Elvégezzük a blur-ozást, és átméretezést, majd mehet a kép a kimenetre. ImageIO.write(resize(blur(bufferedImage), newWidth.intValue(), newHeight.intValue()), extension, out); out.flush(); out.close(); }A meghívott metódusok:
//Átméretezi a képet. private BufferedImage resize(BufferedImage image, int width, int height) { BufferedImage result = new BufferedImage(width, height, image.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : image.getType()); Graphics2D g = result.createGraphics(); g.setComposite(AlphaComposite.Src); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.drawImage(image, 0, 0, width, height, null); g.dispose(); return result; } //Blur-ozza a képet. private BufferedImage blur(BufferedImage image) { float ninth = 1.0f / 9.0f; float[] blurKernel = { ninth, ninth, ninth, ninth, ninth, ninth, ninth, ninth, ninth }; Map map = new HashMap(); map.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); map.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); map.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, new RenderingHints(map)); return op.filter(image, null); } //Átalakítja a típusát a képnek. private BufferedImage convert(BufferedImage image, int type) { BufferedImage result = new BufferedImage(image.getWidth(), image.getHeight(), type); Graphics2D g = result.createGraphics(); g.drawRenderedImage(image, null); g.dispose(); return result; } //Kompatibilissé teszi a képet. private static BufferedImage createCompatibleImage(BufferedImage image) { GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image); BufferedImage result = gc.createCompatibleImage(image.getWidth(), image.getHeight(), Transparency.BITMASK); Graphics2D g = result.createGraphics(); g.drawRenderedImage(image, null); g.dispose(); return result; }A nehezebb eset, mint említettem, animált gifek átméretezése, mivel a Graphics2D nem támogatja alapértelmezetten azokat. A megoldás nem egyedüli érdemem, bár a letöltött kódokat javítanom kellett. A lényeg, hogy a gif kép-kockáin egyesével végig kell iterálni, és az előbb említett műveletek végrehajtása után, a cél képbe beletenni az immár átméretezett példányokat.
try { GifDecoder d = new GifDecoder(); d.read(image.getAbsolutePath()); AnimatedGifEncoder e = new AnimatedGifEncoder(); e.setRepeat(d.getLoopCount()); e.start(out); int type = bufferedImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : bufferedImage.getType(); for (int i = 0; i < d.getFrameCount(); i++) { e.setDelay(d.getDelay(i)); BufferedImage frameBuffer = new BufferedImage(origWidth, origHeight, BufferedImage.TYPE_BYTE_INDEXED); frameBuffer.getGraphics().drawImage(d.getFrame(i), 0, 0, null); if (mimeType.equals("image/jpeg") || mimeType.equals("image/pjpeg")) { frameBuffer = convert(frameBuffer, BufferedImage.TYPE_INT_RGB); } else { frameBuffer = createCompatibleImage(frameBuffer); } e.addFrame(resize(blur(frameBuffer), newWidth.intValue(), newHeight.intValue())); } e.finish(); out.flush(); out.close(); } catch (Exception e) {}
Nem állítom, hogy ez a legjobb és legszebb megoldás, és azt sem, hogy tökéletes eredményt hoz minden típusú képnél, csak azt tudom, hogy a transzparens képek kivételével eddig bevált.
Nincsenek megjegyzések:
Megjegyzés küldése