Chargement d'une image

Résolu
cs_mathmax
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008
- 9 avril 2007 à 00:15
cs_mathmax
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008
- 10 avril 2007 à 16:50
Bonjour,

J'aimerais savoir si il existe un moyen plus performant pour créer un rendu image miniature à partir d'un fichier image. Voici la techique que j'utilise actuellement :

Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(delegate {return false;});
pictureBox1.Image = Image.FromFile(img.FullName).GetThumbnailImage(80, 80, myCallback, IntPtr.Zero);

Merci d'avance pour vos conseils.

Mathmax

26 réponses

Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
9 avril 2007 à 22:51
Tu m'etonnes Bidou ^^

Des flags pas des tags.. Le type UINT du C++ c'est aussi uint en C# ( System.Uint32 ) même si dans 90% des exemples tu verras des System.Int32 pour être CLS Compliant mais ça peut jouer des tours.

LR_DEFAULTSIZE et compagnie sont effectivement des constantes de type INT. Tu trouveras leurs définition dans winuser.h et d'autres dans wingdi.h.

Pour P/Invoke la référence c'est www.pinvoke.net.

Et pourquoi il fait 2km de largeur ce thread !!
3
Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
10 avril 2007 à 16:22
la définition de GdipLoadImageFromFile se trouve dans GdiPLusFlat.h et elle renvoie un GpStatus. GpStatus se trouve dans GdiPlusTypes.h et c'est l'enum que j'ai écris plus haut. en C/C++ les enums sont des int.

Là ou l'astuce est bien pensé c'est qu'il utilise la réflexion pour appeller un constructeur internal de la classe Bitmap.
3
Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
9 avril 2007 à 00:35
Salut, ça par exemple.. ou DrawImage.

Bitmap thumb = new Bitmap( bmp, new Size( 80, 80 ) );
0
Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
9 avril 2007 à 00:49
Pour la meilleur qualité possible :

Bitmap bmp = new Bitmap( "c:\\test.jpg" );
Bitmap thumb = new Bitmap( 80, 80, PixelFormat.Format24bppRgb );


using ( Graphics g = Graphics.FromImage( thumb ) )
{
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.DrawImage( bmp, new Rectangle( 0, 0, 80, 80 ) );
}
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_mathmax
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

9 avril 2007 à 03:11
Merci.
En fait je ne cherche pas la qualité. Je cherche à générer un aperçu d'une image le plus rapidement possible. Ce que tu m'as donné est optimal en terme de rapidité ?

Mathmax
0
Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
9 avril 2007 à 04:14
HighQualityBicubic est le mode le plus lent car c'est celui de meilleure qualité, le mode Defaut ou Low sont surement plus rapide. A part ça je pense que c'est la solution 100% .NET la plus rapide.. après travailler avec l'objet Graphics ça ne sera jamais aussi rapide que de passer directement par GDI via l'interop ( P/Invoke, DllImport tout ça.. ).
0
WishhhMaster
Messages postés
327
Date d'inscription
mardi 17 février 2004
Statut
Membre
Dernière intervention
10 avril 2010
8
9 avril 2007 à 08:44
Si c'est d'une image JPEG qu'il s'agit et que cette image a une miniature déjà incluse dans les données exif, alors tu peux récupérer cette miniature directement.  Ca va beaucoup plus vite que de créer une miniature.

Moi je fais comme ça:
<li>private Image CreateThumbnail(string filename)
</li><li> {
</li><li> Image img;
</li><li> PropertyItem p = null;
</li><li>byte[] imageBytes;
</li><li> MemoryStream stream = null; ;
</li><li>
</li><li> Stream originalstream = new FileStream(filename, FileMode.Open, FileAccess.Read);
</li><li>// Please do not remove :)</li><li>// Written by Kourosh Derakshan</li><li> img = Image.FromStream(originalstream, false, false);
</li><li>
</li><li>// Checks that the file contains a exif thumbnail</li><li>for (int k = 0; k < img.PropertyIdList.Length; k++)
</li><li>if (img.PropertyIdList[k] == THUMBNAIL_DATA)
</li><li> {
</li><li> p = img.GetPropertyItem(THUMBNAIL_DATA);
</li><li>break;
</li><li> }
</li><li>
</li><li> img.Dispose();
</li><li>
</li><li>if (p != null) // if the file contains an exif thumbnail</li><li> {
</li><li>// The image data is in the form of a byte array. Write all </li><li>// the bytes to a stream and create a new image from that stream</li><li> imageBytes = p.Value;
</li><li> stream = new MemoryStream(imageBytes.Length);
</li><li> stream.Write(imageBytes, 0, imageBytes.Length);
</li><li> img = Image.FromStream(stream);
</li><li> stream.Close();
</li><li>
</li><li> }
</li><li>else</li><li> {</li><li>
</li><li>// Ici tu met une des méthodes proposées au-dessus</li><li> // img = ....
</li><li>
</li><li> }
</li><li>
</li><li> originalstream.Close();
</li><li>
</li><li>return img;
</li><li> }
</li>

 http://www.csharpfr.com/codes/VISIONNEUSE-PHOTOS-IMAGE-VIEWER_41539.aspx
(fichier MyListView.cs)

++
0
WishhhMaster
Messages postés
327
Date d'inscription
mardi 17 février 2004
Statut
Membre
Dernière intervention
10 avril 2010
8
9 avril 2007 à 08:47
oops le formattage de mon message précédent est un peu moche.  désolé
0
cs_mathmax
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

9 avril 2007 à 11:03
Merci beaucoup pour vos réponse

après travailler avec l'objet Graphics ça ne sera jamais aussi rapide
que de passer directement par GDI via l'interop ( P/Invoke, DllImport
tout ça.. ).
Lutinore, pourrais-tu m'expliquer ce que celà veux dire, je comprends pas trop. Est-ce que quand on fait :
img = Image.FromStream(originalstream, false, false); on utilise le GDI ?

Sinon l'histoire des données exif ça m'interesse beaucoup. D'autant plus que je pourrais les ajouter à mes images, à chaque fois que celles-ci n'en possèdent pas car je réutilise les images d'une exécution de programme à une autre. Est ce possible de faire celà en .net ? Comment ?

Mathmax
0
Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
9 avril 2007 à 15:22
Tu connais l'interop, c'est à chaque fois qu'on appelle une fonction externe non managée avec l'attribut DllImport etc.. GDI+ du framework est basé sur GDI et GDI+ de Windows. En passant directement par ces fonctions on doit gagner un peu en performance.
 As tu fait des test avec la version qui utilise DrawImage sans le mode HighQualityBicubic, ça doit être déja rapide, non ??
0
cs_mathmax
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

9 avril 2007 à 18:43
En passant directement par ces fonctions on doit gagner un peu en performance.
Comment fait-on pour utiliser directement ces fonctions ? Je veux dire : dans quelle dll se trouve t-elles et quelles sont les noms de ces fonctions ?

J'ai testé DrawImage sans le mode HighQualityBicubic, mais en fait ca ne correspond pas trop à ce que je veux, car je veux au final avoir un objet Image.

Il semble cependant qu'en chargeant l'image à partir d'une stream comme le fait WishhhMaster, ça soit bien plus rapide... mais pas encore tout à fait assez à mon goût.
Si je pouvais ajouter une miniature de l'image dans les meta datas pour les utilisations future ça pourrait être pas mal. J'ai cherché un peu comment faire cela sur le web.
Ce n'est pas si évident que cela car il faut créer un PropertyItem qui n'a pas de constructeur public. J'ai trouvé cet article : http://www.pixvillage.com/blogs/devblog/category/12.aspx/rss qui explique une astuce pour contourner ce problème.
Ca consiste à attacher une image en ressource du projet et prendre sa meta data. Puis après je fais :

                PropertyItem item= ExifProperty.CreatePropertyItem(THUMBNAIL_DATA, 0, thumbBytes.Length, thumbBytes);
                img.SetPropertyItem(item);

CreatePropertyItem retourne la meta data de l'image ressource en lui changeant les propriété id, len, short et value.

Le problème est que je reçoit un message d'erreur qui dit que la propriété item est invalide. Et je comprend pas pourquoi....
Avez-vous une idée du problème, ou une autre technique pour ajouter une meta donnée à une image ?

Mathmax
0
Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
9 avril 2007 à 19:08
"dans quelle dll se trouve t-elles et quelles sont les noms de ces fonctions ?"


StretchBlt ou StretchDIBits dans GDI32.dll par exemple..



"J'ai testé DrawImage sans le mode HighQualityBicubic, mais en fait ca ne correspond pas trop à ce que je veux, car je veux au final avoir un objet Image."


Dans mon exemple DrawImage dessine dans le bitmap "thumb", cette fonction pourrait aussi dessiner dans un objet Image mais peu importe.. un Bitmap c'est une Image, suffit de faire un cast.


Image img = ( Image )thumb;
0
cs_mathmax
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

9 avril 2007 à 19:38
Je n'arrive pas à ajouter une référence à GDI32.dll. J'ai essayé de faire Add Reference puis Browse et j'ai pris le fichier dans WINDOWS\System32, mais j'obtiens un message d'erreur me disant que je ne peux pas ajouter cette dll en référence.

Sinon j'ai essayé ta technique. C'est en fait la création de l'bjet bitmap "bmp" qui prends du temps (10 secondes pour charger 130 images).

Mathmax
0
Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
9 avril 2007 à 21:13
Mais je t'ai dit que c'était des fonctions externes non managées qu'on utilise avec l'attribut DllImport, je l'ai écris noir sur blanc quand même. C'est pas des librairies en .NET, elles sont en C, faut faire de l'interop, aucune chance de les ajouter en référence dans ton projet. Mais bon je ne t'encourage pas sur cette voie puisque tu ne connais pas..
0
cs_Bidou
Messages postés
5487
Date d'inscription
dimanche 4 août 2002
Statut
Membre
Dernière intervention
20 juin 2013
59
9 avril 2007 à 21:24
Ouais, tu sais pas dans quoi tu t'engages ^^
Ceci dit, les performences de GetThumbnail ne sont pas si mauvaises il me semble...

<hr />
-Blog-
0
cs_mathmax
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

9 avril 2007 à 21:27
Excuse-moi je ne connaissais pas du tout le concept du code non managé. J'essaie de tester pour comprendre de quoi il s'agit. Je suis en train de lire ces tutoriaux :
http://nico-pyright.developpez.com/tutoriel/vc2005/interop/
http://morpheus.developpez.com/dlldotnet/
http://www.moteurprog.com/Articles/Article.php?ID_article=34

Pourquoi ne m'encourages-tu pas à creuser le sujet ? C'est si difficile que ça à mettre en pratique ?
Mathmax
0
Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
9 avril 2007 à 21:50
Si il s'agit d'utiliser une ou deux fonctions et si tu connais les différents types du C/C++, notamment les pointeurs alors non c'est pas trop compliqué. Là il se trouve que les fonctions de GDI ne sont pas parmis les plus simples et en plus elles sont dépendantes de tout un tas de structures etc..
0
cs_mathmax
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

9 avril 2007 à 22:12
Je peux te demander encore un peu d'aide ? J'ai envie de tester quand même cette histoire de fonctions du GDI. Tant pis si je me casse les dents dessus J'ai trouvé cette page (http://www.gamedev.net/reference/articles/article1251.asp) qui explique pas mal les chôse je crois.
Je pense qu'il faut que je charge mon image Bitmap avec la fonction LoadImage dont le prototype est le suivant :
HANDLE LoadImage(
HINSTANCE hinst, // handle of the instance containing the image
LPCTSTR lpszName, // name or identifier of image
UINT uType, // type of image
int cxDesired, // desired width
int cyDesired, // desired height
UINT fuLoad // load flags );

Les paramètre qui me posent problèmes sont :
UINT uType: Depending on what you want to load, this should be set to either IMAGE_BITMAP, IMAGE_CURSOR, or IMAGE_ICON.
UINT fuLoad: Like everything else we've done today, this is one or more of a series of flags which can be logically combined with the | operator. Here are the useful flags: LR_CREATEDIBSECTION, LR_DEFAULTSIZE, LR_LOADFROMFILE

Ce que je comprends pas c'est qu'on me dit par ailleurs que le type UINT c++ correspond au type System.Int32 en .net. Or ils me parlent de tags ici... y aurait-il une correspondance entre les tags proposés et des nombres int32 ? Comment par exemple spécifier le tag LR_LOADFROMFILE pour le paramètre fuLoad ?

Merci pour ton aide.

Mathmax
0
cs_Bidou
Messages postés
5487
Date d'inscription
dimanche 4 août 2002
Statut
Membre
Dernière intervention
20 juin 2013
59
9 avril 2007 à 22:29
LR_LOADFROMFILE  et compagnie sont surement des constantes de type int...
Allez Lutinore, bon courage si tu lances la dedans ^^












<hr />
-Blog-
0
Lutinore
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Membre
Dernière intervention
27 octobre 2012
42
9 avril 2007 à 23:25
Ce code prends 2 secondes en RELEASE sur mon Pentium 3Ghz pour faire 100 thumbnails en 80x80, les images sont à la base en 640x480. Ca me semble correct comme temps.


public Bitmap[ ] GetThumbnails( string[ ] paths, int width, int height )
{
    int len = paths.Length;
    Bitmap[ ] thumbnails = new Bitmap[ len ];


    for( int i = 0; i < len; i++ )
    {
        try
        {
            Bitmap bmp = new Bitmap( paths[ i ] );
            thumbnails[ i ] = new Bitmap( width, height, PixelFormat.Format24bppRgb );


            using ( Graphics g = Graphics.FromImage( thumbnails[ i ] ) )
            {
                //g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage( bmp, new Rectangle( 0, 0, width, height ) );
            }


            bmp.Dispose( );
        }
        catch
        {


        }
    }


    return thumbnails;
}
0