wxDev.fr, le portail francophone consacré à wxWidgets ! ( The french portal for wxWidgets )  
Esp. membre
Recheche rapide



Recherche avancée
Statistiques
Membres inscrits :2359

Membres en ligne : 0
Invités en ligne : 5
Pub hébergeur
Pourquoi cette pub ?

Valid XHTML 1.0 Transitional

Valid CSS2

Menu forum (navigation):
Pages: 1  
 
Accueil » Accueil forums » Développement C/C++
» Faire du drop shadow avec wxGraphicsContext c'est possible?
Conversation : Faire du drop shadow avec wxGraphicsContext c'est possible?
08-07-2011 19:39:30  Faire du drop shadow avec wxGraphicsContext c'est possible? #1
starmate (Membre)
Inscrit le : 28-06-2011
Messages: 23
Snippets: 1
Tutoriels: 0
Hors ligne
Bonjour à tous,

Je viens vers vous, car je suis face à un problème.
Je développe actuellement une application utilisant wxWidgets, et je voudrais créer une image png avec fond transparent et à l'intérieur un rectangle avec des bords arrondis et un drop shadow appliqué à ce rectangle. J'ai eu beau cherché un peu partout, mais je n'ai rien trouvé. Alors je me suis décidé à utiliser un "trick", c'est à dire créer x rectangles en dessous du rectangle principal, avec une transparence alpha, les uns décalés par rapport aux autres.
Voici mon code:

Code wxWidgets:

 
wxString fname = wxGetCwd()+"/test_generated.png";
    wxRect rect(0,0,600,600);
    wxBitmap *backstore = new wxBitmap( rect.GetWidth(), rect.GetHeight() );
    #if wxUSE_LIBPNG
        wxImage::AddHandler( new wxPNGHandler );
    #endif
    wxMemoryDC memDC;
    memDC.SelectObject( *backstore );
    memDC.Clear();
 
    wxGraphicsContext *gc0 = wxGraphicsContext::Create(memDC);
    if (gc0)
    {
        gc0->SetInterpolationQuality(wxINTERPOLATION_BEST);
        gc0->SetCompositionMode(wxCOMPOSITION_CLEAR);
        gc0->SetAntialiasMode(wxANTIALIAS_DEFAULT);
 
        wxGraphicsPath path0 = gc0->CreatePath();
        path0.AddRoundedRectangle(20, 20, 60, 60,10);   
        gc0->SetBrush( wxBrush( wxColour(0, 0, 0, 90) ) );
        gc0->FillPath(path0);    
        gc0->StrokePath(path0);
 
        delete gc0;
    }
 
 
 
    wxGraphicsContext *gc1 = wxGraphicsContext::Create(memDC);
    if (gc1)
    {
        gc1->SetInterpolationQuality(wxINTERPOLATION_BEST);
        gc1->SetCompositionMode(wxCOMPOSITION_CLEAR);
        gc1->SetAntialiasMode(wxANTIALIAS_DEFAULT);
 
        wxGraphicsPath path1 = gc1->CreatePath();
        path1.AddRoundedRectangle(20, 20, 60, 60,10);   
        gc1->SetBrush( wxBrush( wxColour(0, 0, 0, 90) ) );
        gc1->FillPath(path1);    
        gc1->StrokePath(path1);
 
        delete gc1;
    }
    wxGraphicsContext *gc2 = wxGraphicsContext::Create(memDC);
    if (gc2)
    {
        gc2->SetInterpolationQuality(wxINTERPOLATION_BEST);
        gc2->SetCompositionMode(wxCOMPOSITION_CLEAR);
        gc2->SetAntialiasMode(wxANTIALIAS_DEFAULT);
        wxGraphicsPath path2 = gc2->CreatePath();
        path2.AddRoundedRectangle(21, 21, 58, 58,9);   
        gc2->SetBrush( wxBrush( wxColour(0, 0, 0, 90) ) );
        gc2->FillPath(path2);    
        gc2->StrokePath(path2);
        delete gc2;
    }
    wxGraphicsContext *gc3 = wxGraphicsContext::Create(memDC);
    if (gc3)
    {
        gc3->SetInterpolationQuality(wxINTERPOLATION_BEST);
        gc3->SetCompositionMode(wxCOMPOSITION_CLEAR);
        gc3->SetAntialiasMode(wxANTIALIAS_DEFAULT);
        wxGraphicsPath path3 = gc3->CreatePath();
        path3.AddRoundedRectangle(22, 22, 56, 56,8);   
        gc3->SetBrush( wxBrush( wxColour(0, 0, 0, 90) ) );
        gc3->FillPath(path3);    
        gc3->StrokePath(path3);
        delete gc3;
    }
    wxGraphicsContext *gc4 = wxGraphicsContext::Create(memDC);
    if (gc4)
    {
        gc4->SetInterpolationQuality(wxINTERPOLATION_BEST);
        gc4->SetCompositionMode(wxCOMPOSITION_CLEAR);
        gc4->SetAntialiasMode(wxANTIALIAS_DEFAULT);
        wxGraphicsPath path4 = gc4->CreatePath();
        path4.AddRoundedRectangle(23, 23, 54, 54,7);   
        gc4->SetBrush( wxBrush( wxColour(0, 0, 0, 90) ) );
        gc4->FillPath(path4);    
        gc4->StrokePath(path4);
        delete gc4;
    }
    wxGraphicsContext *gc5 = wxGraphicsContext::Create(memDC);
    if (gc5)
    {
        gc5->SetInterpolationQuality(wxINTERPOLATION_BEST);
        gc5->SetCompositionMode(wxCOMPOSITION_CLEAR);
        gc5->SetAntialiasMode(wxANTIALIAS_DEFAULT);
        wxGraphicsPath path5 = gc5->CreatePath();
        path5.AddRoundedRectangle(24, 24, 52, 52,6);   
        gc5->SetBrush( wxBrush( wxColour(0, 0, 0, 90) ) );
        gc5->FillPath(path5);    
        gc5->StrokePath(path5);
        delete gc5;
    }
 
 
    wxGraphicsContext *gc = wxGraphicsContext::Create(memDC);
    if (gc)
    {
        gc->SetPen( *wxBLACK_PEN );
        gc->SetAntialiasMode(wxANTIALIAS_DEFAULT);
        wxGraphicsPath path = gc->CreatePath();
        gc->SetCompositionMode(wxCOMPOSITION_CLEAR);
        gc->SetAntialiasMode(wxANTIALIAS_DEFAULT);
        path.AddRoundedRectangle(25, 25, 50, 50,5);   
        gc->SetBrush( wxBrush( wxColour(255, 255, 255, 255) ) );
 
 
        gc->FillPath(path);    
        gc->StrokePath(path);
        delete gc;
    }
 
    memDC.SelectObject( wxNullBitmap );
    backstore->SaveFile( fname, wxBITMAP_TYPE_PNG, (wxPalette*)NULL );
    delete backstore;
 


Bon la manip marche presque, sauf que les bords sont parfois pas très beaux. J'avoue que c'est un peu laid, mais c'est pour tester...

Alors ma question est la suivante : connaissez vous une bonne librairie pouvant m'aider à faire ce que je veux? Je connais ImageMagick (avec php) mais je ne sais pas ce que ça pourrait donner avec wxWidgets (je ne sais pas si l'application serait vraiment stand alone).

Si quelqu'un a une réponse concernant ce problème, je suis preneur! ;)

Merci d'avance,

Jon
08-07-2011 22:40:49  Re: Faire du drop shadow avec wxGraphicsContext c'est possible? #2
Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1365
Snippets: 25
Tutoriels: 6
Site web
Hors ligne
Salut.

Tu devrais jeter un coup d'oeil à l'exemple "drawing" fourni avec les libs, et notamment la page "gradient" : il me semble qu'avec ce que cette page propose, il y a moyen de faire quelque chose qui devrait correspondre.
@+
Xav'

Le nouveau portail wxWidgets francophone : www.wxdev.fr
Ben en fait, vous y êtes déjà...
11-07-2011 09:26:56  Re: Faire du drop shadow avec wxGraphicsContext c'est possible? #3
starmate (Membre)
Inscrit le : 28-06-2011
Messages: 23
Snippets: 1
Tutoriels: 0
Hors ligne
Salut et merci pour le retour,

Alors, a première vue pas de drop shadow possible, mais j'ai essayé avec des gradient et ça ne donne pas un résultat super non plus... Je continue à chercher. Je vais surement passer par une lib externe... Je ne connais pas encore laquelle, mais j'ai testé cimg, sans succès pour le moment...

A bientôt,

Jon
----------
Re-Bonjour,

J'ai presque réussi à avoir un rendu proche de ce que je veux avec le code ci-dessous:

Code wxWidgets:

wxString sPath = wxGetCwd()+"/test_generated.png";
 
    wxMemoryDC memDC, memDC_shadow;
 
    wxBitmap m_bitmap(600,600);
    wxBitmap m_bitmap_rectangle(600,600);
 
    memDC_shadow.SelectObject(m_bitmap_rectangle);
    memDC_shadow.Clear();
    memDC_shadow.SetBackground(wxBrush( wxColour(255, 255, 255, 0) ));
    memDC_shadow.SetPen(*wxTRANSPARENT_PEN);
    memDC_shadow.SetBrush(wxBrush( wxColour(20, 20, 20, 255) ));
    memDC_shadow.DrawRoundedRectangle(10, 10, 100, 100, 10);
    memDC_shadow.SelectObject(wxNullBitmap);
 
    wxImage image_rectangle;
    image_rectangle = m_bitmap_rectangle.ConvertToImage();
    image_rectangle = image_rectangle.Blur(5);
    m_bitmap = wxBitmap(image_rectangle);
 
    memDC.SelectObject(m_bitmap);
 
    wxGraphicsContext *gc2 = wxGraphicsContext::Create(memDC);
    if (gc2)
    {
        gc2->SetPen( wxPen(    wxColour(29, 125, 18, 255), 2 , wxPENSTYLE_SOLID) );
        gc2->SetInterpolationQuality(wxINTERPOLATION_BEST);
        gc2->SetAntialiasMode(wxANTIALIAS_DEFAULT);
        wxGraphicsPath path2 = gc2->CreatePath();
        path2.AddRoundedRectangle(10, 10, 100, 100, 10);   
        gc2->SetBrush( wxBrush( wxColour(255, 255, 255, 255) ) );
        gc2->FillPath(path2);    
        gc2->StrokePath(path2);
        delete gc2;
    }
    memDC.SelectObject(wxNullBitmap);
 
 
 
#if wxUSE_LIBPNG
    wxImage::AddHandler( new wxPNGHandler );
#endif
    wxImage image, image_temp;
    image= m_bitmap.ConvertToImage();
 
    image.SaveFile(sPath, wxBITMAP_TYPE_PNG);
    image.Destroy();


Le problème est que le fond doit être transparent... ce qui n'est pas encore le cas... je continue à chercher. ;)
----------
Voici une solution. J'espère que ça pourra aider plus d'un.

Code wxWidgets:

 
wxString sPath = wxGetCwd()+"/test_generated.png";
 
    #if wxUSE_LIBPNG
        wxImage::AddHandler( new wxPNGHandler );
    #endif
 
    wxMemoryDC memDC, memDC_shadow;
 
    wxBitmap m_bitmap(600,600);
    wxBitmap m_bitmap_rectangle(600,600);
 
 
    //create background image for shadow
    memDC_shadow.SelectObject( m_bitmap_rectangle );
    memDC_shadow.Clear();
 
    wxGraphicsContext *gc0 = wxGraphicsContext::Create(memDC_shadow);
    if (gc0)
    {
        gc0->SetPen(*wxTRANSPARENT_PEN);
        wxGraphicsPath path0 = gc0->CreatePath();
        path0.AddRoundedRectangle(5, 5, 110, 110, 10);
        gc0->SetBrush( wxBrush( wxColour(0, 0, 0, 180) ) );
        gc0->FillPath(path0);    
        gc0->StrokePath(path0);
        delete gc0;
    }
    memDC_shadow.SelectObject( wxNullBitmap );
 
 
    wxImage image_bkg;
    image_bkg = m_bitmap_rectangle.ConvertToImage();
 
    memDC.SelectObject(m_bitmap);
    memDC.DrawBitmap(wxBitmap(image_bkg.Blur(5)),0,0,true);
 
    wxGraphicsContext *gc2 = wxGraphicsContext::Create(memDC);
    if (gc2)
    {
        gc2->SetPen( wxPen(    wxColour(29, 125, 18, 255), 2 , wxPENSTYLE_SOLID) );
        gc2->SetInterpolationQuality(wxINTERPOLATION_BEST);
        gc2->SetAntialiasMode(wxANTIALIAS_DEFAULT);
        wxGraphicsPath path2 = gc2->CreatePath();
        path2.AddRoundedRectangle(10, 10, 100, 100, 10);   
        gc2->SetBrush( wxBrush( wxColour(255, 255, 255, 255) ) );
        gc2->FillPath(path2);    
        gc2->StrokePath(path2);
        delete gc2;
    }
    memDC.SelectObject(wxNullBitmap);
 
 
    wxImage image, image_temp;
    image_temp = m_bitmap.ConvertToImage();
 
 
    image = image_temp;
    image.SaveFile(sPath, wxBITMAP_TYPE_PNG);
    image.Destroy();
 


Ça fonctionne uniquement avec wxWidgets 2.9.x (ou supérieur) à mon avis. Il y a peut être des solutions plus simples, mais je ne vois rien de plus simple pour créer une ombre portée avec fond transparent.

@+

Jon

Dernière modification par starmate (11-07-2011 15:20:36)

12-07-2011 17:55:01  Re: Faire du drop shadow avec wxGraphicsContext c'est possible? #4
Xaviou (Administrateur)
Lieu: Annecy (74)
Inscrit le : 27-08-2007
Messages: 1365
Snippets: 25
Tutoriels: 6
Site web
Hors ligne
Salut.

J'ai enfin pris le temps d'essayer, et effectivement, ça marche.

Juste une petite correction : lorsque tu crées le rectangle pour l'ombre, tu mets le même rayon de coin que lorsque tu dessines le rectangle "normal".

Mais vu que le premier est 5 pixels plus grand, le rayon doit lui aussi être augmenté (essayes avec un rayon de 15 dans ton code, et tu verras que c'est plus joli).

Tu as précisé que le code ne marcherait qu'avec wxWidgets-2.9.x, je ne paux pas te le confirmer.
Par contre, il faut également préciser que ça ne marche qu'uniquement si wxGraphicsContext est activé (ce qui n'est généralement pas le cas avec MinGW).

Ça serait sympa de nous en faire un petit snippet, en rajoutant des commentaires dans le code pour que l'utilisateur lambda comprenne la technique utilisée.

En tout cas, ça risque d'être très utile.
Merci pour cette astuce.

@+
Xav'

Le nouveau portail wxWidgets francophone : www.wxdev.fr
Ben en fait, vous y êtes déjà...
13-07-2011 10:08:41  Re: Faire du drop shadow avec wxGraphicsContext c'est possible? #5
starmate (Membre)
Inscrit le : 28-06-2011
Messages: 23
Snippets: 1
Tutoriels: 0
Hors ligne
Salut,

Merci pour les explications et autres conseils.
J'ai modifié le code entre temps pour permettre différent types d'ombres mais je n'ai pas totalement fini. Je mettrai en ligne le code dès que je fini.

A bientôt,

Jon
Menu forum (navigation):
Pages: 1  
 
Accueil » Accueil forums » Développement C/C++
» Faire du drop shadow avec wxGraphicsContext c'est possible?