Partage
  • Partager sur Facebook
  • Partager sur Twitter

Excel / C++

Insertion d'image

    12 février 2020 à 9:47:58

    Bonjour communauté,

    Je développe actuellement, dans le cadre de mon entreprise, de petites application très connues sous le nom de "moulinettes".

    A la base, j'ai attaqué une application simple qui a fini en "boite à outils" et qui est assez appréciée de mes collaborateurs. Aujourd'hui, énième moulinette, je dois trouver un moyen d'insérer une image dans un fichier .xlsx mais je n'y arrive pas. J'ai bien essayé des bibliothèques sur Github,(XLNT, OenXLS,etc..) mais rien ne permet de travailler avec une image. Il y a bien LibXL mais 199$ la bibliothèque, mon chef a un peu grincé des dents.. Bref. J'ai besoin, par n'importe quel moyen, d'insérer une image, dans une cellule donnée, a une taille défini (si possible). Je suis preneur de tout, même de code ou méthode "sale", il faut que ça fonctionne. 

    "Pourquoi ne pas faire une macro directement ?" -Me demanderez vous. J'y ai pensé et je m'y refuse du moins pour l'instant. Cette boite à outil est désormais intégrée à plusieurs services et rajouter un bouton semblerait plus simple que rediffuser une macro..

    "Pourquoi du xlsx ?" Jusqu'a présent, je me suis débrouillé pour sortir du csv et le fait de pouvoir exploiter du xlsx me permettrai d'effectuer quelques update sur mes précédents codes sources.

    "Pourquoi du C++ ?" Il s'agit ici de C++/CLR, permettant justement de faire rapidement, des petites applications en fenêtre (oui, je sais, c'est plus d'actu... Ce que je regrette personnellement).

    Je reste à l'écoute et continue mes recherches en parallèle :)

    • Partager sur Facebook
    • Partager sur Twitter
      12 février 2020 à 10:15:30

      Le temps que tu vas perdre à chercher une méthode casse gueule qui ne marchera pas à tous les coups va vous faire perdre bien plus que 199$ je pense ...

      • Partager sur Facebook
      • Partager sur Twitter

      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

        12 février 2020 à 11:09:42

        T'as regardé du côté d'ActiveX ? Je sais pas si ça peut insérer des images dans Excel mais en tout cas ça permet d'interagir avec...
        • Partager sur Facebook
        • Partager sur Twitter
          12 février 2020 à 11:20:16

          Je suis plutôt d'accord avec @Fvirtman.

          Mais après, je ne peux juger de la qualité de cette librairie sans l'avoir utilisé.

          Pour le coup, vous avez un peu de chance.

          le format ".xlsx" est un format ouvert standardisé, le OOXML, et il est donc totalement possible de faire sa tambouille "toute à la main" en assimilant les quelques milliers de pages imbuvables de la norme ECMA correspondante.

          Mais vous avez encore de la chance, M$ fourni un SDK .NET pour lire et écrire des fichiers au format OOXML, l' OOXML SDK, et c'est gratuit.

          (il faut quand même maitriser un peu les format OOXML).

          https://docs.microsoft.com/fr-fr/office/open-xml/open-xml-sdk

          EDIT : @hennoo, on va laisser cette cochonnerie d'Automation mourir paisiblement, hein. ;)

          -
          Edité par bacelar 12 février 2020 à 14:20:50

          • Partager sur Facebook
          • Partager sur Twitter
          Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
            12 février 2020 à 13:27:42

            Salut,

            Par expérience, plutôt que générer un classeur Excel "par code", il est préférable de créer au préalable un classeur "template" dans lequel tu n'auras plus qu'a insérer les données.
            Ton classeur "Template" devras contenir toutes les formules, images, graphiques, tables, macro et mises en forme nécessaire a son fonctionnement.

            Voir encore mieux:
            Ton programme se contente de générer un fichier de données (CSV par exemple), que le fichier Excel ira lire via Power BI.
            Il sera de la responsabilité de ton programme de maintenir la source de données à jour,
            et il sera de la responsabilité des utilisateurs d'Excel de mettre à jour (rafraichir) leur classeur.

            -
            Edité par Deedolith 12 février 2020 à 13:30:32

            • Partager sur Facebook
            • Partager sur Twitter
              12 février 2020 à 13:49:19

              Tout d'abord,
              Merci pour vos réponse, rapides qui plus sont.
              Fvirtman :
              j'entends bien ton point de vue. Ces applications sont prévues pour gagner du temps mais je ne bosse pas pour une boite de dev mais de télécom et ce sont des développement que je prends sur mes temps morts ou libres. Ces applications ne sont pas déclarées au niveau du SI et ce même SI ne validera pas une demande d'investissement pour du développement non déclaré.
              hennoo:
              Je vais mirer de ce côté là voir ce que ça peut donner.

              bacelar:
              j'ai effectivement déja vu cette partie du SDK .NET mais elle me paraît, bien que complète, réservée à une élite du dev .NET. Je garde tous tes liens et conseils sous le coude car je sens que je vais devoir m'y coller de toutes façons. (La gratuité, c'est un mot qu'on aime bien en entreprise ça :D )
              je ne génère par d'Excel par code. Je veux ouvrir des documents pour y insérer des photos, nuance.. Ces documents sont des documents que nous devons rendre à l'opérateur pour lequel nous travaillons. Ces documents .xlsx sont mis en forme d'une certaine manière et nous devons modifier uniquement ce qui nous concerne : Je ne peux donc pas les générer à ma guise.
              De mon côté, j'ai pensé à une méthode à l'arrache mais qui pourrait être fonctionnelle :
              Créer un macro qui ferait tout ce beau travail.
              Lancer cette macro depuis mon code via system() en passant la macro et le document en arguments. ( https://support.office.com/fr-fr/article/commutateurs-de-ligne-de-commande-pour-les-produits-microsoft-office-079164cd-4ef5-4178-b235-441737deb3a6)
              Ce n'est pas portable, certes, mais ça n'est pas le but. Tout le système est basé sur dse produits M$ ( à ma grande déception).

              je ferai des test à l'occasion et vous tiendrai au courant des performances même si elle n'ont pas besoin d'être excellentes (il s'agit tout de même d'ouvrir quasiment un millier de .xlsx et de coller deux photos, voila pourquoi je veux développer ça aujourd'hui)
              Cordialement,
              Un ancien futur développeur qui gratte dans son coin ;)


              -
              Edité par Troglodytarum infernum 12 février 2020 à 14:30:58

              • Partager sur Facebook
              • Partager sur Twitter
                12 février 2020 à 15:51:41

                - Fvirtman

                Les manager "Autruche", c'est pas une espèce en voie de disparition, malheureusement.

                - hennoo

                Franchement, de l'Automation, il n'y a QUE des inconvénients.

                - bacelar

                "Reservé à une élite" ??? What ??? Mais vous faites du C++, vous êtes l'élite, l'élu !!! ;)

                Ça casse vraiment pas 3 pattes à un canard:

                Exemple d'implémentation en C# très très facilement traduisible en C++/CLI

                https://stackoverflow.com/questions/5793950/c-sharp-openxml-insert-an-image-into-an-excel-document

                - Deedolith

                L'approche par template est clairement plus carrée et complémentaire à l'utilisation de OOXML (SDK).

                Franchement, ce que vous proposez, c'est une usine à gaz avec de trucs qui sont même pas autorisé par les éditeurs. Office (toutes applications confondues) n'a été homologué pour tourner sur des serveurs (aucun OS serveur M$ n'a à le supporter, c'est vos emmerdes, M$ s'en lave les mains si vous n'écoutez pas leurs recommandations).

                Ne vous prenez pas la tête avec ces MACRO pourries et autre Automation foireuses : OOXML SDK.

                • Partager sur Facebook
                • Partager sur Twitter
                Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                  12 février 2020 à 16:02:45

                  Troglodytarum infernum a écrit:

                  Tout d'abord,
                  Merci pour vos réponse, rapides qui plus sont.
                  Fvirtman :
                  j'entends bien ton point de vue. Ces applications sont prévues pour gagner du temps mais je ne bosse pas pour une boite de dev mais de télécom et ce sont des développement que je prends sur mes temps morts ou libres. Ces applications ne sont pas déclarées au niveau du SI et ce même SI ne validera pas une demande d'investissement pour du développement non déclaré.

                  Tu es bien bon de faire ça sur ton temps libre...

                  Chapeau. Je me demande quelle reconnaissance tu attends en échange. Et surtout si tu l'auras... 

                  Sinon, le code proposé pour Bacelar semble correspondre a tes attentes. Après, si c'est du C#, même pas besoin de traduire je dirais, si c'est pour faire un programme indépendant, autant le laisser en C#.

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                    12 février 2020 à 17:09:33

                    Fvirtman

                    J'attends rien de spécial, sinon de montrer des compétences qui ne sont pas en rapport avec mon métier. Ce sont mes études et une partie de ma vie de pauvre geek solitaire (mais ça, c'était avant x) ) donc avant tout un plaisir. Ceci dit, ça m'apporte à mes collègues et moi même un temps considérable. Comme je l'ai déjà dit, il s'agit pour l'instant d'ouvrir des milliers de documents et d'y coller des photos : Perte de temps et intérêt plus que discutable mais action obligatoire..

                    bacelar

                    C'était une sorte d'ironie. Mais effectivement, quand on commence à mettre le nez dans ce genre de SDK, faut s'accrocher. J'ai un certain niveau en développement (qui me permettrait surement d'être dev junior) mais apparemment plus suffisant pour ce niveau. Le C++ reste un chouette langage et celui que j'ai le plus utilisé même si j'ai fait du Python, du Java, etc..

                    Je regarde en détail ce https://stackoverflow.com/questions/5793950/c-sharp-openxml-insert-an-image-into-an-excel-document et essaye de traduire ça en c++.

                    • Partager sur Facebook
                    • Partager sur Twitter
                      13 février 2020 à 11:20:26

                      Lancer cette macro depuis mon code via system() en passant la macro et le document en arguments. ( https://support.office.com/fr-fr/article/commutateurs-de-ligne-de-commande-pour-les-produits-microsoft-office-079164cd-4ef5-4178-b235-441737deb3a6)

                      Heu … NON !!!!!

                      Si tu veux lancer une macro lors de l'ouverture de ton document, c'est VBA qui s'en charge, certainement pas C++.

                      Contentes-toi de mettre les données à disposition quelque part, et le classeur se mettra à jour en fonction de cela.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        14 février 2020 à 10:57:39

                        Deedolith

                        Oui, j'ai rapidement abandonné cette idée.. TOUT COURT.

                        Je suis en train  de tenter la traduction du code posté plus haut (C# vers C++). j'avoue en chier un max... j'arrive à des choses mais je me retrouve toujours bloqué par certaines syntaxes du C# sachant que c'est un langage que je ne connais pas. Mais on va s'en sortir et je publierai avec joie ma victoire ;)

                        -
                        Edité par Troglodytarum infernum 14 février 2020 à 10:58:12

                        • Partager sur Facebook
                        • Partager sur Twitter
                          14 février 2020 à 11:00:13

                          Si tu coince sur le C#->C++, n'hésites pas à demander de l'aide ici. ;-)
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                            14 février 2020 à 11:40:13

                            J'ai mis du temps à comprendre que l'équivalent des surcharges du C++ se font par un une fonction qui ne prend pas les même paramètres, que ces dits paramètres sont "convertis" avant d'être balancés dans la fonction de base. Donc la fonction "surchargée" appelle la fonction de base (ce que je trouve absolument dégueu mais c'est fonctionnel et justifiable d'un point de vue dév.


                            un exemple :

                            public static void AddImage(bool createFile, string excelFile, string sheetName,
                                                                string imageFileName, string imgDesc,
                                                                int colNumber, int rowNumber)
                                    {
                                        using (var imageStream = new FileStream(imageFileName, FileMode.Open))
                                        {
                                            AddImage(createFile, excelFile, sheetName, imageStream, imgDesc, colNumber, rowNumber);
                                        }
                                    }

                            est une surcharge de :

                             public static void AddImage(WorksheetPart worksheetPart,
                                                                Stream imageStream, string imgDesc,
                                                                int colNumber, int rowNumber)
                                    {
                                        // We need the image stream more than once, thus we create a memory copy
                                        MemoryStream imageMemStream = new MemoryStream();
                                        imageStream.Position = 0;
                                        imageStream.CopyTo(imageMemStream);
                                        imageStream.Position = 0;
                            
                                        var drawingsPart = worksheetPart.DrawingsPart;
                                        if (drawingsPart == null)
                                            drawingsPart = worksheetPart.AddNewPart<DrawingsPart>();
                            
                                        if (!worksheetPart.Worksheet.ChildElements.OfType<Drawing>().Any())
                                        {
                                            worksheetPart.Worksheet.Append(new Drawing { Id = worksheetPart.GetIdOfPart(drawingsPart) });
                                        }
                            
                                        if (drawingsPart.WorksheetDrawing == null)
                                        {
                                            drawingsPart.WorksheetDrawing = new Xdr.WorksheetDrawing();
                                        }
                            
                                        var worksheetDrawing = drawingsPart.WorksheetDrawing;
                            
                                        Bitmap bm = new Bitmap(imageMemStream);
                                        var imagePart = drawingsPart.AddImagePart(GetImagePartTypeByBitmap(bm));
                                        imagePart.FeedData(imageStream);
                            
                                        A.Extents extents = new A.Extents();
                                        var extentsCx = bm.Width * (long)(914400 / bm.HorizontalResolution);
                                        var extentsCy = bm.Height * (long)(914400 / bm.VerticalResolution);
                                        bm.Dispose();
                            
                                        var colOffset = 0;
                                        var rowOffset = 0;
                            
                                        var nvps = worksheetDrawing.Descendants<Xdr.NonVisualDrawingProperties>();
                                        var nvpId = nvps.Count() > 0
                                            ? (UInt32Value)worksheetDrawing.Descendants<Xdr.NonVisualDrawingProperties>().Max(p => p.Id.Value) + 1
                                            : 1U;
                            
                                        var oneCellAnchor = new Xdr.OneCellAnchor(
                                            new Xdr.FromMarker
                                            {
                                                ColumnId = new Xdr.ColumnId((colNumber - 1).ToString()),
                                                RowId = new Xdr.RowId((rowNumber - 1).ToString()),
                                                ColumnOffset = new Xdr.ColumnOffset(colOffset.ToString()),
                                                RowOffset = new Xdr.RowOffset(rowOffset.ToString())
                                            },
                                            new Xdr.Extent { Cx = extentsCx, Cy = extentsCy },
                                            new Xdr.Picture(
                                                new Xdr.NonVisualPictureProperties(
                                                    new Xdr.NonVisualDrawingProperties { Id = nvpId, Name = "Picture " + nvpId, Description = imgDesc },
                                                    new Xdr.NonVisualPictureDrawingProperties(new A.PictureLocks { NoChangeAspect = true })
                                                ),
                                                new Xdr.BlipFill(
                                                    new A.Blip { Embed = drawingsPart.GetIdOfPart(imagePart), CompressionState = A.BlipCompressionValues.Print },
                                                    new A.Stretch(new A.FillRectangle())
                                                ),
                                                new Xdr.ShapeProperties(
                                                    new A.Transform2D(
                                                        new A.Offset { X = 0, Y = 0 },
                                                        new A.Extents { Cx = extentsCx, Cy = extentsCy }
                                                    ),
                                                    new A.PresetGeometry { Preset = A.ShapeTypeValues.Rectangle }
                                                )
                                            ),
                                            new Xdr.ClientData()
                                        );
                            
                                        worksheetDrawing.Append(oneCellAnchor);
                                    }


                            Bref, ce post est une parenthèse. Dans un post suivant, je vous montrerai ou j'en suis, ainsi, vous pourrez me dire ce que vous en pensez ;)


                            • Partager sur Facebook
                            • Partager sur Twitter
                              14 février 2020 à 14:24:03

                              Heu, là, je vois rien de dégueulasse ni de spécifique au C#, mais bien au contraire, une bonne approche "rendre facile les 'bonnes' utilisations et difficiles les 'mauvaises'".

                              La première méthode n'est qu'un wrapper autour d'une version plus bas niveau, qui gère en mode RAII l'ouverture et la fermeture d'un fichier (le fichier de l'image, ici).

                              Cela rend le tout bien plus fiable. Le garbage-collector ne fait pas tout, c'est pas magic.

                              La seconde méthode n'est pas celle appelée par la première, il doit encore avoir 1 ou 2 niveaux d'abstractions entre les 2, toujours pour "rendre facile les 'bonnes' utilisations et difficiles les 'mauvaises'".

                              Les C#-istes ne sont pas des demeurés de la POO, bien au contraire.

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

                              Excel / C++

                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                              • Editeur
                              • Markdown