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
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 ...
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).
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.
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 )
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 :
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
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.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
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#.
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..
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..
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
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
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.
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é.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html