mercredi 6 mars 2013

Archive multi-image

Voici un exemple de classe permettant de regrouper plusieurs images dans une archive unique.

L'archive présente la structure suivante :
- Version : 1 byte
- Count   : 1 integer
{ offsetStart : 1 integer | length : 1 integer }
# --> cible : { offsetStart : 1 integer | length : 1 integer | type : 1 byte }#
{ filesContent }

Quatre commandes permettent de constituer et manipuler les archives d'images :
  • pack
Cette commande permet de constituer une archive d'image à partir d'un répertoire contenant des images.
Exemple : pack("/~/imgArcTest", 355);
  • unpack
Cette commande permet d'extraire une image d'une archive d'images.
Exemple : unpack("/~/imgArcTest", "Test-355.img", 355);
  • unpackAll
Cette commande permet d'extraire toutes les images d'une archive d'images.
Exemple : unpackAll("/~/imgArc/Test", "Test-355.img");
  • unpackrange
Cette commande permet d'extraire une série d'images d'une archive d'images.
Exemple : unpackRange("/~/imgArc/Test", "Test-355.img", 200, 225);

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * Concatène des fichers (de type image) dans un fichier archive dont la structure est la suivante :
 * - Version : 1 byte
 * - Count    : 1 integer
 * { offsetStart : 1 integer | length : 1 integer }
 * # --> cible : { offsetStart : 1 integer | length : 1 integer | type : 1 byte }#
 * { filesContent }
 * 
 * @author ede
 */
public class ImageArchive {

    /**
     * Numéro de version du format
     */
    private final static byte VERSION=1;

    /**
     * Taille du buffer d'écriture (et de lecture)
     */
    private final static int BUFFER_SIZE=40960;
    
    /**
     * Pattern des fichiers lus.
     * Ex : x-001.png
     */
    public static String ENCODE_PREFIX="x-";
    public static int DIGIT_NUMBER=3;
    public static String ENCODE_SUFIX=".png";

    /**
     * Pattern des fichiers extraits.
     */
    public static String DECODE_PREFIX=ENCODE_PREFIX;
    public static String DECODE_SUFIX=ENCODE_SUFIX;

    
    /**
     * Package un ensemble d'images dans une archive
     * 
     * @param path : Chemin d'accès aux fichiers à packager.
     * @param count : Nombre de fichier à packager. L'index commence à 0.
     * @param destFilename : Nom du fichier à prendre en compte.
     * @return Chemin d'accès au fichier packagé
     */
    public static String pack(final String path, final int count, final String destFilename) {
        
        FileInputStream fis = null;
        RandomAccessFile raf = null;
        byte[] b = new byte[BUFFER_SIZE];
        int offsetStart=0;
        int length=1+4+count*8;
        int len = -1;
        String oPath = path+File.separator+destFilename;
        
        try {
            raf = new RandomAccessFile(oPath, "rw");
            raf.writeByte(VERSION);
            raf.writeInt(count);
            for(int i=0; i<count; i++) {
                fis = new FileInputStream(path+File.separator+ENCODE_PREFIX+format(i+1,DIGIT_NUMBER)+ENCODE_SUFIX);
                offsetStart+=length;
                raf.seek(offsetStart);
                length=0;
                while((len = fis.read(b)) >= 0) {
                    raf.write(b,0,len);
                    length+=len;
                }
                raf.seek(1+4+i*8);
                raf.writeInt(offsetStart);
                raf.writeInt(length);
            }
            raf.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return oPath;
    }
    
    /**
     * Extrait les fichiers contenu dans une archive.
     * 
     * @param path : Chemin d'accès au répertoire contenant le fichier archive source
     * @param filename : Nom du fichier archive à partir duquel extraire
     * @return Chemin d'accès au répertoire contenant les fichiers extraits
     */
    public static String unpackAll(final String path, final String filename) {
        
        byte version;
        FileOutputStream fos = null;
        RandomAccessFile raf = null;
        int count = 0;
        byte[] b = new byte[BUFFER_SIZE];
        int offsetStart = 0;
        int length = 0;
        int num = 0;
        int mod = 0;
        File f = null;
        
        try {
            raf = new RandomAccessFile(path+File.separator+filename, "r");
            version = raf.readByte();
            count = raf.readInt();
            for(int i=0; i<count; i++) {
                raf.seek(1+4+i*8);
                offsetStart = raf.readInt();
                length = raf.readInt();
                
                raf.seek(offsetStart);
                
                f = new File(path+File.separator+"unpack"+File.separator+DECODE_PREFIX+format(i,DIGIT_NUMBER)+DECODE_SUFIX);
                if(f.createNewFile()) {
                    fos = new FileOutputStream(f, true);
                    
                    num = length / BUFFER_SIZE;
                    mod = length % BUFFER_SIZE;
                    for(int j=0; j<num; j++) {
                        raf.read(b);
                        fos.write(b);
                        fos.flush();
                    }
                    raf.read(b,0,mod);
                    fos.write(b,0,mod);
                    fos.flush();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos!=null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        return path+File.separator+"unpack";
    }
 
    /**
     * Extrait le fichier contenu dans une archive correspondant à l'index donné.
     *
     * @param path : Chemin d'accès au répertoire contenant le fichier archive source
     * @param filename : Nom du fichier archive à partir duquel extraire
     * @param index : index du fichier à extraire. L'index commence à 0.
     * @return Chemin d'accès au répertoire contenant les fichiers extraits
     */
    public static String unpack(final String path, final String filename, final int index) {
       
        byte version;
        FileOutputStream fos = null;
        RandomAccessFile raf = null;
        byte[] b = new byte[BUFFER_SIZE];
        int offsetStart = 0;
        int length = 0;
        int num = 0;
        int mod = 0;
        File f = null;
        int count = 0;

        try {
            raf = new RandomAccessFile(path+File.separator+filename, "r");
            version = raf.readByte();
            count = raf.readInt();
            if (index<0 || index>count)
                throw new ArrayIndexOutOfBoundsException();

            raf.seek(1+4+index*8);
            offsetStart = raf.readInt();
            length = raf.readInt();
               
            raf.seek(offsetStart);
               
            f = new File(path+File.separator+"unpack"+File.separator+DECODE_PREFIX+format(index,DIGIT_NUMBER)+DECODE_SUFIX);
            if(f.createNewFile()) {
                fos = new FileOutputStream(f, true);
                   
                num = length / BUFFER_SIZE;
                mod = length % BUFFER_SIZE;
                for(int j=0; j<num; j++) {
                    raf.read(b);
                    fos.write(b);
                    fos.flush();
                }
                raf.read(b,0,mod);
                fos.write(b,0,mod);
                fos.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos!=null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
       
        return path+File.separator+"unpack";
    }
   
    /**
     * Extrait le fichier contenu dans une archive correspondant à l'index donné.
     *
     * @param path : Chemin d'accès au répertoire contenant le fichier archive source
     * @param filename : Nom du fichier archive à partir duquel extraire
     * @param index1 : index inférieur de la plage de fichiers à extraire. L'index commence à 0.
     * @param index2 : index supérieur de la plage de fichiers à extraire.
     * @return Chemin d'accès au répertoire contenant les fichiers extraits
     */
    public static String unpackRange(final String path, final String filename, final int index1, final int index2) {
       
        byte version;
        FileOutputStream fos = null;
        RandomAccessFile raf = null;
        int count = 0;
        byte[] b = new byte[BUFFER_SIZE];
        int offsetStart = 0;
        int length = 0;
        int num = 0;
        int mod = 0;
        File f = null;
       
        try {
            raf = new RandomAccessFile(path+File.separator+filename, "r");
            version = raf.readByte();
            count = raf.readInt();
           
            if (index1<0 || index2>count || index1>index2)
                throw new ArrayIndexOutOfBoundsException();
           
            for(int i=index1; i<index2; i++) {
                raf.seek(1+4+i*8);
                offsetStart = raf.readInt();
                length = raf.readInt();
               
                raf.seek(offsetStart);
               
                f = new File(path+File.separator+"decode"+File.separator+DECODE_PREFIX+format(i,DIGIT_NUMBER)+DECODE_SUFIX);
                if(f.createNewFile()) {
                    fos = new FileOutputStream(f, true);
                   
                    num = length / BUFFER_SIZE;
                    mod = length % BUFFER_SIZE;
                    for(int j=0; j<num; j++) {
                        raf.read(b);
                        fos.write(b);
                        fos.flush();
                    }
                    raf.read(b,0,mod);
                    fos.write(b,0,mod);
                    fos.flush();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos!=null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
       
        return path;
    }      
    /**
     * Produit un compteur de fichier formaté de la forme suivante :
     * 001, 002, ..., 00N sur 3 digits.
     *
     * @param num : index à formater
     * @param size : nombre de digit à prendre en compte
     * @return Compteur formaté
     */
    private static String format(int num, int size) {
   
        String str=Integer.toString(num);       
        while(str.length()<size) {
            str = "0"+str;
        }
        return str;
    }
   
    /**
     * Méthode de test...
     *
     * @param args
     */
    public static void main(String[] args) {

        long t0 = System.currentTimeMillis();
       
        ENCODE_PREFIX = "x-";
        ENCODE_SUFIX = ".png";
        DECODE_PREFIX = "y-";
        //ENCODE_SUFIX = ".png";
       
        if ("-pack".equals(args[0])) {
            String path = args[1];
            int count = Integer.parseInt(args[2]) ;
            pack(path, count, "Test-"+count+".img");           
        }
       
        if ("-unpackAll".equals(args[0])) {
            String path = args[1];
            String name = args[2];
            unpackAll(path, name);           
        }

        if ("-unpack".equals(args[0])) {
            String path = args[1];
            String name = args[2];
            int count = Integer.parseInt(args[3]) ;
            unpack(path, name, count);           
        }

        if ("-unpackRange".equals(args[0])) {
            String path = args[1];
            String name = args[2];
            int index1 = Integer.parseInt(args[3]);
            int index2 = Integer.parseInt(args[4]);
            unpackRange(path, name, index1, index2);           
        }

        long t1 = System.currentTimeMillis();
        System.out.println("--> time="+(t1-t0));

//        unpackAll("/~/imgArc/Test", "Test-355.img");
//        unpack("/~/imgArcTest", "Test-355.img", 355);
//        unpackRange("/~/imgArc/Test", "Test-355.img", 200, 225);
    }
}
Related Posts Plugin for WordPress, Blogger...