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

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 à 00:28
Super ton site Lutinore . J'ai testé cette fonction http://www.pinvoke.net/default.aspx/gdi32.GdipLoadImage. Ca marche bien mais par contre c'est pas si rapide que ça... 9 secondes pour charger 130 images en release (processeur 3Ghz aussi).
Je crois que je vais devoir me contenter de ces performances...

merci beaucoup pour votre aide.

Mathmax
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
10 avril 2007 à 00:49
Rajoute ça et dis moi si c'est plus rapide, ça devrait..

[ DllImport( .. ), System.Security.SuppressUnmanagedCodeSecurity]
LoadImage( ... )

Il y'a d'autres facteurs, si tu charges toutes les images d'un coup, tu ne dois pas avoir assez de mémoire vive, Windows est obligé de swapper sur le disque dur et ça prend beaucoup de temps, c'est pour ça que dans mon code je dispose les images au fur et à mesure pour ne garder que les thumbs en mémoire.
0
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 à 01:29
Ca ne change pas grand chôse...

Concernant Dispose() c'est une méthode qui me renvoie l'image  et ensuite celle-ci est affectée à la propriété Image d'une PictureBox. Je pense que, automatiquement, après un return les resources sont libérées (comme si on appelait Dispose()), non ?

Voici le code de la méthode en question :

    public class FastImageGdiPlus
    {
        [DllImport("gdiplus.dll", CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
        public static extern int GdipLoadImageFromFile(string filename, out IntPtr image);

        private static Type imageType = typeof(Bitmap);

        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        internal static Image FastFromFile(string filename)
        {
            try
            {
                filename = Path.GetFullPath(filename);
                IntPtr loadingImage = IntPtr.Zero;

                // We are not using ICM at all, fudge that, this should be FAAAAAST!
                if (GdipLoadImageFromFile(filename, out loadingImage) != 0)
                {
                    throw new Exception("GDI+ threw a status error code.");
                }

                return (Bitmap)imageType.InvokeMember("FromGDIplus", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { loadingImage });
            }
            catch (SecurityException)
            {
                return Image.FromFile(filename);
            }
        }
    }

Mathmax
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
10 avril 2007 à 02:53
Sa méthode marche super bien, je l'ai un peu optimisée et j'obtiens 0 secondes et des poussières pour 100 images en 640x480 réduit en 80x80

public partial class Form1 : Form
{
    public Form1( )
    {
        InitializeComponent( );


        Button b = new Button( );
        b.Parent = this;
        b.Text = "Start";
        b.Click += delegate
        {
            string[ ] paths = Directory.GetFiles( @"C:\Users\Mike\Desktop\Angel" , "*.jpg" );


            Stopwatch sw = new Stopwatch( );
            sw.Reset( ); sw.Start( );


            Bitmap[ ] thumbnails = GetThumbnails( paths, 80, 80 );


            sw.Stop( );
            MessageBox.Show( string.Format( "Time: {0}\nCount: {1}", sw.Elapsed, thumbnails.Length ) );
        };
    }


    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 = LoadBitmapFromFile( 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;
    }


    public enum GpStatus
    {
        Ok = 0,
        GenericError = 1,
        InvalidParameter = 2,
        OutOfMemory = 3,
        ObjectBusy = 4,
        InsufficientBuffer = 5,
        NotImplemented = 6,
        Win32Error = 7,
        WrongState = 8,
        Aborted = 9,
        FileNotFound = 10,
        ValueOverflow = 11,
        AccessDenied = 12,
        UnknownImageFormat = 13,
        FontFamilyNotFound = 14,
        FontStyleNotFound = 15,
        NotTrueTypeFont = 16,
        UnsupportedGdiplusVersion = 17,
        GdiplusNotInitialized = 18,
        PropertyNotFound = 19,
        PropertyNotSupported = 20,
        ProfileNotFound = 21
    }


    [ DllImport( "gdiplus.dll", CharSet = CharSet.Unicode ), SuppressUnmanagedCodeSecurity ]
    private static extern GpStatus GdipLoadImageFromFile( string filename, out IntPtr image );


    private readonly MethodInfo BitmapFromGdiPLus =
        typeof( Bitmap ).GetMethod( "FromGDIplus", BindingFlags.NonPublic | BindingFlags.Static );


    public Bitmap LoadBitmapFromFile( string filename )
    {
        IntPtr gpImage = IntPtr.Zero;


        GpStatus gpStatus = GdipLoadImageFromFile( filename, out gpImage );


        if ( gpStatus != GpStatus.Ok )
            throw new ApplicationException( string.Format( "GdiPlus error: {0}.", gpStatus ) );


        return ( Bitmap )BitmapFromGdiPLus.Invoke
        (
            null,
            BindingFlags.Default,
            null,
            new object[ ] { gpImage },
            null
        );
    }
}
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
10 avril 2007 à 14:47
Merci ça marche bien : 0.3 secondes pour 130 images chez moi.
Comment peux-tu controler le type de retour de GdipLoadImageFromFile qui à priori est fixé dans la dll. Pourquoi choisis-tu une enum pour ce type de retour ?
Mathmax
0
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
ok
Merci beaucoup pour toutes ces explications Lutinore.

Mathmax
0
Rejoignez-nous