Почему Java неправильно воссоздает это изображение из InputStream? - PullRequest
2 голосов
/ 13 июля 2010

Я смотрел на это всеми возможными способами ... Проблема в том, что я заканчиваю тем, что записал ИДЕАЛЬНОЕ количество байтов, и файлы ОЧЕНЬ похожи, но некоторые байты разные. Я открыл сгенерированный Java-файл в Scite так же, как и в оригинале, и, хотя они близки, они не совпадают. Есть ли способ это исправить? Я пытался сделать все возможное - я использовал разные обертки, читатели, писатели и разные методы, чтобы взять байтовый массив (или принять его как символы - попробовал оба) и превратить его в файл.

Изображение для теста находится на http://www.google.com/images/srpr/nav_logo13.png. Вот код:

import java.awt.Image;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.imageio.ImageIO;

public class ImgExample
{

    private String address = "http://www.google.com";
    /**
     * Returns a 3 dimensional array that holds the RGB values of each pixel at the position of the current
     * webcam picture. For example, getPicture()[1][2][3] is the pixel at (2,1) and the BLUE value.
     * [row][col][0] is alpha
     * [row][col][1] is red
     * [row][col][2] is green
     * [row][col][3] is blue
     */
    public int[][][] getPicture()
    {
        Image camera = null;
        try {
            int maxChars = 35000;
            //The image in question is 28,736 bytes, but I want to make sure it's bigger
            //for testing purposes as in my case, it's an image stream so it's unpredictable
            byte[] buffer = new byte[maxChars];
            //create the connection
            HttpURLConnection conn = (HttpURLConnection)(new URL(this.address+"/images/srpr/nav_logo13.png")).openConnection();
            conn.setUseCaches(false);
            //wrap a buffer around our input stream
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            int bytesRead = 0;
            while ( bytesRead < maxChars && reader.ready() )
            {
                //reader.read returns an int - I'm assuming this is okay?
                buffer[bytesRead] = (byte)reader.read();
                bytesRead++;
                if ( !reader.ready() )
                {
                    //This is here to make sure the stream has time to download the next segment
                    Thread.sleep(10);
                }
            }
            reader.close();

            //Great, write out the file for viewing
            File writeOutFile = new File("testgoog.png");
            if ( writeOutFile.exists() )
            {
                writeOutFile.delete();
                writeOutFile.createNewFile();
            }
            FileOutputStream fout = new FileOutputStream(writeOutFile, false);
            //FileWriter fout = new FileWriter(writeOutFile, false);
            //needed to make sure I was actually reading 100% of the file in question
            System.out.println("Bytes read = "+bytesRead);
            //write out the byte buffer from the first byte to the end of all the chars read
            fout.write(buffer, 0, bytesRead);
            fout.flush();
            fout.close();

            //Finally use a byte stream to create an image
            ByteArrayInputStream byteImgStream = new ByteArrayInputStream(buffer);
            camera = ImageIO.read(byteImgStream);
            byteImgStream.close();
        } catch ( Exception e ) { e.printStackTrace(); }
        return ImgExample.imageToPixels(camera);
    }

    public static int[][][] imageToPixels (Image image)
    {
        //there's a bunch of code here that works in the real program, no worries
        //it creates a 3d arr that goes [x][y][alpha, r, g, b val]
        //e.g. imageToPixels(camera)[1][2][3] gives the pixel's blue value for row 1 col 2
        return new int[][][]{{{-1,-1,-1}}};
    }

    public static void main(String[] args)
    {
        ImgExample ex = new ImgExample();
        ex.getPicture();
    }
}

Ответы [ 4 ]

11 голосов
/ 13 июля 2010

Проблема, как я вижу, в том, что вы используете Reader с.В Java Reader s предназначены для обработки символьных потоков, а не двоичных потоков, и преобразования символов, которые он выполняет, скорее всего, меняют ваши байты на вас.

Вместо этого вы должны read() из InputStream напрямую.InputStream 'read() будет блокироваться до тех пор, пока данные не станут доступны, но возвращает -1, когда достигнут конец потока.

Редактировать: Вы также можете заключить InputStream в BufferedInputStream.

3 голосов
/ 13 июля 2010

Я думаю, что ваша проблема в том, что вы используете InputStreamReader. Из ага

An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted.

Вам не нужно преобразование в символьные потоки.

3 голосов
/ 13 июля 2010

BufferedReader предназначен для чтения символьных потоков, а не байтовых / двоичных потоков.

BufferedReader.read () возвращает Символ чтения в виде целого числа в диапазоне от 0 до 65535 .Это, вероятно, усечет любые двоичные данные, где значение байта больше 65535.

Я думаю, что вы хотите использовать InputStream.read() напрямую, а не в BufferedReader / InputStreamReader.

И, наконец, не связано с проблемой, но если вы откроете FileOutputStream для append = false, на самом деле нет никакого смысла удалять любой файл, который уже существует - append = false делает то же самое.

1 голос
/ 14 июля 2010

И вы также не должны использовать готовый (), как это.Ты просто тратишь время на это и спишь.read () будет блокировать до тех пор, пока данные не поступят в любом случае, и заблокирует правильный отрезок времени, а не произвольное предположение.Канонический цикл копирования в Java выглядит следующим образом:

int count;
byte[] buffer; // whatever size you like
while ((count = in.read(buffer)) > 0)
{
  out.write(buffer, 0, count);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...