Laden...

PPT Präsentations-Erstellung beschleuningen?

Erstellt von emtcho vor 10 Jahren Letzter Beitrag vor 10 Jahren 4.904 Views
E
emtcho Themenstarter:in
16 Beiträge seit 2014
vor 10 Jahren
PPT Präsentations-Erstellung beschleuningen?

Moin,

ich habe eine C# Anwendung, die aus Messdaten eine PPT - Präsentation generiert. Layout etc werden automatisch berechnet, da die Messpunkte erst zur Laufzeit definiert werden.

NetOffice sei Dank!

Es werden 4 bis XXX Folien generiert. Leider habe ich feststellen müssen, dass hinzufügen von Shapes langsam ist...
Generieren von "Grafiken" kann man "vergessen" - dies habe ich umgegangen mit Zeichnen im Bitmap/Graphics und einfügen von fertigen Bildern in der Präsentation.

Trotzdem dauert es (wegen Tabellen Erstellung / Messwerte schreiben)... 200 Messpunkte > 1 Minute 20 sek... (Man kann mit **bloßem Auge sehen **wie die Textboxen nach und nach hinzugefügt werden ...

Ich habe probiert via DLL Import (einfach die VBA Anleitung vom PowerPoint VBA Equivalent of Application.ScreenUpdating in C# umgesetzt) die "Application.ScreenUpdating" für PPT nachzubauen:

        [DllImport("User32.dll")]
        public static extern Int32 FindWindow(string lpClassName, Int32 lpWindowName);

        [DllImport("User32.dll")]
        public static extern Int32 LockWindowUpdate(Int32 hwndLock);

        [DllImport("User32.dll")]
        public static extern Int32 UpdateWindow(Int32 hwnd);

        public void NewReport()
        {
            pp = new PowerPoint.Application();
            ppt = pp.Presentations.Add();
            this.sliderCounter = 0;

            Int32 hwnd = FindWindow("PPTFrameClass", 0);
            LockWindowUpdate(hwnd);

            CreateOverview();
            CreateDetailedSlides();

            UpdateWindow(hwnd);

        }

Leider ohne Erfolg - es gibt zwar keine Updates, dauert trotzdem genauso lange...

Hat jemand evtl. ein Hinweis, welche "Schräubchen" man "drehen" könnte um etwas mehr Performance herauszupressen?

Vielen Dank im Voraus!

emtcho

D
500 Beiträge seit 2007
vor 10 Jahren

Moin emtcho,

sag mal, ist es nicht irgendwie umstaendlich, so wie Du momentan eine PowerPoint Praesentation erstellst?

In wieweit waere bspw. das OpenXML SDK von Microsoft fuer Dich, um direkt ueber Code deine PPTX zu erstellen? Man muss dazu sagen, dass nur das "neuere" pptx Format unterstuezt wird.

Hat zwar nichts mit Charts zu tun, zeigt aber auf, wie man programmatisch auf PowerPoint zugreifen kann:
PowerPoint OpenXML

Gruss,
DaMoe

E
emtcho Themenstarter:in
16 Beiträge seit 2014
vor 10 Jahren

Moin DaMoe80.

Vielen Dank!

Sieht zwar ganz anders aus (ich komme aus der "VB6/VBA Welt" und deswegen konnte mich recht schnell im NetOffice zurechtfinden), aber es kann durchaus sein, dass es genau das ist wonach ich gesucht habe.

Ich werde natürlich umdenken müssen, aber falls es schneller ist, dann lohnt sich das auf jeden Fall!

Noch mal danke für den Tipp (man lernt ja nie aus...) 😉

emtcho

16.835 Beiträge seit 2008
vor 10 Jahren

Nur zum Verständnis: NetOffice ist nicht OpenXML.
Funktioniert ähnlich wie Dein aktuelles Vorhaben; aber halt über COM.

An die Geschwindigkeit und die Funktionalität von OpenXML wird es (vermutlich) nicht kommen; aber es ist schon gut vom Feedback, was man so liest.

D
500 Beiträge seit 2007
vor 10 Jahren

Moin zusammen,

@ Abt:

Funktioniert ähnlich wie Dein aktuelles Vorhaben; aber halt über COM.

Worauf beziehst Du diese Aussage?

@emtcho:
Von dem Code her, welchen Du gepostet hast, mutet es ein wenig merkwuerdig an, dass das PPT Window gesucht, gelockt und dann "irgendwie" aktualisiert wird. Natuerlich kenne ich Deine Anforderung im Detail nicht.
Muss denn ubedingt das PPT Fenster geoffnet sein, damit Daten dann generiert werden, oder ist es nicht besser, nachdem Du die Daten generiert hast, daraus eine PPT Praesentation zu erstellen?

NetOffice ist nicht OpenXML, das stimmt. OpenXML ist ein Standard, welcher von "aktuelleren" Office Applikationen umgesetzt wurde. Mit dem Open XML SDK for Office von Microsoft, kann man man ohne ein installiertes Office, alle auf dem OpenXML Standard basierten Office Dateien (docx, pptx, xlsx, etc.) zugreifen und bearbeiten.
Natuerlich kann man auch auf dem "guten, alten" Interop arbeiten, welches wiederum ein installiertes Office Produkt voraussetzt:

PPT Interop

Bzgl. der Performance, kommt es natuerlich darauf an, wie Du die Daten generierst und dann auch in die Praesentation schreibst. Ich sehe nicht, wie Deine Daten generierst und in die Slides der PPT Praesentation schreibst.
Es kann natuerlich sein, dass Du mit dem OpenXML SDK nicht schneller bist.
Wie gross werden denn Deine PPT Praesentationen ungefaehr?

Gruss,
DaMoe

16.835 Beiträge seit 2008
vor 10 Jahren

Worauf beziehst Du diese Aussage?

Nachvollziehbarerweise auf NetOffice.

E
emtcho Themenstarter:in
16 Beiträge seit 2014
vor 10 Jahren

Moin,

es hängt vom Benutzerauswahl ab - mann kann beliebig viele Messpunkte in beliebig viele "Mess-Zonen" definieren. Danach wird das PPT generiert:

Es gibt ein "Deckblatt" mit eine Gesamt-Übersicht.

Dann jeweils ein Übersichtsblatt pro Messzone.

Da nicht mehr als 17 Messergebnisse auf ein Blatt passen (wegen Lesbarkeit) muss ich die Messergebnisse aufteilen - daraus ergeben sich viele Detailansichtsblätter.

Ich wollte ursprünglich mit Shapes (Linien etc.) meine Übersichten und Detailansichten erstellen, erwies sich aber sehr Zeitaufwändig.

Deshalb "male" ich im Hintergrund auf Bitmap via Graphics (geht super schnell).

Das Funktioniert alles.

Mein Problem ist, dass die "schriftliche Ausgabe" der Messergebnisse - mit Textboxen etc., auch sehr langsam ist. Bei gerade mal 2 Messzonen und 550 Messpunkte (1650 Textboxen - je eine für Messpunktbezeichnung, Soll- und Istwert) dauert es bereits 3:50 Min. Kann ich nicht vertretten...

Ich werde mal den "OpenXML" Weg durchprobieren und mich wieder melden.

Vielen Dank für deine Hilfe!

emtcho

Gelöschter Account
vor 10 Jahren

Für die reine Generierung von Dokumenten sollte man natürlich (wenn unterstützt) das XML basierte Format verwenden, was in einem Addin nicht immer möglich ist.

Um dein Verfahren via COM zu beschleunigen musst du die Anzahl der Aufrufe reduzieren. Kingt wie eine Binsenweisheit, hat aber den Hintergrund das der Contextwechsel von .NET(managed) zu COM(unmanaged) bei einem Aufruf recht teuer ist was die Performance angeht. Von daher rührt deine starke Performance Einbuße, du hast wahrscheinliche zich-tausende Calls, da spielts auch keine Rolle welche COM basierte API du verwendest. Ich weiss nicht wie du die Messpunkte darstellst aber die meisten Office Anwendungen bieten auch immer Möglichkeiten eine grössere Anzahl an Werten als Array zu übergeben, wenn es um Dokumentenbearbeitung geht. Das würde den Vorgang sehr stark beschleunigen.

(Bei der Menge an Calls hoffe ich, du rufst ab und an mal Dispose() auf um den Speicher nicht über Gebühr zu belasten)

E
emtcho Themenstarter:in
16 Beiträge seit 2014
vor 10 Jahren

Moin,

@Sebastian - Vielen Dank für die ausführliche Erklärung! Ich habe bereits dran gedacht... Leider scheidet die Array-Übergabe für mein Spezialfall aus, da ich jedes "Segment" einzeln und je nach Messwert gesondert färben muss.
Soweit ich weiß, gibt es eine solche "multicolor"-Polyline leider nicht... Oder?
Ausserdem habe ich feststellen müssen, dass der abschlißenden Aufruf von PowerPoints-Umwandlungsroutine - xxx.ConvertToShape() - leider auch sehr langsam ist...
Naja, deshalb bin ich dazu übergegangen die "Malereien" über Bitmap/Graphics auszugeben...

@DaMoe80 - Ich habe nach reichlich fehlgeschlagenen Versuchen es endlich geschafft eine sinnvolle Ausgabe via OpenXML hinzubekommen...
Die Dokumentation ist echt miserabel. Erschwerend hinzu kommt noch, dass die im Netz vorhandenen Beispiele (Stackowerflow etc.) sich auf verschiedene Versionen beziehen die teilweise unterschiedliche Properties und Methoden exponieren...

Lange Rede - kurzer Sinn: der Geschwindigkeitvorteil ist wie erwartet berauschend!!!

Meine testweise erzeugten 1650 Shapes kriege auf Slide "gebannt" in sage und schreibe 0.42 Sek. verglichen 03:50 Min. vorher.

Die Lernkurve ist aber aus og. Gründen echt steil (oder ich bin zu doof).

FAZIT: Ich für mein Teil (und mit meine VBA-"Vorbelastung") würde viel lieber bei NetOffice bleiben (alles Nachvollziehbar, logische Strukturierung, bekanntes Objekt-Modell). Für Performance-hungrige Spezialfälle ist leider nur OpenXML die mittel der Wahl...

Vielen Dank an alle für die Anregungen und die Tipps!

emtcho

E
emtcho Themenstarter:in
16 Beiträge seit 2014
vor 10 Jahren

Moin,

ich habe das Rad echt neu erfunden... darauf bin ich nicht besonders stolz und hoffe mit folgenden Tipp jemand die Wiederholung dieser Großtat zu ersparen......

Es gibt doch ein Weg sich im OpenXML zu orientieren und wirkungsvoll die MSDN Dokumentation einzusetzen...

Nämlich so etwas wie "Reverse Engineering" mit PowerPoint...

Angenommen ich möchte ein abgerundetes Rechteck mit Schatten und Text in benutzerdefinierten Farben via OpenXML erzeugen - als Folien-Kopf...

Man startet PowerPoint und erstellt eine Präsentation die genau das enthält was man braucht.

Dann **abspeichern **und mit irgendein "ZIP-Format-Beherschendes-Programm" irgendwo entpacken... (Oberstes Verzeichnisname heisst wie die PPTX Datei).

Im Verzeichnis-Struktur "eintauchen" - Unterverzeichnis ../ppt/slides/ öffnen.

Die entsprechende** slideXYZ.XML Datei öffnen** (XYZ steht für den Foliennummer)

Dort steht irgendwo (ich habe mich nach meine Beschriftung orientiert):


<p:sp>
 <p:nvSpPr>
  <p:cNvPr name="Abgerundetes Rechteck 1" id="2"/>
   <p:cNvSpPr/>
  <p:nvPr/>
 </p:nvSpPr>
 <p:spPr>
 <a:xfrm>
  <a:off y="254000" x="254000"/>
  <a:ext cy="381000" cx="8636000"/>
 </a:xfrm>
 <a:prstGeom prst="roundRect">
  <a:avLst/>
 </a:prstGeom>
 <a:solidFill>
  <a:srgbClr val="C8D8E0"/>
 </a:solidFill>
 <a:ln algn="ctr" cmpd="sng" cap="flat" w="25400">
  <a:noFill/>
  <a:prstDash val="solid"/>
 </a:ln>
 <a:effectLst>
   <a:outerShdw dir="2700000" algn="tl" dist="38100" blurRad="50800">
     <a:prstClr val="black">
     <a:alpha val="40000"/>
   </a:prstClr>
 </a:outerShdw>
</a:effectLst>

Man beachte die kryptischen Bezeichner** a:effectLst, a:prstClr** etc.

Danach lässt sich wunderbar im MSDN suchen und bringt tatsächlich brauchbare Hilfe zu Tage...

So findet man heraus:

  • dass die Klasse **OuterShadow **wenn sie mal serializiert wird a:outerShdw heisst und über entsprechende Kindelemente und Eigenschaften verfügt.

  • dass algn="tl" die Eigenschaft **Alignment **mit Wert DocumentFormat.OpenXml.Drawing.RectangleAlignmentValues.TopLeft ist.

  • dass a:xfrm mit ihre Kindelementen a:off und a:ext die Position und Größe des Shapes definiert und dass es sich hierbei eigentlich um **Transform2D ** mit **Extent **und **Offset **handelt...

u.s.w. u.s.w.

Etwas "rumprobieren" und ...

daraus wird mal tatsächlich funktionierenden C# Quelltext:


        #region [ Create Header ]
        private static P.Shape CreateHeader(string headerText)
        {
            P.Shape header = new P.Shape
            (
                    new P.NonVisualShapeProperties
                    (
                        new P.NonVisualDrawingProperties() { Id = (UInt32Value)2U, Name = "Header" },
                        new P.NonVisualShapeDrawingProperties(new ShapeLocks() { NoGrouping = true }),
                        new ApplicationNonVisualDrawingProperties(new PlaceholderShape())
                    ),
                    new P.ShapeProperties
                    (
                        new D.Transform2D
                        (
                            new D.Offset() { X = 254000, Y = 254000 },
                            new D.Extents() { Cx = 9449940, Cy = 381000 }
                        ),
                        new D.PresetGeometry
                        (
                            new D.AdjustValueList()
                        ) { Preset = D.ShapeTypeValues.RoundRectangle },
                        new D.SolidFill
                        (
                            new D.RgbColorModelHex() { Val = "C8D8E0" }
                        ),
                        new EffectList(
                            new OuterShadow
                            (
                                new PresetColor
                                    (
                                        new Alpha() { Val = 40000 }
                                    ) { Val = D.PresetColorValues.Black }
                            ) { Alignment = D.RectangleAlignmentValues.TopLeft, Direction = 2700000, BlurRadius = 50800, Distance = 38100, RotateWithShape = true }
                        ),
                        new D.Outline
                        (
                            new D.NoFill()
                        ) { Width = 12700 }
                    ),
                    new P.TextBody
                    (
                        new BodyProperties() { Anchor = D.TextAnchoringTypeValues.Center },
                        new ListStyle(),
                        new Paragraph
                        (
                            new Run
                            (
                                new RunProperties
                                    (
                                        new D.SolidFill
                                        (
                                            new D.RgbColorModelHex() { Val = "3C5A69" }
                                        ),
                                        new D.LatinFont() { Typeface = "Arial" }
                                    )
                                {
                                    Language = "de-DE",
                                    FontSize = 1200,
                                    Dirty = false,
                                    Bold = true,
                                    SmartTagClean = false
                                },
                                new D.Text(headerText)
                            ),
                            new EndParagraphRunProperties
                                (
                                    new D.SolidFill
                                    (
                                        new D.RgbColorModelHex() { Val = "3C5A69" }
                                    ),
                                    new D.LatinFont() { Typeface = "Arial" }
                                )
                            {
                                Language = "de-DE",
                                FontSize = 1200,
                                Dirty = false,
                                Bold = true
                            }
                        )
                    )
            );

            return header;
        }
        #endregion

Frohes Schaffen!

emtcho