简体   繁体   English

JPEG文件结构无效:两个SOI标记错误?

[英]Invalid JPEG file structure: two SOI markers error?

This is the image that causes an error 这是导致错误的图像

I have this problem and I tried everything I know but nothing worked. 我有这个问题,我尝试了所有我知道但没有任何效果。 I'm trying to send multiple images (one image at time) from a database to client application through socket, sometimes everything works just fine, but sometimes it declare this "invalid JPEG file structure: two SOI markers" error? 我试图通过套接字从数据库向客户端应用程序发送多个图像(一次一个图像),有时一切正常,但有时它声明这个“无效的JPEG文件结构:两个SOI标记”错误?

client side : 客户端 :

for(User user : users){
    int cmpt=0;

    byteToread =in.readInt();
    bytesOut=new ByteArrayOutputStream();
    bos = new BufferedOutputStream(bytesOut);    

    while (byteToread >cmpt) {
        cmpt = in.read(dataEntre);
        bos.write(dataEntre, 0, cmpt);
        bos.flush();
        byteToread-=cmpt;
    } 
    BufferedImage bi = ImageIO.read(new ByteArrayInputStream(bytesOut.toByteArray()));

    user.setPhoto(new ImageIcon(bi));
    System.out.println("------------------end");
}
bos.close();
bytesOut.close();

server side : 服务器端 :

InputStream input =null;

Statement myStmt = null;
ResultSet myRs = null;
BufferedInputStream bis=null;
try {
    myStmt = Conn.createStatement();
    myRs = myStmt.executeQuery("select Photo from users order by Name");
    byte[] buffer; 

    int k =1;

    while (myRs.next()) {
        input=myRs.getBinaryStream("Photo");
        bis = new BufferedInputStream(input);
        buffer = new byte[1024];

        try {
            int byteToread = 0;
            int cmpt=0;

            byteToread=input.available();
            out.writeInt(byteToread);
            out.flush(); 

            int i=0;  
            while (byteToread>cmpt) {
                cmpt = bis.read(buffer);
                out.write(buffer, 0, cmpt);
                out.flush();
                byteToread -= cmpt;
            } 
        } catch (IOException ex) {
            return ;
        }
    }

Don't use available() as a measure of the length of the input. 不要使用available()作为输入长度的度量。 There is a specific warning in the Javadoc against that. Javadoc中有一个特定的警告。 That's not what it's for. 这不是它的用途。

Your copy loops should look like this: 您的副本循环应如下所示:

while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

First things first: the error you encounter: 首先要做的事情:你遇到的错误:

each JPEG image always starts with a StartOfImage marker which in hex is: FFD8 The bytes in the buffer you are creating contain this SOI marker twice. 每个JPEG图像始终以StartOfImage标记开始,该标记的十六进制为:FFD8您正在创建的缓冲区中的字节包含此SOI标记两次。 It is very likely that you are getting the bytes of image 1 + some bytes of image2, in particular the starting bytes that contain the marker of the second image. 您很可能获得图像1的字节+图像2的某些字节,特别是包含第二个图像标记的起始字节。

I think you are making a mistake here: 我想你在这里犯了一个错误:

byteToread =in.readInt();
bytesOut=new ByteArrayOutputStream();
bos = new BufferedOutputStream(bytesOut);     
while (byteToread >cmpt) {
    cmpt = in.read(dataEntre);
    bos.write(dataEntre, 0, cmpt);
    bos.flush();
    byteToread-=cmpt;
} 

take for instance a situation where you have a total of 100 bytes. 例如,总共有100个字节的情况。 for some reason you will read these 100 bytes in chunks of 50, 30, 20 bytes. 由于某种原因,您将以50,30,20字节的块读取这100个字节。

this will give the following: 这将给出以下内容:

iteration 1:
during while:   
    bytesToRead: 100
    cmpt: 0
at the end of the loop:
    bytesToRead: 50
    cmpt: 50
iteration 2:
during while:   
    bytesToRead: 50
    cmpt: 50

at this point, byteToRead (50) is not > than cmpt (50) so the loop ends while you don't write the last 50 bytes. 此时,byteToRead(50)不是> cmpt(50),因此循环结束,而不写最后50个字节。

you probably need something like: 你可能需要这样的东西:

bytesToread = in.readInt();
bytesOut=new ByteArrayOutputStream();
bos = new BufferedOutputStream(bytesOut);     
while (byteToread > 0) {
    cmpt = in.read(dataEntre);
    bos.write(dataEntre, 0, cmpt);
    bos.flush();
    byteToread-=cmpt;
}

Probably with small images you'll read the entire amount of bytes in one go (though this isn't guaranteed, but just likely). 可能对于小图像,您将一次性读取整个字节数量(尽管这不是保证,但很可能)。 If this happens then you'll finish in one iteration and never encounter the problem. 如果发生这种情况,那么您将在一次迭代中完成并且永远不会遇到问题。 But with larger images you risk that the last chunk you read causes you to miss some bytes at the end of your image. 但是对于较大的图像,您可能会因为您读取的最后一个块而导致错过图像末尾的某些字节。 and this can cause trouble (I think) 这会造成麻烦(我认为)

A second issue could be (on serverside) 第二个问题可能是(在服务器端)

byteToread=input.available();

The resultset you get from the db might not have all the bytes available for you to use yet. 从db获得的结果集可能没有可供您使用的所有字节。

from the documentation of available() 来自available()的文档

Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. 请注意,虽然InputStream的某些实现将返回流中的总字节数,但许多实现不会。 It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream. 使用此方法的返回值来分配用于保存此流中所有数据的缓冲区绝对不正确。

From what I can see that's going wrong (and based on my testing program) the following occurs: 从我可以看到出错(并且基于我的测试程序),会发生以下情况:

1: you get image1 (say 200 bytes). 1:你得到image1(比如200字节)。 2: you write length (200) to your output stream 3: you write less than 200 bytes to the output stream (say 150). 2:您将长度(200)写入输出流3:您将少于200个字节写入输出流(例如150)。 (because of faulty logic) 4: you get image2 (say 300 bytes) 5: you write length (300) to your output stream 6: you write N bytes to the output stream. (因为逻辑错误)4:你得到image2(比如说300字节)5:你把长度(300)写入输出流6:你把N个字节写入输出流。

when you read 当你读

1: you read image1.length. 1:你读了image1.length。 this returns you 200. 2: you read 200 bytes. 这将返回200. 2:您读取200个字节。 because you only wrote 150 bytes from image 1, this means you get 150 bytes from image1, length of image2 and then 46 bytes from image2. 因为你只从图像1写了150个字节,这意味着你从image1获得150个字节,从image2获得长度,然后从image2获得46个字节。

this results in the bytes you think are image 1 containing 2 headers for the jpg. 这会导致您认为图像1的字节包含jpg的2个标头。 (the first 46 bytes of image2 will contain the header for image2 afterall) (image2的前46个字节将包含image2的标题)

I think you need to attach your debugger and step through this and find out what else is going wrong. 我认为您需要附加调试器并逐步完成此操作并找出其他问题。 the other answer given shows how to loop through and count your read bytes properly. 给出的另一个答案显示了如何正确循环并计算您的读取字节。 There may be more issues. 可能会有更多问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM