ecrire bytes dans une bufferedImage

thesuixx
ecrire bytes dans une bufferedImage

bonjour, je voudrais savoir s'il existe un moyen d'écrire un tableau de bytes dans une bufferedImage ou dans un objet dont on pourra récuperer le contenu dans une bufferedImage. J'ai deja cherché sur la javadoc et sur le forum mais je n'ai rien trouvé.
(je précise que je ne veux pas créer de fichier, je voudrais passer directement d'un tableau de bytes à une bufferedImage que j'afficherai plus tard dans mon programme)


Remember, there are no stupid questions, just stupid people.

gzii_7811

Salut,
je viens de trouver ça :
http://prevert.upmf-grenoble.fr/Prog/Java/swing/image.html
Avec en particulier :

Quote:

Le Raster d'une BufferedImage est un tableau à deux dimensions de pixels. Ces pixels peuvent être lus ou modifiés par :
la méthode setRGB de BufferedImage

BufferedImage img;
...
img.setRGB(i, j, r<<8|v<<8|b);

la méthode getRGB de BufferedImage

BufferedImage img;
...
int c = img.getRGB(i, j);

Ou les méthodes setPixel de la classe WritableRaster :

void setPixel(int x, int y, double[] t)
void setPixel(int x, int y, float[] t)
void setPixel(int x, int y, int[] t)

Affecte le pixel d'indices i et j de la valeur de trouvant dans le tableau t.

* pour les types TYPE_INT_RGB et TYPE_INT_ARGB, le tableau t sera un tableau de 3 ou 4 int contenant le rouge, puis le vert, puis le bleu et enfin la transparence.
* pour le type TYPE_BYTE_GRAY le tableau t est un tableau de 1 entier qui contient la valeur de gris du pixel.
* ...

void setPixels(int x, int y, int l int h, double[] t)
void setPixels(int x, int y, int l, int h, float[] t)
void setPixels(int x, int y, int l, int h, int[] t)

affecte les pixels du rectangle donné, avec les valeurs se trouvant dans le tableau

thesuixx

merci pour ta reponse rapide
Le probleme, c'est que je ne connais ni les dimensions, ni l'encodage des images et que je peux avoir toutes sortes de formats. En fait, dans mon projet, je voudrais dézipper une archive mais sans écrire les fichiers, c-a-d que au lieu d'ecrire mes bytes dans un fichier je voudrais les écrire directement dans une buffered image pour pouvoir les afficher plus tard.
J'avais pensé à mettre les bytes dans un file buffer et de lire ce buffer avec ImageIO.read(), mais je n'ai pas trouvé de moyen pour bufferiser le contenu d'un fichier...
Je vais voir du coté de java.util.zip, histoire de voir si je peux pas mettre mes bytes dans un input stream

gzii_7811

Salut,

J'ai juste répondu après une petite recherche google, je ne connais pas du tout le sujet.

thesuixx

j'ai trouvé une methode un peu maladroite de le faire, mais il y a comme un probleme, apparemment, le premier byte ecrit est -1 donc la methode read de Image IO s'arrete là


        // Décompresse un fichier zip à l'adresse indiquée par le dossier
    public static BufferedImage decompressBufferedImage(final File fichierADecompresser, String nomFichier)
    throws IOException {
            
        // le flux pour lire le zip    
        ZipInputStream zis = new ZipInputStream(new BufferedInputStream(
        		new FileInputStream(fichierADecompresser.getCanonicalFile())));
        // un fichier du zip
        ZipEntry ze;
  
        // le compteur de bytes
        int cptBytes = 0;
        
	// on Parcourt tous les fichiers jusqu'à trouver le bon
	while (null != (ze = zis.getNextEntry()) && !ze.getName().equals(nomFichier)); 
            
        // si le bon a été trouvé
        if (ze != null && ze.getName().equals(nomFichier)){
            
            // on compte le nombre de bytes
            final byte[] buf = new byte[8192];
            //final byte[] buf = new byte[1];
	    int bytesRead;
	    while (-1 != (bytesRead = zis.read(buf))){
                 cptBytes+=bytesRead;
            }
            
            System.out.println("cptBytes = "+cptBytes);
            
            // on recommence le desarchivage
            zis = new ZipInputStream(new BufferedInputStream(
        		new FileInputStream(fichierADecompresser.getCanonicalFile())));
            // Parcourt tous les fichiers jusqu'à trouver le bon
            while (null != (ze = zis.getNextEntry()) && !ze.getName().equals(nomFichier)) ; 
            
            myInputStream mis = new myInputStream(cptBytes);
            
            // on écrit dans le inputstream
            while (-1 != (bytesRead = zis.read(buf))){
                for (int i = 0; i<bytesRead; i++) 
                    mis.write(buf[i]);
            }    
            
            BufferedImage bufIma = ImageIO.read(mis);
            
            return bufIma;
        }
        else return null;
    }

class myInputStream extends InputStream{

    private byte[] octets;
    
    private int compteurRead, compteurWrite;
    
    protected myInputStream(int nbBytes){
        compteurRead = 0;
        compteurWrite = 0;
        octets = new byte[nbBytes];
        
    }
    
    /**
     * @return le prochain byte de la liste
     * @throws java.io.IOException
     */
    @Override
    public int read() throws IOException {
        compteurRead++;
        if (compteurRead-1 < octets.length)
            return (int) octets[compteurRead-1];
        else return -1;
    }
    
    /**
     * ajoute le byte b à la liste de bytes
     * @param b
     */
    public void write (byte b){
        if (compteurWrite<octets.length){
            octets[compteurWrite] = b;
        compteurWrite++;
        }
    }
}

La facon de compter les bytes est un peu maladroite mais j'ai pas trouvé mieux
Mais ca marche toujours pas :S
fredericmazue

Quote:
mais il y a comme un probleme, apparemment, le premier byte ecrit est -1 donc la methode read de Image IO s'arrete là

Utilise public int read(byte[] b)
thesuixx

donc la methode read(InputStream in) de ImageIO appelle in.read(byte[] b) et non pas in.read(byte b) ?
je vais tester ca ce soir, merci pour ta reponse

fredericmazue

Quelle ImageIO ?

Tu as parlé d'un octet lu égal à -1 qui arrête la lecture . J'ai cru que tu parlais de

Quote:
while (-1 != (bytesRead = zis.read(buf))){
cptBytes+=bytesRead;
}

Alors je t'ai dit d'utiliser public int read(byte[] b), zis qui dérive de InputStream en dispose forcément.

thesuixx

c'est la methode read(byte[] b) que j'utilise: la preuve:

final byte[] buf = new byte[8192]; 

le contenu du fichier est bien ecrit dans l'objet de type myinputStream.
le probleme, c'est qu'il semble que le premier octet de mon image jpeg dans l'archive soit -1

(quand je print le contenu du tableau de byte de mon objet de type myInputStream, j'ai un -1 au debut)

or, la valeur -1 sert de sentinelle

public abstract int read()
                  throws IOException

    Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.

    A subclass must provide an implementation of this method.

    Returns:
        the next byte of data, or -1 if the end of the stream is reached. 
    Throws:
        IOException - if an I/O error occurs.

Et je pense que la methode ImageIO.read(Inputstream ins) appelle la methode ins.read(), donc quand ins.read retourne -1, imageIo.read(Inputstream ins) considere avoir atteint la fin de l'image et arrete la lecture.

fredericmazue

Quote:
c'est la methode read(byte[] b) que j'utilise: la preuve:

Oui en effet, je t'avais mal lu :oops:
thesuixx

J'ai cherché un peu partout mais j'ai toujours pas trouvé la methode pour dézipper sans écrire les images, je crois que je vais devoir écrire un fichier temp quelque part dans l'arborescence de mon projet puis charger ce fichier avec ImageIO.read() dans une bufferedImage, mais je trouve ca assez dommage parce que l'écriture d'un fichier va un peu ralentir mon programme et la création de fichiers ca peut toujours faire des couilles...
Donc, si quelqu'un a une idée pour dézipper mes images sans faire les fichiers, je suis preneur, sinon, tant pis, je ferai avec les fichiers temp.
merci

fredericmazue

Je vais peut être dire une ânerie. Je suis le sujet de loin comme tu as pu le voir hier :oops:

Mais je me dis qu'au lieu de passer par un fichier temporaire sur disque, tu peux peut être passer par un java.nio.FileChannel ?

thesuixx

ca pourrait être une solution, le probleme c'est que ImageIO ne propose que read(File f), read(InputStream in) et read(ImageInputStream) donc je ne peux pas lire le filechannel par la suite, à moins qu'il n'y ait un moyen de recuperer son contenu avec un inputstream ou une classe qui en herite ?

thesuixx

Je vais peut être dire une ânerie. Je suis le sujet de loin comme tu as pu le voir hier

Pas grave, je suis reconnaissant pour toute l'aide que je peux avoir ;)

J'ai eu une idée: je crée une classe myinputstream qui hérite de inputstream et qui recoit en parametre dans son constructeur le filechannel, elle va ensuite lire ce filechannel et stocker ses valeurs dans un tableau de byte. Ce qui donne:
FileChannel f = new FileChannel();
// ecriture des bytes dans le channel
... for(...) f.write(...)
...
myinputstream mis = new myinputstream (f); // le constructeur remplit automatiquement le tableau de bytes avec les bytes du filechannel en appellant la methode read de fileChannel
BufferedImage buf = ImageIO.read(mis); // et je lis le inputstream
Bien sur, il faut surcharger la methode read de myinputstream pour qu'elle retourne les bytes du tableau et non pas jenesaisquoi.

je teste ca dés ce soir, merci pour le conseil

thesuixx

j'ai testé, mais je me retrouve avec le même probleme vu que je dois obligatoirement surcharger les methodes read et write du FileChannel donc ca revient au même et ca ne marche toujours pas :/

gzii_7811

Si tu retournes un octet binaire non signé, il ne peut pas avoir la valeur -1.
(0-255)

thesuixx

oué mais du coup mon image elle ressemble plus à rien :/