简体   繁体   中英

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?

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. There is a specific warning in the Javadoc against that. 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. 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.

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. for some reason you will read these 100 bytes in chunks of 50, 30, 20 bytes.

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.

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.

from the documentation of available()

Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. 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). 2: you write length (200) to your output stream 3: you write less than 200 bytes to the output stream (say 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.

when you read

1: you read image1.length. this returns you 200. 2: you read 200 bytes. 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.

this results in the bytes you think are image 1 containing 2 headers for the jpg. (the first 46 bytes of image2 will contain the header for image2 afterall)

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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