簡體   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