Bonjour à tous,

Je manipule des images satellite en haute résolution (par exemple 8000 * 4000) dans du code Java, images que je voudrais pouvoir sauver dans différents formats : JPEG, PNG, TIFF (avec header GeoTIFF).

Les images sont générées à partir de données sur le disque qui ne sont pas chargées intégralement en mémoire (sorte de cache), ce qui rend la consommation mémoire faible (Malgrés la taille importante des images)

Pour l'instant, je les sauvegarde selon le même principe, en écrivant mon image au fur et à mesure sur le disque. Pour ce faire, j'ai écris une classe de gestion d'image qui passe par un fichier disque (l'image est au format PNM, format très simple qui d'ailleurs me permet de faire facilement ce que je fait).

Par contre les choses se compliquent si je veux sauver mes images dans d'autres formats plus complexe (PNG, JPG, TIFF). C'est pour ça que je compte passer par des librairies déjà existante, mais qui ne nécessiterait pas d'avoir l'image en totalité en mémoire pour procéder à la sauvegarde.

J'ai essayé de chercher dans la lib "standard", et du coté de JAI, mais je n'ai pas trouvé moyen de faire ça.

Dans le détail :

En passant par le classiques "ImageIO.write(....)" j'obtiens évidemment un "Memory Heap Space". J'ai donc cherché d'autres moyens, par exemple en passant par un "ImageWriter", que je n'arrive pas à faire fonctionner :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
	FileImageOutputStream outputImage = new FileImageOutputStream(new File(outputName + ".png"));
	PNGImageWriterSpi pngWriterSpi = new PNGImageWriterSpi();
	ImageWriter imageWriter = pngWriterSpi.createWriterInstance();
	imageWriter.setOutput(outputImage);
 
 
	Rectangle region = new Rectangle(tileWidth,tileHeight);
	ImageWriteParam writeParam = imageWriter.getDefaultWriteParam();
	writeParam.setSourceRegion(region);
 
	int tileWidth  = 256;
	int tileHeight = 256;
	BufferedImage tile = new BufferedImage(tileWidth,tileHeight,BufferedImage.TYPE_3BYTE_BGR);
 
	/*
	 * modification de la BufferedImage "tile"
	 */
 
	region.x = offsetX;
	region.Y = offsetY;
 
	imageWriter.prepareReplacePixels(0,region);
	imageWriter.replacePixels(tile,writeParam);
Avec ce code, j'obtiens un "Exception in thread "main" java.lang.UnsupportedOperationException: Unsupported write variant!"
ce qui me fait penser que le "PNGImageWriterSpi" crée un "ImageWriter" qui ne supporte pas ce genre d'opération. J'ai tenté avec un "JPGImageWriterSpi", mais même erreur.

Par contre pas de problème pour son homologue "ImageReader" :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
	//ça pourra peut être servir à quelqu'un
 
	//ouvre un fichier JPG avec un ImageReader
	FileImageInputStream inputImage = new FileImageInputStream(new File(inputName));
	JPEGImageReaderSpi jpegReaderSpi = new JPEGImageReaderSpi();
	ImageReader imageReader = jpegReaderSpi.createReaderInstance();
	imageReader.setInput(inputImage);
 
	//La lecture de l'image se fait ensuite par "tuile", chaque tuile représentant une partie de l'image
	int tileWidth  = 256;
	int tileHeight = 256;
	BufferedImage tile = new BufferedImage(tileWidth,tileHeight,BufferedImage.TYPE_3BYTE_BGR);
	Rectangle region = new Rectangle(tileWidth,tileHeight);
 
	//création d'un ImageReadParam pour selectionner la zone à lire
	ImageReadParam readParam = new ImageReadParam();
	readParam.setDestination(tile);
	readParam.setSourceRegion(region);
 
	region.x = offsetX;  //abscisse du pixel haut gauche de la zone
	region.y = offsetY;  //ordonnée du pixel haut gauche de la zone
 
	//ImageReader gère les images à plusieurs layer. Dans le cas usuel, il n'y a qu'un seul layer, qu'il faut spécifier, d'ou le 0
	imageRead.read(0,readParam);
 
	//la "partie d'image" se retrouve ensuite dans le BufferedImage tile
J'ai aussi penser à utiliser des objets / méthodes "classiques" (BufferedImage, ImageIO.write(...)) mais en faisant en sorte que la mémoire utilisée utilise un cache disque. Je n'ai par contre pas trouvé comment faire (utilisation de la classe FileCacheImageOutputStream ?)

Enfin, j'ai regardé du coté de JAI. En lecture, j'arrive bien à ouvrir des images sans les chargées en mémoire. Par contre dès qu'il s'agit d'écrire, j'obtiens un "memory heap exception", ce qui me fait dire qu'il faut que l'image soit en totalité en mémoire pour qu'elle soit sauvée.

Il existe peut être d'autre librairies qui permettent de faire ça (JIMI ??), ou bien j'ai peut être déjà les bonnes lib mais pas le bon code. Merci d'avance pour vos réponses / informations.