Zoomer une image sans consommer de mémoire

Le
ChP
Bonjour à toutes et à tous,

Dans l'environnement Windows (je ne sais pas sous Linux et autres), des
logiciels permettent de charger des images et de les visualiser à
différents taux de zoom. La plupart de ces logiciels prennent un
quantité de mémoire égale au nombre de pixels de l'image multiplié par
le nombre d'octets par pixel. Il n'en prennent pas plus même si on
visualise ces images avec un taux de zoom supérieur à 100 %. La
visualisation se faisant aisément par scrolling.

En Java, je n'ai pas trouvé de classe ou de méthode permettant d'en
faire autant. Les méthodes que j'ai trouvées consomment de la mémoire à
hauteur du taux de zoom. Par exemple, pour une image de 8 Mpixels à 3
octets par pixel, la mémoire nécessaire à son chargement est 8 x 3 = 24
Mo. Si je fais un zoom x4 linéaire, la mémoire consommée est alors 24 x
4 x 4 = 384 Mo !!!

J'ai bien essayé la forme suivante :

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int
sy1, int sx2, int sy2, ImageObserver observer)

en la plaçant dans un écouteur des mouvements des ascenseurs du
JScrollPane. J'ai obtenu des quantités de trucs bizarres, mais rien de
cohérent. Je ne m'en sort pas.

Je pense que j'ai dû rater quelque chose. En bref, existe-t-il en Java
des classes ou méthodes permettant d'y arriver.

Si vous avez des exemples.

Merci de votre aide.

Pierre.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
TestMan
Le #228625
Bonjour à toutes et à tous,

Dans l'environnement Windows (je ne sais pas sous Linux et autres), des
logiciels permettent de charger des images et de les visualiser à
différents taux de zoom. La plupart de ces logiciels prennent un
quantité de mémoire égale au nombre de pixels de l'image multiplié par
le nombre d'octets par pixel. Il n'en prennent pas plus même si on
visualise ces images avec un taux de zoom supérieur à 100 %. La
visualisation se faisant aisément par scrolling.

En Java, je n'ai pas trouvé de classe ou de méthode permettant d'en
faire autant. Les méthodes que j'ai trouvées consomment de la mémoire à
hauteur du taux de zoom. Par exemple, pour une image de 8 Mpixels à 3
octets par pixel, la mémoire nécessaire à son chargement est 8 x 3 = 24
Mo. Si je fais un zoom x4 linéaire, la mémoire consommée est alors 24 x
4 x 4 = 384 Mo !!!

J'ai bien essayé la forme suivante :

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int
sy1, int sx2, int sy2, ImageObserver observer)

en la plaçant dans un écouteur des mouvements des ascenseurs du
JScrollPane. J'ai obtenu des quantités de trucs bizarres, mais rien de
cohérent. Je ne m'en sort pas.

Je pense que j'ai dû rater quelque chose. En bref, existe-t-il en Java
des classes ou méthodes permettant d'y arriver.

Si vous avez des exemples.

Merci de votre aide.

Pierre.


Bonjour,

Version longue :

Je suis pas sûr d'avoir tout saisit ...

1- Comment tu charges ton Image ?
2- Qu'est-ce que tu veux faire ? L'afficher avec mise à l'échelle (avec
respect du ratio / ou non) ? Afficher une zone scrollable de l'image (et
ainsi permettre de la parcourir quelque soit les dimensions de l'image ?
Autre chose ?

Pour info, Java permet de controler trés finement le mode de stockage du
raster celà permet par exemple de jouer (cf. point 1).

Pour ce qui est du zoom, il faut bien comprendre quel sont les
opérations que l'on va demander au pipeline 2D (et donc les éventuels
calculs intermédiaires nécessaires si la plateforme ne le supporte pas
en natif). Par exemple, lorsqu'on affiche une image à une taille
différente du raster, selon la méthode choisie, les performances sont
trés différentes.

Version courte :

http://weblogs.java.net/blog/gfx/archive/2005/09/zoom_pictures_w.html

Bonne lecture ... et si ce n'est pas suffisant, répond à la version
longue ;)

A+
TM

ChP
Le #228623
Bonjour à toutes et à tous,

Dans l'environnement Windows (je ne sais pas sous Linux et autres),
des logiciels permettent de charger des images et de les visualiser à
différents taux de zoom. La plupart de ces logiciels prennent un
quantité de mémoire égale au nombre de pixels de l'image multiplié par
le nombre d'octets par pixel. Il n'en prennent pas plus même si on
visualise ces images avec un taux de zoom supérieur à 100 %. La
visualisation se faisant aisément par scrolling.

En Java, je n'ai pas trouvé de classe ou de méthode permettant d'en
faire autant. Les méthodes que j'ai trouvées consomment de la mémoire
à hauteur du taux de zoom. Par exemple, pour une image de 8 Mpixels à
3 octets par pixel, la mémoire nécessaire à son chargement est 8 x 3 =
24 Mo. Si je fais un zoom x4 linéaire, la mémoire consommée est alors
24 x 4 x 4 = 384 Mo !!!

J'ai bien essayé la forme suivante :

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int
sy1, int sx2, int sy2, ImageObserver observer)

en la plaçant dans un écouteur des mouvements des ascenseurs du
JScrollPane. J'ai obtenu des quantités de trucs bizarres, mais rien de
cohérent. Je ne m'en sort pas.

Je pense que j'ai dû rater quelque chose. En bref, existe-t-il en Java
des classes ou méthodes permettant d'y arriver.

Si vous avez des exemples.

Merci de votre aide.

Pierre.


Bonjour,

Version longue :

...


Version courte :

http://weblogs.java.net/blog/gfx/archive/2005/09/zoom_pictures_w.html

Bonne lecture ... et si ce n'est pas suffisant, répond à la version
longue ;)


Merci "TestMan", cela correspond à ce que je souhaite faire. Je vais
donc lire attentivement cette version.

Cordialement.

Pierre


Michel
Le #228584
"ChP" :

En Java, je n'ai pas trouvé de classe ou de méthode permettant d'en faire autant. Les méthodes que
j'ai trouvées consomment de la mémoire à hauteur du taux de zoom. Par exemple, pour une image de 8
Mpixels à 3 octets par pixel, la mémoire nécessaire à son chargement est 8 x 3 = 24 Mo. Si je fais
un zoom x4 linéaire, la mémoire consommée est alors 24 x 4 x 4 = 384 Mo !!!


J'utilise encore souvent la classe MemoryImageSource, qui permet de
manipuler directement les pixels dans un array de int (pratique pour les
applets : elle existe dans toutes les versions de java, même les plus
anciennes). Pour permettre des rafraichissements de l'image, mettre
setAnimated(true). Puis tu mets ce que tu veux dans ce tableau, et
quand ton image à afficher est prête, tu l'envoie à l'écran via la méthode
newPixels(). Le rendu lui-même est rapide (le reste dépend des
algorithmes que tu utilises pour générer ton tableau de pixels).

Pour ton problème, tu peux par exemple extraire le tableau de
pixels de ton image originale, créer un autre tableau de pixels de
la taille de l'image à afficher, et, selon ce que fait ton programme,
transférer les pixels d'un tableau à l'autre ou peindre sur ton
tableau-cible. Tu ne boufferas alors pas plus de mémoire que
celle occupée par ces deux tableaux, quelle que soit la taille de
ton image-source et de ton image-cible.

Pour un zoom, tu peux alors choisir l'algorithme qui te convient
le mieux : simple (copie du pixel courant sur plusieurs lignes et
colonnes), interpolation linéaire (tu génères des gradients de couleurs
sur les pixels-cible, en fonction de la valeur des pixels-source),
ou tu peux même t'offrir un zoom fractal qui bluffera tout le monde,
en générant les pixels manquants via une fonction gaussienne
(si l'image visible n'est pas trop grande : ça bouffe du CPU !).

J'ai bien essayé la forme suivante :

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
ImageObserver observer)

en la plaçant dans un écouteur des mouvements des ascenseurs du JScrollPane. J'ai obtenu des
quantités de trucs bizarres, mais rien de cohérent. Je ne m'en sort pas.


Tu peux fabriquer un "faux" scrollpane : tu mets ton composant
qui affiche l'image-cible au centre, et tu l'entoures de 2 (ou 4)
scrollbar. Dans le composant central, tu crées une variable
proportion. En fonction de la puissance de zoom du moment et
des dimensions de ton image-source, tu fais varier cette
variable. Et un listener sur tes scrollbars envoie un % de
déplacement vers la droite et vers le bas. Tu as alors tout
pour savoir par quel pixel commencer le transfert du
tableau-souce au tableau-cible.

Michel

ChP
Le #228581
"ChP" :

En Java, je n'ai pas trouvé de classe ou de méthode permettant d'en faire autant. Les méthodes que
j'ai trouvées consomment de la mémoire à hauteur du taux de zoom. Par exemple, pour une image de 8
Mpixels à 3 octets par pixel, la mémoire nécessaire à son chargement est 8 x 3 = 24 Mo. Si je fais
un zoom x4 linéaire, la mémoire consommée est alors 24 x 4 x 4 = 384 Mo !!!


J'utilise encore souvent la classe MemoryImageSource, qui permet de
manipuler directement les pixels dans un array de int (pratique pour les
applets : elle existe dans toutes les versions de java, même les plus
anciennes). Pour permettre des rafraichissements de l'image, mettre
setAnimated(true). Puis tu mets ce que tu veux dans ce tableau, et
quand ton image à afficher est prête, tu l'envoie à l'écran via la méthode
newPixels(). Le rendu lui-même est rapide (le reste dépend des
algorithmes que tu utilises pour générer ton tableau de pixels).

Pour ton problème, tu peux par exemple extraire le tableau de
pixels de ton image originale, créer un autre tableau de pixels de
la taille de l'image à afficher, et, selon ce que fait ton programme,
transférer les pixels d'un tableau à l'autre ou peindre sur ton
tableau-cible. Tu ne boufferas alors pas plus de mémoire que
celle occupée par ces deux tableaux, quelle que soit la taille de
ton image-source et de ton image-cible.

Pour un zoom, tu peux alors choisir l'algorithme qui te convient
le mieux : simple (copie du pixel courant sur plusieurs lignes et
colonnes), interpolation linéaire (tu génères des gradients de couleurs
sur les pixels-cible, en fonction de la valeur des pixels-source),
ou tu peux même t'offrir un zoom fractal qui bluffera tout le monde,
en générant les pixels manquants via une fonction gaussienne
(si l'image visible n'est pas trop grande : ça bouffe du CPU !).

J'ai bien essayé la forme suivante :

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
ImageObserver observer)

en la plaçant dans un écouteur des mouvements des ascenseurs du JScrollPane. J'ai obtenu des
quantités de trucs bizarres, mais rien de cohérent. Je ne m'en sort pas.


Tu peux fabriquer un "faux" scrollpane : tu mets ton composant
qui affiche l'image-cible au centre, et tu l'entoures de 2 (ou 4)
scrollbar. Dans le composant central, tu crées une variable
proportion. En fonction de la puissance de zoom du moment et
des dimensions de ton image-source, tu fais varier cette
variable. Et un listener sur tes scrollbars envoie un % de
déplacement vers la droite et vers le bas. Tu as alors tout
pour savoir par quel pixel commencer le transfert du
tableau-souce au tableau-cible.

Michel


Le but de mon programme étant de faire du traiteùent d'image, les

solutions que tu me proposes vont dans le bon sens.

Je t'en remercie et je vais étudier ça de plus près.

Cordialement.

Pierre.


Xavier Tarrago
Le #228575
Je ne comprends pas bien le problème. Il est clair que pour bénéficier de la
gestion automatique des scrollbars, il faut une image de la taille réelle x
facteur de zoom. En revanche, avec la gestion manuelle des scrollbars, il
suffit d'afficher l'image réelle dans la zone visible en controllant le zoom
avec les paramètres de la méthode drawImage (par exemple AffineTransform).
L'interpolation est controlée par les rendering hints (cf classe
RenderingHints) du Graphic2D.

En clair, on stocke l'image avec sa résolution d'origine, et en paint
dynamiquement la zone sélectionnée par l'état zoom/scrollbars dans la
fenêtre désirée. En plus, si swing est assez intelligent, le zoom est
accéléré matériellement et la performance devrait être bonne (mais bon, je
ne parierais pas là-dessus^^).

"ChP" 4663dd43$0$2132$
"ChP" :

En Java, je n'ai pas trouvé de classe ou de méthode permettant d'en
faire autant. Les méthodes que j'ai trouvées consomment de la mémoire à
hauteur du taux de zoom. Par exemple, pour une image de 8 Mpixels à 3
octets par pixel, la mémoire nécessaire à son chargement est 8 x 3 = 24
Mo. Si je fais un zoom x4 linéaire, la mémoire consommée est alors 24 x
4 x 4 = 384 Mo !!!


J'utilise encore souvent la classe MemoryImageSource, qui permet de
manipuler directement les pixels dans un array de int (pratique pour les
applets : elle existe dans toutes les versions de java, même les plus
anciennes). Pour permettre des rafraichissements de l'image, mettre
setAnimated(true). Puis tu mets ce que tu veux dans ce tableau, et
quand ton image à afficher est prête, tu l'envoie à l'écran via la
méthode
newPixels(). Le rendu lui-même est rapide (le reste dépend des
algorithmes que tu utilises pour générer ton tableau de pixels).

Pour ton problème, tu peux par exemple extraire le tableau de
pixels de ton image originale, créer un autre tableau de pixels de
la taille de l'image à afficher, et, selon ce que fait ton programme,
transférer les pixels d'un tableau à l'autre ou peindre sur ton
tableau-cible. Tu ne boufferas alors pas plus de mémoire que
celle occupée par ces deux tableaux, quelle que soit la taille de
ton image-source et de ton image-cible.

Pour un zoom, tu peux alors choisir l'algorithme qui te convient
le mieux : simple (copie du pixel courant sur plusieurs lignes et
colonnes), interpolation linéaire (tu génères des gradients de couleurs
sur les pixels-cible, en fonction de la valeur des pixels-source),
ou tu peux même t'offrir un zoom fractal qui bluffera tout le monde,
en générant les pixels manquants via une fonction gaussienne
(si l'image visible n'est pas trop grande : ça bouffe du CPU !).

J'ai bien essayé la forme suivante :

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int
sy1, int sx2, int sy2, ImageObserver observer)

en la plaçant dans un écouteur des mouvements des ascenseurs du
JScrollPane. J'ai obtenu des quantités de trucs bizarres, mais rien de
cohérent. Je ne m'en sort pas.


Tu peux fabriquer un "faux" scrollpane : tu mets ton composant
qui affiche l'image-cible au centre, et tu l'entoures de 2 (ou 4)
scrollbar. Dans le composant central, tu crées une variable
proportion. En fonction de la puissance de zoom du moment et
des dimensions de ton image-source, tu fais varier cette
variable. Et un listener sur tes scrollbars envoie un % de
déplacement vers la droite et vers le bas. Tu as alors tout
pour savoir par quel pixel commencer le transfert du
tableau-souce au tableau-cible.

Michel


Le but de mon programme étant de faire du traiteùent d'image, les

solutions que tu me proposes vont dans le bon sens.

Je t'en remercie et je vais étudier ça de plus près.

Cordialement.

Pierre.




ChP
Le #228534
Je ne comprends pas bien le problème. Il est clair que pour bénéficier de la
gestion automatique des scrollbars, il faut une image de la taille réelle x
facteur de zoom. En revanche, avec la gestion manuelle des scrollbars, il
suffit d'afficher l'image réelle dans la zone visible en controllant le zoom
avec les paramètres de la méthode drawImage (par exemple AffineTransform).
L'interpolation est controlée par les rendering hints (cf classe
RenderingHints) du Graphic2D.

En clair, on stocke l'image avec sa résolution d'origine, et en paint
dynamiquement la zone sélectionnée par l'état zoom/scrollbars dans la
fenêtre désirée. En plus, si swing est assez intelligent, le zoom est
accéléré matériellement et la performance devrait être bonne (mais bon, je
ne parierais pas là-dessus^^).

Apparemment, il est possible de bénéficier de la gestion automatique des

scrollbars, sans pour autant consommer de la mémoire. Voir le lien suivant :

http://www.developpez.net/forums/showthread.php?t46904

Je l'ai mis en oeuvre, ainsi que la classe "ZoomableImagePanel" : c'est
tout bon.

Maintenant, mon problème est de dessiner sur une image zoomée un
rectangle de sélection (pour définir une partie de l'image sur laquelle
je veux travailler par exemple) qui, si sa taille devra refléter le taux
de zoom modifié, l'épaisseur de son trait ne devra pas varier.

Cordialement.

Pierre

Publicité
Poster une réponse
Anonyme