使用ImageIO发送图像流? [英] Send a stream of images using ImageIO?

查看:179
本文介绍了使用ImageIO发送图像流?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a ServerSocket and a Socket set up so the ServerSocket sends a stream of images using ImageIO.write(....) and the Socket tries to read them and update a JFrame with them. So I wondered if ImageIO could detect the end of an image. (I have absolutely no knowledge of the JPEG format, so I tested it instead)

显然,不是。

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

On the server side, I sent images continuously by using ImageIO.write(...) in loop with some sleeping in between. On the client side, ImageIO read the first image no problem, but on the next one it returned null. This is confusing. I was expecting it to either block on reading the first image (because it thinks the next image is still part of the same image), or succeed at reading all of them (because it works). What is going on? It looks like ImageIO detects the end of the first image, but not the second one. (The images, by the way, are similar to each other roughly) Is there an easy way to stream images like this or do I have to make my own mechanism that reads the bytes into a buffer until it reaches a specified byte or sequence of bytes, at which point it reads the image out of the buffer?

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

This is the useful part of my server code:

        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
        }


推荐答案

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

ImageIO.read(InputStream) creates an ImageInputStream and calls read(ImageInputStream) internally. That latter method is documented to close the stream when it's done reading the image.

所以,从理论上讲,你可以得到 ImageReader ,自己创建一个 ImageInputStream ,并从中读取 ImageReader ImageInputStream 重复。

So, in theory, you can just get the ImageReader, create an ImageInputStream yourself, and have the ImageReader read from the ImageInputStream repeatedly.

除了,它出现 ImageInputStream 设计用于一个并且只有一个图像(可能包含也可能不包含多个图像)。如果您不止一次调用 ImageReader.read(0),它将每次回退到(缓存的)流数据的开头,一遍又一遍地为您提供相同的图像。 ImageReader.read(1)将在多帧图像中寻找第二帧,这当然对JPEG没有意义。

Except, it appears an ImageInputStream is designed to work with one and only one image (which may or may not contain multiple frames). If you call ImageReader.read(0) more than once, it will rewind to the beginning of the (cached) stream data each time, giving you the same image over and over. ImageReader.read(1) will look for a second frame in a multi-frame image, which of course makes no sense with a JPEG.

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

So, maybe we can create an ImageInputStream, have the ImageReader read from it, and then create a new ImageInputStream to handle subsequent image data in the stream, right? Except, it appears ImageInputStream does all sorts of caching, read-ahead and pushback, which makes it quite difficult to know the read position of the wrapped InputStream. The next ImageInputStream will start reading data from somewhere, but it's not at the end of the first image's data like we would expect.

确定底层数据的唯一方法stream的位置是 mark reset 。由于图像可能很大,您可能需要一个 BufferedInputStream 来允许一个大的 readLimit

The only way to be certain of your underlying stream's position is with mark and reset. Since images can be large, you'll probably need a BufferedInputStream to allow a large 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);
    }
}

这篇关于使用ImageIO发送图像流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆