Response.SetContentType - enviar texto e imagem no mesmo servlet?

Olá Pessoal,

estou tentando fazer enviar do servlet tanto texto como imagem, com o código abaixo:


        // ENVIANDO TEXTO

        response.setContentType("text/html;charset=UTF-8");
        ServletOutputStream out = response.getOutputStream();
      
        out.print("<html>\n");
        out.print("<head>\n    ");        
        out.print("\n");
        out.print("</head>\n\n");
        out.print("<body link=\"#CCCCCC\" vlink=\"#CCCCCC\" alink=\"#CCCCCC\">\n\n\n");
        out.println("<br><br>");
        out.println("<hr align='center' width=500 color='#000080'>");
        out.println("<center><b><font face='verdana' color='#000080' size='3'>Imagens Localizadas</font></b></center>");
        out.println("<center>");
        out.println("<hr align='center' width=500 color='#000080'>");
        out.println("</center>");
        out.println("<br><br>");
        out.println("<center>");
        out.println("<form name='frmImagens' method='post'>");
        out.println("<table align = 'center' border=0 style='Groove' bordercolor='#000080'>");
        out.println("<tr>");
        out.println("<th>");

        // ENVIANDO IMAGEM

        response.setContentType("image/jpeg");
        ServletOutputStream outimg = response.getOutputStream();
        
     
        String arquivo = "C:\\imagem.tif";

        RenderedOp src = JAI.create("fileload", arquivo);
        ImageEncoder encoder = ImageCodec.createImageEncoder("JPEG",outimg, null);    
        encoder.encode(src);            

        // ENVIANDO TEXTO NOVAMENTE

        response.setContentType("text/html;charset=UTF-8");
        out.println("</th>");


        outimg.close();
        out.close();
                

Pois é, mas o problema do código acima é que no momento em que o Servlet manda a imagem, o browser recebe como texto também…

Alguém tem alguma sugestão para eu resolver isso ?

OBRIGADO !!!

Emidio

Na pesma página você quer imprimir texto a uma imagem?

Desse jeito não consigo imaginar uma maneira possível.

Se você quer um Servlet que gera uma imagem, então vc precisará de um servlet separado só para isso.

Então Lipe,

na verdade, o que preciso fazer é apresentar na página várias imagens, mas antes, preciso formatar a página normalmente.

Antes, eu havia feito assim: criado um JSP que formatava a página e quando abria a célula eu fazia referência ao Servlet que apresentava a imagem.

JSP:

out.println("<tr>");
  for(int intAux=0;intAux<6;intAux++){
     arquivo = "C:\\arquivo"+intAux+".tif"
     out.println("<th>");
     out.println("<img src=ShowImg?arquivo=" + arquivo>");
     out.println("</th>");
     }

e o Servlet:

        response.setContentType("image/jpeg");
        ServletOutputStream outimg = response.getOutputStream();
        
     
        String arquivo = request.getParameter("arquivo");

        RenderedOp src = JAI.create("fileload", arquivo);
        ImageEncoder encoder = ImageCodec.createImageEncoder("JPEG",outimg, null);    
        encoder.encode(src);      

Mas assim, eu tenho outro problema que é a execução simultânea do Servlet para cada imagem que carrego, ou seja, todas as ocorrências, e acaba estourando a memória heap e apenas algumas imagens são mostradas.

Considerando a boa prática (ainda sou iniciante) qual o melhor jeito de fazer isso ???

Bom, antes havia a interface SingleThreadModel para os Servlets, porém isso foi “deprecated”. Não sei se vale usar ainda.

Então Daniel,

eu tentei usar esse SingleThreadModel no Servlet, mas o problema continuou, pq, pelo que eu entendi, essa interface não impede que sejam executadas várias instâncias da mesma classe, e sim que o MultiThread não aconteça dentro da mesma classe (espero não estar dizendo bobagem… ).

Pra vc ter uma idéia eu modifiquei o Servlet de modo que ao invés de converter em memória e enviar, a imagemera salva em disco e era enviada o endereço físico do arquivo. mas nesse caso, nem toda imagem era salva, era como se ele começasse a executar e se perdesse pois foram criados alguns arquivos com tamanho 0kb.

Eu já não sei mais o que tentar para resolver essa pendenga… :frowning:

Parece que você está com problemas de multi-threading. Parece que está compartilhando recursos que não deveria. Coloca o código desse Servlet aí.

Aí vai ele inteiro… o JSP é, grosso modo, aquele que postei acima…
se eu não passar o parâmetro “resize” a envia é renderizada diretamente no browser.
se eu passar o parâmetro “resize”, a imagem é salva em disco com um tamanho bem menor. fiz isso para resolver o problema de memória, mas daí não é sempre que a imagem é salva corretamente, ou seja, apenas mudei de problema, mas acredito que a causa de ambos problemas seja justamente a questão de multithreading.

*
 * ShowImg.java
 *
 * Created on 5 de Novembro de 2004, 11:27
 */
package classes;

import java.io.*;
import java.net.*;

import javax.servlet.*;
import javax.servlet.http.*;

import com.sun.media.jai.codec.ImageCodec;
import javax.media.jai.JAI;
import com.sun.media.jai.codec.ImageEncoder;
import javax.media.jai.RenderedOp;

import com.sun.image.codec.jpeg.JPEGImageDecoder; 
import com.sun.image.codec.jpeg.JPEGCodec; 
import com.sun.image.codec.jpeg.JPEGImageEncoder; 
import com.sun.image.codec.jpeg.JPEGEncodeParam; 
    
import java.awt.image.BufferedImage; 
import java.awt.image.AffineTransformOp; 
import java.awt.geom.AffineTransform; 
import java.awt.RenderingHints;
    

/**
 *
 * @author  lruiz
 * @version
 */
public class ShowImg extends HttpServlet {
    
    /** Initializes the servlet.
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        
    }
    
    /** Destroys the servlet.
     */
    public void destroy() {
        
    }
    
    /** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        String arquivo = null;
        String resize  = null;
        response.setContentType("image/jpeg");
        ServletOutputStream sos = response.getOutputStream();
        arquivo = request.getParameter("arquivo");
        resize  = request.getParameter("resize");
        
        RenderedOp src = JAI.create("fileload", arquivo);
        
        if ((resize != null)&&(resize.equals("true"))) {                        
            JAI.create("filestore", src, arquivo.substring(0,arquivo.length()-3)+"jpg", "JPEG",null);               
            JPEGImageDecoder decoder=JPEGCodec.createJPEGDecoder(new FileInputStream(arquivo.substring(0,arquivo.length()-3)+"jpg"));
            //JPEGImageEncoder encoder=JPEGCodec.createJPEGEncoder(new FileOutputStream(arquivo.substring(arquivo.length()-3)+"jpg"));
            JPEGImageEncoder encoder=JPEGCodec.createJPEGEncoder(sos);    
            BufferedImage sourceImg=decoder.decodeAsBufferedImage();
            BufferedImage imgThumb = scaleToSize(300,200, sourceImg);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(imgThumb);
            param.setQuality(1.0f, false);
            encoder.setJPEGEncodeParam(param);
            encoder.encode(imgThumb);
        } else {
            ImageEncoder encoder = ImageCodec.createImageEncoder("JPEG",sos, null);    
            encoder.encode(src);            
        }       
        
        sos.close();
        
    }
    
    /** Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        processRequest(request, response);
    }
    
    /** Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        processRequest(request, response);
    }
    
    /** Returns a short description of the servlet.
     */
    public String getServletInfo() {
        return "Short description";
    }

    public static BufferedImage scaleToSize(int nMaxWidth, int nMaxHeight, BufferedImage imgSrc) { 
            int nHeight = imgSrc.getHeight(); 
            int nWidth = imgSrc.getWidth(); 
            double scaleX = (double)nMaxWidth / (double)nWidth; 
            double scaleY = (double)nMaxHeight / (double)nHeight; 
            double fScale = Math.min(scaleX, scaleY); 
            return scale(fScale, imgSrc); 
    } 
    
    public static BufferedImage scale(double scale, BufferedImage srcImg) { 
            if (scale == 1 ) { 
                return srcImg; 
            } 
            AffineTransform xform = AffineTransform.getScaleInstance(scale, scale); 

            RenderingHints hints = new RenderingHints(RenderingHints.KEY_RENDERING, 
            RenderingHints.VALUE_RENDER_QUALITY); 
            
            AffineTransformOp op = new AffineTransformOp(xform, hints); 

            BufferedImage dstImg = op.createCompatibleDestImage(srcImg, 
            srcImg.getColorModel()); 

            return op.filter(srcImg, dstImg); 
     } 
    
}

VALEU !!!

Comece tirando o “static” dos dois últimos métodos. Não há a necessidade deles aí.

Talvez o processo de transformação das imagens seja muito pesado. Já verificou isso?

Pois é , esse processo de transformação não deve ser muito light realmente. Mas só encontrei essa API JAI para conseguir transformar as imagens, uma vez que o browser não carrega TIF nativamente…
Eu notei uma coisa: uma imagem de TIFF 18kb quando convertida para JPG passa a ter 531kb, ou seja, o tráfego para o browser é muito intenso, principalmente se multiplicarmos isso por 6 a 15 imagens, por isso, estou utilizando os métodos para redimensionarem a imagem, daí elas passam a ter uns 20kb.
Por outro lado, se o servlet for executado uma vez sem concorrência consigo mesmo, dá certo e nem fica muito lento. Por isso eu queria fazer o controle do fluxo tudo no Servlet, formatar a página com html e depois de abrir uma célula eu carregava a imagem, uma a uma…

Estranho, pois geralmente TIFF é bem maior que JPG.

Tb sempre achei, mas acontece isso mesmo. se vc pegar uma imagem tif qualquer e submeter ao código abaixo, poderá verificar esse fato.

 RenderedOp src = JAI.create("fileload", arquivotif);
  JAI.create("filestore", src, arquivojpg, "JPEG",null);

Pelo que eu li na documentação, existem até outros métodos para conversão mas todos que testei chegaram ao mesmo tamanho de arquivo.

http://java.sun.com/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/JAITOC.fm.html

Daí então, estou buscando alternativas para apresentar todas essas imagens no browser sem dar pau em algumas delas… (já faz mais de uma mês que estou estudando alternativas sem sucesso…)

Faz um teste de conversão no Photoshop e verifique o tamanho do TIFF e do JPG gerado.

Acho que voce ja pensou nisso, mas…

Nao rola criar um processo offline que fizesse os tratamentos adequados nas imagens e salvasse em disco para posterior utilizacao da maneira “padrao”?

Mas o lance da conversao eh algo a ser investigado como o destro colocou - 15 imagens de 500kb cada uma nao sera nada agradavel para baixar no navegador. :smiley:

Marcio Kuchma

Então Daniel fiz o teste:
uma imagem tiff de 7kb foi convertida para um jpg 172kb.
outra tif de 90kb foi convertida para um jpg de 1403kb, a API tinha convertido para 1022kb.

No fim, acho que faz sentido, pois o arquivo tif é preto e branco e o jpg colorido (não tem como configurar…) daí é natural que fique maior, não ?

kuchma ,

offline propriamente não daria para fazer, senão eu teria que converter meu banco de imagens com mais de 6 milhões de imagens para jpg, pois é imprevisível saber o que o usuário quer consultar…

Mas o que pensei foi, inclusive tem a ver com o título do tópico, quando o usuário fizesse a escolha do processo que quisesse consultar, eu converteria todas as imagens em disco mesmo e daí faria o link no modo tradicional. mas daí eu tenho um problema de performance, pois eu precisaria salvar esses arquivos em disco e depois ainda trafegá-los.
Se vc reparar no código acima é o que eu faço ,só que redimensionando, pois as 15 imagens são carregadas na tela como thumbnail, então eu posso reduzi-las a um tamanho interessante. Quando eu precisar delas em tamanho original, aí é tranquilo, pois carrego uma a uma…

O problema realmente é chamar várias vezes o Servlet a partir do JSP, seja para converter em memória e enviar seja para salvar em disco redimensionando.

Ja tentou converter pra GIF ou PNG pra ver se melhora?

Marcio Kuchma

Eh - realmente nao da. :smiley:

JPG diminui se comprimido, certo? Este artigo aborda compressao de conteudo com filtros de servlet: http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html. De repente serve para o teu caso.

Marcio Kuchma

Beleza !

vou converter para essas outras extensões para ver o que rola… preciso estudar a API JAI para esses outros formatos…

eu estou fazendo também alguns testes de performance, gerando os arquivos todos em disco e depois utilizando o caminho direto da imagem ao invés de utilizar o caminho do Servlet, como vc sugeriu…

eu achei interessante o seguinte:
para carregar 12 imagens JPG SALVAS EM DISCO, demorou 50s
para carregar as mesmas imagens convertendo direto para o browser demorou 30s, sendo que mais da metade deu erro no envio/conversão.

Agora, fazendo o mesmo teste com imagens bem menores, os tempos ficaram muito próximos aos de cima, ou seja, o tamanho da imagem aparentemente não está interfirindo no envio (!!!). Talvez por um detalhe que esqueci de dizer, estou em uma rede local…

Mas de qualquer forma vou estudar esse link e ver o que consigo fazer…

Depois eu dou um feedback do que rolou…

Obrigadão a todos pela força !

No meu caso, eu preciso carregar um arquivo swf, mais este não funciona…

eu fiz o seguinte código amsi o arquivo não carrega:

public void processRequest(HttpServletRequest request, HttpServletResponse response)  
     throws ServletException, IOException {  
           
           
     arquivo = (String) request.getAttribute("fileCode");  
   
         //Conteúdo em Base64 adquirido através de uma dll  
         content = new MySharedLibrary().carregaArquivo3(arquivo);  
           
         content = content.replaceAll("@", "\n").trim();  
   
         try  
         {  
                //Decodificação de Base64 para Binário  
             bytes = base.decode(content);  
               
             if(bytes != null)  
             {  
                 response.setContentType("application/x-shockwave-flash");                 
                 OutputStream fos = response.getOutputStream();  
                 fos.write(bytes);  
                 fos.flush();  
                 fos.close();  
   
             }  
         }  
         catch(Exception ex)  
         {  
             ex.printStackTrace();  
         log(ex.getMessage());  
         }  
    }  

Agluém pode me ajudar? :cry: