Chargement d'une image [Résolu]

cs_mathmax 404 Messages postés vendredi 28 octobre 2005Date d'inscription 31 août 2008 Dernière intervention - 9 avril 2007 à 00:15 - Dernière réponse : cs_mathmax 404 Messages postés vendredi 28 octobre 2005Date d'inscription 31 août 2008 Dernière intervention
- 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
Afficher la suite 

Votre réponse

26 réponses

Meilleure réponse
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 9 avril 2007 à 22:51
3
Merci
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 !!

Merci Lutinore 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 69 internautes ce mois-ci

Commenter la réponse de Lutinore
Meilleure réponse
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 10 avril 2007 à 16:22
3
Merci
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.

Merci Lutinore 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 69 internautes ce mois-ci

Commenter la réponse de Lutinore
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 9 avril 2007 à 00:35
0
Merci
Salut, ça par exemple.. ou DrawImage.

Bitmap thumb = new Bitmap( bmp, new Size( 80, 80 ) );
Commenter la réponse de Lutinore
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 9 avril 2007 à 00:49
0
Merci
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 ) );
}
Commenter la réponse de Lutinore
cs_mathmax 404 Messages postés vendredi 28 octobre 2005Date d'inscription 31 août 2008 Dernière intervention - 9 avril 2007 à 03:11
0
Merci
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
Commenter la réponse de cs_mathmax
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 9 avril 2007 à 04:14
0
Merci
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.. ).
Commenter la réponse de Lutinore
WishhhMaster 327 Messages postés mardi 17 février 2004Date d'inscription 10 avril 2010 Dernière intervention - 9 avril 2007 à 08:44
0
Merci
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)

++
Commenter la réponse de WishhhMaster
WishhhMaster 327 Messages postés mardi 17 février 2004Date d'inscription 10 avril 2010 Dernière intervention - 9 avril 2007 à 08:47
0
Merci
oops le formattage de mon message précédent est un peu moche.  désolé
Commenter la réponse de WishhhMaster
cs_mathmax 404 Messages postés vendredi 28 octobre 2005Date d'inscription 31 août 2008 Dernière intervention - 9 avril 2007 à 11:03
0
Merci
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
Commenter la réponse de cs_mathmax
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 9 avril 2007 à 15:22
0
Merci
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 ??
Commenter la réponse de Lutinore
cs_mathmax 404 Messages postés vendredi 28 octobre 2005Date d'inscription 31 août 2008 Dernière intervention - 9 avril 2007 à 18:43
0
Merci
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
Commenter la réponse de cs_mathmax
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 9 avril 2007 à 19:08
0
Merci
"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;
Commenter la réponse de Lutinore
cs_mathmax 404 Messages postés vendredi 28 octobre 2005Date d'inscription 31 août 2008 Dernière intervention - 9 avril 2007 à 19:38
0
Merci
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
Commenter la réponse de cs_mathmax
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 9 avril 2007 à 21:13
0
Merci
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..
Commenter la réponse de Lutinore
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 9 avril 2007 à 21:24
0
Merci
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-
Commenter la réponse de cs_Bidou
cs_mathmax 404 Messages postés vendredi 28 octobre 2005Date d'inscription 31 août 2008 Dernière intervention - 9 avril 2007 à 21:27
0
Merci
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
Commenter la réponse de cs_mathmax
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 9 avril 2007 à 21:50
0
Merci
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..
Commenter la réponse de Lutinore
cs_mathmax 404 Messages postés vendredi 28 octobre 2005Date d'inscription 31 août 2008 Dernière intervention - 9 avril 2007 à 22:12
0
Merci
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
Commenter la réponse de cs_mathmax
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 9 avril 2007 à 22:29
0
Merci
LR_LOADFROMFILE  et compagnie sont surement des constantes de type int...
Allez Lutinore, bon courage si tu lances la dedans ^^












<hr />
-Blog-
Commenter la réponse de cs_Bidou
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 9 avril 2007 à 23:25
0
Merci
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;
}
Commenter la réponse de Lutinore

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.