Gambas France BETA


Pas de compte ? Incription

Vider la RAM

Ce sujet est résolu.

12
AuteurMessages
spheris#16 Posté le 21/11/2018 à 20:11:26
Flachy,
doucement nos cerveaux lents ont du mal à suivre.
Lancer un logiciel pour exécuter un script php au travers d'un programme interprété par gambas qui lui même est codé en C, bonjour l'optimisation ;-).
Enfin, si tu dis que 500mo sont lus en 1,5sec, ce n'est pas un ordi que tu as, c'est un gros cluster de provider ;-).

Foromus,
Je traduis la solution de flachyjoe pour nos cerveaux fatigués:
La solution de flachy consiste à installer un logiciel nommé imagemagick puis de lancer un script en php en mode console qui fera intervenir ce logiciel imagemagick afin d'identifier les images dans le répertoire de ton choix, que tu auras défini avec la commande linux classique:
cd xxxx

concernant le fait de ne pas recréer une picturebox, c'est sûr que tu vas considérablement augmenter la vitesse de ton prog sans surcharger la RAM.
;)


Flachy Joe#17 Posté le 21/11/2018 à 21:36:15
Iguane : Il Gambas Uniquement pour Activer ses NEuronesC'est pas du php, c'est directement une commande linux lancée avec le mot clef SHELL de Gambas et son résultat interprété en Gambas.
Donc il n'y a "que" 3 niveaux de process
Gambas
- Bash (l'interpréteur de commande)
-- identify
Et c'est complètement transparent, tu lances ta commande avec SHELL et tu récupères les infos dans une chaîne de caractère. Il n'y a plus qu'à traiter le texte avec une regexp pour filtrer les infos nécessaires.

doc de Shell : http://gambaswiki.org/wiki/lang/shell?l=fr
doc des regexp : http://gambaswiki.org/wiki/comp/gb.pcre/regexp?l=fr

En fait l'astuce d'identify, qui fait sa vitesse, c'est de ne lire que l'entête qui contient les infos, pas les données de pixels. Donc ça fait quelques 10aines d'octets par image quelle que soit sa résolution.

EDIT :

Voila un exemple rapide sans regexp qui stock les noms de fichiers dans le tableau f et leurs dimensions dans le tableau d, attention si il y a des espaces dans les chemins ça ne fonctionne plus...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DIM test0 AS STRING
DIM test1 AS String[]
DIM t AS STRING
DIM l AS String[]
DIM f AS NEW String[], d AS NEW String[]

SHELL "identify /media/Photos/2018/2018-08/*.JPG" TO test0
'ici ça freeze jusqu'a ce que la commande soit terminée
test1 = Split(test0, gb.NewLine)
FOR EACH t IN test1
l = Split(t, " ")
IF l.Count > 0 THEN
f.Push(l[0])
d.Push(l[2])
ENDIF
NEXT
;) Flachy Joe ;)
spheris#18 Posté le 22/11/2018 à 08:26:23
Effectivement c'est carrément d'un autre niveau, merci Flachy cela fonctionne super.
Au passage j'apprends des trucs sur le code comme :

pouvoir déclarer des variables avec un DIM en les séparant avec des virgules.
Utiliser PUSH et non ADD dans une liste.
Bravo pour cette petite démonstration et merci encore
;)

Foromus, c'est bon tu as suivi?
:)
Flachy Joe#19 Posté le 22/11/2018 à 19:51:29
Iguane : Il Gambas Uniquement pour Activer ses NEuronesAprès réflexion, pour prendre en compte les espaces dans les noms de dossiers/fichiers, ce n'est pas la peine d'utiliser une regexp, il suffit de compter les champs depuis la fin de la ligne.
Les espaces dans les noms de dossiers devront être échappées avec double back-slash : "\\" pour obtenir "\" dans la chaîne Gambas donc "\\ " pour obtenir "\ " puis " " dans la chaîne interprétée par le shell. Dans les noms de fichier on s'en fiche puisque le shell s'en dépatouille avec le wildcard "*"
Donc voila une maj :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
DIM test0 AS STRING
DIM test1 AS String[]
DIM t AS STRING
DIM l AS String[]
DIM f AS NEW String[], d AS NEW String[]
DIM n AS INTEGER
DIM p AS STRING

SHELL "identify /Photos/2018/2018-08/a\\ la\\ mer/*.JPG" TO test0
TextArea1.Text = test0
test1 = Split(test0, gb.NewLine)
FOR EACH t IN test1
l = Split(t, " ")
IF l.Count > 0 THEN
f.Push(l[0])
IF l.Count > 9 THEN
'espace dans le chemin
FOR n = 1 TO l.Count - 9
f[f.count - 1] &= " " & l[n]
NEXT
ENDIF
d.Push(l[l.Count - 7])
ENDIF
NEXT
;) Flachy Joe ;)
Foromus#20 Posté le 15/1/2020 à 15:29:30
Bonjour à tous,

Et bonne année !

Donc je reviens sur un truc un peu ancien, mais qui n'a jamais été résolu.
Merci à 0livier pour le code

1
2
3
4
5
6
7
8
.......
aTabLigne = Split(ResultatCmd, "\n")

FOR EACH sLigne IN aTabLigne
PRINT "ligne: " & sLigne
' >> Traitement de chaque ligne de la commande ICI <<
NEXT
.....


En fait, ça marche mais en console, par exemple, je trouve ça (en console, donc) :

ligne: image_16.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, Exif Standard: [TIFF image data,
big-endian, direntries=4, xresolution=62, yresolution=70, resolutionunit=2], progressive, precision 8, 991x733, frames 3



Et donc, je trouve bien quelque part mes tailles, ici 991x733. Et ce sont justement ces deux valeurs que j'aimerais récupérer, mais je ne sais pas comment faire. J'ai essayé plusieurs combinaisons, soit je me suis fait balancer, soit il ne s'est rien passé...
Donc, je sèche toujours...
Flachy Joe#21 Posté le 16/1/2020 à 21:10:07
Iguane : Il Gambas Uniquement pour Activer ses NEuronesForomus : tu ne vois pas mes messages ou tu ne veux pas tester les codes qu'ils contiennent ?
Tu as une solution pour obtenir le texte "991x733" juste au dessus : http://www.gambasforge.org/sujet-4953-vider-la-ram--page-2.html#m19
Et une solution pour obtenir 991 dans la variable Largeur et 733 dans la variable Hauteur dans ce post : http://www.gambasforge.org/sujet-4996-cest-ouvert-page-1.html#m9

NB : si c'est l'utilisation de la commande identify qui te pose problème, sache que le paquet ImageMagick fait de moins de 1Mo et est dispo dans toutes les distrib. ( sudo apt-get install imagemagick )
;) Flachy Joe ;)
Foromus#22 Posté le 17/1/2020 à 12:34:50
Foromus : tu ne vois pas mes messages ou tu ne veux pas tester les codes qu'ils contiennent ?


Bonjour,

Ah diable de moi !
Si si, je lis toujours les messages, surtout quand j'ai besoin d'une réponse (mais même sans besoin).
Pour le paquet ImageMagick, je pense qu'il doit y être car c'était installé avec l'imprimante (je me demandas du reste à quoi ça pouvait bien servir).
Je suis passé sur les deux liens, honnêtement, je ne me souviens pas de les avoir vus, je n'ai pas du regarder au bon endroit.
Bon, j'essaie de voir ça, donc, et si je comprends bien, je commence par vérifier la présence du paquet, et si absent, je l'installe, Synaptic fera l'affaire je pense, dans les deux cas, non ?
Après, le code (vu rapidement) devrait faire l'affaire lui aussi.
Désolé pour mon incompréhension !
linuxos#23 Posté le 18/1/2020 à 16:16:14
Un peu de sel, de poivre et la crevette sera... Bonjour Foromus,

Je n’étais pas passé sur la Forge depuis un petit bout et je constate que tu te bats toujours avec ton projet.
Je ne pense pas qu'il y ait besoin d'aller chercher une commande exterieure a Gambas pour identifier tes fichiers image.
Bien évidement certaines commandes Linux, écris en C et optimisées pour ce travaille seront plus rapide que nous, Gambasiens en train de re-inventer la roue (moi y compris aussi)

Donc au final, si le cœur t'en dit, il te restera a choisir si tu veux que ce soit écrit en Gambas ou a l'aide de commande Unix/Linux.

En ce qui concerne le remplissage de mémoire, voici un peu d'explication de comment est gérée (rapidement) la suppression des Objets (Form, Picture, etc...) dans Gambas.

En gros le fait de faire:
Dim MonImage = New Picture

ou
Public MonImage = New Picture


=> va chercher un peu de mémoire libre pour pouvoir créer un nouvel objet de type Picture et récupérer le Pointer (l'adresse mémoire) de ce nouvel Objet.
Donc au final la variable MonImage va contenir l'adresse mémoire de ce nouvel Objet.
Si par la suite, dans ton programme, tu re-execute 'MonImage = New Picture', alors une nouvelle adresse mémoire est recherchée pour créer un nouvel Objet et ta variable MonImage pointera sur cette nouvelle adresse mémoire.
Pour faire le nettoyage, Gambas intègre un mécanisme qui nettoie les Objets qui ne sont plus utilisés (que l'on peut assimilé a un 'Garbage collector'). Pour cela chaque objet a un compteur de références, c'est a dire que chaque fois qu'une variable ou autre fait référence a cet Objet, le compteur va augmenter et dès qu'une référence est libérée, le compteur du dit Objet diminue.

Pour exemple, si je me trompe pas, si tu crées une nouvelle image avec: Dim MonImage = new Picture,
alors ton objet est crée et son numéro de compteur passe a 1
Si apres cela tu fait: MonImage = Null, alors l'objet devient NUL et sont compteur passe a 0, et Gambas pourra libérer la mémoire.

Donc, je te propose de tester d'ajouter simplement dans ton code, avant de re-créer une nouvelle Picture, ceci:

picImage.Picture = NULL

Nous verrons si cela change quelque chose.

Nota: je constate d’après ton code que tu utilises une PictureBox dans un Formulaire et que tu manipules son .Picture dans ton code. Il y peut etre une raison a cela mais dans ton cas il me semble plus facile de charger l'image dans une variable Picture comme ceci:

Dim picMonImage As Picture

picMonImage.Load("/mon/chemin/vers/images.jpg")

Print "Image Largeur: " & picMonImage.Width, "Hauteur: " & picMonImage.Height

picMonImage = Null


Je te laisse adapter ce code a tes besoins, mais je pense que cela devrait faire l'affaire pour ton projet.

Olivier

Lorsqu'on s'occupe d'informatique, il faut faire comme les canards... Paraître calme en surface et pédaler comme un forcené par en dessous.
Foromus#24 Posté le 19/1/2020 à 10:40:39
Bonjour,

Merci beaucoup pour toutes ces précisions.
A vrai dire, je n'ai pas obtenu le résultat souhaité.
Dans un premier temps, j'ai simplement rajouté la ligne
1
picMonImage = NULL

qui a paru, sur le moment, efficace. J'ai testé un bloc de 60 ou 80 images (me souviens plus exactement), et ce, dix fois de suite : pas de saturation de la Ram !
Après, je suis passé sur du plus concret : un répertoire de 600 images. Et là, saturation, comme avant (j'ai un indicateur de l'activité cpu et ram dans le tableau de bord). Donc d'un côté, 60 x 10, ça va, 600, ça ne va plus... Il est vrai que dans le premier cas, ce sont 10 fois les mêmes : y aurait-il un problème de cache ?
Soit. J'ai donc tenté le
1
2
3
4
DIM picMonImage AS Picture
picMonImage.Load("/mon/chemin/vers/images.jpg")
PRINT "Image Largeur: " & picMonImage.Width, "Hauteur: " & picMonImage.Height
picMonImage = NULL

Sur le coup, ça m'a bien plu. En fonctionnement, ça a calé avec l'erreur : Référence d'objet NULL (ligne 2)
Et quand je tape le code, l'offre de remplissage auto me propose
1
picMonImage.Load(Path AS STRING) AS Picture

Evidemment, j'ai rajouté le As Picture, mais il est refusé !
Et pourtant, dans ma variable, le chemin est parfaitement renseigné.
Pour le moment, cette deuxième solution ne tourne pas. Et j'en suis sincèrement désolé.
J'ai toujours la ressource d'arrêter le programme en fin de contrôle d'un répertoire, puis de le relancer pour le répertoire suivant, mais c'est quand même un peu chiant...
Voilà pour les derniers essais !
linuxos#25 Posté le 19/1/2020 à 18:02:06
Un peu de sel, de poivre et la crevette sera... Bonjour Foromus,

En effet il y a une petite erreur dans mon code, il faut ecrire plutot ceci:

1
DIM picMonImage AS NEW Picture


De plus il semblerait que l'Objet Picture se garde un genre de 'cache mémoire' interne qu'il est possible de 'flusher' comme suit:

1
picMonImage.Flush()


Je ne sais pas si ça aidera mais c'est a essayer.

De mon coté j'ai fait un petit projet pour résoudre ton problème. J'ai essayer de 2 manières différentes.
La 1ère en pur Gambas, en chargeant toutes les images d'un répertoire, une par une, mais c'est très long car il faut charger dans la mémoire toute l'image a chaque fois. Hors toutes les informations d'une image se trouve au début du fichier image, donc la lecture de quelques octets est suffisant pour avoir les infos de l'image.

Donc pour cela j'ai essayé la commande 'file' (standard Unix/Linux), qui fonctionne trop bien au final. Cela veut dire qu'il y a trop d'informations, comme la géolocalisation, la focale,etc... et les champs varies trop souvent. En bref c'est une galère a analyser.

Je me suis donc tourné vers la commande 'identify', qui doit venir avec le package de ImageMagic', et qui le même travaille comme tu le souhaites.
Je peux aisément filtrer les fichier a analyser par leur extension (Ex: identify /home/MonUser/Images/*.{jpg,png}), et récupérer les infos de taille que tu souhaites.

Le projet est disponible mais je ne sais pas comment te le transmettre.
Dis moi comment veux tu procéder.

Je peux simplement le déposer sur la 'Logithèque' de Gambas pour que tout le monde en profite, et surtout tous ceux qui ont participé a répondre a ce sujet.

A toi de me dire.

Olivier

Lorsqu'on s'occupe d'informatique, il faut faire comme les canards... Paraître calme en surface et pédaler comme un forcené par en dessous.
Flachy Joe#26 Posté le 19/1/2020 à 22:00:32
Iguane : Il Gambas Uniquement pour Activer ses NEuronesOn pourrais aller lire directement en binaire la dimension de l'image dans le fichier (sans la charger du coup) avec Open, Read etc mais si les dimensions se trouve dans l'entête pour les bitmap, gif et autre png, ce n'est pas le cas des jpeg ce qui complique un peu la chose (cf https://stackoverflow.com/questions/18264357/how-to-get-the-width-height-of-jpeg-file-without-using-library ).

;) Flachy Joe ;)
Foromus#27 Posté le 20/1/2020 à 11:52:04
Bonjour à tous,

Et donc, j'ai fait les modif - ou croyant les avoirs faites, ou je ne sais pas, bref, j'ai merdoyé pas mal, tant et si bien que rien ne fonctionne !
Mon projet avait dessein de me donner la taille d'une image, largeur et hauteur, en pixels, vu que c'est l'unité principalement usitée chez Gimp. Et puis, je suis habitué avec. En plus, j'avais l'idée d'afficher une vignette (ou pas d'où la variable binaire a dans mon code, et j'avais utilisé une image cachée où il me suffisait de prendre la cote car la fenêtre s'ajustait à la cote de l'image, avec la fonction "Strech". Et ça marchait bien, sauf le problème de mémoire qui ne se vide pas, et qui m'est tombé dessus, sans que je m'en aperçoive !
Il me semble devoir prendre une autre direction. Je laisse tout ce que j'ai fait de côté, et repars sur l'idée de voir déjà une méthode de récupération desdites cotes, sachant que mes fichiers sont tous de type.jpg.
Vous m'avez fourni plusieurs pistes, c'est fort aimable à vous, je n'ai pas tout testé, les dernières me semblaient plus accessibles et plus compréhensibles, j'ai donc commencé par là, après, et quand ça ne suffit pas, on passe à autre chose.
Voilà pour le point !

Edit : Il y a des centaines d'applications qui font, peu ou prou, ce genre de chose, comme Ristretto sous xubuntu, je ne parle pas de gThumb, beaucoup plus élaboré. Et tout ça sans saturer la RAM. Il m'étonnerait quand même que cela pose de gros problèmes en Gambas, non ?..
Mais mon projet, c'est d'abord et avant tout plus pour le plaisir de faire, ce n'est pas une question vitale qui entraînera un bouleversement mondial...
Flachy Joe#28 Posté le 20/1/2020 à 22:02:20
Iguane : Il Gambas Uniquement pour Activer ses NEuronesLe problème de charger l'image dans Gambas c'est que ça lit la totalité du fichier (déjà mentionné) mais aussi que ça décompresse l'image pour charger tous les pixels.

J'ai donc bossé un code qui récupère les dimensions directement dans un fichier JPEG. Le fichier est parcouru jusqu'au bout mais avec des sauts à travers les blocs de données dont on sait qu'ils ne contiennent pas les infos de dimensions.
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
'Lit un entier non signé sur 2 octets (il n'y a que Byte qui ne soit pas signé en Gambas)
FUNCTION Read_uShort(hFile AS Stream, OPTIONAL BigEndian AS BOOLEAN = TRUE) AS LONG
DIM b0 AS BYTE, b1 AS BYTE
b0 = READ #hFile AS BYTE
b1 = READ #hFile AS BYTE
IF BigEndian THEN
RETURN b0 * 256 + b1
ELSE
RETURN b1 * 256 + b0
ENDIF
END

SUB List_JPEG_sizes(path AS STRING)
DIM Filename AS STRING
DIM hFile AS Stream
DIM soi_marker AS SHORT, marker AS SHORT
DIM cluster_size AS LONG
DIM width AS LONG, height AS LONG

FOR EACH Filename IN Dir(path, "*.jpg")
hFile = OPEN path &/ Filename FOR READ
hFile.ByteOrder = gb.BigEndian
soi_marker = READ #hFile AS SHORT
IF soi_marker = &hffd8 THEN 'vérifie le marqueur initial
DO
marker = READ #hFile AS SHORT
IF marker AND &hff00 = &hff00 THEN 'verif que c'est un marqueur JPEG = &hff##
cluster_size = Read_uShort(hFile) 'juste après le marqueur il y a la taille du bloc sur 2 octets
IF marker = &hffc2 OR marker = &hffc0 THEN 'si c'est un marqueur de frame
SEEK #hFile, Seek(hFile) + 1 'on passe l'octet suivant (bitperpixel)
width = Read_uShort(hFile) 'on récupère les valeurs qui nous interesse
height = Read_uShort(hFile)
SEEK #hFile, Seek(hFile) - 4 'on revient en arrière pour que le saut suivant arrive au bon endroit
ENDIF
SEEK #hFile, Seek(hFile) + cluster_size - 2 ' on saute à la fin du bloc
ENDIF
LOOP UNTIL Eof(hFile) 'on boucle jusqu'à la fin du fichier car il peut y avoir plusieurs frames (miniature ?)
PRINT Filename, width, height
ELSE
PRINT Filename, "is not a valid JPEG" 'le marqueur initial n'est pas bon
ENDIF
CLOSE #hFile
NEXT

END


NB : j'ai testé avec 150 photos 4309x2868, ça va sensiblement aussi vite que la commande identify...
;) Flachy Joe ;)
linuxos#29 Posté le 21/1/2020 à 16:29:52
Un peu de sel, de poivre et la crevette sera... Flachy Joe,

Joli boulot. Chapeau

Olivier
Lorsqu'on s'occupe d'informatique, il faut faire comme les canards... Paraître calme en surface et pédaler comme un forcené par en dessous.
Foromus#30 Posté le 25/1/2020 à 12:59:24
Bonjour à tous,

Tout d'abord, je voudrais adresser mes plus sincères et chaleureux remerciements à tous ceux qui m'ont aidé et qui m'ont sorti de situation délicates.
Je considère que maintenant, il me faut vraiment prendre du recul, il faut savoir faire le point et en tirer les conséquences.
Naturellement, j'ai admiré le code de Flachy Joe, et j'en reste ébahi. D'un autre côté, où est l'intérêt de prendre bêtement un code que l'on ne maîtrise pas ?..
J'ai contourné mon problème : puisque, seule la commande Quit est apte à vider la mémoire, je l'ai utilisée, je sais, ce n'est pas très glorieux, mais ça fonctionne ave 5 lignes de code supplémentaires et un clic de plus à l'utilisation. Et donc, je l'utiliserai comme telle.
Quand j'ai commencé à coder il y a quarante ans sur mon ZX 80 (1 k de RAM), fallait tout faire, même chose avec l'apple II C. Quand je suis passé au PC et Win$, j'ai trouvé un réel bonheur avec la programmation en Visual Basic, il est vrai que j'ai eu la chance de trouver un pavé de 824 pages, écrites par un professionnel doublé d'un vrai pédagooque, bref, le cas qui ne se trouve pas sous la pas d'un cheval.
Ma migration sous linux m'a désespéré de perdre VB, aussi, ai-je été heureux de découvrir Gambas, mais j'ai du très vite déchanter, tant les problèmes surgissaient les uns à la suite des autres. Je redoute le pire quand juin m'apportera la nouvelle mise à niveau de xubuntu, probable que, là encore, plus rien ne fonctionnera sous la nouvelle mouture. Et si encore on pouvait trouver les anciennes versions de Gambas, celles qui tournent...
Dès maintenant je vais me contenter de tenter de faire tourner ce qui a été conçu, hors de question de me lancer dans de nouvelles aventures ! Je vais me remettre au C++, non pas que je prétende devenir un codeur chevronné, mon approche est purement culturelle, jusqu'alors, je n'a fait que des petits trucs en console, et je n'ai même pas la prétention ni dessein d'en arriver au graphisme, ce serait trop de choses à apprendre à un âge où la mémoire n'est plus ce qu'elle était... Mais des fois, je me demande si le C ne serait pas plus simple que le Gambas... Au fond, le Gambas n'a plus grand chose de commun avec le Basic d'antan, il a été revu et corrigé par la montée en puissance du matériel et on sent une influence marquée de Pascal ou de C, mais je ne sais pas vraiment définir, normal, vu mon niveau.

Encore un grand merci à tous, et ma foi, longue vie à Gambas...
12