繁体   English   中英

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

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

这是导致错误的图像

我有这个问题,我尝试了所有我知道但没有任何效果。 我试图通过套接字从数据库向客户端应用程序发送多个图像(一次一个图像),有时一切正常,但有时它声明这个“无效的JPEG文件结构:两个SOI标记”错误?

客户端 :

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();

服务器端 :

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 ;
        }
    }

不要使用available()作为输入长度的度量。 Javadoc中有一个特定的警告。 这不是它的用途。

您的副本循环应如下所示:

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

首先要做的事情:你遇到的错误:

每个JPEG图像始终以StartOfImage标记开始,该标记的十六进制为:FFD8您正在创建的缓冲区中的字节包含此SOI标记两次。 您很可能获得图像1的字节+图像2的某些字节,特别是包含第二个图像标记的起始字节。

我想你在这里犯了一个错误:

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;
} 

例如,总共有100个字节的情况。 由于某种原因,您将以50,30,20字节的块读取这100个字节。

这将给出以下内容:

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

此时,byteToRead(50)不是> cmpt(50),因此循环结束,而不写最后50个字节。

你可能需要这样的东西:

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;
}

可能对于小图像,您将一次性读取整个字节数量(尽管这不是保证,但很可能)。 如果发生这种情况,那么您将在一次迭代中完成并且永远不会遇到问题。 但是对于较大的图像,您可能会因为您读取的最后一个块而导致错过图像末尾的某些字节。 这会造成麻烦(我认为)

第二个问题可能是(在服务器端)

byteToread=input.available();

从db获得的结果集可能没有可供您使用的所有字节。

来自available()的文档

请注意,虽然InputStream的某些实现将返回流中的总字节数,但许多实现不会。 使用此方法的返回值来分配用于保存此流中所有数据的缓冲区绝对不正确。

从我可以看到出错(并且基于我的测试程序),会发生以下情况:

1:你得到image1(比如200字节)。 2:您将长度(200)写入输出流3:您将少于200个字节写入输出流(例如150)。 (因为逻辑错误)4:你得到image2(比如说300字节)5:你把长度(300)写入输出流6:你把N个字节写入输出流。

当你读

1:你读了image1.length。 这将返回200. 2:您读取200个字节。 因为你只从图像1写了150个字节,这意味着你从image1获得150个字节,从image2获得长度,然后从image2获得46个字节。

这会导致您认为图像1的字节包含jpg的2个标头。 (image2的前46个字节将包含image2的标题)

我认为您需要附加调试器并逐步完成此操作并找出其他问题。 给出的另一个答案显示了如何正确循环并计算您的读取字节。 可能会有更多问题。

暂无
暂无

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

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