在Java中通过套接字发送图像的有效方法

enj*_*joi 1 java sockets image javax.imageio

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

现在,我已经设置了imageIO;

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

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

ImageIO.write(captureImg(),"JPG",client.getOutputStream());
Run Code Online (Sandbox Code Playgroud)

和接收者:

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

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

ImageIO.write(img, "jpg", outputfile);
Run Code Online (Sandbox Code Playgroud)

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

Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());              
BufferedImage capture = new Robot().createScreenCapture(screenRect);
Run Code Online (Sandbox Code Playgroud)

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

任何帮助将不胜感激,请询问您是否要我为字节数组添加任何其他信息或代码!

谢谢。

编辑:帕特里克:

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

Mar*_*o13 5

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

您需要在几个条件之间进行权衡:

  • 最小化网络流量
  • 最小化CPU负载
  • 最大化图像质量

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

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

还提到了将图像数据压缩的选项。确实,压缩图像的JPG或PNG数据几乎不会减少数据量(因为数据已经压缩)。但是,压缩原始图像数据可能是可行的选择,可以替代JPG或PNG。

哪种压缩技术(JPG,PNG或ZIP)合适,还取决于图像内容:JPG更适用于“自然”图像,例如照片或渲染图像。它们可以承受较高的压缩力而不会造成伪影。对于人造图像(如线条图),它将迅速引起不良的伪像,尤其是在锐利边缘或图像包含文字时。与此相反:当图像包含单色的大区域时,由于这些压缩方法的“游程压缩”特性,像PNG(或ZIP)这样的压缩可以减小图像大小。

相当早以前,我已经为这种图像传输进行了一些实验,并以易于调整和调整这些参数以及在不同方法之间进行切换以及比较不同应用案例的速度的方式来实现它。但是从我的脑海中,我无法给出结果的深刻总结。

BTW:根据什么你真的想转让,你可以考虑用不同的技术比获得的图像数据Robot#createScreenCapture(Rectangle)。众所周知,这种方法非常缓慢。例如,当您要传输Swing应用程序时,可以让您的应用程序直接绘制成图像。大致像

BufferedImage image = new BufferedImage(w,h,type);
Graphics g = image.getGraphics();
myMainFrame.paint(g);
g.dispose();
Run Code Online (Sandbox Code Playgroud)

(这只是一个草图,以显示基本思想!)

此外,您可以考虑使用其他选项来提高这种图像传输的“实际速度”。例如,您可以将图像划分为图块,然后将这些图块一个接一个地转移。如果图像尽可能快地至少部分可见,则接收者可能会欣赏它。这个想法可以进一步扩展。例如,通过检测哪些图块在两个帧之间确实发生了更改,而仅传输这些更改的图块。(可以通过检测必须转移的“最小区域”,以相当复杂的方式扩展和实施此方法)

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

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