使用ImageIO发送图像流?

Dan*_*mes 5 java streaming networking image

我有一个ServerSocket和一个Socket设置,所以ServerSocket使用ImageIO.write(....)发送图像流,Socket尝试读取它们并用它们更新JFrame.所以我想知道ImageIO是否可以检测到图像的结束.(我完全不了解JPEG格式,所以我测试了它)

显然不是.

在服务器端,我通过循环使用ImageIO.write(...)连续发送图像,其间有一些睡眠.在客户端,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");
        }
Run Code Online (Sandbox Code Playgroud)

我的客户代码:

        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
        }
Run Code Online (Sandbox Code Playgroud)

VGR*_*VGR 4

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

因此,理论上,您可以获取ImageReader,自己创建一个ImageInputStream,然后重复ImageReader读取ImageInputStream

除此之外,它似乎ImageInputStream被设计用于处理一张且仅一张图像(可能包含也可能不包含多个帧)。ImageReader.read(0)如果您多次 调用,它每次都会倒回到(缓存的)流数据的开头,一遍又一遍地为您提供相同的图像。ImageReader.read(1)会在多帧图像中寻找第二帧,这对于 JPEG 来说当然没有意义。

那么,也许我们可以创建一个 ImageInputStream,让 ImageReader 从中读取,然后创建一个新的 ImageInputStream 来处理流中的后续图像数据,对吗?除此之外,它似乎ImageInputStream执行了各种缓存、预读和推回操作,这使得很难知道包装的 InputStream 的读取位置。下一个 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);
    }
}
Run Code Online (Sandbox Code Playgroud)