Erro ao redimensionar Imagens

9 respostas
laelsonc

Ai pessoal, to usando o seguinte método para reduzir imagens:

public static void gerarThumbnail(InputStream inputStream, OutputStream out, int thumbAltura, float quality) throws Exception{

            Image image = null;
            int largura = 0;
            int altura = 0;


            try {
            //Recuperar os valores de LARGURA/ALTURA e ALTERAR no registro da FOTO
            image = ImageIO.read(inputStream);
            largura = image.getWidth(null);
            altura = image.getHeight(null);
            
            
            
            } catch (Exception e) {
            throw new Exception("ERRO ALTERANDO TAMANHO DA IMAGEM " + e);
            }

            try {

            //Fazer a geracao do TumbNail levando em conta o tamanho da ALTURA
            MediaTracker mediaTracker = new MediaTracker(new Container());
            mediaTracker.addImage(image, 0);
            mediaTracker.waitForID(0);

            // determine thumbnail size from WIDTH and HEIGHT
            
            
            double thumbPorcentagem = ((thumbAltura*100.0)/altura)/100.0;
            int thumbLargura = (int)(largura * thumbPorcentagem);
            

            // draw original image to thumbnail image object and
            // scale it to the new size on-the-fly
            BufferedImage thumbImage = new BufferedImage(thumbLargura,thumbAltura, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics2D = thumbImage.createGraphics();
            graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC); //For speed better use RenderingHints.VALUE_INTERPOLATION_BILINEAR
            graphics2D.drawImage(image, 0, 0, thumbLargura, thumbAltura, null);

            // save thumbnail image to OUTFILE
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(thumbImage);

            param.setQuality(quality, false); //The quality argument from the command line is converted from the interval 0 to 100 to the interval 0.0f to 1.0f, because that's what the codec expects (I mostly use 0.75f).
            encoder.setJPEGEncodeParam(param);
            encoder.encode(thumbImage);
            
            inputStream.close();
            out.flush();
            out.close();
            

            } catch (Exception e) {
            throw new Exception("ERRO SALVANDO O THUMBNAIL DA IMAGEM " + e);
            }
            }

O problema é que ele esta dando erro ao tentar reduzir imagens que tenham grande resolução. Com imagens de baixa resolução ele resolve sem problemas.
Agora imagens com tamanho acima de 4mb por exemplo ele dah "ERRO ALTERANDO TAMANHO DA IMAGEM".

Alguem ai saberia com resolver essa parada ?? Poxa, ficou tudo bonitinho aqui, mas quando fui testar com outras fotos maiores...

Aqui vai o erro:

Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:524)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:417)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)

root cause

javax.servlet.ServletException: java.lang.Exception: ERRO ALTERANDO TAMANHO DA IMAGEM javax.imageio.IIOException: Unsupported Image Type
org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:850)
org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:779)
org.apache.jsp.galeriaFotos.classes.classeReduzir_jsp._jspService(classeReduzir_jsp.java:77)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:393)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)

root cause

java.lang.Exception: ERRO ALTERANDO TAMANHO DA IMAGEM javax.imageio.IIOException: Unsupported Image Type
utilitarios.MyImages.gerarThumbnail(MyImages.java:57)
org.apache.jsp.galeriaFotos.classes.classeReduzir_jsp._jspService(classeReduzir_jsp.java:64)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:393)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)

Obs.: A linha 57 é a que se refere ao catch/try do erro.

9 Respostas

rrigoni

Cara,
Para redimensionar imagens use a Library JIU,
http://schmidt.devlib.org/jiu/, nao tenho tido problemas com a mesma , muito simples de usar.

Segue exemplo de crop e resimensionamento.

//lendo imagem em disco
PixelImage originalImage = ToolkitLoader.loadAsRgb24Image(imageFile.getAbsolutedPath());
//Objeto crop
		Crop crop = new Crop();
		//Objeto redimensionador
		Resample resample = new Resample();
		//setando a imagem para crop
		crop.setInputImage(originalImage);
		// setando as coordenadas para crop
		crop.setBounds((int)_x1,(int) _y1,(int)_x2,(int)_y2);
		//efetuando o crop
		crop.process();
		
		//capturando a imagem recortada
		PixelImage cropedImage = crop.getOutputImage();
		
		//redimensionando a imagem media
		resample.setInputImage(cropedImage);
		//setando as medidas para o novo tamanho da imagem media
		resample.setSize(UploadImage.MEDIUN_WIDTH, UploadImage.MEDIUN_HEIGHT);
		//redimensionando a imagem media
		resample.process();
		// Convertendo para BufferedImage
		BufferedImage averageImage = ImageCreator.convertToAwtBufferedImage(resample.getOutputImage());
		//Escrevendo imagem em disco
		ImageIO.write(averageImage, "jpg", new File(originalImagePath+imageName));

Abraco

rrigoni

E se for utilizar java.awt.image nao utilize InputStream para escrever em disco e sim ImageWriter.
Fiz testes e a qualidade da imagem e bem maior.
Pegando o writer apropriado de acordo com o tipo de imagem a ser escrito em disco, como abaixo.

ImageWriter writer = null;  
            Iterator iter = ImageIO.getImageWritersByFormatName(imageExtension);  
            if (iter.hasNext()) {  
            	writer = (ImageWriter)iter.next();  
            }

Ronaldo

laelsonc

Vc tem algum exemplo ai de aplicar Carimbo ( Marca d’agua ) na foto ( com posicionamento ) com essa biblioteca ?
Se tiver manda ai pra me analisar. Valeu pela ajuda.
Mas tem alguem ai que entende o erro lá da Graphics2D lá ?

rrigoni

Com esta biblioteca nao cheguei a ver nada.
Mas tem um servlet que encontrei dando uma googleada.

try
        {
            File file = new File("myFilePath");
            
            ImageIcon photo = new ImageIcon(file.getAbsolutedPath);

            //Create an image 200 x 200
            BufferedImage bufferedImage = new BufferedImage(photo.getIconWidth(),
                    photo.getIconHeight(),
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();

            g2d.drawImage(photo.getImage(), 0, 0, null);

         
            AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,                                                               0.5f);
            g2d.setComposite(alpha);

            g2d.setColor(Color.white);
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                                 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

            g2d.setFont(new Font("Arial", Font.BOLD, 30));

            String watermark = "Copyright © 2006";

            FontMetrics fontMetrics = g2d.getFontMetrics();
            Rectangle2D rect = fontMetrics.getStringBounds(watermark, g2d);

            g2d.drawString(watermark,
                            (photo.getIconWidth() - (int) rect.getWidth()) / 2,
                            (photo.getIconHeight() - (int) rect.getHeight()) / 2);

            g2d.dispose();


            OutputStream out = res.getOutputStream();
            ImageIO.write(bufferedImage, "jpg", out);
            out.close();
        }
        catch (IOException ioe)
        {
        }
    }

Isso que vc precisa?
Ronaldo

laelsonc

Sim amigo, eu to usando uma similar aqui que resolve bem:

public static void gerarWatermark(InputStream imagemOriginal, InputStream imagemWatermark, OutputStream imagemGerada,String posicao,float alpha){

            try {

            BufferedImage im = ImageIO.read(imagemOriginal);
            BufferedImage im2 = ImageIO.read(imagemWatermark);
            Graphics2D g = im.createGraphics();
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
            
            //g.drawImage(im2, (im.getWidth()-im2.getWidth())/2, (im.getHeight()-im2.getHeight())/2, null);
            
                       
            // TOP ESQUERDO 
            if(posicao.equals("7")){
            g.drawImage(im2, 0, 0, null); 
                        
            // TOP CENTRO
            }else if(posicao.equals("8")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth())/2, 0, null); 
                        
            // TOP DIREITO
            }else if(posicao.equals("9")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth()), 0, null); 
                        
            // CENTRO ESQUERDO
            }else if(posicao.equals("4")){
            g.drawImage(im2, 0, (im.getHeight()-im2.getHeight())/2, null);

            // CENTRO
            }else if(posicao.equals("5")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth())/2, (im.getHeight()-im2.getHeight())/2, null);
            
            // CENTRO DIREITO
            }else if(posicao.equals("6")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth()), (im.getHeight()-im2.getHeight())/2, null);
            
            // BASE ESQUERDA
            }else if(posicao.equals("1")){
            g.drawImage(im2, 0, (im.getHeight()-im2.getHeight()), null);

            // BASE CENTRO
            }else if(posicao.equals("2")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth())/2, (im.getHeight()-im2.getHeight()), null);
            
            // BASE DIREITA
            }else if(posicao.equals("3")){
            g.drawImage(im2, (im.getWidth()-im2.getWidth()), (im.getHeight()-im2.getHeight()), null);
            }
            
            g.dispose();
            ImageIO.write(im, "jpeg", imagemGerada);
            
            imagemOriginal.close();
            imagemWatermark.close();
            imagemGerada.flush();
            imagemGerada.close();
            
            

            } catch (Exception e) {
            System.out.println(e);
            }

Só que estou aberto a melhores soluções, levando em conta que realmente as imagens geradas ( principalmente os thumbs ) não estão lá essas
coca-colas com estes métodos.
Como não sou expert em JAVA gostaria de pegar uma receita de bolo por ai. Quem poder me ajudar agradeço.
Valeu cara !

rrigoni

Ja tive problemas tambem com questao de qualidade de tumbs.
A melhor qualidade que consegui foi com o codigo abaixo.

//leitor de imagens recuperado pela extensão da imagem
            ImageWriter writer = null;  
            Iterator iter = ImageIO.getImageWritersByFormatName(fileEx);  
            if (iter.hasNext()) {  
            	writer = (ImageWriter)iter.next();  
            }
            //Cria parametros para a qualidade de compressão da imagem.
            ImageWriteParam imageParams = new JPEGImageWriteParam(Locale.getDefault());  
            imageParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT) ;  
            imageParams.setCompressionQuality(1F);
            
            //imagem final no disco
            File finalImagemInFile = new File(imageFullPath+"."+fileEx);
            // onde finalImagemInFile é o BufferedImage vindo do crop ou redimensionamento
            ImageOutputStream ios = ImageIO.createImageOutputStream(finalImagemInFile);
            writer.setOutput(ios);
            //escreve na imagem com os parametros de qualidade setados
            writer.write(null, new IIOImage(finalBufferedImage, null, null), imageParams);
laelsonc

Olá rrigoni, cara não consegui aplicar este seu último exemplo ai, vc tem ele com mais detalhes ( bem basiquinho mesmo…rs )

To precisando urgente de um método que crie thumbs com boa qualidade.

Quanto ao erro do meu método o lance era que
as imagens que eu estava tentando reduzir estavam em Modo CYMK. Eram fotos que peguei de um gráfica. Quando converti elas
para RGB funcionou beleza. Agora quando crio os thumbs com o mesmo método elas ficam com uma nitidez muito feia. Qualidade ruim.
Apensar de setar o quality para 1.0f;

Alguem tem algo melhor por ai ??

laelsonc

Ninguém tem um método ou biblioteca que melhore as imagens redimensionadas com JAVA ?

Rapaz, ja tentei umas dez classes aqui e todas deixam a imagem ruim quando redimensiona entre 100 e 200px.

Alguma luz ?

rrigoni
Cara, Que melhore nao, mas que conserve a qualidade da imagem pode usar assim. Use a biblioteca GIU como mensionei acima. Sete este filtro de qualidade de imagem antes de processar.
Resample resample = new Resample();
            
            //converte a imagem cortada em uma imagem em buffer
            if(croppedImage != null)
            	resample.setInputImage(croppedImage);
            else
            	resample.setInputImage(originalImage);
            //processa o redimencionamento;
            resample.setFilter(Resample.FILTER_TYPE_LANCZOS3);

Ronaldo

Criado 4 de agosto de 2008
Ultima resposta 11 de ago. de 2008
Respostas 9
Participantes 2