在Java中通过套接字发送图像的有效方法 [英] Efficient way to send an image over socket in Java

查看:121
本文介绍了在Java中通过套接字发送图像的有效方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有点像Java菜鸟,我已经阅读了一些关于套接字的基础知识,我可以使用ImageIO成功地通过套接字发送图像,但我希望减少发送的数据量。最终,我希望以尽可能小的文件大小尽可能快地发送图像(屏幕截图)。

I'm a bit of a Java noob, and I have read some basics about sockets and I can successfully send images over socket using ImageIO, but I want to reduce the amount of data that is sent. Ultimately I want the image (screen capture) to be send as fast as possible with the smallest possible file size.

现在,我已经设置了imageIO;

Right now, I have imageIO set up as such;

DataInputStream in=new DataInputStream(client.getInputStream());

DataOutputStream out = new DataOutputStream(client.getOutputStream());

ImageIO.write(captureImg(),"JPG",client.getOutputStream());

接收方:

BufferedImage img=ImageIO.read(ImageIO.createImageInputStream(server.getInputStream()));

File outputfile = new File("Screen"+(date.toString())+".jpg");

ImageIO.write(img, "jpg", outputfile);

如果您想知道,这是我用来拍摄图像的方法。

In case you're wondering, this is my method that is used to take the image.

Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());              
BufferedImage capture = new Robot().createScreenCapture(screenRect);

我听说过字节数组,你可以发送字节然后在另一端绘制图像。但是我不确定这是否更有效率。

I have heard about Byte arrays, where you can send the bytes then draw the image at the other end. However I'm not sure if this is more efficient.

我们非常感谢您的帮助,请询问您是否希望我为字节数组添加任何额外的信息或代码!

Any help would be greatly appreciated, please ask if you would like me to add any extra info or code for the byte array!

谢谢。

编辑:Patrick:

Patrick:

ByteArrayOutputStream bScrn = new ByteArrayOutputStream(); 
ImageIO.write(captureImg(), "JPG", bScrn); 
byte imgBytes[] = bScrn.toByteArray();


out.write((Integer.toString(imgBytes.length)).getBytes());
out.write(imgBytes,0,imgBytes.length);


推荐答案

评论中已经进行了广泛的讨论,但总结一些我认为重要的观点:

There already has been an extensive discussion in the comments, but to summarize a few points that I find important:

你需要在几个标准之间进行权衡:

You have a trade-off between several criteria:


  • 最小化网络流量

  • 最小化CPU负载

  • 最大化图像质量

您可以通过高图像压缩来减少网络流量。但这会增加CPU负载并可能降低图像质量。

You can reduce the network traffic with a high image compression. But this will increase the CPU load and might reduce the image quality.

是否降低图像质量取决于压缩类型:对于JPG,可以使图像任意小,但图像的质量将是......好吧,任意不好。对于PNG,图像质量将保持不变(因为它是无损压缩),但CPU负载和生成的图像大小可能更大。

Whether it reduces the image quality depends on the compression type: For JPG, you can make the image arbitrarily small, but the quality of the image will then be ... well, arbitrarily bad. For PNG, the image quality will stay the same (since it is a lossless compression), but the CPU load and the resulting image size may be greater.

选项还提到了压缩图像数据。对图像的JPG或PNG数据进行压缩确实很难减少数据量(因为已经 压缩的数据)。但压缩原始图像数据可能是一种可行的选择,可替代JPG或PNG。

The option of ZIPping the image data was also mentioned. It is true that ZIPping the JPG or PNG data of an image will hardly reduce the amount of data (because the data already is compressed). But compressing the raw image data can be a feasible option, as an alternative to JPG or PNG.

适合哪种压缩技术(JPG,PNG或ZIP)还取决于图像内容:JPG更适合自然图像,如照片或渲染图像。它们可以承受高压缩而不会造成伪影。对于人工图像(如线条图),它会很快产生不希望的伪像,特别是在锐边或图像包含文本时。与此形成对比:当图像包含单个颜色的大区域时,由于这些压缩方法的游程长度压缩性质,像PNG(或ZIP)这样的压缩会缩小图像大小。

Which compression technique (JPG, PNG or ZIP) is appropriate also depends on the image content: JPG is more suitable for "natural" images, like photos or rendered images. These can withstand a high compression without causing artefacts. For artifical images (like line drawings), it will quickly cause undesirable artefacts, particularly at sharp edges or when the image contains texts. In contrast to that: When the image contains large areas with a single color, then a compression like PNG (or ZIP) can reduce the image size due to the "run length compression" nature of these compression methods.

我前段时间已经对这种图像传输进行了一些实验,并以一种容易调整和调整这些参数并在不同方法之间切换的方式实现它,并比较速度不同的应用案例。但从我的头脑中,我无法对结果作出深刻的总结。

I already made some experiments for such an image transfer quite a while ago, and implemented it in a way that easily allowed tweaking and tuning these parameters and switching between the different methods, and comparing the speed for different application cases. But from the tip of my head, I can not give a profound summary of the results.

BTW:根据您实际想要传输的 ,您可以考虑使用与机器人#createScreenCapture(矩形)。众所周知,这种方法令人痛苦地缓慢。例如,当您想要传输Swing应用程序时,可以让应用程序直接绘制到图像中。粗略地使用类似

BTW: Depending on what you actually want to transfer, you could consider obtaining the image data with a different technique than Robot#createScreenCapture(Rectangle). This method is well-known to be distressingly slow. For example, when you want to transfer a Swing application, you could let your application directly paint into an image. Roughly with a pattern like

BufferedImage image = new BufferedImage(w,h,type);
Graphics g = image.getGraphics();
myMainFrame.paint(g);
g.dispose();

(这是草图,以显示基本想法!)

(This is only a sketch, to show the basic idea!)

此外,您可以考虑进一步增加此类图像传输的感知速度的选项。例如,您可以将图像划分为 tiles ,然后一个接一个地传输这些图块。如果图像尽可能快地部分可见,则接收器可能会欣赏它。这个想法可以进一步扩展。例如,通过检测哪些图块在两个帧之间确实发生了变化,并且仅传输这些更改的图块。 (这种方法可以通过检测必须转移的最小区域以相当复杂的方式扩展和实施)

Additionally, you could consider further options for increasing the "percieved speed" of such an image transfer. For example, you could divide your image into tiles, and transfer these tiles one after another. The receiver will possibly appreciate it if the image would at least be partially visible as quickly as possible. This idea could be extended further. For example, by detecting which tiles have really changed between two frames, and only transfer these changed tiles. (This approach could be extended and implemented in a rather sophisticated way, by detecting the "minimum regions" that have to be transferred)

但是,对于你的第一种情况想要使用最明显的调整参数:这是一种允许将质量值介于0.0和1.0之间的JPG图像写入输出流的方法:

However, for the case that you first want to play around with the most obvious tuning parameter: Here is a method that allows writing a JPG image with a quality value between 0.0 and 1.0 into an output stream:

public static void writeJPG(
    BufferedImage bufferedImage,
    OutputStream outputStream,
    float quality) throws IOException
{
    Iterator<ImageWriter> iterator =
        ImageIO.getImageWritersByFormatName("jpg");
    ImageWriter imageWriter = iterator.next();
    ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
    imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    imageWriteParam.setCompressionQuality(quality);
    ImageOutputStream imageOutputStream =
        new MemoryCacheImageOutputStream(outputStream);
    imageWriter.setOutput(imageOutputStream);
    IIOImage iioimage = new IIOImage(bufferedImage, null, null);
    imageWriter.write(null, iioimage, imageWriteParam);
    imageOutputStream.flush();
}

这篇关于在Java中通过套接字发送图像的有效方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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