Wednesday, November 7, 2012

Conectando sua aplicação Java a um Scanner


Scanners, câmeras digitais, e outros dispositivos de aquisição de imagens estão constantemente presentes no panorama da computação. Em que pese essa ubiquidade, Java ainda não possui uma especificação ou uma API padrão para interagir com estes componentes.

Quando se faz necessário integrar uma aplicação Java a tais dispositivos, o programador deve recorrer a bindings, que usam métodos nativos fora da JVM.

Atualmente existem dois protocolos, conhecidos como TWAIN e SANE, que especificam a comunicação entre um software e um dispositivo de imagens.

TWAIN, além de um protocolo, também representa uma organização formada pelas principais marcas da indústria da imagem. SANE (Scanner Access Now Easy), comumente usade em Linux, é uma API que padroniza o acesso a dispositivos de imagens, e difere de TWAIN a medida em que separa claramente o frontend (programa do usuário) e o backend (driver), o que torna mais fácil e transparente o acesso aos dispositivos dentro de uma rede (como uma LAN cheia de máquinas, mas com scanners conectados a apenas um ou duas máquinas, por exemplo).

Segue uma implementação simples que exibe uma janela e um botão que ativa o scanner local para digitalizar o documento contido bandeja. E necessário configurar seu classpath com as bibliotecas do projeto mm's computing, Scan_.jar e uk.co.mmscomputing.device.twain.jar, as quais podem ser baixadas aqui. Use JDK 7 32bit.

public class ScannerImageTest extends JFrame implements ScannerListener{

    Scanner scanner;
    ImagePanel imagePanel;
    JButton capturar;
    
    public ScannerImageTest() {                        
        setUpJFrame();
        //busca um scanner conectado à máquina local
        scanner = Scanner.getDevice();
        //registra um objeto ScannerListener para capturar os eventos
        scanner.addListener(this);
        setVisible(true);        
    }        

    private void setUpJFrame() {
        imagePanel = new ImagePanel();        
        capturar = new JButton("Capturar Imagem");
        capturar.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    //inicia a digitalização da imagem
                    scanner.acquire();
                } catch (ScannerIOException ex) {
                    ex.printStackTrace();
                }
            }
        });                    
        
        setSize(410, 510);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());                
        getContentPane().add(capturar, BorderLayout.NORTH);
        getContentPane().add(imagePanel, BorderLayout.CENTER);
        setTitle("Hello Scanner!");
}

    //chamado automaticamente pelo listener do scanner
    @Override
    public void update(ScannerIOMetadata.Type type, ScannerIOMetadata siom) {
        if(type.equals(ScannerIOMetadata.ACQUIRED)){            
            //neste ponto o documento foi totalmente digitalizado
            BufferedImage bufferedImage = siom.getImage();
            imagePanel.setScannedImage(bufferedImage);
        }
    }
    
    public static void main(String[] args) {
        //inicia a aplicação
        new ScannerImageTest();
    }
}

class ImagePanel extends JPanel{
    
    Image scannedImage;

    public void setScannedImage(Image scannedImage) {
        this.scannedImage = scannedImage;
        if(scannedImage != null){
            this.scannedImage = scannedImage.getScaledInstance(400, 500, 0);
        }
        super.repaint();
    }
    
    @Override
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);  
      if(scannedImage != null){        
        Graphics2D g2d = (Graphics2D) g.create();        
        g2d.drawImage(scannedImage, 0, 0, null);
        g2d.dispose();
      }
    }        
}

A aplicação captura a imagem e a exibe em um painel:




A biblioteca do projeto mm's computing permite que o programador utilize uma interface gráfica padrão, com mais recursos de digitalização, neste caso uma nova janela é exibida durante o processo; ou é possível acoplar uma interface mais simples no frame, chamando o método:

Scanner.getDevice().getScanGUI()

15 comments:

  1. I was just looking for it, thanks a lot !!

    ReplyDelete
  2. Olá Rafael bom dia.

    Cara tentei D+ usar esta biblioteca mm's computing, primeiro que o site dele não esta mais no ar, ao fazer uso da mesma com scanner tive dificuldades para obter a imagem, o programa travava, e não consegui resolver ficava a duvida se era algo errado com a biblioteca, criei uma conta para o morena e consegui usar para fazer uns testes, mais gostaria de poder usar esta mm´s computing.

    ReplyDelete
  3. Tem como reupar o link das bibliotecas ou enviar para meu email diherllys@live.com por favor vai ajudar mt, obrigado ^^

    ReplyDelete
  4. olá, amigos, o link é o que segue: http://rsbweb.nih.gov/ij/plugins/twain-scan.html

    ReplyDelete
  5. Hello,
    please can u help me
    i have problem when i try to capture image from scanner
    Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: C:\Windows\System32\AspriseJTwain.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform

    ReplyDelete
    Replies
    1. you have to use a jvm 32 bits. Eu nao estou conseguindo fazer funcionar! dá o seguinte erro "uk.co.mmscomputing.device.twain.TwainFailureException: Failed during call to twain source.
      cc=No Data Source
      rc=1" Já pesquisei pra baralho. helpe-me please.

      Delete
    2. Tbm to com esse mesmo problema. Estou com o 32 bits e não ta funcionando.

      Delete
  6. Usei em uma aplicação desktop e funciona perfeitamente, abrigada amigo.

    ReplyDelete
  7. run:
    Erro: Não foi possível localizar nem carregar a classe principal javaapplication1.Main
    Java Result: 1
    BUILD SUCCESSFUL (total time: 0 seconds)

    ReplyDelete
  8. Bom dia Rafael muito bom seu post têm como me enviar o projeto completo o meu deu problema ?

    ReplyDelete
  9. Amigos, preciso de ajuda. Alguem tem como me enviar este projeto?
    periclesrodrigues@msn.com

    ReplyDelete
  10. Boa noite Rafael, tudo bem? Deixa eu te fazer uma pergunta. Se eu não tiver o scanner para fazer o teste, e no momento que eu executar o arquivo ele vai dar um erro? Outra coisa, teria como vc me enviar esse projeto? meu email é ramiltoncosta@gmail.com

    Abraços,

    ReplyDelete
    Replies
    1. olá, Ramilton!
      Faz muito tempo que não mecho nesse projeto, mas que eu me lembre se não houver scanner conectado à maquina o método getDevice() na linha 10 retorna null, portanto, se vc tratar essa condição, acredito que não haverá problemas.
      Não posso enviar o projeto devido à razões legais.

      abraços!

      Delete