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 }
- 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
Exemple : pack("/~/imgArcTest", 355);
- unpack
Exemple : unpack("/~/imgArcTest", "Test-355.img", 355);
- unpackAll
Exemple : unpackAll("/~/imgArc/Test", "Test-355.img");
- unpackrange
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);
}
}