有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用ImageIO发送图像流?

我设置了一个ServerSocket和一个socket,以便ServerSocket使用ImageIO发送图像流。写(…)socket尝试读取它们并用它们更新JFrame。所以我想知道ImageIO是否能检测到图像的结尾。(我完全不知道JPEG格式,所以我测试了它)

显然不是

在服务器端,我使用ImageIO连续发送图像。写(…)在循环中,中间有一些睡眠。在客户端,ImageIO读取第一个图像没有问题,但在下一个图像上返回null。这令人困惑。我希望它要么在读取第一个图像时阻塞(因为它认为下一个图像仍然是同一个图像的一部分),要么在读取所有图像时成功(因为它可以工作)。怎么回事?看起来ImageIO检测到了第一张图像的结尾,但没有检测到第二张图像。(顺便问一下,这些图像彼此大致相似)有没有一种简单的方法可以像这样流式传输图像,还是我必须自己制作一种机制,将字节读入缓冲区,直到它达到指定的字节或字节序列,然后从缓冲区中读取图像

这是我的服务器代码中有用的部分:

        while(true){
            Socket sock=s.accept();
            System.out.println("Connection");
            OutputStream out=sock.getOutputStream();
            while(!socket.isClosed()){
                BufferedImage img=//get image
                ImageIO.write(img, "jpg", out);
                Thread.sleep(100);
            }
            System.out.println("Closed");
        }

我的客户代码:

        Socket s=new Socket(InetAddress.getByName("localhost"), 1998);
        InputStream in=s.getInputStream();
        while(!s.isClosed()){
            BufferedImage img=ImageIO.read(in);
            if(img==null)//this is what happens on the SECOND image
            else // do something useful with the image
        }

共 (1) 个答案

  1. # 1 楼答案

    ImageIO.read(InputStream)创建一个ImageInputStream并在内部调用read(ImageInputStream)。后一种方法是在完成图像读取后关闭流

    因此,从理论上讲,您只需获取ImageReader,自己创建一个ImageInputStream,然后让ImageReaderImageInputStream重复读取

    除此之外,ImageInputStream似乎被设计为只处理一个图像(可能包含也可能不包含多个帧)。如果你多次调用ImageReader.read(0),它每次都会倒回(缓存的)流数据的开头,一遍又一遍地给你相同的图像ImageReader.read(1)将在多帧图像中查找第二帧,这对于JPEG来说毫无意义

    所以,也许我们可以创建一个ImageInputStream,让ImageReader从中读取,然后创建一个新的ImageInputStream来处理流中的后续图像数据,对吗?除此之外,ImageInputStream似乎进行了各种缓存、预读和回写,这使得很难知道包装输入流的读取位置。下一个ImageInputStream将开始从某处读取数据,但它并不像我们预期的那样位于第一个图像数据的末尾

    确定底层流位置的唯一方法是使用markreset。因为图像可能很大,所以可能需要一个BufferedInputStream来允许一个大的readLimit

    这对我很有用:

    private static final int MAX_IMAGE_SIZE = 50 * 1024 * 1024;
    
    static void readImages(InputStream stream)
    throws IOException {
        stream = new BufferedInputStream(stream);
    
        while (true) {
            stream.mark(MAX_IMAGE_SIZE);
    
            ImageInputStream imgStream =
                ImageIO.createImageInputStream(stream);
    
            Iterator<ImageReader> i = 
                ImageIO.getImageReaders(imgStream);
            if (!i.hasNext()) {
                logger.log(Level.FINE, "No ImageReaders found, exiting.");
                break;
            }
    
            ImageReader reader = i.next();
            reader.setInput(imgStream);
    
            BufferedImage image = reader.read(0);
            if (image == null) {
                logger.log(Level.FINE, "No more images to read, exiting.");
                break;
            }
    
            logger.log(Level.INFO,
                "Read {0,number}\u00d7{1,number} image",
                new Object[] { image.getWidth(), image.getHeight() });
    
            long bytesRead = imgStream.getStreamPosition();
    
            stream.reset();
            stream.skip(bytesRead);
        }
    }