├── .gitignore ├── .npmignore ├── LICENSE ├── gulpfile.js ├── index.js ├── lib └── powerpoint │ ├── application.js │ ├── character.attr.js │ ├── character.js │ ├── edge │ └── application.js │ ├── index.js │ ├── paragraph.attr.js │ ├── paragraph.js │ ├── presentation.js │ ├── shape.attr.js │ ├── shape.js │ ├── slide.attr.js │ └── slide.js ├── package-lock.json ├── package.json ├── readme.md ├── src └── OfficeScript │ ├── .nuget │ ├── NuGet.Config │ ├── NuGet.exe │ └── NuGet.targets │ ├── OfficeScript.sln │ └── OfficeScript │ ├── DocumentProperty.cs │ ├── OfficeScript.csproj │ ├── OfficeScriptType.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── Report │ ├── Application.cs │ ├── Character.cs │ ├── Font.cs │ ├── Format.cs │ ├── Paragraph.cs │ ├── PowerPointTags.cs │ ├── Presentation.cs │ ├── Shape.cs │ ├── Slide.cs │ └── _Character.cs │ ├── Startup.cs │ ├── Util.cs │ └── packages.config └── test ├── data ├── Testpptx_00.pptx ├── Testpptx_01.pptx ├── Testpptx_02.pptx ├── Testpptx_Table.pptx ├── Testpptx_mocha.pptx ├── Testxlsx_01.xlsx └── ga.png ├── mocha.test.powerpoint.js ├── mocha.test.presentation.js └── sandbox.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Deployed apps should consider commenting this line out: 24 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 25 | node_modules 26 | 27 | 28 | ## Ignore Visual Studio temporary files, build results, and 29 | ## files generated by popular Visual Studio add-ons. 30 | 31 | # User-specific files 32 | *.suo 33 | *.user 34 | *.sln.docstates 35 | .vs 36 | 37 | # Build results 38 | [Dd]ebug/ 39 | [Dd]ebugPublic/ 40 | [Rr]elease/ 41 | x64/ 42 | build/ 43 | bld/ 44 | [Bb]in/ 45 | [Oo]bj/ 46 | packages/ 47 | 48 | # VS node tools 49 | .ntvs_analysis.dat 50 | 51 | # MSTest test Results 52 | [Tt]est[Rr]esult*/ 53 | [Bb]uild[Ll]og.* 54 | 55 | #NUNIT 56 | *.VisualState.xml 57 | TestResult.xml 58 | 59 | #VSCode config 60 | .vscode 61 | 62 | dist/ 63 | test/dest 64 | 65 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | test/data 3 | test/sandbox.js -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Jahr 2016, Fabian Roloff 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp') 2 | var exec = require('child_process').exec 3 | var path = require('path') 4 | var del = require('del') 5 | 6 | var dest = './dist' 7 | var src = './src/OfficeScript/OfficeScript/bin/Debug/*.dll' 8 | 9 | gulp.task('compile', function (cb) { 10 | exec(`MSBuild ${path.normalize('src/OfficeScript/OfficeScript.sln')} /clp:ErrorsOnly`, function (err, stdout, stderr) { 11 | console.log(stdout) 12 | console.log(stderr) 13 | cb(err) 14 | }) 15 | }) 16 | 17 | gulp.task('clean', function () { 18 | // clean /dist 19 | return del(dest) 20 | }) 21 | 22 | gulp.task('deploy', gulp.series('clean', 'compile', function () { 23 | // Copy .NET functionsto /dist 24 | return gulp.src(src) 25 | .pipe(gulp.dest(dest)) 26 | })) 27 | gulp.task('build', gulp.series('deploy'), function () {}) 28 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | Presentation: require('./lib/powerpoint/presentation'), 4 | powerpoint: require('./lib/powerpoint/application') 5 | } 6 | -------------------------------------------------------------------------------- /lib/powerpoint/application.js: -------------------------------------------------------------------------------- 1 | var application = require('./edge/application') 2 | var app 3 | 4 | module.exports = { 5 | application: application, 6 | open: function (path, cb) { 7 | if (!app) { 8 | app = application(null, true) 9 | } 10 | return app.open(path, cb) 11 | }, 12 | quit: function (param, cb) { 13 | if (app) { 14 | app.quit(param, cb) 15 | app = null 16 | } 17 | }, 18 | fetch: function (name, cb) { 19 | if (!app) { 20 | app = application(null, true) 21 | } 22 | return app.fetch(name, cb) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/powerpoint/character.attr.js: -------------------------------------------------------------------------------- 1 | var attributes = { 2 | text: function (text) { 3 | return this.attr('Text', text) 4 | }, 5 | 6 | count: function () { 7 | return this.attr('Count') 8 | }, 9 | 10 | // Font properties 11 | fontName: function (fontName) { 12 | return this.attr('Name', fontName, 'font') 13 | }, 14 | 15 | fontSize: function (fontName) { 16 | return this.attr('Size', fontName, 'font') 17 | }, 18 | 19 | fontColor: function (fontName) { 20 | return this.attr('Color', fontName, 'font') 21 | }, 22 | 23 | fontItalic: function (fontName) { 24 | return this.attr('Italic', fontName, 'font') 25 | }, 26 | 27 | fontBold: function (fontName) { 28 | return this.attr('Bold', fontName, 'font') 29 | } 30 | } 31 | 32 | module.exports = attributes 33 | -------------------------------------------------------------------------------- /lib/powerpoint/character.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash') 2 | 3 | function Character (nativeCharacter) { 4 | var character = this 5 | var native = { 6 | character: nativeCharacter, 7 | font: nativeCharacter.font(null, true) 8 | } 9 | character.attr = function (name, value, target) { 10 | target = target || 'character' 11 | if (typeof value !== 'undefined') { 12 | return new Character(native[target].attr({name: name, value: value}, true)) 13 | } 14 | return native[target].attr(name, true) 15 | } 16 | 17 | // inject attr 18 | _.assign(character, require('./character.attr')) 19 | 20 | character.remove = function () { 21 | return nativeCharacter.remove(null, true) 22 | } 23 | 24 | character._font = function () { 25 | return native.font 26 | } 27 | } 28 | 29 | module.exports = Character 30 | -------------------------------------------------------------------------------- /lib/powerpoint/edge/application.js: -------------------------------------------------------------------------------- 1 | /* global __dirname */ 2 | 'use strict' 3 | var path = require('path') 4 | var edge = require('edge-js') 5 | 6 | var application = edge.func({ 7 | assemblyFile: path.join(__dirname, '../../../dist/OfficeScript.dll'), 8 | typeName: 'OfficeScript.Startup', 9 | methodName: 'PowerPointApplication' 10 | }) 11 | 12 | module.exports = application 13 | -------------------------------------------------------------------------------- /lib/powerpoint/index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = require('./presentation') 3 | -------------------------------------------------------------------------------- /lib/powerpoint/paragraph.attr.js: -------------------------------------------------------------------------------- 1 | var attributes = { 2 | text: function (text) { 3 | return this.attr('Text', text) 4 | }, 5 | 6 | count: function () { 7 | return this.attr('Count') 8 | }, 9 | 10 | // Font properties 11 | fontName: function (fontName) { 12 | return this.attr('Name', fontName, 'font') 13 | }, 14 | 15 | fontSize: function (fontName) { 16 | return this.attr('Size', fontName, 'font') 17 | }, 18 | 19 | fontColor: function (fontName) { 20 | return this.attr('Color', fontName, 'font') 21 | }, 22 | 23 | fontItalic: function (fontName) { 24 | return this.attr('Italic', fontName, 'font') 25 | }, 26 | 27 | fontBold: function (fontName) { 28 | return this.attr('Bold', fontName, 'font') 29 | }, 30 | 31 | // Format properties 32 | align: function (align) { 33 | return this.attr('Alignment', align, 'format') 34 | }, 35 | 36 | indent: function (indent) { 37 | return this.attr('IndentLevel', indent, 'format') 38 | }, 39 | 40 | bulletCharacter: function (bulletCharacter) { 41 | return this.attr('BulletCharacter', bulletCharacter, 'format') 42 | }, 43 | 44 | bulletFontName: function (bulletFontName) { 45 | return this.attr('BulletFontName', bulletFontName, 'format') 46 | }, 47 | 48 | bulletFontBold: function (bulletFontBold) { 49 | return this.attr('BulletFontBold', bulletFontBold, 'format') 50 | }, 51 | 52 | bulletFontSize: function (bulletFontSize) { 53 | return this.attr('BulletFontSize', bulletFontSize, 'format') 54 | }, 55 | 56 | bulletFontColor: function (bulletFontColor) { 57 | return this.attr('BulletFontColor', bulletFontColor, 'format') 58 | }, 59 | 60 | bulletVisible: function (bulletVisible) { 61 | return this.attr('BulletVisible', bulletVisible, 'format') 62 | }, 63 | 64 | bulletRelativeSize: function (bulletRelativeSize) { 65 | return this.attr('BulletRelativeSize', bulletRelativeSize, 'format') 66 | }, 67 | 68 | firstLineIndent: function (firstLineIndent) { 69 | return this.attr('FirstLineIndent', firstLineIndent, 'format') 70 | }, 71 | 72 | leftIndent: function (leftIndent) { 73 | return this.attr('LeftIndent', leftIndent, 'format') 74 | }, 75 | 76 | lineRuleBefore: function (lineRuleBefore) { 77 | return this.attr('LineRuleBefore', lineRuleBefore, 'format') 78 | }, 79 | 80 | lineRuleAfter: function (lineRuleAfter) { 81 | return this.attr('LineRuleAfter', lineRuleAfter, 'format') 82 | }, 83 | 84 | hangingPunctuation: function (hangingPunctuation) { 85 | return this.attr('HangingPunctuation', hangingPunctuation, 'format') 86 | }, 87 | 88 | spaceBefore: function (spaceBefore) { 89 | return this.attr('SpaceBefore', spaceBefore, 'format') 90 | }, 91 | 92 | spaceAfter: function (spaceAfter) { 93 | return this.attr('SpaceAfter', spaceAfter, 'format') 94 | }, 95 | 96 | spaceWithin: function (spaceWithin) { 97 | return this.attr('SpaceWithin', spaceWithin, 'format') 98 | } 99 | } 100 | 101 | module.exports = attributes 102 | -------------------------------------------------------------------------------- /lib/powerpoint/paragraph.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash') 2 | 3 | function Paragraph (nativeParagraph) { 4 | var paragraph = this 5 | var native = { 6 | paragraph: nativeParagraph, 7 | format: nativeParagraph.format(null, true), 8 | font: nativeParagraph.font(null, true) 9 | } 10 | paragraph.attr = function (name, value, target) { 11 | target = target || 'paragraph' 12 | if (typeof value !== 'undefined') { 13 | return new Paragraph(native[target].attr({name: name, value: value}, true)) 14 | } 15 | return native[target].attr(name, true) 16 | } 17 | 18 | // inject attr 19 | _.assign(paragraph, require('./paragraph.attr')) 20 | 21 | paragraph.remove = function () { 22 | return nativeParagraph.remove(null, true) 23 | } 24 | 25 | paragraph._format = function () { 26 | return native.format 27 | } 28 | 29 | paragraph._font = function () { 30 | return native.font 31 | } 32 | 33 | paragraph.copyFont = function (srcParagraph) { 34 | paragraph.fontName(srcParagraph.fontName()) 35 | paragraph.fontSize(srcParagraph.fontSize()) 36 | paragraph.fontColor(srcParagraph.fontColor()) 37 | paragraph.fontItalic(srcParagraph.fontItalic()) 38 | paragraph.fontBold(srcParagraph.fontBold()) 39 | } 40 | 41 | paragraph.copyFormat = function (srcParagraph) { 42 | paragraph.align(srcParagraph.align()) 43 | paragraph.indent(srcParagraph.indent()) 44 | paragraph.bulletCharacter(srcParagraph.bulletCharacter()) 45 | paragraph.bulletFontName(srcParagraph.bulletFontName()) 46 | paragraph.bulletFontBold(srcParagraph.bulletFontBold()) 47 | paragraph.bulletFontSize(srcParagraph.bulletFontSize()) 48 | paragraph.bulletFontColor(srcParagraph.bulletFontColor()) 49 | paragraph.bulletVisible(srcParagraph.bulletVisible()) 50 | paragraph.bulletRelativeSize(srcParagraph.bulletRelativeSize()) 51 | paragraph.firstLineIndent(srcParagraph.firstLineIndent()) 52 | paragraph.leftIndent(srcParagraph.leftIndent()) 53 | paragraph.lineRuleBefore(srcParagraph.lineRuleBefore()) 54 | paragraph.hangingPunctuation(srcParagraph.hangingPunctuation()) 55 | paragraph.spaceBefore(srcParagraph.spaceBefore()) 56 | paragraph.spaceAfter(srcParagraph.spaceAfter()) 57 | paragraph.spaceWithin(srcParagraph.spaceWithin()) 58 | return paragraph 59 | } 60 | 61 | paragraph.copyStyle = function (srcParagraph) { 62 | paragraph.copyFont(srcParagraph) 63 | paragraph.copyFormat(srcParagraph) 64 | return paragraph 65 | } 66 | } 67 | 68 | module.exports = Paragraph 69 | -------------------------------------------------------------------------------- /lib/powerpoint/presentation.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var application = require('./application') 3 | var Slide = require('./slide') 4 | var Shape = require('./shape') 5 | 6 | function Presentation (presentationPath) { 7 | presentationPath = presentationPath || null 8 | var nativePresentation 9 | var presentation = this 10 | if (fs.existsSync(presentationPath)) { 11 | nativePresentation = application.open(presentationPath, true) 12 | } else { 13 | nativePresentation = application.fetch(presentationPath, true) 14 | } 15 | 16 | presentation.slides = function (selector) { 17 | var slides = [] 18 | var i 19 | var nativeSlides = nativePresentation.slides(selector, true) 20 | for (i = 0; i < nativeSlides.length; i++) { 21 | slides.push(new Slide(nativeSlides[i])) 22 | } 23 | return slides 24 | } 25 | 26 | presentation.addSlide = function (options) { 27 | return new Slide(nativePresentation.addSlide(options, true)) 28 | } 29 | 30 | presentation.textReplace = function (find, replace) { 31 | if (typeof find === 'string' && typeof replace === 'string') { 32 | nativePresentation.textReplace({'find': find, 'replace': replace}, true) 33 | } else if (typeof find === 'object') { 34 | replace = (typeof replace === 'function') ? replace : true 35 | nativePresentation.textReplace({'batch': find}, replace) 36 | } 37 | return presentation 38 | } 39 | 40 | presentation.nativeSlides = function (selector) { 41 | return nativePresentation.slides(selector, true) 42 | } 43 | 44 | presentation.shapes = function (selector, slides) { 45 | var shapes = [] 46 | var i 47 | slides = (typeof slides === 'string') ? presentation.slides(slides) : slides 48 | slides = (typeof slides === 'undefined') ? presentation.slides() : slides 49 | slides = (slides.length) ? slides : [slides] 50 | 51 | for (i = 0; i < slides.length; i++) { 52 | shapes = shapes.concat(slides[i].shapes(selector)) 53 | } 54 | return shapes 55 | } 56 | 57 | presentation.attr = function (input, cb) { 58 | cb = cb || true 59 | return nativePresentation.attr(input, cb) 60 | } 61 | 62 | presentation.dispose = function () { 63 | return nativePresentation.dispose(null, true) 64 | } 65 | 66 | presentation.quit = function (cb) { 67 | cb = cb || true 68 | nativePresentation.close(null, true) 69 | application.quit(null, cb) 70 | } 71 | presentation.close = function (cb) { 72 | cb = cb || true 73 | nativePresentation.close(null, cb) 74 | } 75 | 76 | presentation.save = function (cb) { 77 | cb = cb || true 78 | nativePresentation.save(null, cb) 79 | } 80 | 81 | presentation.saveAs = function (input, cb) { 82 | cb = cb || true 83 | nativePresentation.saveAs(input, cb) 84 | } 85 | 86 | presentation.saveAsCopy = function (input, cb) { 87 | cb = cb || true 88 | nativePresentation.saveAs(input, cb) 89 | } 90 | 91 | // * Attr shortcuts 92 | presentation.path = function () { 93 | return presentation.attr('Path', true) 94 | } 95 | 96 | presentation.name = function () { 97 | return presentation.attr('Name', true) 98 | } 99 | 100 | presentation.fullName = function () { 101 | return presentation.attr('FullName', true) 102 | } 103 | 104 | presentation.builtinProp = function (prop, value) { 105 | if (typeof prop !== 'string') { 106 | return nativePresentation.properties(null, true).getAllBuiltinProperties(null, true) 107 | } else if (typeof value !== 'string') { 108 | return nativePresentation.properties(null, true).getBuiltinProperty(prop, true) 109 | } else { 110 | return nativePresentation.properties(null, true).setBuiltinProperty({'prop': prop, 'value': value}, true) 111 | } 112 | } 113 | 114 | presentation.customProp = function (prop, value) { 115 | if (typeof prop !== 'string') { 116 | return nativePresentation.properties(null, true).getAllCustomProperties(null, true) 117 | } else if (typeof value !== 'string') { 118 | return nativePresentation.properties(null, true).getCustomProperty(prop, true) 119 | } else { 120 | return nativePresentation.properties(null, true).setCustomProperty({'prop': prop, 'value': value}, true) 121 | } 122 | } 123 | 124 | presentation.tag = { 125 | get: function (name) { 126 | return nativePresentation.tags(null, true).get(name, true) 127 | }, 128 | set: function (name, value) { 129 | nativePresentation.tags(null, true).set({name: name, value: value}, true) 130 | return presentation 131 | }, 132 | remove: function (name) { 133 | nativePresentation.tags(null, true).remove(name, true) 134 | return presentation 135 | } 136 | } 137 | 138 | presentation.tags = nativePresentation.tags(null, true).all(null, true) 139 | 140 | presentation.getType = function () { 141 | return nativePresentation.getType(null, true) 142 | } 143 | 144 | presentation.getSelectedShape = function () { 145 | return new Shape(nativePresentation.getSelectedShape(null, true)) 146 | } 147 | presentation.selectedShape = presentation.getSelectedShape 148 | 149 | presentation.getActiveSlide = function () { 150 | return new Slide(nativePresentation.getActiveSlide(null, true)) 151 | } 152 | presentation.activeSlide = presentation.getActiveSlide 153 | 154 | presentation.slideHeight = function () { 155 | return presentation.attr('SlideHeight', true) 156 | } 157 | 158 | presentation.slideWidth = function () { 159 | return presentation.attr('SlideWidth', true) 160 | } 161 | 162 | presentation.pasteSlide = function (index) { 163 | index = index || 1 164 | if (typeof index !== 'number') throw new Error('presentation.pasteSlide(index) : Index must be a number! ') 165 | index = (index === -1) ? presentation.slides().length + 1 : index 166 | index = (index < 1) ? 1 : index 167 | return new Slide(nativePresentation.pasteSlide(index, true)) 168 | } 169 | } 170 | 171 | module.exports = Presentation 172 | -------------------------------------------------------------------------------- /lib/powerpoint/shape.attr.js: -------------------------------------------------------------------------------- 1 | var attributes = { 2 | /** 3 | * Setzt den Namen eines PowerPoint-Objekts auf den übergebenen Wert oder gibt den Namen des PowerPoint-Objekts zurück, wenn der Parameter 'name' nicht definiert ist. 4 | * @method name 5 | * @param {String} name 6 | * @chainable 7 | * 8 | * @example 9 | * Liest den Namen des PowerPoint-Objekts aus und schreibt diesen in die Variable 'shapeName'. 10 | * @example 11 | * var shapeName = $shapes('selector').name(); 12 | * 13 | * @example 14 | * Ändert den Namen des PowerPoint-Objekts in 'Textbox_1337'. 15 | * @example 16 | * $shapes('selector').name('Textbox_1337') 17 | */ 18 | name: function (name) { 19 | return this.attr('Name', name) 20 | }, 21 | 22 | /** 23 | * Setzt den Text eines PowerPoint-Objekts auf den übergebenen Wert oder gib den Text des PowerPoint-Objekts zurück, wenn der Parameter 'text' nicht definiert ist. 24 | * @method text 25 | * @param {String} text 26 | * @chainable 27 | * 28 | * @example 29 | * Liest den Text des PowerPoint-Objekts aus und schreibt diesen in die Variable 'shapeText'. 30 | * @example 31 | * var shapeText = $shapes('selector').text() 32 | * 33 | * @example 34 | * Setzt den Text des PowerPoint-Objekts auf 'Fu Bar'. 35 | * @example 36 | * $shapes('selector').text('Fu Bar') 37 | */ 38 | text: function (text) { 39 | return this.attr('Text', text) 40 | }, 41 | 42 | /** 43 | * Setzt den Wert des Abstands nach oben eines PowerPoint-Objekts auf den übergebenen Wert oder gibt den Wert des Abstands nach oben des PowerPoint-Objekts zurück, wenn der Parameter 'top' nicht definiert ist. 44 | * @method top 45 | * @param {Number} top 46 | * @chainable 47 | * 48 | * @example 49 | * Liest den Wert des Abstands nach oben des PowerPoint-Objekts aus und schreibt diesen in die Variable 'shapeTop'. 50 | * @example 51 | * var shapeTop = $shapes('selector').top() 52 | * 53 | * @example 54 | * Setzt den Wert des Abstands nach oben des PowerPoint-Objekts auf 1337. 55 | * @example 56 | * $shapes('selector').top(1337) 57 | */ 58 | top: function (top) { 59 | return this.attr('Top', top) 60 | }, 61 | 62 | /** 63 | * Setzt den Wert des Abstands nach links eines PowerPoint-Objekts auf den übergebenen Wert oder gibt den Wert des Abstands nach links des PowerPoint-Objekts zurück, wenn der Parameter 'left' nicht definiert ist. 64 | * @method left 65 | * @param {Number} left 66 | * @chainable 67 | * 68 | * @example 69 | * Liest den Wert des Abstands nach links des PowerPoint-Objekts aus und schreibt diesen in die Variable 'shapeLeft'. 70 | * @example 71 | * var shapeLeft = $shapes('selector').left() 72 | * 73 | * @example 74 | * Setzt den Wert des Abstands nach links des PowerPoint-Objekts auf 1337. 75 | * @example 76 | * $shapes('selector').left(1337) 77 | */ 78 | left: function (left) { 79 | return this.attr('Left', left) 80 | }, 81 | 82 | /** 83 | * Setzt die Höhe eines PowerPoint-Objekts auf den übergebenen Wert oder gibt den Wert der Höhe des PowerPoint-Objekts zurück, wenn der Parameter 'height' nicht definiert ist. 84 | * @method height 85 | * @param {Number} height 86 | * @chainable 87 | * 88 | * @example 89 | * Liest den Wert der Höhe des PowerPoint-Objekts aus und schreibt diesen in die Variable 'shapeHeight'. 90 | * @example 91 | * var shapeHeight = $shapes('selector').height() 92 | * 93 | * @example 94 | * Setzt den Wert der Höhe des PowerPoint-Objekts auf 1337. 95 | * @example 96 | * $shapes('selector').height(1337) 97 | */ 98 | height: function (height) { 99 | return this.attr('Height', height) 100 | }, 101 | 102 | /** 103 | * Setzt die Breite eines PowerPoint-Objekts auf den übergebenen Wert oder gibt den Wert der Breite des PowerPoint-Objekts zurück, wenn der Parameter 'width' nicht definiert ist. 104 | * @method width 105 | * @param {Number} width 106 | * @chainable 107 | * 108 | * @example 109 | * Liest den Wert der Breite des PowerPoint-Objekts aus und schreibt diesen in die Variable 'shapeWidth'. 110 | * @example 111 | * var shapeWidth = $shapes('selector').width() 112 | * 113 | * @example 114 | * Setzt den Wert der Breite des PowerPoint-Objekts auf 1337. 115 | * @example 116 | * $shapes('selector').width(1337) 117 | */ 118 | width: function (width) { 119 | return this.attr('Width', width) 120 | }, 121 | 122 | /** 123 | * Rotiert ein PowerPoint-Objekt um den übergebenen Wert in Grad nach rechts oder gibt den Wert der Rotation eines PowerPoint-Objekts zurück, wenn der Parameter 'rotation' nicht definbiert ist. 124 | * @method rotation 125 | * @param {Number} rotation 126 | * @chainable 127 | * 128 | * @example 129 | * Liest den Wert der Rotation des PowerPoint-Objekts aus und schreibt diesen in die Variable 'shapeRotation'. 130 | * @example 131 | * var shapeRotation = $shapes('selector').rotation() 132 | * 133 | * @example 134 | * Dreht das PowerPoint-Objekt um 90 Grad nach rechts. 135 | * @example 136 | * $shapes('selector').rotation(90) 137 | */ 138 | rotation: function (rotation) { 139 | return this.attr('Rotation', rotation) 140 | }, 141 | 142 | /** 143 | * Befüllt ein PowerPoint-Objekt mit der Farbe mit dem übergebenen Wert oder gibt den Wert der Farbe mit welcher das PowerPoint-Objekt gefüllt ist aus, wenn der Parameter 'fill' nicht definiert ist. 144 | * @method fill 145 | * @param {Number} fill 146 | * @chainable 147 | * 148 | * @example 149 | * Liest den Wert der Farbe des PowerPoint-Objekts aus und schreibt diesen in die Variable 'shapeColor'. 150 | * @example 151 | * var shapeColor = $shapes('selector').fill() 152 | * 153 | * @example 154 | * Befüllt das PowerPoint-Objekt mit der Farbe mit dem Wert '#FF9900'. 155 | * @example 156 | * $shapes('selector').fill('FF9900') 157 | */ 158 | fill: function (fill) { 159 | return this.attr('Fill', fill) 160 | }, 161 | 162 | /** 163 | * Gibt den nächsten sog. 'Parent' (Elternteil, übergeordnetes Objekt) eines PowerPoint-Objekts zurück. 164 | * @method parent 165 | * @chainable 166 | * 167 | * @example 168 | * Liest den Parent des PowerPoint-Objekts aus und schreibt diesen in die Variable 'shapeParent'. 169 | * @example 170 | * var shapeParent = $shapes('selector').parent() 171 | */ 172 | parent: function () { 173 | throw new Error('Not implemented.') 174 | // return this.attr('Parent') 175 | }, 176 | 177 | altText: function (altText) { 178 | return this.attr('AltText', altText) 179 | }, 180 | 181 | title: function (title) { 182 | return this.attr('Title', title) 183 | }, 184 | 185 | type: function () { 186 | return this.attr('Type') 187 | } 188 | 189 | } 190 | 191 | module.exports = attributes 192 | -------------------------------------------------------------------------------- /lib/powerpoint/shape.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash') 2 | var Paragraph = require('./paragraph') 3 | var Character = require('./character') 4 | 5 | function Shape (nativeShape, isTableCell) { 6 | isTableCell = isTableCell || false 7 | var shape = this 8 | 9 | shape.attr = function (name, value) { 10 | if (typeof value !== 'undefined') { 11 | return new Shape(nativeShape.attr({ name: name, value: value }, true), isTableCell) 12 | } 13 | return nativeShape.attr(name, true) 14 | } 15 | 16 | shape.dispose = function () { 17 | return nativeShape.dispose(null, true) 18 | } 19 | 20 | // inject attr 21 | _.assign(shape, require('./shape.attr')) 22 | 23 | shape.has = function (objectName) { 24 | return nativeShape.hasObject(objectName, true) 25 | } 26 | 27 | shape.paragraph = function (start, length) { 28 | start = start || -1 29 | length = length || -1 30 | if (shape.text() === null) { 31 | return null 32 | } 33 | return new Paragraph(nativeShape.paragraph({ start: start, length: length }, true)) 34 | } 35 | 36 | shape.p = shape.paragraph 37 | 38 | shape.character = function (start, length) { 39 | start = start || -1 40 | length = length || -1 41 | if (shape.text() === null) { 42 | return null 43 | } 44 | return new Character(nativeShape.character({ start: start, length: length }, true)) 45 | } 46 | 47 | shape.c = shape.character 48 | shape.char = shape.character 49 | 50 | shape.textReplace = function (findString, replaceString) { 51 | return new Shape(nativeShape.textReplace({ find: findString, replace: replaceString }, true), isTableCell) 52 | } 53 | 54 | shape.getType = function () { 55 | return nativeShape.getType(null, true) 56 | } 57 | 58 | if (!isTableCell) { 59 | shape.remove = function () { 60 | return nativeShape.remove(null, true) 61 | } 62 | 63 | shape.duplicate = function () { 64 | return new Shape(nativeShape.duplicate(null, true)) 65 | } 66 | 67 | shape.copy = function () { 68 | nativeShape.copy(null, true) 69 | return shape 70 | } 71 | 72 | shape.addLine = function (text, pos) { 73 | if (typeof pos !== 'number') { 74 | shape.paragraph(shape.paragraph().count() + 1, -1).text(text) 75 | return shape 76 | } else { 77 | shape.paragraph(pos, -1).text(text) 78 | return shape 79 | } 80 | } 81 | 82 | shape.removeLine = function (pos) { 83 | if (typeof pos !== 'number') { 84 | shape.paragraph(shape.paragraph().count(), -1).remove() 85 | return shape 86 | } else { 87 | shape.paragraph(pos, -1).remove() 88 | return shape 89 | } 90 | } 91 | 92 | shape.exportAs = function (options) { 93 | if (typeof options === 'string') { 94 | var path = options 95 | options = { path: path } 96 | return nativeShape.exportAs(options) 97 | } else if (typeof options === 'object') { 98 | return nativeShape.exportAs(options) 99 | } 100 | } 101 | 102 | shape.zIndex = function (cmd) { 103 | if (typeof cmd === 'string') { 104 | return nativeShape.setZindex(cmd, true) 105 | } else if (typeof cmd === 'number') { 106 | var command 107 | var index = nativeShape.getZindex(null, true) 108 | if (index < cmd) { 109 | command = 'forward' 110 | } else if (index > cmd) { 111 | command = 'back' 112 | } 113 | while (index !== cmd) { 114 | nativeShape.setZindex(command, true) 115 | index = nativeShape.getZindex(null, true) 116 | } 117 | return new Shape(nativeShape) 118 | } else { 119 | return nativeShape.getZindex(null, true) 120 | } 121 | } 122 | 123 | shape.z = shape.zIndex 124 | 125 | shape.tag = { 126 | get: function (name) { 127 | return nativeShape.tags(null, true).get(name, true) 128 | }, 129 | set: function (name, value) { 130 | nativeShape.tags(null, true).set({ name: name, value: value }, true) 131 | return shape 132 | }, 133 | remove: function (name) { 134 | nativeShape.tags(null, true).remove(name, true) 135 | return shape 136 | } 137 | } 138 | 139 | shape.tags = nativeShape.tags(null, true).all(null, true) 140 | 141 | shape.table = function () { 142 | var nativeTable = shape.attr('Table') 143 | var table = [] 144 | var rowIndex = 0 145 | var colIndex = 0 146 | var row 147 | 148 | for (rowIndex = 0; rowIndex < nativeTable.length; rowIndex++) { 149 | row = [] 150 | for (colIndex = 0; colIndex < nativeTable[rowIndex].length; colIndex++) { 151 | var cell = new Shape(nativeTable[rowIndex][colIndex], true) 152 | row.push(cell) 153 | } 154 | table.push(row) 155 | } 156 | return table 157 | } 158 | } 159 | } 160 | 161 | module.exports = Shape 162 | -------------------------------------------------------------------------------- /lib/powerpoint/slide.attr.js: -------------------------------------------------------------------------------- 1 | var attributes = { 2 | /** 3 | * Setzt die PowerPoint-Folie an die übergebene Name oder gibt den Namen einer PowerPoint-Folie aus, wenn der der Parameter 'name' nicht definiert wird. 4 | * @method pos 5 | * @param {Number} pos 6 | * @chainable 7 | * 8 | * @example 9 | * Gibt dName der Folie zurück und schreibt diese in die Variable 'slideName'. 10 | * @example 11 | * var slideName = slide.name() 12 | * 13 | * @example 14 | * Setzt den Folie Name. 15 | * @example 16 | * slide.name('Slide Fu Bar') 17 | */ 18 | name: function (name) { 19 | return this.attr('Name', name) 20 | }, 21 | 22 | /** 23 | * Setzt die PowerPoint-Folie an die übergebene Position oder gibt die Position einer PowerPoint-Folie aus, wenn der der Parameter 'pos' nicht definiert wird. 24 | * @method pos 25 | * @param {Number} pos 26 | * @chainable 27 | * 28 | * @example 29 | * Gibt die Position der Folie aus und schreibt diese in die Variable 'sildePos'. 30 | * @example 31 | * var slidePos = slide.pos() 32 | * 33 | * @example 34 | * Schiebt die Folie an die dritte Stelle. 35 | * @example 36 | * slide.pos(3) 37 | */ 38 | pos: function (pos) { 39 | return this.attr('Pos', pos) 40 | }, 41 | 42 | /** 43 | * Gibt die Nummer einer PowerPoint-Folie aus. 44 | * @method number 45 | * @chainable 46 | * @readonly 47 | * 48 | * @example 49 | * Gibt die Nummer der Folie aus und schreibt diese in die Variable 'sildeNum'. 50 | * @example 51 | * var slideNum = slide.number() 52 | */ 53 | number: function () { 54 | return this.attr('Number') 55 | }, 56 | 57 | /** 58 | * Get Slide Notes. 59 | * @method notes 60 | * @chainable 61 | * @readonly 62 | */ 63 | notes: function () { 64 | return this.attr('Notes') 65 | } 66 | 67 | } 68 | 69 | module.exports = attributes 70 | -------------------------------------------------------------------------------- /lib/powerpoint/slide.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash') 2 | var Shape = require('./shape') 3 | 4 | function Slide (nativeSlide) { 5 | var slide = this 6 | 7 | slide.attr = function (name, value) { 8 | if (typeof value !== 'undefined') { 9 | return new Slide(nativeSlide.attr({ name: name, value: value }, true)) 10 | } 11 | return nativeSlide.attr(name, true) 12 | } 13 | 14 | slide.dispose = function () { 15 | return nativeSlide.dispose(null, true) 16 | } 17 | 18 | // inject attr 19 | _.assign(slide, require('./slide.attr')) 20 | 21 | slide.remove = function () { 22 | return nativeSlide.remove(null, true) 23 | } 24 | 25 | slide.duplicate = function () { 26 | return new Slide(nativeSlide.duplicate(null, true)) 27 | } 28 | 29 | slide.copy = function () { 30 | return new Slide(nativeSlide.copy(null, true)) 31 | } 32 | 33 | slide.pasteShape = function () { 34 | return new Shape(nativeSlide.pasteShape(null, true)) 35 | } 36 | 37 | slide.select = function () { 38 | return new Slide(nativeSlide.select(null, true)) 39 | } 40 | 41 | slide.textReplace = function (find, replace) { 42 | if (typeof find === 'string' && typeof replace === 'string') { 43 | nativeSlide.textReplace({ find: find, replace: replace }, true) 44 | } else if (typeof find === 'object') { 45 | replace = (typeof replace === 'function') ? replace : true 46 | nativeSlide.textReplace({ batch: find }, replace) 47 | } 48 | return slide 49 | } 50 | 51 | slide.addTextbox = function (options) { 52 | options = options || {} 53 | options.left = (typeof options.left !== 'undefined') ? options.left : 0 54 | options.top = (typeof options.top !== 'undefined') ? options.top : 0 55 | options.height = (typeof options.height !== 'undefined') ? options.height : 100 56 | options.width = (typeof options.width !== 'undefined') ? options.width : 100 57 | 58 | return new Shape(nativeSlide.addTextbox(options, true)) 59 | } 60 | 61 | slide.addPicture = function (path, options) { 62 | if (typeof path !== 'string') { 63 | throw new Error('Missing path!') 64 | } 65 | options = options || {} 66 | options.left = (typeof options.left !== 'undefined') ? options.left : 0 67 | options.top = (typeof options.top !== 'undefined') ? options.top : 0 68 | options.path = path 69 | return new Shape(nativeSlide.addPicture(options, true)) 70 | } 71 | 72 | slide.shapes = function (selector) { 73 | var shapes = [] 74 | var i 75 | var nativeShapes = nativeSlide.shapes(selector, true) 76 | for (i = 0; i < nativeShapes.length; i++) { 77 | shapes.push(new Shape(nativeShapes[i])) 78 | } 79 | return shapes 80 | } 81 | 82 | slide.tag = { 83 | get: function (name) { 84 | return nativeSlide.tags(null, true).get(name, true) 85 | }, 86 | set: function (name, value) { 87 | nativeSlide.tags(null, true).set({ name: name, value: value }, true) 88 | return slide 89 | }, 90 | remove: function (name) { 91 | nativeSlide.tags(null, true).remove(name, true) 92 | return slide 93 | } 94 | } 95 | 96 | slide.tags = nativeSlide.tags(null, true).all(null, true) 97 | } 98 | 99 | module.exports = Slide 100 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "office-script", 3 | "version": "1.7.0", 4 | "description": "Microsoft Office application automation.", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "mocha ./test/mocha.*.js", 11 | "build": "gulp build" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/Miramac/node-office-script.git" 16 | }, 17 | "author": { 18 | "name": "Fabian Roloff", 19 | "email": "fabian.roloff@vocatus.de" 20 | }, 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/Miramac/node-office-script/issues" 24 | }, 25 | "keywords": [ 26 | "office", 27 | "presentation", 28 | "powerpoint", 29 | "ppt", 30 | "pptx" 31 | ], 32 | "homepage": "https://github.com/Miramac/node-office-script", 33 | "dependencies": { 34 | "edge-js": "^15.5.2", 35 | "lodash": "^4.17.20" 36 | }, 37 | "devDependencies": { 38 | "del": "^4.1.1", 39 | "gulp": "^4.0.2", 40 | "mocha": "^10.2.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # OfficeScript 2 | 3 | Office-Script is a Microsoft Office application automation with node.js. 4 | It does not work with the Open Office XML document, instead it accesses the COM interop interface of the Offices application. 5 | Therefore, you must have Office installed! Also be carefull, **Microsoft strongly recommends against Office Automation from software solutions** https://support.microsoft.com/en-us/kb/257757 6 | 7 | *Only on tested with Office 2007 and Office 2016.* 8 | 9 | > *Work in progress.. Just ask if you have any question or feature requests!* 10 | 11 | ## Install 12 | ```sh 13 | npm install office-script --save 14 | ``` 15 | 16 | # PowerPoint 17 | 18 | PowerPoint application automation. 19 | ```javascript 20 | var path = require('path'); 21 | var powerpoint = require('office-script').powerpoint; 22 | 23 | //Create a new instance of PowerPoint and try to open the presentation 24 | powerpoint.open(path.join(__dirname, 'Presentation01.pptx'), function(err, presentation) { 25 | if(err) throw err; 26 | //use presentation object 27 | console.log('Presentation path:', presentation.attr({name:'Path'}, true)); 28 | //Get slides 29 | presentation.slides(null, function(err, slides) { 30 | if(err) throw err; 31 | console.log('Slides count:', slides.length); 32 | //get shapes on slide 1 33 | slides[0].shapes(null, function(err, shapes) { 34 | console.log('Shape count on slide 1:', shapes.length); 35 | shapes[0].attr({'name':'Text', 'value': 'Fu Bar'}, true); //Set text value 36 | console.log('Get text first shape:', shapes[0].attr({'name':'Text'}, true)); 37 | //close presentation 38 | presentation.close(null, function(err) { 39 | if(err) throw err; 40 | //exit powerpoint 41 | powerpoint.quit() 42 | }); 43 | }); 44 | }); 45 | }); 46 | ``` 47 | # sync vs. async 48 | Office-Script is written in an async pattern, but application automation can has serious problems with async... 49 | 50 | Because of this, I recommend to use the sync presentation wrapper. It also has the more readable API. 51 | 52 | ```javascript 53 | var path = require('path') 54 | var Presentation = require('office-script').Presentation 55 | var presentation 56 | try { 57 | // open a new PPT Presentation 58 | presentation = new Presentation(path.join(__dirname, 'Presentation01.pptx')) 59 | 60 | // get presentation slides 61 | var slides = presentation.slides() 62 | console.log('Slide count: ', slides.length) 63 | 64 | // Get all shapes of the first slide 65 | var shapes = slides[0].shapes() 66 | console.log('Title shape count:', shapes.length) 67 | 68 | // get name and text of the first shape 69 | console.log('shape name:', shapes[0].name()) 70 | console.log('Title shape text:', shapes[0].text()) 71 | 72 | // change name of the first 73 | shapes[0].name('First Shape') 74 | // change text of the first 75 | shapes[0].text('FuBar') 76 | 77 | // Setter retun the destination object so you can chain them 78 | shapes[0].top(10).left(10).height(100).width(100) 79 | 80 | // Save presentation as PDF (sync) 81 | presentation.saveAs({name: path.join(__dirname, 'Presentation01.pdf'), type: 'pdf'}) 82 | // SaveAs new presentation and quit application 83 | presentation.saveAs(path.join(__dirname, 'Presentation01_New.pptx')) 84 | } catch (e) { 85 | console.error(e) 86 | } 87 | if (presentation) { 88 | presentation.quit() // Close presentation & quit application 89 | } 90 | 91 | ``` 92 | # Synchronous API 93 | ## Presentation([path]); 94 | If path exists the presentation will be open. 95 | If `path` does not exist, an allready open presentation with the name of `path` will be used. 96 | If `path` is missing or `null`, the active presentation is used. 97 | ___ 98 | 99 | ### Presentation methods 100 | 101 | #### .addSlide([pos]) *returns slide object* 102 | Adds a new empty slide on the provided postiton an returns it. If no postiton was provided, the new slide will be added at the end. 103 | ___ 104 | #### .close([callback]) 105 | Closes the presentation without exiting powerpoint itself. 106 | ___ 107 | #### .quit([callback]) 108 | Closes the presentation and powerpoint itself. 109 | ___ 110 | #### .save([callback]) 111 | Saves the presentation. 112 | ___ 113 | #### .saveAs(fullName [, callback]) 114 | Saves the presentation to the provided path and name. 115 | ___ 116 | #### .saveAsCopy(fullName [, callback]) 117 | Saves the presentation as copy to the provided path and name. 118 | ___ 119 | #### .textReplace(find, replace) 120 | Find and replace text in the entire presentation. 121 | ___ 122 | 123 | 124 | ### Property methods 125 | 126 | #### .builtinProp([property, value]) `multifunctional` 127 | Without parameters, returns all builtin properties with their vlaues. 128 | With `property`, returns value of the specific builtin property. 129 | With `property` and `value`, sets value of specific builtin property. 130 | ___ 131 | #### .customProp([property, value]) `multifunctional` 132 | Without parameters, returns all custom properties with their vlaues. 133 | With `property`, returns value of the specific custom property. 134 | With `property` and `value`, sets/ccustomreates value of specific custom property 135 | ___ 136 | #### .fullName() `String readonly` Presentation path with presentation name 137 | #### .name() `String readonly` Presentation name 138 | #### .path() `String readonly` Presentation path 139 | #### .slideHeight() `Number readonly` Slide/presentation height 140 | #### .slideWidth() `Number readonly` Slide/presentation width 141 | #### .type() `String readonly` Presentation type 142 | 143 | ### Tag methods 144 | #### .tags returns all tags 145 | #### .tag *object with tag functions* 146 | #### .tag.get(name) returns value of specific tag 147 | #### .tag.set(name, value) set value of specific tag 148 | #### .tag.remove(name) removes tag 149 | 150 | ## presentation.slides([selector]) 151 | Get presentation slides. Optional filterd by the selector. 152 | ## presentation.activeSlide() 153 | Get active slide. 154 | #### presentation.pasteSlide([index]) 155 | Pastes the slides on the Clipboard into the Slides collection for the presentation. Returns the pasted slide. Index `-1` moves the slide to the end of the presentation. 156 | 157 | ### Slide methods 158 | #### .addTextbox(options) *returns shape object* 159 | #### .addPicture(options) *returns shape object* 160 | #### .duplicate() *returns slide object* 161 | #### .remove() *delete the slide* 162 | #### .copy() *copy the slide to the Clipboard* (to paste the slide in an other presentation) 163 | ```javascript 164 | presentation01.slides()[0].copy() // Copy first slide from presentation presentation01 165 | presentation02.pasteSlide() // Paste it on the end in presentation presentation02 166 | ``` 167 | 168 | ### Property methods 169 | If `value` is provided, it will set the property and return the slide 170 | #### .name([value]) `String` 171 | #### .number([value]) `Int readonly` 172 | #### .pos([value]) `Int` 173 | #### .notes() `String` 174 | 175 | ### Slide tag methods 176 | #### .tags returns all tags 177 | #### .tag *object with tag functions* 178 | #### .tag.get(name) returns value of specific tag 179 | #### .tag.set(name, value) set value of specific tag 180 | #### .tag.remove(name) removes tag 181 | 182 | ## presentation.shapes([selector] [, context]) 183 | Get presentation shapes. Optional filterd by the selector. Context is an optional slides array. 184 | ## presentation.selectedShape() 185 | Get selected shape. 186 | ## slide.shapes([selector]) 187 | Get slide shapes. Optional filterd by the selector. 188 | 189 | ### Shape methods 190 | #### .addline(text[, pos]) *returns paragraph object* 191 | #### .duplicate() *returns shape object* 192 | #### .exportAs(options) *returns shape object* 193 | #### .remove() 194 | #### .shape.removeLine(pos) *returns paragraph object* 195 | #### .textReplace(findString, replaceString) *returns shape object* 196 | #### .zIndex([command]) *returns shape object* 197 | #### .has(name) *Check if the current shape has a table, chart or textframe* 198 | ```javascript 199 | // export chart-shapes as EMF 200 | if (shapes[i].has('chart')) { 201 | shapes[i].exportAs({path: path.join(__dirname, shapes[i].name() + '.emf'), type: 'emf'}) 202 | } 203 | ``` 204 | ### Property methods 205 | 206 | If `value` is provided, it will set the property and return the shape. If not, it will return the value. 207 | 208 | #### .altText([value]) `String` 209 | #### .title([value]) `String` 210 | #### .fill([value]) `String` 211 | #### .height([value]) `Float` 212 | #### .left([value]) `Float` 213 | #### .name([value]) `String` 214 | #### .parent() *Not implemented yet* 215 | #### .rotation([value]) `Float` 216 | #### .table() `array` *Read-Only* 217 | #### .text([value]) `String` 218 | #### .top([value]) `Float` 219 | #### .width([value]) `Float` 220 | 221 | ### Shape tag methods 222 | #### .tags returns all tags 223 | #### .tag *object with tag functions* 224 | #### .tag.get(name) returns value of specific tag 225 | #### .tag.set(name, value) set value of specific tag 226 | #### .tag.remove(name) removes tag 227 | 228 | ## shape.paragraph(start, length) 229 | Get paragraph object. Optional filterd by start and length. 230 | 231 | ### Property methods 232 | If `value` is provided, it will set the property and return the shape. If not, it will return the value. 233 | #### .text([value]) 234 | #### .count() 235 | #### .fontName([value]) 236 | #### .fontSize([value]) 237 | #### .fontColor([value]) 238 | #### .fontItalic([value]) 239 | #### .fontBold([value]) 240 | #### .align([value]) 241 | #### .indent([value]) 242 | #### .bulletCharacter([value]) 243 | #### .bulletFontName([value]) 244 | #### .bulletFontBold([value]) 245 | #### .bulletFontSize([value]) 246 | #### .bulletFontColor([value]) 247 | #### .bulletVisible([value]) 248 | #### .bulletRelativeSize([value]) 249 | #### .firstLineIndent([value]) 250 | #### .leftIndent([value]) 251 | #### .lineRuleBefore([value]) 252 | #### .lineRuleAfter([value]) 253 | #### .hangingPunctuation([value]) 254 | #### .spaceBefore([value]) 255 | #### .spaceAfter([value]) 256 | #### .spaceWithin([value]) 257 | 258 | ### Paragraph methods 259 | #### .copyFont(srcParagraph) 260 | #### .copyFormat(srcParagraph) 261 | #### .copyStyle(srcParagraph) 262 | #### .remove() 263 | Delete paragraph 264 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /src/OfficeScript/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/OfficeScript/.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miramac/node-office-script/160e916d520da3fd7249c4c4a68047446d92806f/src/OfficeScript/.nuget/NuGet.exe -------------------------------------------------------------------------------- /src/OfficeScript/.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | 32 | 33 | 34 | 35 | $(SolutionDir).nuget 36 | 37 | 38 | 39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config 40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config 41 | 42 | 43 | 44 | $(MSBuildProjectDirectory)\packages.config 45 | $(PackagesProjectConfig) 46 | 47 | 48 | 49 | 50 | $(NuGetToolsPath)\NuGet.exe 51 | @(PackageSource) 52 | 53 | "$(NuGetExePath)" 54 | mono --runtime=v4.0.30319 "$(NuGetExePath)" 55 | 56 | $(TargetDir.Trim('\\')) 57 | 58 | -RequireConsent 59 | -NonInteractive 60 | 61 | "$(SolutionDir) " 62 | "$(SolutionDir)" 63 | 64 | 65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 67 | 68 | 69 | 70 | RestorePackages; 71 | $(BuildDependsOn); 72 | 73 | 74 | 75 | 76 | $(BuildDependsOn); 77 | BuildPackage; 78 | 79 | 80 | 81 | 82 | 83 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 99 | 100 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OfficeScript", "OfficeScript\OfficeScript.csproj", "{B24BC5C2-CFAE-41A6-BF95-76B6B877EEDC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {B24BC5C2-CFAE-41A6-BF95-76B6B877EEDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {B24BC5C2-CFAE-41A6-BF95-76B6B877EEDC}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {B24BC5C2-CFAE-41A6-BF95-76B6B877EEDC}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {B24BC5C2-CFAE-41A6-BF95-76B6B877EEDC}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/DocumentProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using PowerPoint = NetOffice.PowerPointApi; 6 | 7 | namespace OfficeScript.Report 8 | { 9 | class DocumentProperty 10 | { 11 | private dynamic element; 12 | 13 | public DocumentProperty(PowerPoint.Presentation presentation) 14 | { 15 | this.element = presentation; 16 | } 17 | 18 | public object Invoke() 19 | { 20 | return new 21 | { 22 | getCustomProperty = (Func>)( 23 | async (input) => 24 | { 25 | return this.GetCustomProperty((string)input); 26 | } 27 | ), 28 | getBuiltinProperty = (Func>)( 29 | async (input) => 30 | { 31 | return this.GetBuiltinProperty((string)input); 32 | } 33 | ), 34 | setBuiltinProperty = (Func>)( 35 | async (input) => 36 | { 37 | this.SetBuiltinProperty((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 38 | return this.Invoke(); 39 | } 40 | ), 41 | setCustomProperty = (Func>)( 42 | async (input) => 43 | { 44 | this.SetCustomProperty((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 45 | return this.Invoke(); 46 | } 47 | ), 48 | getAllCustomProperties = (Func>)( 49 | async (input) => 50 | { 51 | return this.GetAllCustomProperties(); 52 | } 53 | ), 54 | getAllBuiltinProperties = (Func>)( 55 | async (input) => 56 | { 57 | return this.GetAllBuiltinProperties(); 58 | } 59 | ) 60 | }; 61 | } 62 | private Dictionary GetAllCustomProperties() 63 | { 64 | NetOffice.OfficeApi.DocumentProperties properties; 65 | properties = (NetOffice.OfficeApi.DocumentProperties)this.element.CustomDocumentProperties; 66 | var props = new Dictionary(); 67 | 68 | foreach (NetOffice.OfficeApi.DocumentProperty prop in properties) 69 | { 70 | try 71 | { 72 | if (prop.Value != null) 73 | { 74 | props.Add(prop.Name.ToString(), prop.Value.ToString()); 75 | } 76 | } 77 | catch 78 | { 79 | 80 | } 81 | } 82 | return props; 83 | } 84 | 85 | private Dictionary GetAllBuiltinProperties() 86 | { 87 | NetOffice.OfficeApi.DocumentProperties properties; 88 | properties = (NetOffice.OfficeApi.DocumentProperties)this.element.BuiltInDocumentProperties; 89 | var props = new Dictionary(); 90 | 91 | foreach (NetOffice.OfficeApi.DocumentProperty prop in properties) 92 | { 93 | try 94 | { 95 | if (prop.Value != null) 96 | { 97 | props.Add(prop.Name.ToString(), prop.Value.ToString()); 98 | } 99 | } 100 | catch 101 | { 102 | 103 | } 104 | } 105 | return props; 106 | } 107 | 108 | private string GetCustomProperty(string propertyName) 109 | { 110 | NetOffice.OfficeApi.DocumentProperties properties; 111 | properties = (NetOffice.OfficeApi.DocumentProperties)this.element.CustomDocumentProperties; 112 | 113 | foreach (NetOffice.OfficeApi.DocumentProperty prop in properties) 114 | { 115 | if (prop.Name.ToString().ToUpper() == propertyName.ToUpper()) 116 | { 117 | return prop.Value.ToString(); 118 | } 119 | } 120 | return null; 121 | } 122 | 123 | private void SetCustomProperty(Dictionary parameters) 124 | { 125 | NetOffice.OfficeApi.DocumentProperties properties; 126 | properties = (NetOffice.OfficeApi.DocumentProperties)this.element.CustomDocumentProperties; 127 | String propertyName = (string)parameters["prop"]; 128 | String propertyVal = (string)parameters["value"]; 129 | 130 | if (GetCustomProperty(propertyName) != null) 131 | { 132 | properties[propertyName].Delete(); 133 | } 134 | 135 | properties.Add(propertyName, false, NetOffice.OfficeApi.Enums.MsoDocProperties.msoPropertyTypeString, propertyVal); 136 | } 137 | 138 | private string GetBuiltinProperty(string propertyName) 139 | { 140 | NetOffice.OfficeApi.DocumentProperties properties; 141 | properties = (NetOffice.OfficeApi.DocumentProperties)this.element.BuiltInDocumentProperties; 142 | 143 | foreach (NetOffice.OfficeApi.DocumentProperty prop in properties) 144 | { 145 | if (prop.Name.ToString() == propertyName) 146 | { 147 | return prop.Value.ToString(); 148 | } 149 | } 150 | return null; 151 | } 152 | 153 | private void SetBuiltinProperty(Dictionary parameters) 154 | { 155 | NetOffice.OfficeApi.DocumentProperties properties; 156 | properties = (NetOffice.OfficeApi.DocumentProperties)this.element.BuiltInDocumentProperties; 157 | String propertyName = (string)parameters["prop"]; 158 | String propertyVal = (string)parameters["value"]; 159 | 160 | if (GetBuiltinProperty(propertyName) != null) 161 | { 162 | properties[propertyName].Value = propertyVal; 163 | 164 | } 165 | } 166 | 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/OfficeScript.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B24BC5C2-CFAE-41A6-BF95-76B6B877EEDC} 8 | Library 9 | Properties 10 | OfficeScript 11 | OfficeScript 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | False 37 | False 38 | ..\packages\NetOffice.Core.1.7.2.0\lib\net45\NetOffice.dll 39 | True 40 | 41 | 42 | False 43 | False 44 | ..\packages\NetOffice.Core.1.7.2.0\lib\net45\OfficeApi.dll 45 | True 46 | 47 | 48 | False 49 | False 50 | ..\packages\NetOffice.PowerPoint.1.7.2.0\lib\net45\PowerPointApi.dll 51 | True 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | False 63 | False 64 | ..\packages\NetOffice.Core.1.7.2.0\lib\net45\VBIDEApi.dll 65 | True 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 92 | 93 | 94 | 95 | 96 | 97 | 104 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/OfficeScriptType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace OfficeScript 8 | { 9 | public enum OfficeScriptType 10 | { 11 | Application, 12 | //Report Types 13 | Presentation, 14 | Shape, 15 | Slide, 16 | Paragraph 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Allgemeine Informationen über eine Assembly werden über die folgenden 6 | // Attr gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 7 | // die mit einer Assembly verknüpft sind. 8 | [assembly: AssemblyTitle("OfficeScript")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("OfficeScript")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar 18 | // für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von 19 | // COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. 20 | [assembly: ComVisible(false)] 21 | 22 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird 23 | [assembly: Guid("f55b49f1-d5f1-4703-89d4-4e26e2a70c87")] 24 | 25 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 26 | // 27 | // Hauptversion 28 | // Nebenversion 29 | // Buildnummer 30 | // Revision 31 | // 32 | // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern 33 | // übernehmen, indem Sie "*" eingeben: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/Application.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using PowerPoint = NetOffice.PowerPointApi; 7 | 8 | namespace OfficeScript.Report 9 | { 10 | public class PowerPointApplication : IDisposable 11 | { 12 | 13 | private PowerPoint.Application application = null; 14 | private bool closeApplication = false; 15 | private bool disposed = false; 16 | 17 | 18 | // Destruktor 19 | ~PowerPointApplication() 20 | { 21 | Dispose(false); 22 | } 23 | 24 | #region Dispose 25 | 26 | // Implement IDisposable. 27 | // Do not make this method virtual. 28 | // A derived class should not be able to override this method. 29 | public void Dispose() 30 | { 31 | Dispose(true); 32 | // This object will be cleaned up by the Dispose method. 33 | // Therefore, you should call GC.SupressFinalize to 34 | // take this object off the finalization queue 35 | // and prevent finalization code for this object 36 | // from executing a second time. 37 | GC.SuppressFinalize(this); 38 | } 39 | // Dispose(bool disposing) executes in two distinct scenarios. 40 | // If disposing equals true, the method has been called directly 41 | // or indirectly by a user's code. Managed and unmanaged resources 42 | // can be disposed. 43 | // If disposing equals false, the method has been called by the 44 | // runtime from inside the finalizer and you should not reference 45 | // other objects. Only unmanaged resources can be disposed. 46 | protected virtual void Dispose(bool disposing) 47 | { 48 | // Check to see if Dispose has already been called. 49 | if (!this.disposed) 50 | { 51 | // If disposing equals true, dispose all managed 52 | // and unmanaged resources. 53 | if (disposing) 54 | { 55 | if (this.closeApplication) 56 | { 57 | 58 | this.application.Quit(); 59 | } 60 | this.application.Dispose(); 61 | this.application = null; 62 | } 63 | // Note disposing has been done. 64 | this.disposed = true; 65 | 66 | } 67 | } 68 | 69 | #endregion Dispose 70 | 71 | /// 72 | /// Retuns an object with async functions for node.js 73 | /// 74 | /// 75 | public object Invoke() 76 | { 77 | return new 78 | { 79 | open = (Func>)( 80 | async (input) => 81 | { 82 | return this.Open((string)input).Invoke(); 83 | }), 84 | fetch = (Func>)( 85 | async (input) => 86 | { 87 | return this.Fetch((string)input).Invoke(); 88 | }), 89 | quit = (Func>)( 90 | async (input) => 91 | { 92 | 93 | if (input != null) 94 | { 95 | if ((bool)input == true) 96 | { 97 | this.closeApplication = false; 98 | } 99 | else if ((bool)input == false) 100 | { 101 | this.closeApplication = false; 102 | } 103 | } 104 | this.Dispose(); 105 | return null; 106 | }) 107 | }; 108 | } 109 | 110 | /// 111 | /// 112 | /// 113 | /// 114 | /// 115 | public Presentation Open(string name) 116 | { 117 | //try to get the active PPT Instance 118 | this.application = PowerPoint.Application.GetActiveInstance(); 119 | if (this.application == null) 120 | { 121 | //start PPT if ther is no active instance 122 | this.application = new PowerPoint.Application(); 123 | this.closeApplication = true; 124 | } 125 | 126 | this.application.Visible = NetOffice.OfficeApi.Enums.MsoTriState.msoTrue; 127 | name = name.Replace('/', '\\'); 128 | return new Presentation(this.application.Presentations.Open(name)); 129 | } 130 | 131 | /// 132 | /// 133 | /// 134 | /// 135 | /// 136 | public Presentation Fetch(string name) 137 | { 138 | //try to get the active PPT Instance 139 | this.application = PowerPoint.Application.GetActiveInstance(); 140 | if (this.application == null) 141 | { 142 | //start PPT if ther is no active instance 143 | throw new Exception("Missing PowerPoint Application"); 144 | } 145 | this.application.Visible = NetOffice.OfficeApi.Enums.MsoTriState.msoTrue; 146 | Presentation presentation = null; 147 | if (name != null) 148 | { 149 | try 150 | { 151 | presentation = new Presentation(this.application.Presentations[name]); 152 | }catch 153 | { 154 | throw new Exception("Cannot find the PowerPoint presentations"); 155 | } 156 | } 157 | else 158 | { 159 | presentation = new Presentation(this.application.ActivePresentation); 160 | 161 | } 162 | 163 | return presentation; 164 | } 165 | 166 | /// 167 | /// 168 | /// 169 | public PowerPoint.Application GetUnderlyingObject() 170 | { 171 | return this.application; 172 | } 173 | 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/Character.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using PowerPoint = NetOffice.PowerPointApi; 7 | 8 | namespace OfficeScript.Report 9 | { 10 | public class Character 11 | { 12 | private PowerPoint.Shape shape; 13 | private int start; 14 | private int length; 15 | 16 | public Character(PowerPoint.Shape shape, Dictionary parameters) 17 | { 18 | this.shape = shape; 19 | object tmp; 20 | if (parameters.TryGetValue("start", out tmp)) 21 | { 22 | this.start = (int)tmp; 23 | } 24 | else 25 | { 26 | this.start = -1; 27 | } 28 | if (parameters.TryGetValue("length", out tmp)) 29 | { 30 | this.length = (int)tmp; 31 | } 32 | else 33 | { 34 | this.length = -1; 35 | } 36 | 37 | 38 | } 39 | 40 | /// 41 | /// Retuns an object with async functions for node.js 42 | /// 43 | /// 44 | public object Invoke() 45 | { 46 | return new 47 | { 48 | attr = (Func>)( 49 | async (input) => 50 | { 51 | if (input is string) 52 | { 53 | var tmp = new Dictionary(); 54 | tmp.Add("name", input); 55 | input = tmp; 56 | } 57 | return Util.Attr(this, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value), Invoke); 58 | }), 59 | remove = (Func>)( 60 | async (input) => 61 | { 62 | this.Remove(); 63 | return null; 64 | }), 65 | font = (Func>)( 66 | async (input) => 67 | { 68 | return new Font(this, this.Invoke).Invoke(); 69 | }) 70 | }; 71 | } 72 | 73 | /// 74 | /// 75 | /// 76 | private void Remove() 77 | { 78 | this.shape.TextFrame.TextRange.Characters(this.start, this.length).Delete(); 79 | } 80 | 81 | /// 82 | /// Get or Set the Text-Property for this element. 83 | /// 84 | public string Text 85 | { 86 | get 87 | { 88 | return this.shape.TextFrame.TextRange.Characters(this.start, this.length).Text; 89 | } 90 | set 91 | { 92 | this.shape.TextFrame.TextRange.Characters(this.start, this.length).Text = value; 93 | } 94 | } 95 | /// 96 | /// 97 | /// 98 | public int Count 99 | { 100 | get 101 | { 102 | return this.shape.TextFrame.TextRange.Characters(this.start, this.length).Count; 103 | } 104 | } 105 | 106 | /// 107 | /// 108 | /// 109 | /// 110 | public NetOffice.OfficeApi.TextRange2 GetUnderlyingObject() 111 | { 112 | return this.shape.TextFrame2.TextRange.Characters(this.start, this.length); 113 | } 114 | 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/Font.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Threading.Tasks; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using NetOffice.OfficeApi.Enums; 7 | using Office = NetOffice.OfficeApi; 8 | 9 | namespace OfficeScript.Report 10 | { 11 | class Font 12 | { 13 | private Office.Font2 font; 14 | private Paragraph paragraph = null; 15 | private Character character = null; 16 | private bool disposed; 17 | private Func parentInvoke; 18 | 19 | public Font(Office.Font2 font, Func parentInvoke) 20 | { 21 | this.font = font; 22 | this.parentInvoke = parentInvoke; 23 | } 24 | 25 | public Font(Paragraph paragraph, Func parentInvoke) 26 | { 27 | this.paragraph = paragraph; 28 | this.parentInvoke = parentInvoke; 29 | } 30 | 31 | public Font(Character character, Func parentInvoke) 32 | { 33 | this.character = character; 34 | this.parentInvoke = parentInvoke; 35 | } 36 | 37 | private void Init() 38 | { 39 | if(this.paragraph != null) 40 | { 41 | this.font = this.paragraph.GetUnderlyingObject().Font; 42 | } 43 | if (this.character != null) 44 | { 45 | this.font = this.character.GetUnderlyingObject().Font; 46 | } 47 | } 48 | 49 | public object Invoke() 50 | { 51 | return new 52 | { 53 | attr = (Func>)( 54 | async (input) => 55 | { 56 | if (input is string) 57 | { 58 | var tmp = new Dictionary(); 59 | tmp.Add("name", input); 60 | input = tmp; 61 | } 62 | Init(); 63 | return Util.Attr(this, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value), parentInvoke); 64 | }), 65 | }; 66 | } 67 | 68 | /// 69 | /// Get or Set the Bold-Property for this element. 70 | /// 71 | public bool Bold 72 | { 73 | get 74 | { 75 | return (this.font.Bold == MsoTriState.msoTrue ? true : false); 76 | } 77 | set 78 | { 79 | if (value == true) 80 | { 81 | this.font.Bold = MsoTriState.msoTrue; 82 | } 83 | else 84 | { 85 | this.font.Bold = MsoTriState.msoFalse; 86 | } 87 | } 88 | } 89 | /// 90 | /// Get or Set the Italic-Property for this element. 91 | /// 92 | public bool Italic 93 | { 94 | get 95 | { 96 | return (this.font.Italic == MsoTriState.msoTrue ? true : false); 97 | } 98 | set 99 | { 100 | if (value == true) 101 | { 102 | this.font.Italic = MsoTriState.msoTrue; 103 | } 104 | else 105 | { 106 | this.font.Italic = MsoTriState.msoFalse; 107 | } 108 | } 109 | } 110 | /// 111 | /// Get or Set the Color-Property for this element. 112 | /// 113 | public string Color 114 | { 115 | get 116 | { 117 | string bgr = "#" + this.font.Fill.ForeColor.RGB.ToString("x6"); 118 | return Util.BGRtoRGB(bgr); 119 | } 120 | set 121 | { 122 | this.font.Fill.ForeColor.RGB = ColorTranslator.FromHtml(Util.BGRtoRGB(value)).ToArgb(); 123 | } 124 | } 125 | 126 | /// 127 | /// Get or Set the Size-Property for this element. 128 | /// 129 | public float Size 130 | { 131 | get 132 | { 133 | return this.font.Size; 134 | } 135 | set 136 | { 137 | this.font.Size = value; 138 | } 139 | } 140 | /// 141 | /// Get or Set the Name-Property for this element. 142 | /// 143 | public string Name 144 | { 145 | get 146 | { 147 | return this.font.Name; 148 | } 149 | set 150 | { 151 | this.font.Name = value; 152 | } 153 | } 154 | 155 | public void Copy(Font src) 156 | { 157 | this.Bold = src.Bold; 158 | this.Italic = src.Italic; 159 | this.Name = src.Name; 160 | this.Size = src.Size; 161 | } 162 | 163 | 164 | internal NetOffice.OfficeApi.Font2 GetUnderlyingObject() 165 | { 166 | return this.font; 167 | } 168 | 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/Format.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NetOffice.OfficeApi.Enums; 3 | using System.Drawing; 4 | using System.Threading.Tasks; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | 9 | namespace OfficeScript.Report 10 | { 11 | 12 | class Format 13 | { 14 | private NetOffice.OfficeApi.ParagraphFormat2 format; 15 | private Paragraph paragraph; 16 | 17 | public Format(NetOffice.OfficeApi.ParagraphFormat2 format) 18 | { 19 | this.format = format; 20 | } 21 | 22 | public Format(Paragraph paragraph) 23 | { 24 | this.paragraph = paragraph; 25 | } 26 | 27 | private void Init() 28 | { 29 | this.format = this.paragraph.GetUnderlyingObject().ParagraphFormat; 30 | } 31 | 32 | public object Invoke() 33 | { 34 | return new 35 | { 36 | attr = (Func>)( 37 | async (input) => 38 | { 39 | if (input is string) 40 | { 41 | var tmp = new Dictionary(); 42 | tmp.Add("name", input); 43 | input = tmp; 44 | } 45 | Init(); 46 | return Util.Attr(this, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value), paragraph.Invoke); 47 | }), 48 | }; 49 | } 50 | 51 | /// 52 | /// Get or Set the Alignment-Property for this element. 53 | /// Parameters are: "left", "right", "center" 54 | /// 55 | public string Alignment 56 | { 57 | get 58 | { 59 | switch (this.format.Alignment) 60 | { 61 | case MsoParagraphAlignment.msoAlignLeft: 62 | return "left"; 63 | case MsoParagraphAlignment.msoAlignRight: 64 | return "right"; 65 | case MsoParagraphAlignment.msoAlignCenter: 66 | return "center"; 67 | default: 68 | return this.format.Alignment.ToString(); 69 | } 70 | } 71 | set 72 | { 73 | switch (value.ToLower()) 74 | { 75 | case "left": 76 | this.format.Alignment = MsoParagraphAlignment.msoAlignLeft; 77 | break; 78 | case "right": 79 | this.format.Alignment = MsoParagraphAlignment.msoAlignRight; 80 | break; 81 | case "center": 82 | this.format.Alignment = MsoParagraphAlignment.msoAlignCenter; 83 | break; 84 | } 85 | } 86 | } 87 | 88 | /// 89 | /// Get or Set the Bullet-Property for this element. 90 | /// 91 | public int BulletCharacter 92 | { 93 | get 94 | { 95 | return (int)this.format.Bullet.Character; 96 | } 97 | set 98 | { 99 | this.format.Bullet.Character = value; 100 | } 101 | } 102 | 103 | public String BulletFontName 104 | { 105 | get 106 | { 107 | return (String)this.format.Bullet.Font.Name; 108 | } 109 | set 110 | { 111 | this.format.Bullet.Font.Name = value; 112 | } 113 | } 114 | 115 | public string BulletFontBold 116 | { 117 | get 118 | { 119 | switch (this.format.Bullet.Font.Bold) 120 | { 121 | case MsoTriState.msoTrue: 122 | return "true"; 123 | case MsoTriState.msoFalse: 124 | return "false"; 125 | default: 126 | return this.format.Bullet.Font.Bold.ToString(); 127 | } 128 | } 129 | set 130 | { 131 | switch (value.ToLower()) 132 | { 133 | case "true": 134 | this.format.Bullet.Font.Bold = MsoTriState.msoTrue; 135 | break; 136 | case "false": 137 | this.format.Bullet.Font.Bold = MsoTriState.msoFalse; 138 | break; 139 | } 140 | } 141 | } 142 | 143 | public int BulletFontSize 144 | { 145 | get 146 | { 147 | return (int)this.format.Bullet.Font.Size; 148 | } 149 | set 150 | { 151 | this.format.Bullet.Font.Size = value; 152 | } 153 | } 154 | 155 | public string BulletFontColor 156 | { 157 | get 158 | { 159 | string bgr = "#" + this.format.Bullet.Font.Fill.ForeColor.RGB.ToString("x6"); 160 | return Util.BGRtoRGB(bgr); 161 | } 162 | set 163 | { 164 | this.format.Bullet.Font.Fill.ForeColor.RGB = ColorTranslator.FromHtml(Util.BGRtoRGB(value)).ToArgb(); 165 | } 166 | } 167 | 168 | public float BulletRelativeSize 169 | { 170 | get 171 | { 172 | return (float)this.format.Bullet.RelativeSize; 173 | } 174 | set 175 | { 176 | this.format.Bullet.RelativeSize = value; 177 | } 178 | } 179 | 180 | public string BulletVisible 181 | { 182 | get 183 | { 184 | switch (this.format.Bullet.Visible) 185 | { 186 | case MsoTriState.msoTrue: 187 | return "true"; 188 | case MsoTriState.msoFalse: 189 | return "false"; 190 | default: 191 | return this.format.Bullet.Visible.ToString(); 192 | } 193 | } 194 | set 195 | { 196 | switch (value.ToLower()) 197 | { 198 | case "true": 199 | this.format.Bullet.Visible = MsoTriState.msoTrue; 200 | break; 201 | case "false": 202 | this.format.Bullet.Visible = MsoTriState.msoFalse; 203 | break; 204 | } 205 | } 206 | } 207 | 208 | public float FirstLineIndent 209 | { 210 | get 211 | { 212 | return (float)this.format.FirstLineIndent; 213 | } 214 | set 215 | { 216 | this.format.FirstLineIndent = value; 217 | } 218 | } 219 | 220 | public float LeftIndent 221 | { 222 | get 223 | { 224 | return (float)this.format.LeftIndent; 225 | } 226 | set 227 | { 228 | this.format.LeftIndent = value; 229 | } 230 | } 231 | 232 | public string HangingPunctuation 233 | { 234 | get 235 | { 236 | switch (this.format.HangingPunctuation) 237 | { 238 | case MsoTriState.msoTrue: 239 | return "true"; 240 | case MsoTriState.msoFalse: 241 | return "false"; 242 | default: 243 | return this.format.HangingPunctuation.ToString(); 244 | } 245 | } 246 | set 247 | { 248 | switch (value.ToLower()) 249 | { 250 | case "true": 251 | this.format.HangingPunctuation = MsoTriState.msoTrue; 252 | break; 253 | case "false": 254 | this.format.HangingPunctuation = MsoTriState.msoFalse; 255 | break; 256 | } 257 | } 258 | } 259 | 260 | public string LineRuleBefore 261 | { 262 | get 263 | { 264 | switch (this.format.LineRuleBefore) 265 | { 266 | case MsoTriState.msoTrue: 267 | return "true"; 268 | case MsoTriState.msoFalse: 269 | return "false"; 270 | default: 271 | return this.format.LineRuleBefore.ToString(); 272 | } 273 | } 274 | set 275 | { 276 | switch (value.ToLower()) 277 | { 278 | case "true": 279 | this.format.LineRuleBefore = MsoTriState.msoTrue; 280 | break; 281 | case "false": 282 | this.format.LineRuleBefore = MsoTriState.msoFalse; 283 | break; 284 | } 285 | } 286 | } 287 | 288 | public string LineRuleAfter 289 | { 290 | get 291 | { 292 | switch (this.format.LineRuleAfter) 293 | { 294 | case MsoTriState.msoTrue: 295 | return "true"; 296 | case MsoTriState.msoFalse: 297 | return "false"; 298 | default: 299 | return this.format.LineRuleAfter.ToString(); 300 | } 301 | } 302 | set 303 | { 304 | switch (value.ToLower()) 305 | { 306 | case "true": 307 | this.format.LineRuleAfter = MsoTriState.msoTrue; 308 | break; 309 | case "false": 310 | this.format.LineRuleAfter = MsoTriState.msoFalse; 311 | break; 312 | } 313 | } 314 | } 315 | 316 | public double SpaceBefore 317 | { 318 | 319 | get 320 | { 321 | return this.format.SpaceBefore; 322 | } 323 | set 324 | { 325 | this.format.SpaceBefore = (float)value; 326 | } 327 | } 328 | 329 | public double SpaceAfter 330 | { 331 | get 332 | { 333 | return this.format.SpaceAfter; 334 | } 335 | set 336 | { 337 | this.format.SpaceAfter = (float)value; 338 | } 339 | } 340 | 341 | public double SpaceWithin 342 | { 343 | get 344 | { 345 | return this.format.SpaceWithin; 346 | } 347 | set 348 | { 349 | this.format.SpaceWithin = (float)value; 350 | } 351 | } 352 | 353 | /// 354 | /// Get or Set the Indent-Property for this element. 355 | /// 356 | public int IndentLevel 357 | { 358 | get 359 | { 360 | return this.format.IndentLevel; 361 | } 362 | set 363 | { 364 | this.format.IndentLevel = value; 365 | } 366 | } 367 | 368 | /// 369 | /// 370 | /// 371 | internal NetOffice.OfficeApi.ParagraphFormat2 GetUnderlyingObject() 372 | { 373 | return this.format; 374 | } 375 | 376 | 377 | 378 | //http://codereview/#3WF 379 | public void Copy(Format src) 380 | { 381 | NetOffice.OfficeApi.ParagraphFormat2 srcFormat = src.GetUnderlyingObject(); 382 | 383 | //Bullets 384 | this.format.Bullet.Font.Name = srcFormat.Bullet.Font.Name; 385 | this.format.Bullet.Font.Bold = srcFormat.Bullet.Font.Bold; 386 | this.format.Bullet.Font.Size = srcFormat.Bullet.Font.Size; 387 | this.format.Bullet.Font.Fill.ForeColor = srcFormat.Bullet.Font.Fill.ForeColor; 388 | this.format.Bullet.Character = srcFormat.Bullet.Character; 389 | this.format.Bullet.RelativeSize = srcFormat.Bullet.RelativeSize; 390 | this.format.Bullet.Visible = srcFormat.Bullet.Visible; 391 | //Indent 392 | this.format.FirstLineIndent = srcFormat.FirstLineIndent; 393 | this.format.IndentLevel = srcFormat.IndentLevel; 394 | this.format.LeftIndent = srcFormat.LeftIndent; 395 | this.format.HangingPunctuation = srcFormat.HangingPunctuation; 396 | this.format.LineRuleBefore = srcFormat.LineRuleBefore; 397 | this.format.LineRuleAfter = srcFormat.LineRuleAfter; 398 | //Spacing 399 | this.format.SpaceBefore = srcFormat.SpaceBefore; 400 | this.format.SpaceAfter = srcFormat.SpaceAfter; 401 | this.format.SpaceWithin = srcFormat.SpaceWithin; 402 | } 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/Paragraph.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using PowerPoint = NetOffice.PowerPointApi; 7 | 8 | namespace OfficeScript.Report 9 | { 10 | public class Paragraph 11 | { 12 | private PowerPoint.Shape shape; 13 | private int start; 14 | private int length; 15 | 16 | public Paragraph(PowerPoint.Shape shape, Dictionary parameters) 17 | { 18 | this.shape = shape; 19 | object tmp; 20 | if (parameters.TryGetValue("start", out tmp)) 21 | { 22 | this.start = (int)tmp; 23 | } 24 | else 25 | { 26 | this.start = -1; 27 | } 28 | if (parameters.TryGetValue("length", out tmp)) 29 | { 30 | this.length = (int)tmp; 31 | } 32 | else 33 | { 34 | this.length = -1; 35 | } 36 | 37 | 38 | } 39 | 40 | /// 41 | /// Retuns an object with async functions for node.js 42 | /// 43 | /// 44 | public object Invoke() 45 | { 46 | return new 47 | { 48 | attr = (Func>)( 49 | async (input) => 50 | { 51 | if (input is string) 52 | { 53 | var tmp = new Dictionary(); 54 | tmp.Add("name", input); 55 | input = tmp; 56 | } 57 | return Util.Attr(this, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value), Invoke); 58 | }), 59 | remove = (Func>)( 60 | async (input) => 61 | { 62 | this.Remove(); 63 | return null; 64 | }), 65 | format = (Func>)( 66 | async (input) => 67 | { 68 | return new Format(this).Invoke(); 69 | }), 70 | font = (Func>)( 71 | async (input) => 72 | { 73 | return new Font(this, this.Invoke).Invoke(); 74 | }) 75 | }; 76 | } 77 | 78 | /// 79 | /// 80 | /// 81 | private void Remove() 82 | { 83 | this.shape.TextFrame.TextRange.Paragraphs(this.start, this.length).Delete(); 84 | } 85 | 86 | /// 87 | /// Get or Set the Text-Property for this element. 88 | /// 89 | public string Text 90 | { 91 | get 92 | { 93 | return this.shape.TextFrame.TextRange.Paragraphs(this.start, this.length).Text.TrimEnd(); 94 | } 95 | set 96 | { 97 | string text = value; 98 | int i; 99 | 100 | for (i = this.shape.TextFrame.TextRange.Paragraphs().Count; i < this.start; i++) 101 | { 102 | this.shape.TextFrame.TextRange.Paragraphs(this.shape.TextFrame.TextRange.Paragraphs().Count).InsertAfter(Environment.NewLine); 103 | } 104 | 105 | //if (this.shape.TextFrame.TextRange.Paragraphs().Count < this.start) 106 | //{ 107 | //text = Environment.NewLine + text; 108 | //} 109 | this.shape.TextFrame.TextRange.Paragraphs(this.start, this.length).Text = text; 110 | } 111 | } 112 | /// 113 | /// 114 | /// 115 | public int Count 116 | { 117 | get 118 | { 119 | return this.shape.TextFrame.TextRange.Paragraphs(this.start, this.length).Lines().Count; 120 | } 121 | } 122 | 123 | /// 124 | /// 125 | /// 126 | /// 127 | public NetOffice.OfficeApi.TextRange2 GetUnderlyingObject() 128 | { 129 | return this.shape.TextFrame2.TextRange.Paragraphs(this.start, this.length); 130 | } 131 | 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/PowerPointTags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using PowerPoint = NetOffice.PowerPointApi; 7 | 8 | namespace OfficeScript.Report 9 | { 10 | public class PowerPointTags 11 | { 12 | private dynamic element; 13 | 14 | public PowerPointTags(PowerPoint.Presentation presentation) 15 | { 16 | this.element = presentation; 17 | } 18 | 19 | public PowerPointTags(PowerPoint.Slide slide) 20 | { 21 | this.element = slide; 22 | } 23 | 24 | public PowerPointTags(PowerPoint.Shape shape) 25 | { 26 | this.element = shape; 27 | } 28 | 29 | /// 30 | /// Retuns an object with async functions for node.js 31 | /// 32 | /// 33 | public object Invoke() 34 | { 35 | return new 36 | { 37 | get = (Func>)( 38 | async (input) => 39 | { 40 | return this.Get((string)input); 41 | }), 42 | set = (Func>)( 43 | async (input) => 44 | { 45 | this.Set((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 46 | return this.Invoke(); 47 | }), 48 | remove = (Func>)( 49 | async (input) => 50 | { 51 | this.Delete((string)input); 52 | return this.Invoke(); 53 | }), 54 | all = (Func>)( 55 | async (input) => 56 | { 57 | return this.GetAll(); 58 | }) 59 | }; 60 | } 61 | 62 | public string Get(string name) 63 | { 64 | return this.element.Tags[name]; 65 | } 66 | 67 | public Dictionary GetAll() 68 | { 69 | var tags = new Dictionary(); 70 | for (int i = 1; i <= this.element.Tags.Count; i++) 71 | { 72 | tags.Add(this.element.Tags.Name(i), this.element.Tags.Value(i)); 73 | } 74 | return tags; 75 | } 76 | 77 | public void Set(Dictionary parameters) 78 | { 79 | this.Set((string)parameters["name"], (string)parameters["value"]); 80 | } 81 | 82 | public void Set(string name, object value) 83 | { 84 | this.Delete(name); //Used tags need to be deleted befor set new 85 | this.element.Tags.Add(name, value.ToString()); 86 | } 87 | 88 | public void Delete(string name) 89 | { 90 | this.element.Tags.Delete(name); 91 | } 92 | 93 | //public void Clone(PowerPointTags dest) 94 | //{ 95 | // for (int i = 1; i <= this.element.Tags.Count; i++) 96 | // { 97 | // dest.Set(this.element.Tags.Name(i), this.element.Tags.Value(i)); 98 | // } 99 | //} 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/Presentation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using PowerPoint = NetOffice.PowerPointApi; 6 | using NetOffice.OfficeApi.Enums; 7 | 8 | 9 | namespace OfficeScript.Report 10 | { 11 | public class Presentation : IDisposable 12 | { 13 | private bool disposed; 14 | private PowerPoint.Presentation presentation; 15 | private const OfficeScriptType officeScriptType = OfficeScriptType.Presentation; 16 | private bool closePresentation = true; 17 | private PowerPointTags tags; 18 | private DocumentProperty properties; 19 | public Presentation(PowerPoint.Presentation presentation) 20 | { 21 | this.presentation = presentation; 22 | this.tags = new PowerPointTags(this.presentation); 23 | this.properties = new DocumentProperty(this.presentation); 24 | } 25 | 26 | // Destruktor 27 | ~Presentation() 28 | { 29 | Dispose(false); 30 | } 31 | 32 | #region Dispose 33 | 34 | // Implement IDisposable. 35 | // Do not make this method virtual. 36 | // A derived class should not be able to override this method. 37 | public void Dispose() 38 | { 39 | Dispose(true); 40 | // This object will be cleaned up by the Dispose method. 41 | // Therefore, you should call GC.SupressFinalize to 42 | // take this object off the finalization queue 43 | // and prevent finalization code for this object 44 | // from executing a second time. 45 | GC.SuppressFinalize(this); 46 | } 47 | // Dispose(bool disposing) executes in two distinct scenarios. 48 | // If disposing equals true, the method has been called directly 49 | // or indirectly by a user's code. Managed and unmanaged resources 50 | // can be disposed. 51 | // If disposing equals false, the method has been called by the 52 | // runtime from inside the finalizer and you should not reference 53 | // other objects. Only unmanaged resources can be disposed. 54 | protected virtual void Dispose(bool disposing) 55 | { 56 | // Check to see if Dispose has already been called. 57 | if (!this.disposed) 58 | { 59 | // If disposing equals true, dispose all managed 60 | // and unmanaged resources. 61 | if (disposing) 62 | { 63 | if (this.closePresentation) 64 | { 65 | this.presentation.Saved = MsoTriState.msoTrue; 66 | this.presentation.Close(); 67 | } 68 | this.presentation.Dispose(); 69 | 70 | } 71 | 72 | // Note disposing has been done. 73 | this.disposed = true; 74 | 75 | } 76 | } 77 | #endregion Dispose 78 | 79 | /// 80 | /// Retuns an object with async functions for node.js 81 | /// 82 | /// 83 | public object Invoke() 84 | { 85 | return new 86 | { 87 | attr = (Func>)( 88 | async (input) => 89 | { 90 | if (input is string) 91 | { 92 | var tmp = new Dictionary(); 93 | tmp.Add("name", input); 94 | input = tmp; 95 | } 96 | return Util.Attr(this, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value), Invoke); 97 | }), 98 | tags = (Func>)( 99 | async (input) => 100 | { 101 | return this.tags.Invoke(); 102 | }), 103 | properties = (Func>)( 104 | async (input) => 105 | { 106 | return this.properties.Invoke(); 107 | }), 108 | save = (Func>)( 109 | async (input) => 110 | { 111 | this.Save(); 112 | return null; 113 | } 114 | ), 115 | saveAs = (Func>)( 116 | async (input) => 117 | { 118 | if (input is string) 119 | { 120 | var tmp = new Dictionary(); 121 | tmp.Add("name", input); 122 | input = tmp; 123 | } 124 | this.SaveAs((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 125 | return null; 126 | } 127 | ), 128 | saveAsCopy = (Func>)( 129 | async (input) => 130 | { 131 | if (input is string) 132 | { 133 | var tmp = new Dictionary(); 134 | tmp.Add("name", input); 135 | input = tmp; 136 | } 137 | this.SaveAsCopy((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 138 | return null; 139 | } 140 | ), 141 | close = (Func>)( 142 | async (input) => 143 | { 144 | this.Dispose(); 145 | return null; 146 | } 147 | ), 148 | slides = (Func>)( 149 | async (input) => 150 | { 151 | input = (input == null) ? new Dictionary() : input; 152 | return this.Slides((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 153 | } 154 | ), 155 | addSlide = (Func>)( 156 | async (input) => 157 | { 158 | if (input is string) 159 | { 160 | var tmp = new Dictionary(); 161 | tmp.Add("name", input); 162 | input = tmp; 163 | } 164 | if (input is int) 165 | { 166 | var tmp = new Dictionary(); 167 | tmp.Add("pos", input); 168 | input = tmp; 169 | } 170 | input = (input == null) ? new Dictionary() : input; 171 | return this.AddSlide((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 172 | } 173 | ), 174 | textReplace = (Func>)( 175 | async (input) => 176 | { 177 | this.TextReplace((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 178 | return this.Invoke(); 179 | } 180 | ), 181 | getSelectedShape = (Func>)( 182 | async (input) => 183 | { 184 | return this.GetSelectedShape(); 185 | } 186 | ), 187 | getActiveSlide = (Func>)( 188 | async (input) => 189 | { 190 | return this.GetActiveSlide(); 191 | } 192 | ), 193 | pasteSlide = (Func>)( 194 | async (input) => 195 | { 196 | 197 | return this.PasteSlide((int)input); 198 | }), 199 | dispose = (Func>)( 200 | async (input) => 201 | { 202 | this.presentation.Dispose(); 203 | return null; 204 | }), 205 | getType = (Func>)( 206 | async (input) => 207 | { 208 | return officeScriptType; 209 | } 210 | ) 211 | }; 212 | } 213 | 214 | 215 | #region Save 216 | private void Save() 217 | { 218 | this.presentation.Save(); 219 | } 220 | 221 | private void SaveAs(IDictionary parameters) 222 | { 223 | string name = (string)(parameters as IDictionary)["name"]; 224 | string type = "pptx"; 225 | object tmp; 226 | if (parameters.TryGetValue("type", out tmp)) 227 | { 228 | type = (string)tmp; 229 | } 230 | this.SaveAs(name, type); 231 | } 232 | 233 | 234 | private void SaveAs(string fileName, string fileType) 235 | { 236 | this.SaveAs(fileName, fileType, false); 237 | } 238 | 239 | private void SaveAsCopy(IDictionary parameters) 240 | { 241 | string name = (string)(parameters as IDictionary)["name"]; 242 | string type = "pptx"; 243 | object tmp; 244 | if (parameters.TryGetValue("type", out tmp)) 245 | { 246 | type = (string)tmp; 247 | } 248 | this.SaveAs(name, type, true); 249 | } 250 | 251 | private void SaveAsCopy(string fileName, string fileType) 252 | { 253 | this.SaveAs(fileName, fileType, true); 254 | } 255 | 256 | private void SaveAs(string fileName, string fileType, bool isCopy) 257 | { 258 | PowerPoint.Enums.PpSaveAsFileType pptFileType; 259 | switch (fileType.ToLower()) 260 | { 261 | case "pdf": 262 | pptFileType = PowerPoint.Enums.PpSaveAsFileType.ppSaveAsPDF; 263 | break; 264 | case "pptx": 265 | pptFileType = PowerPoint.Enums.PpSaveAsFileType.ppSaveAsOpenXMLPresentation; 266 | break; 267 | case "ppt": 268 | pptFileType = PowerPoint.Enums.PpSaveAsFileType.ppSaveAsPresentation; 269 | break; 270 | case "png": 271 | pptFileType = PowerPoint.Enums.PpSaveAsFileType.ppSaveAsPNG; 272 | break; 273 | default: 274 | pptFileType = PowerPoint.Enums.PpSaveAsFileType.ppSaveAsOpenXMLPresentation; 275 | break; 276 | } 277 | if (isCopy) 278 | { 279 | this.presentation.SaveCopyAs(fileName, pptFileType); 280 | } 281 | else 282 | { 283 | this.presentation.SaveAs(fileName, pptFileType); 284 | } 285 | } 286 | #endregion save 287 | 288 | /// 289 | /// Add a new Slide 290 | /// 291 | /// 292 | /// 293 | private object AddSlide(Dictionary parameters) 294 | { 295 | var pos = this.presentation.Slides.Count + 1; 296 | var layout = NetOffice.PowerPointApi.Enums.PpSlideLayout.ppLayoutBlank; 297 | object tmpObject; 298 | int tmpInt; 299 | 300 | if (parameters.TryGetValue("pos", out tmpObject)) 301 | { 302 | if (int.TryParse(tmpObject.ToString(), out tmpInt)) 303 | { 304 | pos = tmpInt; 305 | } 306 | } 307 | if (parameters.TryGetValue("layout", out tmpObject)) 308 | { 309 | switch(tmpObject.ToString().ToLower()) 310 | { 311 | case "blank": 312 | layout = NetOffice.PowerPointApi.Enums.PpSlideLayout.ppLayoutBlank; 313 | break; 314 | case "chart": 315 | layout = NetOffice.PowerPointApi.Enums.PpSlideLayout.ppLayoutChart; 316 | break; 317 | case "text": 318 | layout = NetOffice.PowerPointApi.Enums.PpSlideLayout.ppLayoutText; 319 | break; 320 | case "chartandtext": 321 | layout = NetOffice.PowerPointApi.Enums.PpSlideLayout.ppLayoutChartAndText; 322 | break; 323 | case "custom": 324 | layout = NetOffice.PowerPointApi.Enums.PpSlideLayout.ppLayoutCustom; 325 | break; 326 | } 327 | } 328 | 329 | return new Slide(this.presentation.Slides.Add(pos, layout)).Invoke(); 330 | } 331 | 332 | /// 333 | /// Find and replace in presentation 334 | /// 335 | /// 336 | private void TextReplace(Dictionary parameters) 337 | { 338 | string find = null; 339 | string replace = null; 340 | Dictionary replaces = null; 341 | Dictionary newReplaces = null; 342 | object tmp; 343 | 344 | if (parameters.TryGetValue("find", out tmp)) 345 | { 346 | find = (string)tmp; 347 | } 348 | if (parameters.TryGetValue("replace", out tmp)) 349 | { 350 | replace = (string)tmp; 351 | } 352 | 353 | if (parameters.TryGetValue("batch", out tmp)) 354 | { 355 | replaces = (tmp as IDictionary).ToDictionary(d => d.Key, d => d.Value); 356 | newReplaces = new Dictionary(); 357 | // repalce in Array 358 | foreach(var i in replaces) 359 | { 360 | var newValue = i.Value.ToString(); 361 | foreach(var j in replaces) 362 | { 363 | newValue = newValue.Replace(j.Key, j.Value.ToString()); 364 | } 365 | newReplaces.Add(i.Key, newValue); 366 | } 367 | } 368 | 369 | if(find != null && replace != null){ 370 | BatchTextReplace(new Dictionary() {{find, replace }}); 371 | } 372 | if(newReplaces != null){ 373 | BatchTextReplace(newReplaces); 374 | } 375 | } 376 | 377 | /// 378 | /// Mass Find and replace in presentation 379 | /// 380 | private void BatchTextReplace(Dictionary replaces) 381 | { 382 | foreach (PowerPoint.Slide slide in this.presentation.Slides) 383 | { 384 | foreach(PowerPoint.Shape shape in slide.Shapes) 385 | { 386 | if(shape.HasTextFrame == MsoTriState.msoTrue || shape.HasTable == MsoTriState.msoTrue) 387 | { 388 | //for textboxes 389 | if (shape.HasTextFrame == MsoTriState.msoTrue) 390 | { 391 | Util.ShapeTextReplace(shape.TextFrame.TextRange, replaces); 392 | } 393 | //for Tables 394 | else if (shape.HasTable == MsoTriState.msoTrue) 395 | { 396 | foreach (PowerPoint.Row row in shape.Table.Rows) 397 | { 398 | foreach (PowerPoint.Cell cell in row.Cells) 399 | { 400 | if (cell.Shape.HasTextFrame == MsoTriState.msoTrue) 401 | { 402 | Util.ShapeTextReplace(cell.Shape.TextFrame.TextRange, replaces); 403 | } 404 | } 405 | } 406 | } 407 | } 408 | } 409 | } 410 | } 411 | 412 | /// 413 | /// Init slide Array 414 | /// 415 | /// 416 | private object Slides(IDictionary filter) 417 | { 418 | List slides = new List(); 419 | 420 | foreach (PowerPoint.Slide pptSlide in this.presentation.Slides) 421 | { 422 | 423 | var slide = new Slide(pptSlide); 424 | if (slide.TestFilter(filter)) 425 | { 426 | slides.Add(slide.Invoke()); 427 | } 428 | 429 | } 430 | 431 | return slides.ToArray(); 432 | } 433 | 434 | private object PasteSlide(int index) 435 | { 436 | return new Slide(this.presentation.Slides.Paste(index).FirstOrDefault()).Invoke(); 437 | } 438 | 439 | private object GetSelectedShape() 440 | { 441 | var selection = this.presentation.Application.ActiveWindow.Selection; 442 | if (selection.Type == PowerPoint.Enums.PpSelectionType.ppSelectionShapes) 443 | { 444 | return new Shape(selection.ShapeRange[1]).Invoke(); 445 | } 446 | return null; 447 | } 448 | 449 | private object GetActiveSlide() 450 | { 451 | // Test if PowerPoint Presentation mode is currently running 452 | if (IsInSlideShowMode()){ 453 | return new Slide(this.presentation.Application.SlideShowWindows[1].View.Slide).Invoke(); 454 | } 455 | else { 456 | return new Slide(this.presentation.Application.ActiveWindow.Selection.SlideRange[1]).Invoke(); 457 | } 458 | } 459 | 460 | /// 461 | /// Check if presentation in presentation mode 462 | /// 463 | private bool IsInSlideShowMode() { 464 | return (this.presentation.Application.SlideShowWindows.Count > 0); 465 | } 466 | 467 | /// 468 | /// 469 | /// 470 | public PowerPoint.Presentation GetUnderlyingObject() 471 | { 472 | return this.presentation; 473 | } 474 | 475 | #region Properties 476 | 477 | public string Name 478 | { 479 | get 480 | { 481 | return this.presentation.Name; 482 | } 483 | } 484 | public string Path 485 | { 486 | get 487 | { 488 | return this.presentation.Path; 489 | } 490 | } 491 | public string FullName 492 | { 493 | get 494 | { 495 | return this.presentation.FullName; 496 | } 497 | } 498 | 499 | public float SlideHeight 500 | { 501 | get 502 | { 503 | return this.presentation.PageSetup.SlideHeight; 504 | } 505 | } 506 | 507 | public float SlideWidth 508 | { 509 | get 510 | { 511 | return this.presentation.PageSetup.SlideWidth; 512 | } 513 | } 514 | #endregion 515 | } 516 | } 517 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/Shape.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Drawing; 7 | using NetOffice.OfficeApi.Enums; 8 | using PowerPoint = NetOffice.PowerPointApi; 9 | 10 | namespace OfficeScript.Report 11 | { 12 | class Shape 13 | { 14 | private PowerPoint.Shape shape; 15 | private const OfficeScriptType officeScriptType = OfficeScriptType.Shape; 16 | private PowerPointTags tags; 17 | 18 | public Shape(PowerPoint.Shape shape) 19 | { 20 | this.shape = shape; 21 | this.tags = new PowerPointTags(this.shape); 22 | } 23 | 24 | /// 25 | /// Retuns an object with async functions for node.js 26 | /// 27 | /// 28 | public object Invoke() 29 | { 30 | return new 31 | { 32 | attr = (Func>)( 33 | async (input) => 34 | { 35 | if (input is string) 36 | { 37 | var tmp = new Dictionary(); 38 | tmp.Add("name", input); 39 | input = tmp; 40 | } 41 | return Util.Attr(this, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value), Invoke); 42 | }), 43 | tags = (Func>)( 44 | async (input) => 45 | { 46 | return this.tags.Invoke(); 47 | }), 48 | remove = (Func>)( 49 | async (input) => 50 | { 51 | this.Remove(); 52 | return null; 53 | }), 54 | duplicate = (Func>)( 55 | async (input) => 56 | { 57 | return this.Duplicate(); 58 | }), 59 | copy = (Func>)( 60 | async (input) => 61 | { 62 | this.Copy(); 63 | return null; 64 | }), 65 | paragraph = (Func>)( 66 | async (input) => 67 | { 68 | input = (input == null) ? new Dictionary() : input; 69 | return new Paragraph(this.shape, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value)).Invoke(); 70 | }), 71 | character = (Func>)( 72 | async (input) => 73 | { 74 | input = (input == null) ? new Dictionary() : input; 75 | return new Character(this.shape, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value)).Invoke(); 76 | }), 77 | textReplace = (Func>)( 78 | async (input) => 79 | { 80 | this.TextReplace((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 81 | return this.Invoke(); 82 | }), 83 | exportAs = (Func>)( 84 | async (input) => 85 | { 86 | if (input is string) 87 | { 88 | var tmp = new Dictionary(); 89 | tmp.Add("path", input); 90 | input = tmp; 91 | } 92 | ExportAs((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 93 | return null; 94 | }), 95 | hasObject = (Func>)( 96 | async (input) => 97 | { 98 | return this.HasObject((string)input); 99 | }), 100 | getZindex = (Func>)( 101 | async (input) => 102 | { 103 | return this.GetZindex(); 104 | }), 105 | setZindex = (Func>)( 106 | async (input) => 107 | { 108 | this.SetZindex((string)input); 109 | return this.Invoke(); 110 | }), 111 | dispose = (Func>)( 112 | async (input) => 113 | { 114 | this.shape.Dispose(); 115 | return null; 116 | }), 117 | getType = (Func>)( 118 | async (input) => 119 | { 120 | return officeScriptType; 121 | }) 122 | 123 | }; 124 | } 125 | 126 | /// 127 | /// Duplicate this Shape 128 | /// 129 | /// Shape 130 | private object Duplicate() 131 | { 132 | return new Shape(this.shape.Duplicate()[1]).Invoke(); 133 | } 134 | 135 | /// 136 | /// Copy this Shape 137 | /// 138 | /// Shape 139 | private void Copy() 140 | { 141 | this.shape.Copy(); 142 | } 143 | 144 | /// 145 | /// Deletes the Shape 146 | /// 147 | private void Remove() 148 | { 149 | this.shape.Delete(); 150 | this.shape.Dispose(); 151 | } 152 | 153 | /// 154 | /// Search and replace 155 | /// 156 | /// 157 | private void TextReplace(Dictionary parameters) 158 | { 159 | string find = null; 160 | string replace = null; 161 | object tmp; 162 | 163 | 164 | if (parameters.TryGetValue("find", out tmp)) 165 | { 166 | find = (string)tmp; 167 | } 168 | if (parameters.TryGetValue("replace", out tmp)) 169 | { 170 | replace = (string)tmp; 171 | } 172 | 173 | if(find != null && replace != null){ 174 | TextReplace(find, replace); 175 | } 176 | } 177 | 178 | /// 179 | /// Use PPT buildin search and replace function 180 | /// 181 | private void TextReplace(string find, string replace) 182 | { 183 | //for textboxes 184 | if (this.shape.HasTextFrame == MsoTriState.msoTrue) 185 | { 186 | this.shape.TextFrame.TextRange.Replace(find, replace); 187 | } 188 | //for Tables 189 | else if (this.shape.HasTable == MsoTriState.msoTrue) 190 | { 191 | foreach (PowerPoint.Row row in this.shape.Table.Rows) 192 | { 193 | foreach (PowerPoint.Cell cell in row.Cells) 194 | { 195 | if (cell.Shape.HasTextFrame == MsoTriState.msoTrue) 196 | { 197 | cell.Shape.TextFrame.TextRange.Replace(find, replace); 198 | } 199 | } 200 | } 201 | } 202 | } 203 | 204 | /// 205 | /// Export shape as picture 206 | /// 207 | /// 208 | private void ExportAs(IDictionary parameters) 209 | { 210 | string path = (string)parameters["path"]; 211 | string type = "png"; 212 | // float heigth = 542; 213 | // float width = 722; 214 | // float scale = 2; 215 | float heigth = this.shape.Height; 216 | float width = this.shape.Width; 217 | float scale = 1; 218 | 219 | object tmp; 220 | 221 | PowerPoint.Enums.PpShapeFormat ppShapeFormat = PowerPoint.Enums.PpShapeFormat.ppShapeFormatPNG; 222 | 223 | if (parameters.TryGetValue("type", out tmp)) 224 | { 225 | type = (string)tmp; 226 | } 227 | if (parameters.TryGetValue("heigth", out tmp)) 228 | { 229 | heigth = (float)tmp; 230 | } 231 | if (parameters.TryGetValue("width", out tmp)) 232 | { 233 | width = (float)tmp; 234 | } 235 | if (parameters.TryGetValue("scale", out tmp)) 236 | { 237 | scale = (float)tmp; 238 | } 239 | //couse 240 | switch (type.ToLower()) 241 | { 242 | case "png": 243 | ppShapeFormat = PowerPoint.Enums.PpShapeFormat.ppShapeFormatPNG; 244 | break; 245 | case "wmf": 246 | ppShapeFormat = PowerPoint.Enums.PpShapeFormat.ppShapeFormatWMF; 247 | break; 248 | case "bmp": 249 | ppShapeFormat = PowerPoint.Enums.PpShapeFormat.ppShapeFormatBMP; 250 | break; 251 | case "gif": 252 | ppShapeFormat = PowerPoint.Enums.PpShapeFormat.ppShapeFormatGIF; 253 | break; 254 | case "jpg": 255 | ppShapeFormat = PowerPoint.Enums.PpShapeFormat.ppShapeFormatJPG; 256 | break; 257 | case "emf": 258 | ppShapeFormat = PowerPoint.Enums.PpShapeFormat.ppShapeFormatEMF; 259 | break; 260 | default: 261 | ppShapeFormat = PowerPoint.Enums.PpShapeFormat.ppShapeFormatPNG; 262 | break; 263 | } 264 | this.shape.Export(path, ppShapeFormat, width * scale, heigth * scale, PowerPoint.Enums.PpExportMode.ppRelativeToSlide); 265 | } 266 | 267 | /// 268 | /// 269 | /// 270 | /// 271 | /// 272 | private bool HasObject(string name) 273 | { 274 | switch(name.ToLower()) 275 | { 276 | case "chart": 277 | return (this.shape.HasChart == MsoTriState.msoTrue); 278 | case "diagram": 279 | return (this.shape.HasDiagram == MsoTriState.msoTrue); 280 | case "table": 281 | return (this.shape.HasTable == MsoTriState.msoTrue); 282 | case "img": 283 | case "image": 284 | case "picture": 285 | return (this.shape.Type == MsoShapeType.msoPicture); 286 | case "text": 287 | case "textframe": 288 | return (this.shape.HasTextFrame == MsoTriState.msoTrue); 289 | default: 290 | return false; 291 | } 292 | } 293 | 294 | /// 295 | /// Test if the given Filter matches the shape. Filter can be Tags or Properties. 296 | /// eg: {"tag:mytag", "Some Value", "attr:Name", "Shape Name"} 297 | /// 298 | /// 299 | /// 300 | internal bool TestFilter(IDictionary filter) 301 | { 302 | 303 | //No filter, select all 304 | if (filter.Keys.Count == 0) 305 | { 306 | return true; 307 | } 308 | string typeIdentifier; 309 | 310 | //Test Tag selectors 311 | typeIdentifier = "tag:"; 312 | foreach (string key in filter.Keys.Where(w => w.StartsWith(typeIdentifier)).ToArray()) 313 | { 314 | string tagName = key.Substring(typeIdentifier.Length); 315 | string tagValue = this.tags.Get(tagName); 316 | string[] values = filter[key].ToString().Split(','); 317 | for (int i = 0; i < values.Length; i++) 318 | { 319 | string val = values[i].Trim(); 320 | if (tagValue == val) 321 | { 322 | return true; 323 | } 324 | } 325 | } 326 | 327 | //Test Attr selectors 328 | typeIdentifier = "attr:"; 329 | foreach (string key in filter.Keys.Where(w => w.StartsWith(typeIdentifier)).ToArray()) 330 | { 331 | string attrName = key.Substring(typeIdentifier.Length); 332 | string attrValue = this.GetType().GetProperty(attrName).GetValue(this, null).ToString(); 333 | string[] values = filter[key].ToString().Split(','); 334 | for (int i = 0; i < values.Length; i++) 335 | { 336 | string val = values[i].Trim(); 337 | if (attrValue == val) 338 | { 339 | return true; 340 | } 341 | } 342 | } 343 | return false; 344 | } 345 | 346 | /// 347 | /// 348 | /// 349 | internal PowerPoint.Shape GetUnderlyingObject() 350 | { 351 | return this.shape; 352 | } 353 | 354 | /// 355 | /// 356 | /// 357 | internal PowerPointTags GetTags() 358 | { 359 | return new PowerPointTags(this.shape); 360 | } 361 | 362 | public void SetZindex(string order) 363 | { 364 | switch (order.ToLower()) 365 | { 366 | case "forward": 367 | this.shape.ZOrder(MsoZOrderCmd.msoBringForward); 368 | break; 369 | case "backward": 370 | this.shape.ZOrder(MsoZOrderCmd.msoSendBackward); 371 | break; 372 | case "front": 373 | this.shape.ZOrder(MsoZOrderCmd.msoBringToFront); 374 | break; 375 | case "back": 376 | this.shape.ZOrder(MsoZOrderCmd.msoSendBackward); 377 | break; 378 | case "beforetext": 379 | this.shape.ZOrder(MsoZOrderCmd.msoBringInFrontOfText); 380 | break; 381 | case "behindtext": 382 | this.shape.ZOrder(MsoZOrderCmd.msoSendBehindText); 383 | break; 384 | } 385 | } 386 | 387 | public int GetZindex() 388 | { 389 | return this.shape.ZOrderPosition; 390 | } 391 | 392 | #region Properties 393 | 394 | public string Name 395 | { 396 | get 397 | { 398 | return this.shape.Name; 399 | } 400 | set 401 | { 402 | this.shape.Name = value; 403 | } 404 | } 405 | public string Text 406 | { 407 | get 408 | { 409 | if(this.shape.HasTextFrame == MsoTriState.msoTrue) 410 | { 411 | return this.shape.TextFrame.TextRange.Text; 412 | } else 413 | { 414 | return null; 415 | } 416 | } 417 | set 418 | { 419 | if (this.shape.HasTextFrame == MsoTriState.msoTrue) 420 | { 421 | this.shape.TextFrame.TextRange.Text = value; 422 | } 423 | } 424 | } 425 | 426 | /// 427 | /// Get or Set the Top-Property for this element. 428 | /// 429 | public double Top 430 | { 431 | get 432 | { 433 | return this.shape.Top; 434 | } 435 | set 436 | { 437 | this.shape.Top = (float)value; 438 | } 439 | } 440 | 441 | /// 442 | /// Get or Set the Left-Property for this element. 443 | /// 444 | public double Left 445 | { 446 | get 447 | { 448 | return this.shape.Left; 449 | } 450 | set 451 | { 452 | this.shape.Left = (float)value; 453 | } 454 | } 455 | /// 456 | /// Get or Set the Height-Property for this element. 457 | /// 458 | public double Height 459 | { 460 | get 461 | { 462 | return this.shape.Height; 463 | } 464 | set 465 | { 466 | this.shape.Height = (float)value; 467 | } 468 | } 469 | /// 470 | /// Get or Set the Width-Property for this element. 471 | /// 472 | public double Width 473 | { 474 | get 475 | { 476 | return this.shape.Width; 477 | } 478 | set 479 | { 480 | this.shape.Width = (float)value; 481 | } 482 | } 483 | /// 484 | /// Get or Set the Rotation-Property for this element. 485 | /// 486 | public double Rotation 487 | { 488 | get 489 | { 490 | return this.shape.Rotation; 491 | } 492 | set 493 | { 494 | this.shape.Rotation = (float)value; 495 | } 496 | } 497 | 498 | /// 499 | /// Get or Set the Fill-Property for this element. 500 | /// 501 | public string Fill 502 | { 503 | get 504 | { 505 | string bgr = "#" + this.shape.Fill.ForeColor.RGB.ToString("x6"); 506 | return Util.BGRtoRGB(bgr); 507 | } 508 | set 509 | { 510 | this.shape.Fill.ForeColor.RGB = ColorTranslator.FromHtml(Util.BGRtoRGB(value)).ToArgb(); 511 | } 512 | } 513 | 514 | /// 515 | /// Get or Set the Alt-Text for this element. 516 | /// 517 | public string AltText 518 | { 519 | get 520 | { 521 | return this.shape.AlternativeText; 522 | } 523 | set 524 | { 525 | this.shape.AlternativeText = value; 526 | } 527 | } 528 | 529 | /// 530 | /// Get or Set the Alt-Text for this element. 531 | /// 532 | public string Title 533 | { 534 | get 535 | { 536 | return this.shape.Title; 537 | } 538 | set 539 | { 540 | this.shape.Title = value; 541 | } 542 | } 543 | 544 | /// 545 | /// Get or Set the Top-Property for this element. 546 | /// 547 | public string Type 548 | { 549 | get 550 | { 551 | return this.shape.Type.ToString(); 552 | }set 553 | { 554 | // do nothing :) 555 | } 556 | } 557 | 558 | // public Dictionary Table 559 | public object[] Table 560 | { 561 | get 562 | { 563 | object[] returnTable = null; 564 | int rowCount, columnCount; 565 | if (this.shape.HasTable == MsoTriState.msoTrue) 566 | { 567 | returnTable = new object[shape.Table.Rows.Count]; 568 | 569 | rowCount = 0; 570 | foreach (PowerPoint.Row row in shape.Table.Rows) 571 | { 572 | object[] cells = new object[shape.Table.Columns.Count]; 573 | columnCount = 0; 574 | foreach (PowerPoint.Cell cell in row.Cells) 575 | { 576 | cells[columnCount++] = new Shape(cell.Shape).Invoke(); 577 | // cells[columnCount++] = (cell.Shape.HasTextFrame == MsoTriState.msoTrue) ? cell.Shape.TextFrame.TextRange.Text : null; 578 | } 579 | returnTable[rowCount++] = cells; 580 | 581 | } 582 | } 583 | return returnTable; 584 | } 585 | } 586 | 587 | 588 | #endregion Properties 589 | } 590 | } 591 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/Slide.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using PowerPoint = NetOffice.PowerPointApi; 6 | using NetOffice.OfficeApi.Enums; 7 | 8 | namespace OfficeScript.Report 9 | { 10 | class Slide 11 | { 12 | private PowerPoint.Slide slide; 13 | private const OfficeScriptType officeScriptType = OfficeScriptType.Slide; 14 | private PowerPointTags tags; 15 | 16 | public Slide(PowerPoint.Slide slide) 17 | { 18 | this.slide = slide; 19 | this.tags = new PowerPointTags(this.slide); 20 | } 21 | 22 | /// 23 | /// Retuns an object with async functions for node.js 24 | /// 25 | /// 26 | public object Invoke() 27 | { 28 | return new 29 | { 30 | attr = (Func>)( 31 | async (input) => 32 | { 33 | if (input is string) 34 | { 35 | var tmp = new Dictionary(); 36 | tmp.Add("name", input); 37 | input = tmp; 38 | } 39 | return Util.Attr(this, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value), Invoke); 40 | }), 41 | tags = (Func>)( 42 | async (input) => 43 | { 44 | return this.tags.Invoke(); 45 | }), 46 | remove = (Func>)( 47 | async (input) => 48 | { 49 | this.Remove(); 50 | return null; 51 | }), 52 | duplicate = (Func>)( 53 | async (input) => 54 | { 55 | return this.Duplicate(); 56 | }), 57 | copy = (Func>)( 58 | async (input) => 59 | { 60 | this.Copy(); 61 | return new Slide(this.slide).Invoke(); 62 | }), 63 | select = (Func>)( 64 | async (input) => 65 | { 66 | this.slide.Select(); 67 | return new Slide(this.slide).Invoke(); 68 | }), 69 | shapes = (Func>)( 70 | async (input) => 71 | { 72 | if (input is string) 73 | { 74 | var tmp = new Dictionary(); 75 | tmp.Add("tag:ctobjectdata.id", input); //remove 76 | input = tmp; 77 | } 78 | input = (input == null) ? new Dictionary() : input; 79 | return this.Shapes((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 80 | }), 81 | addTextbox = (Func>)( 82 | async (input) => 83 | { 84 | input = (input == null) ? new Dictionary() : input; 85 | return this.AddTextbox((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 86 | }), 87 | addPicture = (Func>)( 88 | async (input) => 89 | { 90 | input = (input == null) ? new Dictionary() : input; 91 | return this.AddPicture((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 92 | }), 93 | textReplace = (Func>)( 94 | async (input) => 95 | { 96 | this.TextReplace((input as IDictionary).ToDictionary(d => d.Key, d => d.Value)); 97 | return this.Invoke(); 98 | }), 99 | pasteShape = (Func>)( 100 | async (input) => 101 | { 102 | 103 | return this.PasteShape(); 104 | }), 105 | dispose = (Func>)( 106 | async (input) => 107 | { 108 | this.slide.Dispose(); 109 | return null; 110 | }), 111 | getType = (Func>)( 112 | async (input) => 113 | { 114 | return officeScriptType; 115 | } 116 | ) 117 | }; 118 | } 119 | 120 | /// 121 | /// Init shape Array 122 | /// 123 | /// 124 | private object Shapes(IDictionary filter) 125 | { 126 | List shapes = new List(); 127 | 128 | foreach (PowerPoint.Shape pptShape in this.slide.Shapes) 129 | { 130 | var shape = new Shape(pptShape); 131 | if (shape.TestFilter(filter)) 132 | { 133 | shapes.Add(shape.Invoke()); 134 | } 135 | } 136 | 137 | return shapes.ToArray(); 138 | } 139 | 140 | 141 | /// 142 | /// Deletes the Slide 143 | /// 144 | private void Remove() 145 | { 146 | this.slide.Delete(); 147 | } 148 | 149 | /// 150 | /// Duplicate Slide, default position is Slide-Index + 1 151 | /// 152 | private object Duplicate() 153 | { 154 | return new Slide(this.slide.Duplicate()[1]).Invoke(); 155 | } 156 | 157 | /// 158 | /// Copy Slide 159 | /// 160 | private void Copy() 161 | { 162 | this.slide.Copy(); 163 | } 164 | 165 | 166 | /// 167 | /// Paste Shape in Slide 168 | /// 169 | private object PasteShape() 170 | { 171 | return new Shape(this.slide.Shapes.Paste()[1]).Invoke(); 172 | } 173 | 174 | /// 175 | /// Not yet Implemented! 176 | /// 177 | private void Sort() 178 | { 179 | throw new NotImplementedException("No sorting Algorithm implemented!"); 180 | } 181 | 182 | /// 183 | /// AddTextbox and retrun shape object 184 | /// 185 | private object AddTextbox(IDictionary parameters) 186 | { 187 | object tmpObject; 188 | float tmpFloat; 189 | 190 | var orientation = NetOffice.OfficeApi.Enums.MsoTextOrientation.msoTextOrientationHorizontal; 191 | float left = 0; 192 | float top = 0; 193 | float height = 100; 194 | float width = 100; 195 | 196 | 197 | 198 | //Try to get Shape options: OFFSCRIPT-2 199 | if (parameters.TryGetValue("left", out tmpObject)) 200 | { 201 | if (float.TryParse(tmpObject.ToString(), out tmpFloat)) 202 | { 203 | left = tmpFloat; 204 | } 205 | } 206 | if (parameters.TryGetValue("top", out tmpObject)) 207 | { 208 | if (float.TryParse(tmpObject.ToString(), out tmpFloat)) 209 | { 210 | top = tmpFloat; 211 | } 212 | } 213 | if (parameters.TryGetValue("height", out tmpObject)) 214 | { 215 | if (float.TryParse(tmpObject.ToString(), out tmpFloat)) 216 | { 217 | height = tmpFloat; 218 | } 219 | } 220 | if (parameters.TryGetValue("width", out tmpObject)) 221 | { 222 | if (float.TryParse(tmpObject.ToString(), out tmpFloat)) 223 | { 224 | width = tmpFloat; 225 | } 226 | } 227 | 228 | if (parameters.TryGetValue("texOrientation", out tmpObject)) 229 | { 230 | switch (tmpObject.ToString().ToLower()) 231 | { 232 | case "horizontal": 233 | orientation = NetOffice.OfficeApi.Enums.MsoTextOrientation.msoTextOrientationHorizontal; 234 | break; 235 | case "downward": 236 | orientation = NetOffice.OfficeApi.Enums.MsoTextOrientation.msoTextOrientationDownward; 237 | break; 238 | case "rotatedfareast": 239 | orientation = NetOffice.OfficeApi.Enums.MsoTextOrientation.msoTextOrientationHorizontalRotatedFarEast; 240 | break; 241 | case "upward": 242 | orientation = NetOffice.OfficeApi.Enums.MsoTextOrientation.msoTextOrientationUpward; 243 | break; 244 | case "vertical": 245 | orientation = NetOffice.OfficeApi.Enums.MsoTextOrientation.msoTextOrientationVertical; 246 | break; 247 | case "verticalfareast": 248 | orientation = NetOffice.OfficeApi.Enums.MsoTextOrientation.msoTextOrientationVerticalFarEast; 249 | break; 250 | case "mixed": //what is mixed?? 251 | orientation = NetOffice.OfficeApi.Enums.MsoTextOrientation.msoTextOrientationMixed; 252 | break; 253 | default: 254 | orientation = NetOffice.OfficeApi.Enums.MsoTextOrientation.msoTextOrientationHorizontal; 255 | break; 256 | } 257 | } 258 | 259 | return new Shape(this.slide.Shapes.AddTextbox(orientation, left, top, width, height)).Invoke(); 260 | } 261 | 262 | /// 263 | /// Adds an empty textbox on the given slide 264 | /// 265 | /// 266 | /// 267 | /// 268 | public object AddPicture(IDictionary parameters) 269 | { 270 | object tmpObject; 271 | float tmpFloat; 272 | 273 | float left = 0; 274 | float top = 0; 275 | String path = ""; 276 | 277 | if (parameters.TryGetValue("left", out tmpObject)) 278 | { 279 | if (float.TryParse(tmpObject.ToString(), out tmpFloat)) 280 | { 281 | left = tmpFloat; 282 | } 283 | } 284 | if (parameters.TryGetValue("top", out tmpObject)) 285 | { 286 | if (float.TryParse(tmpObject.ToString(), out tmpFloat)) 287 | { 288 | top = tmpFloat; 289 | } 290 | } 291 | if (parameters.TryGetValue("path", out tmpObject)) 292 | { 293 | path = tmpObject.ToString(); 294 | 295 | if (!System.IO.File.Exists(path)) 296 | { 297 | throw new Exception("Missing file!"); 298 | } 299 | } 300 | return new Shape(this.slide.Shapes.AddPicture(path, NetOffice.OfficeApi.Enums.MsoTriState.msoFalse, NetOffice.OfficeApi.Enums.MsoTriState.msoTrue, left, top)).Invoke(); 301 | } 302 | 303 | internal bool TestFilter(IDictionary filter) 304 | { 305 | 306 | //No filter, select all 307 | if (filter.Keys.Count == 0) 308 | { 309 | return true; 310 | } 311 | string typeIdentifier; 312 | 313 | typeIdentifier = "tag:"; 314 | 315 | foreach (string key in filter.Keys.Where(w => w.StartsWith(typeIdentifier)).ToArray()) 316 | { 317 | string tagName = key.Substring(typeIdentifier.Length); 318 | string tagValue = this.tags.Get(tagName); 319 | string[] values = filter[key].ToString().Split(','); 320 | for (int i = 0; i < values.Length; i++) 321 | { 322 | string val = values[i].Trim(); 323 | if (tagValue == val) 324 | { 325 | return true; 326 | } 327 | } 328 | } 329 | 330 | //Test Attr selectors 331 | typeIdentifier = "attr:"; 332 | foreach (string key in filter.Keys.Where(w => w.StartsWith(typeIdentifier)).ToArray()) 333 | { 334 | string attrName = key.Substring(typeIdentifier.Length); 335 | string attrValue = this.GetType().GetProperty(attrName).GetValue(this, null).ToString(); 336 | string[] values = filter[key].ToString().Split(','); 337 | for (int i = 0; i < values.Length; i++) 338 | { 339 | string val = values[i].Trim(); 340 | if (attrValue == val) 341 | { 342 | return true; 343 | } 344 | } 345 | } 346 | return false; 347 | } 348 | 349 | /// 350 | /// Find and replace in presentation 351 | /// 352 | /// 353 | private void TextReplace(Dictionary parameters) 354 | { 355 | string find = null; 356 | string replace = null; 357 | Dictionary replaces = null; 358 | Dictionary newReplaces = null; 359 | object tmp; 360 | 361 | if (parameters.TryGetValue("find", out tmp)) 362 | { 363 | find = (string)tmp; 364 | } 365 | if (parameters.TryGetValue("replace", out tmp)) 366 | { 367 | replace = (string)tmp; 368 | } 369 | 370 | if (parameters.TryGetValue("batch", out tmp)) 371 | { 372 | replaces = (tmp as IDictionary).ToDictionary(d => d.Key, d => d.Value); 373 | newReplaces = new Dictionary(); 374 | // repalce in Array 375 | foreach(var i in replaces) 376 | { 377 | var newValue = i.Value.ToString(); 378 | foreach(var j in replaces) 379 | { 380 | newValue = newValue.Replace(j.Key, j.Value.ToString()); 381 | } 382 | newReplaces.Add(i.Key, newValue); 383 | } 384 | } 385 | 386 | if(find != null && replace != null){ 387 | TextReplace(find, replace); 388 | } 389 | if(newReplaces != null){ 390 | BatchTextReplace(newReplaces); 391 | } 392 | } 393 | 394 | /// 395 | /// Find and replace in presentation 396 | /// 397 | private void TextReplace(string find, string replace) 398 | { 399 | foreach(PowerPoint.Shape shape in slide.Shapes) 400 | { 401 | //for textboxes 402 | if (shape.HasTextFrame == MsoTriState.msoTrue) 403 | { 404 | shape.TextFrame.TextRange.Replace(find, replace); 405 | } 406 | //for Tables 407 | else if (shape.HasTable == MsoTriState.msoTrue) 408 | { 409 | foreach (PowerPoint.Row row in shape.Table.Rows) 410 | { 411 | foreach (PowerPoint.Cell cell in row.Cells) 412 | { 413 | if (cell.Shape.HasTextFrame == MsoTriState.msoTrue) 414 | { 415 | cell.Shape.TextFrame.TextRange.Replace(find, replace); 416 | } 417 | } 418 | } 419 | } 420 | } 421 | } 422 | 423 | /// 424 | /// Mass Find and replace in slide 425 | /// 426 | private void BatchTextReplace(Dictionary replaces) 427 | { 428 | foreach(PowerPoint.Shape shape in slide.Shapes) 429 | { 430 | if(shape.HasTextFrame == MsoTriState.msoTrue || shape.HasTable == MsoTriState.msoTrue) 431 | { 432 | //for textboxes 433 | if (shape.HasTextFrame == MsoTriState.msoTrue) 434 | { 435 | TextReplace(shape.TextFrame.TextRange, replaces); 436 | } 437 | //for Tables 438 | else if (shape.HasTable == MsoTriState.msoTrue) 439 | { 440 | foreach (PowerPoint.Row row in shape.Table.Rows) 441 | { 442 | foreach (PowerPoint.Cell cell in row.Cells) 443 | { 444 | if (cell.Shape.HasTextFrame == MsoTriState.msoTrue) 445 | { 446 | TextReplace(cell.Shape.TextFrame.TextRange, replaces); 447 | } 448 | } 449 | } 450 | } 451 | } 452 | } 453 | } 454 | 455 | private void TextReplace(PowerPoint.TextRange textRange, Dictionary replaces) 456 | { 457 | var text = textRange.Text; 458 | foreach (var replace in replaces) 459 | { 460 | if(text.Contains(replace.Key)) 461 | { 462 | textRange.Replace(replace.Key, replace.Value); 463 | } 464 | } 465 | } 466 | /// 467 | /// Return all slide notes 468 | /// 469 | /// 470 | /// 471 | // https://stackoverflow.com/a/20640637 472 | private string GetNotes(PowerPoint.Slide slide) 473 | { 474 | if (slide.HasNotesPage == MsoTriState.msoFalse) 475 | return string.Empty; 476 | 477 | string slideNodes = string.Empty; 478 | var notesPage = slide.NotesPage; 479 | int length = 0; 480 | foreach (PowerPoint.Shape shape in notesPage.Shapes) 481 | { 482 | if (shape.Type == MsoShapeType.msoPlaceholder) 483 | { 484 | var tf = shape.TextFrame; 485 | try 486 | { 487 | //Some TextFrames do not have a range 488 | var range = tf.TextRange; 489 | if (range.Length > length) 490 | { //Some have a digit in the text, 491 | //so find the longest text item and return that 492 | slideNodes = range.Text; 493 | length = range.Length; 494 | } 495 | } 496 | catch (Exception) 497 | { } 498 | } 499 | } 500 | return slideNodes; 501 | } 502 | 503 | private void SetNotes(PowerPoint.Slide slide, string text) 504 | { 505 | throw new NotImplementedException(); 506 | } 507 | /// 508 | /// 509 | /// 510 | internal PowerPoint.Slide GetUnderlyingObject() 511 | { 512 | return this.slide; 513 | } 514 | 515 | #region Properties 516 | 517 | public int Pos 518 | { 519 | get 520 | { 521 | return this.slide.SlideIndex; 522 | } 523 | set 524 | { 525 | this.slide.MoveTo(value); 526 | } 527 | } 528 | 529 | public int Number 530 | { 531 | get 532 | { 533 | return this.slide.SlideNumber; 534 | } 535 | } 536 | 537 | public string Name 538 | { 539 | get 540 | { 541 | return this.slide.Name; 542 | } 543 | set 544 | { 545 | this.slide.Name = value; 546 | } 547 | } 548 | 549 | public string Notes 550 | { 551 | get 552 | { 553 | return this.GetNotes(this.slide); 554 | } 555 | } 556 | 557 | #endregion Properties 558 | } 559 | } 560 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Report/_Character.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using PowerPoint = NetOffice.PowerPointApi; 7 | using Office = NetOffice.OfficeApi; 8 | 9 | namespace OfficeScript.Report 10 | { 11 | public class Character 12 | { 13 | private PowerPoint.Shape shape; 14 | private int start; 15 | private int length; 16 | 17 | public Character(PowerPoint.Shape shape, Dictionary parameters) 18 | { 19 | this.shape = shape; 20 | object tmp; 21 | if (parameters.TryGetValue("start", out tmp)) 22 | { 23 | this.start = (int)tmp; 24 | } 25 | else 26 | { 27 | this.start = -1; 28 | } 29 | if (parameters.TryGetValue("length", out tmp)) 30 | { 31 | this.length = (int)tmp; 32 | } 33 | else 34 | { 35 | this.length = -1; 36 | } 37 | 38 | 39 | } 40 | 41 | /// 42 | /// Retuns an object with async functions for node.js 43 | /// 44 | /// 45 | public object Invoke() 46 | { 47 | return new 48 | { 49 | attr = (Func>)( 50 | async (input) => 51 | { 52 | if (input is string) 53 | { 54 | var tmp = new Dictionary(); 55 | tmp.Add("name", input); 56 | input = tmp; 57 | } 58 | return Util.Attr(this, (input as IDictionary).ToDictionary(d => d.Key, d => d.Value), Invoke); 59 | }), 60 | remove = (Func>)( 61 | async (input) => 62 | { 63 | this.Remove(); 64 | return null; 65 | }), 66 | format = (Func>)( 67 | async (input) => 68 | { 69 | return new Format(this).Invoke(); 70 | }), 71 | font = (Func>)( 72 | async (input) => 73 | { 74 | return new Font(this, this.Invoke).Invoke(); 75 | }) 76 | }; 77 | } 78 | 79 | /// 80 | /// 81 | /// 82 | private void Remove() 83 | { 84 | this.shape.TextFrame.TextRange.Characters(this.start, this.length).Delete(); 85 | } 86 | 87 | /// 88 | /// Get or Set the Text-Property for this element. 89 | /// 90 | public string Text 91 | { 92 | get 93 | { 94 | return this.shape.TextFrame.TextRange.Paragraphs(this.start, this.length).Text.TrimEnd(); 95 | } 96 | set 97 | { 98 | string text = value; 99 | int i; 100 | 101 | for (i = this.shape.TextFrame.TextRange.Paragraphs().Count; i < this.start; i++) 102 | { 103 | this.shape.TextFrame.TextRange.Paragraphs(this.shape.TextFrame.TextRange.Paragraphs().Count).InsertAfter(Environment.NewLine); 104 | } 105 | 106 | //if (this.shape.TextFrame.TextRange.Paragraphs().Count < this.start) 107 | //{ 108 | //text = Environment.NewLine + text; 109 | //} 110 | this.shape.TextFrame.TextRange.Paragraphs(this.start, this.length).Text = text; 111 | } 112 | } 113 | /// 114 | /// 115 | /// 116 | public int Count 117 | { 118 | get 119 | { 120 | return this.shape.TextFrame.TextRange.Paragraphs(this.start, this.length).Lines().Count; 121 | } 122 | } 123 | 124 | /// 125 | /// 126 | /// 127 | /// 128 | public NetOffice.OfficeApi.TextRange2 GetUnderlyingObject() 129 | { 130 | return this.shape.TextFrame2.TextRange.Paragraphs(this.start, this.length); 131 | } 132 | 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Dynamic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using OfficeScript.Report; 8 | 9 | namespace OfficeScript 10 | { 11 | class Startup 12 | { 13 | public async Task PowerPointApplication(dynamic options) 14 | { 15 | return new PowerPointApplication().Invoke(); 16 | } 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/Util.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using PowerPoint = NetOffice.PowerPointApi; 7 | 8 | namespace OfficeScript 9 | { 10 | public static class Util 11 | { 12 | 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | public static object Attr(object thisObject, Dictionary parameters, Func Invoke) 19 | { 20 | string name = (string)(parameters as Dictionary)["name"]; 21 | object value = null; 22 | object tmp; 23 | if (parameters.TryGetValue("value", out tmp)) 24 | { 25 | value = tmp; 26 | } 27 | 28 | return Attr(thisObject, name, value, Invoke); 29 | } 30 | 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | /// 37 | public static object Attr(object thisObject, string name, object value, Func Invoke) 38 | { 39 | if (value != null) 40 | { 41 | thisObject.GetType().GetProperty(name).SetValue(thisObject, value, null); 42 | return Invoke(); 43 | } 44 | else 45 | { 46 | return thisObject.GetType().GetProperty(name).GetValue(thisObject, null); 47 | } 48 | } 49 | 50 | /// 51 | /// Helper for Fill because .Net treat color as RGB, while Netoffice (Interop aswell) treats color as BGR 52 | /// 53 | public static string BGRtoRGB(string value) 54 | { 55 | string b = value.Substring(1, 2); 56 | string g = value.Substring(3, 2); 57 | string r = value.Substring(5, 2); 58 | return "#" + r + g + b; 59 | } 60 | 61 | public static void ShapeTextReplace(PowerPoint.TextRange textRange, Dictionary replaces) 62 | { 63 | // var text = textRange.Text; 64 | foreach (var replace in replaces) 65 | { 66 | while(textRange.Text.Contains(replace.Key)) 67 | { 68 | textRange.Replace(replace.Key, replace.Value); 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/OfficeScript/OfficeScript/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /test/data/Testpptx_00.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miramac/node-office-script/160e916d520da3fd7249c4c4a68047446d92806f/test/data/Testpptx_00.pptx -------------------------------------------------------------------------------- /test/data/Testpptx_01.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miramac/node-office-script/160e916d520da3fd7249c4c4a68047446d92806f/test/data/Testpptx_01.pptx -------------------------------------------------------------------------------- /test/data/Testpptx_02.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miramac/node-office-script/160e916d520da3fd7249c4c4a68047446d92806f/test/data/Testpptx_02.pptx -------------------------------------------------------------------------------- /test/data/Testpptx_Table.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miramac/node-office-script/160e916d520da3fd7249c4c4a68047446d92806f/test/data/Testpptx_Table.pptx -------------------------------------------------------------------------------- /test/data/Testpptx_mocha.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miramac/node-office-script/160e916d520da3fd7249c4c4a68047446d92806f/test/data/Testpptx_mocha.pptx -------------------------------------------------------------------------------- /test/data/Testxlsx_01.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miramac/node-office-script/160e916d520da3fd7249c4c4a68047446d92806f/test/data/Testxlsx_01.xlsx -------------------------------------------------------------------------------- /test/data/ga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Miramac/node-office-script/160e916d520da3fd7249c4c4a68047446d92806f/test/data/ga.png -------------------------------------------------------------------------------- /test/mocha.test.powerpoint.js: -------------------------------------------------------------------------------- 1 | /* global describe,it,after,__dirname */ 2 | var assert = require('assert') 3 | var path = require('path') 4 | var powerpoint = require('../').powerpoint 5 | var testPPT01 = 'Testpptx_01.pptx' 6 | var testDataPath = path.join(__dirname, 'data') 7 | 8 | describe('report', function () { 9 | this.timeout(15000) 10 | after(function (done) { powerpoint.quit(null, done) }) 11 | describe('presentation', function () { 12 | describe('#open&close', function () { 13 | it('should open and close the file', function (done) { 14 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 15 | if (err) throw err 16 | presentation.close(null, done) 17 | }) 18 | }) 19 | }) 20 | describe('#fetch', function () { 21 | it('should fetch an open presentation', function (done) { 22 | powerpoint.open(path.join(testDataPath, testPPT01), function (err) { 23 | if (err) throw err 24 | powerpoint.fetch(null, function (err, presentation) { 25 | if (err) throw err 26 | presentation.close(null, done) 27 | }) 28 | }) 29 | }) 30 | }) 31 | describe('#attr', function () { 32 | it('should get a name and path attribute from presentation', function (done) { 33 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 34 | if (err) throw err 35 | // get Path Sync 36 | assert.equal(presentation.attr({name: 'Path'}, true), testDataPath) 37 | assert.equal(presentation.attr('Path', true), testDataPath) 38 | // get name async 39 | presentation.attr({name: 'Name'}, function (err, data) { 40 | if (err) throw err 41 | assert.equal(data, testPPT01) 42 | presentation.close(null, done) 43 | }) 44 | }) 45 | }) 46 | }) 47 | describe('#slides', function () { 48 | it('should have 2 slides', function (done) { 49 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 50 | if (err) throw err 51 | presentation.slides(null, function (err, slides) { 52 | if (err) throw err 53 | assert.equal(slides.length, 2) 54 | presentation.close(null, done) 55 | }) 56 | }) 57 | }) 58 | 59 | it('should have the Attr Name', function (done) { 60 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 61 | if (err) throw err 62 | presentation.slides(null, function (err, slides) { 63 | if (err) throw err 64 | assert.equal(slides[1].attr({name: 'Name'}, true), 'Slide2') 65 | presentation.close(null, done) 66 | }) 67 | }) 68 | }) 69 | 70 | it('should have the Attr Pos', function (done) { 71 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 72 | if (err) throw err 73 | presentation.slides(null, function (err, slides) { 74 | if (err) throw err 75 | slides.forEach(function (slide, index) { 76 | assert.equal(slide.attr({name: 'Pos'}, true), index + 1) 77 | }) 78 | presentation.close(null, done) 79 | }) 80 | }) 81 | }) 82 | it('should be changeable the pos of Slide2', function (done) { 83 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 84 | if (err) throw err 85 | presentation.slides(null, function (err, slides) { 86 | if (err) throw err 87 | assert.equal(slides[1].attr({name: 'Pos'}, true), 2) 88 | assert.equal(slides[1].attr({name: 'Pos', value: 1}, true).attr({name: 'Pos'}, true), 1) 89 | presentation.close(null, done) 90 | }) 91 | }) 92 | }) 93 | it('should be able to delete Slide2', function (done) { 94 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 95 | if (err) throw err 96 | presentation.slides(null, true)[1].remove(null, function (err) { 97 | presentation.slides(null, function (err, slides) { 98 | if (err) throw err 99 | assert.equal(slides.length, 1) 100 | presentation.close(null, done) 101 | }) 102 | }) 103 | }) 104 | }) 105 | it('should be able to duplicate Slide1', function (done) { 106 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 107 | if (err) throw err 108 | presentation.slides(null, true)[0].duplicate(null, function (err, slide) { 109 | if (err) throw err 110 | assert.equal(slide.attr({name: 'Pos'}, true), 2) 111 | presentation.slides(null, function (err, slides) { 112 | if (err) throw err 113 | assert.equal(slides.length, 3) 114 | presentation.close(null, done) 115 | }) 116 | }) 117 | }) 118 | }) 119 | it('should be able to create a shape on slide1', function (done) { 120 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 121 | if (err) throw err 122 | var slide = presentation.slides(null, true)[1] 123 | var shapeCount = slide.shapes(null, true).length 124 | slide.addTextbox(null, function (err, shape) { 125 | if (err) throw err 126 | assert.equal(slide.shapes(null, true).length, shapeCount + 1) 127 | presentation.close(null, done) 128 | }) 129 | }) 130 | }) 131 | it('should be able to create a shape with top=100,left=100,height=200,width=200', function (done) { 132 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 133 | if (err) throw err 134 | var slide = presentation.slides(null, true)[1] 135 | var shapeCount = slide.shapes(null, true).length 136 | slide.addTextbox({top: 100, left: 100, height: 200, width: 200}, function (err, shape) { 137 | if (err) throw err 138 | assert.equal(slide.shapes(null, true).length, shapeCount + 1) 139 | assert.equal(shape.attr({ name: 'Top' }, true), 100) 140 | assert.equal(shape.attr({ name: 'Left' }, true), 100) 141 | assert.equal(shape.attr({ name: 'Height' }, true), 200) 142 | assert.equal(shape.attr({ name: 'Width' }, true), 200) 143 | presentation.close(null, done) 144 | }) 145 | }) 146 | }) 147 | }) 148 | describe('#shapes', function () { 149 | it('should have 2 shapes on slide one', function (done) { 150 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 151 | if (err) throw err 152 | presentation.slides(null, function (err, slides) { 153 | if (err) throw err 154 | slides[0].shapes(null, function (err, shapes) { 155 | assert.equal(shapes.length, 2) 156 | presentation.close(null, done) 157 | }) 158 | }) 159 | }) 160 | }) 161 | it('should have the Attr Name', function (done) { 162 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 163 | if (err) throw err 164 | presentation.slides(null, function (err, slides) { 165 | if (err) throw err 166 | slides[0].shapes(null, function (err, shapes) { 167 | assert.equal(shapes[0].attr({name: 'Name'} , true), 'Title 1') 168 | presentation.close(null, done) 169 | }) 170 | }) 171 | }) 172 | }) 173 | it('should be changeable the Attribute Name', function (done) { 174 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 175 | if (err) throw err 176 | presentation.slides(null, function (err, slides) { 177 | if (err) throw err 178 | slides[0].shapes(null, function (err, shapes) { 179 | assert.equal(shapes[0].attr({name: 'Name', value: 'Test'} , true).attr({name: 'Name'}, true), 'Test') 180 | presentation.close(null, done) 181 | }) 182 | }) 183 | }) 184 | }) 185 | it('should be able to duplicate shape1', function (done) { 186 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 187 | if (err) throw err 188 | presentation.slides(null, function (err, slides) { 189 | if (err) throw err 190 | slides[0].shapes(null, function (err, shapes) { 191 | var shapeCount = shapes.length 192 | shapes[0].duplicate(null, function (err, shape) { 193 | if (err) throw err 194 | assert.equal(slides[0].shapes(null, true).length, shapeCount + 1) 195 | assert.equal(shape.attr({name: 'Text'}, true), shapes[0].attr({name: 'Text'}, true)) 196 | presentation.close(null, done) 197 | }) 198 | }) 199 | }) 200 | }) 201 | }) 202 | it('should be able to remove shape1', function (done) { 203 | powerpoint.open(path.join(testDataPath, testPPT01), function (err, presentation) { 204 | if (err) throw err 205 | presentation.slides(null, function (err, slides) { 206 | if (err) throw err 207 | slides[0].shapes(null, function (err, shapes) { 208 | shapes[0].remove(null, function (err) { 209 | if (err) throw err 210 | presentation.close(null, done) 211 | }) 212 | }) 213 | }) 214 | }) 215 | }) 216 | }) 217 | }) 218 | }) 219 | -------------------------------------------------------------------------------- /test/mocha.test.presentation.js: -------------------------------------------------------------------------------- 1 | /* global describe,it,after,__dirname */ 2 | var assert = require('assert') 3 | var path = require('path') 4 | var Presentation = require('../').Presentation 5 | var powerpoint = require('../').powerpoint 6 | var testPPT01 = 'Testpptx_mocha.pptx' 7 | var testDataPath = path.join(__dirname, 'data') 8 | 9 | describe('report', function () { 10 | this.timeout(15000) 11 | after(function (done) { powerpoint.quit(null, done) }) 12 | describe('presentation', function () { 13 | describe('#open&close', function () { 14 | it('should open and close the file', function (done) { 15 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 16 | // Close file 17 | presentation.close(done) 18 | }) 19 | }) 20 | describe('#attr', function () { 21 | it('should get a name, path, and fullPath attribute from presentation', function (done) { 22 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 23 | // get Path Sync 24 | assert.equal(presentation.path(), testDataPath) 25 | assert.equal(presentation.name(), testPPT01) 26 | assert.equal(presentation.fullName(), path.join(testDataPath, testPPT01)) 27 | // Close file 28 | presentation.close(done) 29 | }) 30 | it('should have slideWidth and slide Height', function (done) { 31 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 32 | assert.equal(presentation.slideHeight(), 540) 33 | assert.equal(presentation.slideWidth(), 720) 34 | presentation.close(done) 35 | }) 36 | }) 37 | describe('#properties', function () { 38 | it('should have 13 builtin properties', function (done) { 39 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 40 | var props = presentation.builtinProp() 41 | var counter = 0 42 | var key 43 | for (key in props) { 44 | if (props.hasOwnProperty(key)) { 45 | counter++ 46 | } 47 | } 48 | assert.equal(counter, 13) 49 | presentation.close(done) 50 | }) 51 | it('should have and set builtin property "Last author"', function (done) { 52 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 53 | presentation.builtinProp('Last author', 'Oliver Queen') 54 | assert.equal(presentation.builtinProp('Last author'), 'Oliver Queen') 55 | presentation.close(done) 56 | }) 57 | it('should have and set custom property', function (done) { 58 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 59 | presentation.customProp('Hero', 'Green Arrow') 60 | assert.equal(presentation.customProp('Hero'), 'Green Arrow') 61 | presentation.close(done) 62 | }) 63 | it('should set a tag', function (done) { 64 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 65 | presentation.tag.set('Green', 'Arrow') 66 | assert.equal(1, 1) 67 | presentation.close(done) 68 | }) 69 | it('should find and replace text', function (done) { 70 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 71 | presentation.textReplace('Testpptx', 'Fu Bar') 72 | assert.equal(presentation.slides()[0].shapes()[0].text(), 'Fu Bar_01') 73 | presentation.close(done) 74 | }) 75 | it('should batch find and replace text', function (done) { 76 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 77 | var replaces = { 78 | '': 1234, 79 | '': 'Fu', 80 | 'Testpptx': ' Bar' 81 | } 82 | presentation.textReplace(replaces) 83 | assert.equal(presentation.slides()[0].shapes()[0].text(), 'Fu Bar_01') 84 | presentation.close(done) 85 | }) 86 | }) 87 | describe('#slides', function () { 88 | it('should have 4 slides', function (done) { 89 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 90 | var slides = presentation.slides() 91 | assert.equal(slides.length, 4) 92 | presentation.close(done) 93 | }) 94 | it('should have the attribute "name"', function (done) { 95 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 96 | var slides = presentation.slides() 97 | assert.equal(slides[1].name(), 'Slide2') 98 | presentation.close(done) 99 | }) 100 | it('should have the attribute "pos"', function (done) { 101 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 102 | var slides = presentation.slides() 103 | slides.forEach(function (slide, index) { 104 | assert.equal(slide.pos(), index + 1) 105 | }) 106 | presentation.close(done) 107 | }) 108 | it('should be able to change the position of slide2', function (done) { 109 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 110 | var slides = presentation.slides() 111 | assert.equal(slides[1].pos(), 2) 112 | assert.equal(slides[1].pos(1).pos(), 1) 113 | presentation.close(done) 114 | }) 115 | it('should be able to delete slide2', function (done) { 116 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 117 | var slides = presentation.slides() 118 | slides[1].remove() 119 | slides = presentation.slides() 120 | assert.equal(slides.length, 3) 121 | presentation.close(done) 122 | }) 123 | it('should be able to duplicate slide1', function (done) { 124 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 125 | assert.equal(presentation.slides()[0].duplicate().pos(), 2) 126 | var slides = presentation.slides() 127 | assert.equal(slides.length, 5) 128 | presentation.close(done) 129 | }) 130 | it('should be able to create a shape on slide1', function (done) { 131 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 132 | var slide = presentation.slides()[1] 133 | var shapeCount = slide.shapes().length 134 | slide.addTextbox() 135 | assert.equal(slide.shapes().length, shapeCount + 1) 136 | presentation.close(done) 137 | }) 138 | it('should be able to create a shape with top=100,left=100,height=200,width=200', function (done) { 139 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 140 | var slide = presentation.slides()[1] 141 | var shapeCount = slide.shapes().length 142 | var shape = slide.addTextbox({top: 100, left: 100, height: 200, width: 200}) 143 | assert.equal(slide.shapes().length, shapeCount + 1) 144 | assert.equal(shape.top(), 100) 145 | assert.equal(shape.left(), 100) 146 | assert.equal(shape.height(), 200) 147 | assert.equal(shape.width(), 200) 148 | presentation.close(done) 149 | }) 150 | it('should be able to insert a picture', function (done) { 151 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 152 | var slide = presentation.slides()[2] 153 | var shapeCount = slide.shapes().length 154 | slide.addPicture(path.join(testDataPath, 'ga.png')) 155 | assert.equal(slide.shapes().length, shapeCount + 1) 156 | presentation.close(done) 157 | }) 158 | it('should be able to insert a picture with top=100,left=100', function (done) { 159 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 160 | var slide = presentation.slides()[2] 161 | var shapeCount = slide.shapes().length 162 | var shape = slide.addPicture(path.join(testDataPath, 'ga.png'), {top: 100, left: 100}) 163 | assert.equal(slide.shapes().length, shapeCount + 1) 164 | assert.equal(shape.top(), 100) 165 | assert.equal(shape.left(), 100) 166 | presentation.close(done) 167 | }) 168 | it('should be able to set and have a tag on slide1', function (done) { 169 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 170 | var slide = presentation.slides()[1] 171 | slide.tag.set('Hero', 'Green Arrow') 172 | slide = presentation.slides()[1] 173 | assert.equal(slide.tag.get('Hero'), 'Green Arrow') 174 | presentation.close(done) 175 | }) 176 | it('should be able to set, have and remove a tag on slide1', function (done) { 177 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 178 | var slide = presentation.slides()[1] 179 | slide.tag.set('Oliver Queen', 'Green Arrow') 180 | slide.tag.set('Batman', 'Bruce Wayne') 181 | slide.tag.set('Flash', 'Barry Allen') 182 | slide = presentation.slides()[1] 183 | var tags = slide.tags 184 | var counter = 0 185 | var key 186 | for (key in tags) { 187 | if (tags.hasOwnProperty(key)) { 188 | counter++ 189 | } 190 | } 191 | assert.equal(counter, 3) 192 | slide.tag.remove('Flash') 193 | slide = presentation.slides()[1] 194 | tags = slide.tags 195 | counter = 0 196 | for (key in tags) { 197 | if (tags.hasOwnProperty(key)) { 198 | counter++ 199 | } 200 | } 201 | assert.equal(counter, 2) 202 | presentation.close(done) 203 | }) 204 | it('should be able to copy/paste a slide', function (done) { 205 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 206 | var slideCount = presentation.slides().length 207 | presentation.slides()[1].copy() 208 | presentation.pasteSlide(-1) 209 | assert.equal(presentation.slides().length, slideCount + 1) 210 | presentation.close(done) 211 | }) 212 | it('should be able read slide notes', function (done) { 213 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 214 | var slideNotes = presentation.slides()[1].notes() 215 | assert.equal(slideNotes, 'Slide 1\rNotes') 216 | presentation.close(done) 217 | }) 218 | }) 219 | describe('#shapes', function () { 220 | it('should have 2 shapes on slide one', function (done) { 221 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 222 | assert.equal(presentation.slides()[0].shapes().length, 2) 223 | presentation.close(done) 224 | }) 225 | it('should have the attribute "name"', function (done) { 226 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 227 | assert.equal(presentation.slides()[0].shapes()[0].name(), 'Title 1') 228 | presentation.close(done) 229 | }) 230 | it('should be able to change the attribute "name"', function (done) { 231 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 232 | assert.equal(presentation.slides()[0].shapes()[0].name('Test').name(), 'Test') 233 | presentation.close(done) 234 | }) 235 | it('should have the attribute "top"', function (done) { 236 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 237 | assert.equal(presentation.slides()[0].shapes()[0].top(), 195.33204650878906) 238 | presentation.close(done) 239 | }) 240 | it('should be able to change the attribute "top"', function (done) { 241 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 242 | assert.equal(presentation.slides()[0].shapes()[0].top(10.5).top(), 10.5) 243 | presentation.close(done) 244 | }) 245 | it('should have the attribute "left"', function (done) { 246 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 247 | assert.equal(presentation.slides()[0].shapes()[0].left(), 54) 248 | presentation.close(done) 249 | }) 250 | it('should be able to change the attribute "left"', function (done) { 251 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 252 | assert.equal(presentation.slides()[0].shapes()[0].left(10.5).left(), 10.5) 253 | presentation.close(done) 254 | }) 255 | it('should have the attribute "height"', function (done) { 256 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 257 | assert.equal(presentation.slides()[0].shapes()[0].height(), 60.585906982421875) 258 | presentation.close(done) 259 | }) 260 | it('should be able to change the attribute "height"', function (done) { 261 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 262 | assert.equal(presentation.slides()[0].shapes()[0].height(10.5).height(), 10.5) 263 | presentation.close(done) 264 | }) 265 | it('should have the attribute "width"', function (done) { 266 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 267 | assert.equal(presentation.slides()[0].shapes()[0].width(), 612) 268 | presentation.close(done) 269 | }) 270 | it('should be able to change the attribute "width"', function (done) { 271 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 272 | assert.equal(presentation.slides()[0].shapes()[0].width(10.5).width(), 10.5) 273 | presentation.close(done) 274 | }) 275 | it('should have the attribute "rotation"', function (done) { 276 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 277 | assert.equal(presentation.slides()[0].shapes()[0].rotation(), 0) 278 | presentation.close(done) 279 | }) 280 | it('should be able to change the attribute "rotation"', function (done) { 281 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 282 | assert.equal(presentation.slides()[0].shapes()[0].rotation(10.5).rotation(), 10.5) 283 | presentation.close(done) 284 | }) 285 | it('should be able to change the attribute "altText"', function (done) { 286 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 287 | assert.equal(presentation.slides()[0].shapes()[0].altText('Fu Bar').altText(), 'Fu Bar') 288 | presentation.close(done) 289 | }) 290 | it('should be able to change the attribute "title"', function (done) { 291 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 292 | assert.equal(presentation.slides()[0].shapes()[0].title('Fu Bar').title(), 'Fu Bar') 293 | presentation.close(done) 294 | }) 295 | 296 | it('should be able to duplicate shape1', function (done) { 297 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 298 | var shapes = presentation.slides()[0].shapes() 299 | var shapeCount = shapes.length 300 | var shape = shapes[0].duplicate() 301 | assert.equal(presentation.slides()[0].shapes().length, shapeCount + 1) 302 | assert.equal(shape.text(), shapes[0].text()) 303 | presentation.close(done) 304 | }) 305 | it('should be able to remove shape1', function (done) { 306 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 307 | presentation.slides()[0].shapes()[0].remove() 308 | presentation.close(done) 309 | }) 310 | it('should be able to add a new line with text', function (done) { 311 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 312 | var counter = presentation.slides()[2].shapes()[1].paragraph().count() 313 | presentation.slides()[2].shapes()[1].addLine('Text2') 314 | assert.equal(presentation.slides()[2].shapes()[1].paragraph(counter + 1).text(), 'Text2') 315 | presentation.close(done) 316 | }) 317 | it('should be able to add a new line on 5 and remove it', function (done) { 318 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 319 | presentation.slides()[2].shapes()[1].addLine('TextTest', 5) 320 | assert.equal(presentation.slides()[2].shapes()[1].removeLine().paragraph().count(), 4) 321 | presentation.close(done) 322 | }) 323 | it('should be able to add a new picture', function (done) { 324 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 325 | var counter = presentation.slides()[2].shapes().length 326 | presentation.slides()[2].addPicture(path.join(testDataPath, 'ga.png')) 327 | assert.equal(presentation.slides()[2].shapes().length, counter + 1) 328 | presentation.close(done) 329 | }) 330 | it('should be able to set and have a tag', function (done) { 331 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 332 | var shape = presentation.slides()[2].shapes()[1] 333 | shape.tag.set('Hero', 'Green Arrow') 334 | shape = presentation.slides()[2].shapes()[1] 335 | assert.equal(shape.tag.get('Hero'), 'Green Arrow') 336 | presentation.close(done) 337 | }) 338 | it('should be able to set, have and remove a tag', function (done) { 339 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 340 | var shape = presentation.slides()[2].shapes()[1] 341 | shape.tag.set('Oliver Queen', 'Green Arrow') 342 | shape.tag.set('Batman', 'Bruce Wayne') 343 | shape.tag.set('Flash', 'Barry Allen') 344 | shape = presentation.slides()[2].shapes()[1] 345 | var tags = shape.tags 346 | var counter = 0 347 | var key 348 | for (key in tags) { 349 | if (tags.hasOwnProperty(key)) { 350 | counter++ 351 | } 352 | } 353 | assert.equal(counter, 14) 354 | shape.tag.remove('Flash') 355 | shape = presentation.slides()[2].shapes()[1] 356 | tags = shape.tags 357 | counter = 0 358 | for (key in tags) { 359 | if (tags.hasOwnProperty(key)) { 360 | counter++ 361 | } 362 | } 363 | assert.equal(counter, 13) 364 | presentation.close(done) 365 | }) 366 | it('should have and set zIndex', function (done) { 367 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 368 | var shape = presentation.slides()[2].shapes()[1] 369 | assert.equal(shape.zIndex(), 2) 370 | shape.zIndex('back') 371 | assert.equal(shape.zIndex(), 1) 372 | shape.zIndex('forward') 373 | assert.equal(shape.zIndex(), 2) 374 | presentation.close(done) 375 | }) 376 | it('should be able to replace a text', function (done) { 377 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 378 | var shape = presentation.slides()[0].shapes()[0] 379 | assert.equal(shape.textReplace('01', 'XX').text(), 'Testpptx_XX') 380 | presentation.close(done) 381 | }) 382 | }) 383 | describe('#paragraphs', function () { 384 | it('should have the attribute "text"', function (done) { 385 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 386 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 387 | assert.equal(para.text(), 'Testpptx_01') 388 | presentation.close(done) 389 | }) 390 | it('should be able to change the attribute "text"', function (done) { 391 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 392 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 393 | assert.equal(para.text('Testi_1').text(), 'Testi_1') 394 | presentation.close(done) 395 | }) 396 | it('should have the attribute "count"', function (done) { 397 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 398 | assert.equal(presentation.slides()[2].shapes()[1].addLine('yay').addLine('yay').paragraph().count(), 3) 399 | presentation.close(done) 400 | }) 401 | it('should have the attribute "fontName"', function (done) { 402 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 403 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 404 | assert.equal(para.fontName(), 'Calibri') 405 | presentation.close(done) 406 | }) 407 | it('should be able to change the attribute "fontName"', function (done) { 408 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 409 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 410 | assert.equal(para.fontName('Arial').fontName(), 'Arial') 411 | presentation.close(done) 412 | }) 413 | it('should have the attribute "fontColor"', function (done) { 414 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 415 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 416 | assert.equal(para.fontColor(), '#000000') 417 | presentation.close(done) 418 | }) 419 | it('should be able to change the attribute "fontColor"', function (done) { 420 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 421 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 422 | assert.equal(para.fontColor('#FF0000').fontColor(), '#ff0000') 423 | presentation.close(done) 424 | }) 425 | it('should have the attribute "fontItalic"', function (done) { 426 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 427 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 428 | assert.equal(para.fontItalic(), false) 429 | presentation.close(done) 430 | }) 431 | it('should be able to change the attribute "fontItalic"', function (done) { 432 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 433 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 434 | assert.equal(para.fontItalic(true).fontItalic(), true) 435 | presentation.close(done) 436 | }) 437 | it('should have the attribute "fontBold"', function (done) { 438 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 439 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 440 | assert.equal(para.fontBold(), false) 441 | presentation.close(done) 442 | }) 443 | it('should be able to change the attribute "fontBold"', function (done) { 444 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 445 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 446 | assert.equal(para.fontBold(true).fontBold(), true) 447 | presentation.close(done) 448 | }) 449 | it('should have the attribute "align"', function (done) { 450 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 451 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 452 | assert.equal(para.align(), 'center') 453 | presentation.close(done) 454 | }) 455 | it('should be able to change the attribute "align"', function (done) { 456 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 457 | var para = presentation.slides()[0].shapes()[0].paragraph(1) 458 | assert.equal(para.align('left').align(), 'left') 459 | presentation.close(done) 460 | }) 461 | it('should have the attribute "indent"', function (done) { 462 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 463 | var para = presentation.slides()[2].shapes()[1].paragraph() 464 | assert.equal(para.indent(), 1) 465 | presentation.close(done) 466 | }) 467 | it('should be able to change the attribute "indent"', function (done) { 468 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 469 | var para = presentation.slides()[2].shapes()[1].paragraph() 470 | assert.equal(para.indent(2).indent(), 2) 471 | presentation.close(done) 472 | }) 473 | }) 474 | describe('#characters', function () { 475 | it('should have the attribute "text"', function (done) { 476 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 477 | var shape = presentation.slides()[0].shapes()[0] 478 | var char = shape.character(2, 3) 479 | assert.equal(char.text(), 'est') 480 | presentation.close(done) 481 | }) 482 | it('should be able to change the attribute "text"', function (done) { 483 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 484 | var shape = presentation.slides()[0].shapes()[0] 485 | var char = shape.character(2, 3) 486 | char.text('XXX') 487 | assert.equal(shape.text(), 'TXXXpptx_01') 488 | presentation.close(done) 489 | }) 490 | it('should have the attribute "count"', function (done) { 491 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 492 | var shape = presentation.slides()[0].shapes()[0] 493 | var char = shape.character(2, 3) 494 | assert.equal(char.count(), 3) 495 | presentation.close(done) 496 | }) 497 | it('should have the attribute "fontName"', function (done) { 498 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 499 | var shape = presentation.slides()[0].shapes()[0] 500 | var char = shape.character(2, 3) 501 | assert.equal(char.fontName(), 'Calibri') 502 | presentation.close(done) 503 | }) 504 | it('should be able to change the attribute "fontName"', function (done) { 505 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 506 | var shape = presentation.slides()[0].shapes()[0] 507 | var char = shape.character(2, 3) 508 | assert.equal(char.fontName('Arial').fontName(), 'Arial') 509 | presentation.close(done) 510 | }) 511 | it('should have the attribute "fontColor"', function (done) { 512 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 513 | var shape = presentation.slides()[0].shapes()[0] 514 | var char = shape.character(2, 3) 515 | assert.equal(char.fontColor(), '#000000') 516 | presentation.close(done) 517 | }) 518 | it('should be able to change the attribute "fontColor"', function (done) { 519 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 520 | var shape = presentation.slides()[0].shapes()[0] 521 | var char = shape.character(2, 3) 522 | assert.equal(char.fontColor('#FF0000').fontColor(), '#ff0000') 523 | presentation.close(done) 524 | }) 525 | it('should have the attribute "fontItalic"', function (done) { 526 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 527 | var shape = presentation.slides()[0].shapes()[0] 528 | var char = shape.character(2, 3) 529 | assert.equal(char.fontItalic(), false) 530 | presentation.close(done) 531 | }) 532 | it('should be able to change the attribute "fontItalic"', function (done) { 533 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 534 | var shape = presentation.slides()[0].shapes()[0] 535 | var char = shape.character(2, 3) 536 | assert.equal(char.fontItalic(true).fontItalic(), true) 537 | presentation.close(done) 538 | }) 539 | it('should have the attribute "fontBold"', function (done) { 540 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 541 | var shape = presentation.slides()[0].shapes()[0] 542 | var char = shape.character(2, 3) 543 | assert.equal(char.fontBold(), false) 544 | presentation.close(done) 545 | }) 546 | it('should be able to change the attribute "fontBold"', function (done) { 547 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 548 | var shape = presentation.slides()[0].shapes()[0] 549 | var char = shape.character(2, 3) 550 | assert.equal(char.fontBold(true).fontBold(), true) 551 | presentation.close(done) 552 | }) 553 | }) 554 | describe('#tables', function () { 555 | it('should have a table with 2 rows and 5 columns', function (done) { 556 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 557 | var shape = presentation.slides()[3].shapes()[1] 558 | assert.equal(shape.has('table'), true) 559 | var table = shape.table() 560 | assert.equal(table.length, 2) 561 | assert.equal(table[0].length, 5) 562 | presentation.close(done) 563 | }) 564 | it('should have cell text and can change it', function (done) { 565 | var presentation = new Presentation(path.join(testDataPath, testPPT01)) 566 | var shape = presentation.slides()[3].shapes()[1] 567 | var table = shape.table() 568 | assert.equal(table[0][0].text(), 'A') 569 | assert.equal(table[0][0].text('XX').text(), 'XX') 570 | presentation.close(done) 571 | }) 572 | }) 573 | }) 574 | }) 575 | -------------------------------------------------------------------------------- /test/sandbox.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var Presentation = require('..').Presentation 3 | 4 | var presentation01 = new Presentation(path.join(__dirname, '/data/Testpptx_01.pptx')) 5 | // var presentation02 = new Presentation(path.join(__dirname, '/data/Testpptx_02.pptx')) 6 | //var presentation01 = new Presentation() 7 | var shape = presentation01.slides()[0].shapes()[0] 8 | var para = shape.paragraph(1) 9 | console.log(para.text()) 10 | var char = shape.char(4, 2) 11 | console.log(char.text()) 12 | console.log(char.fontBold(true)) 13 | 14 | // var i, j 15 | // var slides = presentation01.slides() 16 | // var shapes 17 | // for (i = 0; i < slides.length; i++) { 18 | // shapes = slides[i].shapes() 19 | // for (j = 0; j < shapes.length; j++) { 20 | // shapes[j].textReplace('', '12345') 21 | // } 22 | // } 23 | 24 | 25 | var replaces = { 26 | '': 1234, 27 | '': ' Fu', 28 | 'Testpptx': ' Bar', 29 | '': 'ABC' 30 | } 31 | try { 32 | // presentation01.textReplace('', '12345') 33 | presentation01.textReplace(replaces) 34 | } catch (e) { 35 | console.error(e) 36 | } 37 | 38 | setTimeout(() => { 39 | presentation01.quit() 40 | }, 5000) 41 | 42 | 43 | /* 44 | 45 | 46 | var slide1 = presentation01.slides()[0].copy() 47 | console.log(slide1.name()) 48 | var slide2 = presentation02.pasteSlide(-1) 49 | console.log(slide2.pos()) 50 | setTimeout(() => { 51 | presentation01.close() 52 | presentation02.quit() 53 | }, 5000) 54 | */ 55 | 56 | /* var shapes = presentation.shapes() 57 | 58 | for (var i = 0; i < shapes.length; i++) { 59 | if (shapes[i].altText().indexOf('coc_object_id=0698;') > 0) { 60 | console.log(shapes[i].name()) 61 | } else if (shapes[i].altText() !== '') { 62 | console.log(shapes[i].altText()) 63 | } 64 | } 65 | */ 66 | 67 | // presentation.quit() 68 | 69 | /* 70 | var presentation = new Presentation(path.join(__dirname, '/data/Testpptx_00.pptx')) 71 | //var presentation = new Presentation() 72 | // get presentation slides 73 | var slides = presentation.slides() 74 | console.log('Slide count:', slides.length) 75 | var powerpoint = require('../').powerpoint 76 | var shapes = presentation.shapes() 77 | 78 | for (var i = 0; i < shapes.length; i++) { 79 | if(shapes[i].has('chart')) { 80 | shapes[i].exportAs({path: path.join(__dirname, 'data/chart_4.emf'), type: 'emf'}) 81 | } 82 | if(shapes[i].has('table')) { 83 | console.log(shapes[i].name()) 84 | } 85 | if(shapes[i].has('text')) { 86 | console.log(shapes[i].text()) 87 | } 88 | } 89 | presentation.quit() 90 | powerpoint.quit(true, true) 91 | */ 92 | // var i, j, shapes 93 | 94 | // console.log('Slide count:', slides.length) 95 | // for (i = 0; i < slides.length; i++) { 96 | // shapes = slides[i].shapes() 97 | // console.log('Slide Num:', slides[i].pos()) 98 | // console.log('Shape count:', shapes.length) 99 | // for (j = 0; j < shapes.length; j++) { 100 | // console.log(shapes[j].name(), shapes[j].text(), shapes[j].table()) 101 | // } 102 | // } 103 | 104 | // var shape = presentation.getSelectedShape() 105 | // console.log( shape.textReplace('a', 'X')) 106 | 107 | // shape.textReplace('a', 'X').textReplace('X', 'a') 108 | 109 | // console.log(slides[2].shapes()[0].table().length) 110 | 111 | 112 | // presentation.quit() 113 | 114 | // Get all shapes of the first slide 1 115 | // var shapes = slides[0].shapes(); 116 | 117 | // var p = shapes[0].p(); 118 | // var form = p.format() 119 | // console.log(form.attr('Bullet',true)); 120 | 121 | // console.log('Title shape count:', shapes.length); 122 | // 123 | // //get name and text of the first shape 124 | // var shape = shapes[0]; 125 | // console.log('Title shape count:', shape.text()); 126 | // shape.tag.set('FU', 'bar') 127 | // console.log('tag:', shape.tag.get('fu')); 128 | // shape.tag.remove('FU') 129 | // console.log('allTags:', shape.tags); 130 | // 131 | 132 | 133 | //change name of the first 134 | // shape.name('First Shape'); 135 | // shape.text('FuBar'); 136 | // console.log(shape.name(), shape.text()); 137 | //Setter retun the destination object so you can chain them 138 | // shape.top(10).left(10).height(100).width(200); 139 | 140 | 141 | // //Save presentation as PDF (sync) 142 | // presentation.saveAs({name:path.join(__dirname,'Presentation01.pdf'), type:'pdf'}); 143 | // //SaveAs new presentation and quit application 144 | // presentation.saveAs(path.join(__dirname,'Presentation01_New.pptx')); 145 | // presentation.quit(); //Close presentation & quit application 146 | 147 | 148 | // console.log('shapes', shapes.length); 149 | // console.log('shapes', shapes[0].attr('Name',true)); 150 | // console.log('shapes', shapes[0].attr('Left',true)); 151 | // console.log('shapes', shapes[0].attr({name:'Left', value:10},true)); 152 | // console.log('shapes', shapes[0].attr('Left',true)); 153 | 154 | /* 155 | //get the Slide 156 | var slides = presentation.slides(); 157 | console.log('slides', slides.length); 158 | 159 | console.log( presentation.attr('Name', true)) 160 | 161 | var shapes = presentation.shapes({'attr:Name':'Title 1'}); 162 | 163 | console.log( shapes[0].attr('Text', true)) 164 | // console.log('shapes', shapes[0].attr('Rotation', true)); 165 | 166 | // shapes[0].attr({name:'Rotation',value:200}, true) 167 | attr = presentation.tags(null, true) 168 | console.log(attr); 169 | setTimeout(presentation.quit, 500); 170 | 171 | 172 | /* 173 | var Shape = require('../lib/report/wrapper/shape'); 174 | var Shapes = require('../lib/report/wrapper/shapes'); 175 | //, reportApp = report.application 176 | 177 | 178 | var presentation = application.open(__dirname+'/data/Testpptx_01.pptx', true); 179 | var slides = presentation.slides({"attr:Name":'Slide1,Slide2'}, true) 180 | 181 | var i, j; 182 | 183 | // for(i=0; i