diff --git a/.gitignore b/.gitignore
index 04816ec..0705def 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ test/Generated*
test/InputFiles3*
test/test1/*
newdir2/
+src/__recovery
/releases
src/docto.exe
diff --git a/companion/app/Services/CommandInfoService.php b/companion/app/Services/CommandInfoService.php
index 09ed17d..7a0d65d 100644
--- a/companion/app/Services/CommandInfoService.php
+++ b/companion/app/Services/CommandInfoService.php
@@ -727,9 +727,12 @@ public static function Explanations()
"dddeletefiles" => ['cmd' => '--deletefiles', 'desc' => "Delete the converted file after conversion."],
"ddbookmarksource" => ['cmd' => '--bookmarksource', 'desc' => "Where to get Bookmarks from for PDF. This parameter is only relevant for PDF files."],
"ddexportmarkup" => ['cmd' => '--ExportMarkup', 'desc' => "Export Comments and other markup from Word Document to PDF"],
- "ddnosubdirs" => ['cmd' => '--no-subdirs', 'desc' => "Don't rescurse subdirs. Only convert files in requested dir. "],
+ "ddnosubdirs" => ['cmd' => '--no-subdirs', 'desc' => "Don't recurse sub-dirs. Only convert files in requested dir. "],
"dduseISO190051" => ['cmd' => '--use-iso19005-1', 'desc' => 'Output PDFs from Word as ISO standard 19005-1 for self contained PDFS. Sometimes also refered to as (PDF/A)[https://en.wikipedia.org/wiki/PDF/A]'],
"ddinputfilter" => ['cmd' => '--inputfilter', 'desc' => 'Input filter to use to find documents. eg Project*.doc* will match ProjectA.doc, Project123.doc, ProjectABC.docx '],
+ "ddsheets" => ['cmd' => '--sheets', 'desc' => 'Output specific sheet from a workbook. Sheet will be output with a specific named file. MyWorksheet_(SheetName) This does not work with xlCSV'],
+ "ddallsheets" => ['cmd' => '--allsheets', 'desc' => 'Output all sheets in a workbook. Each sheet will be output to a separate named file. MyWorksheet_(SheetName)'],
+
];
diff --git a/companion/app/Services/DocToCommandBuilder.php b/companion/app/Services/DocToCommandBuilder.php
new file mode 100644
index 0000000..a4fbb7e
--- /dev/null
+++ b/companion/app/Services/DocToCommandBuilder.php
@@ -0,0 +1,29 @@
+add(config('services.docto.path'));
+ }
+
+ public function add($param, $value = null){
+ $this->params[] = [$param,$value];
+ return $this;
+ }
+
+ public function build(){
+ $cmd = '';
+ foreach($this->params as $paramset){
+ $cmd .= ' ' . $paramset[0] ;
+ if (isset($paramset[1])){
+ $cmd .= ' "' . $paramset[1] . '" ';
+ }
+ }
+ return $cmd;
+ }
+ }
diff --git a/companion/app/Services/FileGatherService.php b/companion/app/Services/FileGatherService.php
index b7db42e..dbc3f80 100644
--- a/companion/app/Services/FileGatherService.php
+++ b/companion/app/Services/FileGatherService.php
@@ -7,20 +7,30 @@
class FileGatherService
{
- public static function GatherFiles(Collection $list, $tempDirName)
+ /**
+ * Gather files will take files from specific subdir of the resource InputFiles directory and
+ * copy them to a temporary directory wehre they can be used for a test.
+ * @param Collection $list
+ * @param $tempDirName
+ * @return Collection
+ * @throws \League\Flysystem\FilesystemException
+ */
+ public static function GatherFiles(Collection | string $list, $tempDirName)
{
+ if (is_string($list)){
+ $list = collect([$list]);
+ }
+
// remove exisitn files
if (\Illuminate\Support\Facades\Storage::exists($tempDirName)){
\Illuminate\Support\Facades\Storage::deleteDirectory($tempDirName);
}
$tempDirPath = Storage::path($tempDirName);
- $list->each(function ($dir) use ($tempDirName, $tempDirPath){
- $inputfilesdir = \Illuminate\Support\Facades\Storage::path('inputfiles\\' . $dir );
+ $list->each(function ($inputdir) use ($tempDirName, $tempDirPath){
+ $inputfilesdir = \Illuminate\Support\Facades\Storage::disk('inputfiles')->path($inputdir );
$cmd = "xcopy \"$inputfilesdir\" \"$tempDirPath\\\" ";
$result = \Illuminate\Support\Facades\Process::run( $cmd );
- echo "\n $cmd \n";
- echo "\n" . $result->output() . "\n";
});
return collect(Storage::listContents($tempDirName));
}
diff --git a/companion/app/Services/ResourceFileService.php b/companion/app/Services/ResourceFileService.php
index df0e207..0e236a2 100644
--- a/companion/app/Services/ResourceFileService.php
+++ b/companion/app/Services/ResourceFileService.php
@@ -5,6 +5,8 @@
class ResourceFileService
{
public static function LoadResourceFile($fn) {
+
+
$fullfn = docto_path('\\src\\res\\' . $fn);
return file_get_contents($fullfn);
@@ -18,6 +20,7 @@ public static function LoadResourceFiles(){
if (strlen($fn) > 2 ){ // ignore . ..
//echo $fileinfo['filename'] . ':' . strlen($fileinfo['filename']);
if (strpos( $fn , '__history') !== false){continue;}
+ if (strpos( $fn , '__recovery') !== false){continue;}
$info = pathinfo($fn);
$AllContent[$info['filename']] = ['filename'=> $fn, 'contents' => static::LoadResourceFile($fn)];
diff --git a/companion/config/filesystems.php b/companion/config/filesystems.php
index 0e7d695..63fb5fc 100644
--- a/companion/config/filesystems.php
+++ b/companion/config/filesystems.php
@@ -42,6 +42,12 @@
'throw' => false,
],
+ 'inputfiles' => [
+ 'driver' => 'local',
+ 'root' => resource_path('inputfiles'),
+ 'throw' => false,
+ ],
+
'public' => [
'driver' => 'local',
diff --git a/companion/config/services.php b/companion/config/services.php
index d7fcf9a..d5bda7e 100644
--- a/companion/config/services.php
+++ b/companion/config/services.php
@@ -15,7 +15,8 @@
*/
'docto' => [
- 'path' => env('DOCTO_PATH','..\\exe\\32\\docto.exe'),
+ // 'path' => env('DOCTO_PATH','..\\exe\\32\\docto.exe'),
+ 'path' => env('DOCTO_PATH','..\\exe\\64\\docto.exe'),
],
'mailgun' => [
diff --git a/companion/resources/generator_templates/AllParameters.md b/companion/resources/generator_templates/AllParameters.md
index 89c3408..9d5bc41 100644
--- a/companion/resources/generator_templates/AllParameters.md
+++ b/companion/resources/generator_templates/AllParameters.md
@@ -213,6 +213,27 @@ If you wish for the converted PDF to be opened after creation. No value req.
Only convert certain pages in the document.
+### Convert all or Specific Individual Sheets
+_Excel_
+
+By default when doing a conversion with XL, the first sheet is the only sheet that gets
+output. Often this is what you want, however if you wish to have a specific sheet output
+you can specify that or you can output all sheets and they will be given individual names.
+
+> --allsheets
+
+Output all sheets. Seperate files will be created for each sheet and named appropriatly.
+eg. If you have a workbook.xls with Sheet1 and MySheet and you convert to pdf. You will get
+2 files named workbook_(Sheet1).pdf and workbook_(MySheet).pdf
+
+> --sheets "1,2"
+
+You can specify to only convert certain sheets, eg 1 and 2 or "Sheet1,MySheet"
+
+````cmd
+Note: --sheets does not work with -t xlCSV . You must use --allsheets and output all.
+````
+
### Document Properties
> --no-IncludeDocProperties --no-DocProp [no value required]
diff --git a/companion/resources/inputfiles/docx/DocXFile.docx b/companion/resources/inputfiles/docx/DocXFile.docx
new file mode 100644
index 0000000..c2e376e
Binary files /dev/null and b/companion/resources/inputfiles/docx/DocXFile.docx differ
diff --git a/companion/resources/inputfiles/multisheet/Book1 MultiSheet Test.xlsx b/companion/resources/inputfiles/multisheet/Book1 MultiSheet Test.xlsx
new file mode 100644
index 0000000..8081666
Binary files /dev/null and b/companion/resources/inputfiles/multisheet/Book1 MultiSheet Test.xlsx differ
diff --git a/companion/resources/inputfiles/password/CullohillApplePie_Protected.doc b/companion/resources/inputfiles/password/CullohillApplePie_Protected.doc
new file mode 100644
index 0000000..4d8527a
Binary files /dev/null and b/companion/resources/inputfiles/password/CullohillApplePie_Protected.doc differ
diff --git a/companion/resources/inputfiles/plain/Ballymaloe Mincemeat Tart.doc b/companion/resources/inputfiles/plain/Ballymaloe Mincemeat Tart.doc
new file mode 100644
index 0000000..01a6e15
Binary files /dev/null and b/companion/resources/inputfiles/plain/Ballymaloe Mincemeat Tart.doc differ
diff --git a/companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster (2).doc b/companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster (2).doc
new file mode 100644
index 0000000..472fd9d
Binary files /dev/null and b/companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster (2).doc differ
diff --git a/companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster 3 .doc b/companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster 3 .doc
new file mode 100644
index 0000000..9829de7
Binary files /dev/null and b/companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster 3 .doc differ
diff --git a/companion/resources/inputfiles/plain/Bookmarks+Chocolate+and+Hazelnut+Tart.doc b/companion/resources/inputfiles/plain/Bookmarks+Chocolate+and+Hazelnut+Tart.doc
new file mode 100644
index 0000000..ea9c6b0
Binary files /dev/null and b/companion/resources/inputfiles/plain/Bookmarks+Chocolate+and+Hazelnut+Tart.doc differ
diff --git a/companion/resources/inputfiles/plain/CullohillApplePie - Copy.doc b/companion/resources/inputfiles/plain/CullohillApplePie - Copy.doc
new file mode 100644
index 0000000..388aee1
Binary files /dev/null and b/companion/resources/inputfiles/plain/CullohillApplePie - Copy.doc differ
diff --git a/companion/resources/inputfiles/single/ASingleFile.doc b/companion/resources/inputfiles/single/ASingleFile.doc
new file mode 100644
index 0000000..e9d0f8d
Binary files /dev/null and b/companion/resources/inputfiles/single/ASingleFile.doc differ
diff --git a/companion/tests/Feature/DocX/CompatibilityPestTest.php b/companion/tests/Feature/DocX/CompatibilityPestTest.php
new file mode 100644
index 0000000..387eeb6
--- /dev/null
+++ b/companion/tests/Feature/DocX/CompatibilityPestTest.php
@@ -0,0 +1,141 @@
+add('-WD')
+ ->add('-f', $testinputfilesdir_temp )
+ ->add('-o', $testoutputdir_temp )
+ ->add('-t', 'wdformatPDF')
+ ->build();
+
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output->output());
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir));
+
+ expect($outputDirFiles->count())->toBeGreaterThan(0);
+ expect($outputDirFiles->count())->tobe(1);
+ });
+
+
+
+ it ('can convert doc to docx with compatibility',function (){
+
+ $inputfiledir = 'inputfiles_docx'. uniqid();
+ $outputfiledir = 'outputfiles_docx' . uniqid();
+ // setup
+ $testinputfilesdir_temp = Storage::path($inputfiledir);
+ $testoutputdir_temp = Storage::path($outputfiledir);
+
+ Storage::createDirectory($outputfiledir);
+
+ $dirfiles = \App\Services\FileGatherService::GatherFiles('plain', $inputfiledir);
+
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-WD')
+ ->add('-f', $testinputfilesdir_temp )
+ ->add('-o', $testoutputdir_temp )
+ ->add('-ox', '.docx')
+ ->add('-t', 'wdFormatDocumentDefault')
+ ->add('--COMPATIBILITY', '65535')
+ ->add('-L',10)
+ ->build();
+
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output->output());
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir));
+
+ expect($outputDirFiles->count())->toBeGreaterThan(0);
+ expect($outputDirFiles->count())->tobe(5);
+
+ // ensure -ox parameter is used.
+ $file1 = $outputDirFiles->first();
+ expect(str($file1)->endsWith('.docx'))->toBeTrue();
+
+
+ });
+
+ it ('can convert doc to docx with -c compatibility',function (){
+
+ $inputfiledir = 'inputfiles_docx'. uniqid();
+ $outputfiledir = 'outputfiles_docx' . uniqid();
+ // setup
+ $testinputfilesdir_temp = Storage::path($inputfiledir);
+ $testoutputdir_temp = Storage::path($outputfiledir);
+
+ Storage::createDirectory($outputfiledir);
+
+ $dirfiles = \App\Services\FileGatherService::GatherFiles('plain', $inputfiledir);
+
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-WD')
+ ->add('-f', $testinputfilesdir_temp )
+ ->add('-o', $testoutputdir_temp )
+ ->add('-ox', '.docx')
+ ->add('-t', 'wdFormatDocumentDefault')
+ ->add('-c', '65535')
+ ->add('-L',10)
+ ->build();
+
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output->output());
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir));
+
+ expect($outputDirFiles->count())->toBeGreaterThan(0);
+ expect($outputDirFiles->count())->tobe(5);
+
+ // ensure -ox parameter is used.
+ $file1 = $outputDirFiles->first();
+ expect(str($file1)->endsWith('.docx'))->toBeTrue();
+
+
+ });
+
+
+ it ('can convert doc to alternative compatibility',function ($marker,$compatibility) {
+
+ $inputfiledir = 'inputfiles_docx'. uniqid();
+ $outputfiledir = 'outputfiles_docx' . uniqid();
+ // setup
+ $testinputfilesdir_temp = Storage::path($inputfiledir);
+ $testoutputdir_temp = Storage::path($outputfiledir);
+
+ Storage::createDirectory($outputfiledir);
+
+ $dirfiles = \App\Services\FileGatherService::GatherFiles('plain', $inputfiledir);
+
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-WD')
+ ->add('-f', $testinputfilesdir_temp )
+ ->add('-o', $testoutputdir_temp )
+ ->add('-t', 'wdFormatDocumentDefault')
+ ->add('--COMPATIBILITY', $compatibility)
+ ->add('-L',10)
+ ->build();
+
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output->output());
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir));
+
+ expect($outputDirFiles->count())->toBeGreaterThan(0);
+ expect($outputDirFiles->count())->tobe(5);
+
+
+ })->with(
+ [
+ ['wdCurrent', 65535],
+ ['wdWord2003', 11],
+ ['wdWord2007', 12],
+ ['wdWord2010', 14],
+ ['wdWord2013', 15],
+ ]);
diff --git a/companion/tests/Feature/Remove/RemoveInputFilePestTest.php b/companion/tests/Feature/Remove/RemoveInputFilePestTest.php
index 696ec73..2480e72 100644
--- a/companion/tests/Feature/Remove/RemoveInputFilePestTest.php
+++ b/companion/tests/Feature/Remove/RemoveInputFilePestTest.php
@@ -29,14 +29,78 @@
$dirfilescount = $dirfiles->count();
// do conversion
$docto = config('services.docto.path');
- $doctocmd = "$docto -WD -f $testinputfilesdir_temp -fx .doc -o $testoutputdir_temp -t wdFormatPDF -R true";
+ // $doctocmd = "$docto -WD -f $testinputfilesdir_temp -fx .doc -o $testoutputdir_temp -t wdFormatPDF -R true";
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-WD')
+ ->add('-f',$testinputfilesdir_temp)
+ ->add('-fx','.doc')
+ ->add('-o',$testoutputdir_temp)
+ ->add('-t wdFormatPDF')
+ ->add('-R','true') // the important one fo rthis test
+ ->build();
// echo $doctocmd;
$output = \Illuminate\Support\Facades\Process::run($doctocmd);
-
+// print_r($output);
// check files have been converted and originoals have been created.
- expect(collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'))->count())->tobe($dirfilescount - $docfilecount);
- expect(collect(\Illuminate\Support\Facades\Storage::listContents('outputtemp2'))->count())->tobe( $docfilecount);
+ expect(collect(\Illuminate\Support\Facades\Storage::AllFiles('inputfilestemp'))->count())->tobe($dirfilescount - $docfilecount);
+ expect(collect(\Illuminate\Support\Facades\Storage::AllFiles('outputtemp2'))->count())->tobe( $docfilecount);
+
+
+ });
+
+
+
+it('doesnt delete files from directory', function (){
+ // setup
+ // $testinputfilesdir = \Illuminate\Support\Facades\Storage::path('inputfiles\\plain');
+ $testinputfilesdir_temp = \Illuminate\Support\Facades\Storage::path('inputfilestemp');
+
+
+ $testinputfilesdir_temp = \Illuminate\Support\Facades\Storage::path('inputfilestemp');
+
+ $testoutputdir_temp = \Illuminate\Support\Facades\Storage::path('outputtemp2');
+
+ \Illuminate\Support\Facades\Storage::createDirectory('outputtemp2');
+
+ // $cmd = "xcopy \"$testinputfilesdir\" \"$testinputfilesdir_temp\\\" ";
+ // echo "\n". $cmd;
+ // $result = \Illuminate\Support\Facades\Process::run( $cmd );
+
+ //echo "\n" . $result->output() . "\n";
+ // $dirfiles = collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'));
+ $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['plain']),'inputfilestemp');
+ $docfiles = $dirfiles->filter(function ($item){
+ return str($item->path())->endsWith('.doc');
+ });
+ expect($docfiles->count())->toBeGreaterThan(0);
+ $docfilecount = count($docfiles->toArray());
+
+ $dirfilescount = $dirfiles->count();
+ // do conversion
+ $docto = config('services.docto.path');
+ // $doctocmd = "$docto -WD -f $testinputfilesdir_temp -fx .doc -o $testoutputdir_temp -t wdFormatPDF -R true";
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-WD')
+ ->add('-f',$testinputfilesdir_temp)
+ ->add('-fx','.doc')
+ ->add('-o',$testoutputdir_temp)
+ ->add('-t wdFormatPDF')
+ // ->add('-R','true') // the important one fo rthis test
+ ->build();
+ // echo $doctocmd;
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+
+ expect(collect(\Illuminate\Support\Facades\Storage::AllFiles('inputfilestemp'))->count())->toBeGreaterThan(0);
+ // check files have been converted and originoals have been created.
+ expect(collect(\Illuminate\Support\Facades\Storage::AllFiles('inputfilestemp'))->count())->tobe( $docfilecount);
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::AllFiles('outputtemp2'));
+ expect($outputDirFiles->count())->toBeGreaterThan( 0);
+ expect($outputDirFiles->count())->tobe( $docfilecount);
+ // This will delete all files in the storage/tests directory.
+ // this happens once a test run to prevent files from building up.
+ // could be done a bit more organised if desired.
+ \Illuminate\Support\Facades\Storage::deleteDirectory('\\');
});
diff --git a/companion/tests/Feature/VersionPestTest.php b/companion/tests/Feature/VersionPestTest.php
new file mode 100644
index 0000000..ec4a341
--- /dev/null
+++ b/companion/tests/Feature/VersionPestTest.php
@@ -0,0 +1,29 @@
+add('-h')
+ ->build();
+
+ $result = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output->output());
+ $outputString = $result->output();
+
+ expect($outputString)->toContain('DocTo Version: 1.16.45');
+
+
+ });
+
diff --git a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php
new file mode 100644
index 0000000..1e6f752
--- /dev/null
+++ b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php
@@ -0,0 +1,237 @@
+count())->tobe(0);
+ $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir);
+
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-XL')
+ ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' )
+ ->add('-o', $testoutputdir_temp .'\\Book1 MultiSheet Test.pdf')
+ ->add('-t', 'xlPDF')
+ ->add('--sheets', 'Tab3')
+ ->add('-L 10')
+ ->build();
+
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output);
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir));
+
+ expect($outputDirFiles->count())->toBeGreaterThan(0);
+ expect($outputDirFiles->count())->tobe(1);
+ // Sheet named
+ $sheetNamed = $outputDirFiles->filter(function ($item) {
+ // echo $item . "\n";
+ if (str($item)->contains('Book1 MultiSheet Test_(Sheet1).pdf') ) return true;
+ if (str($item)->contains('Book1 MultiSheet Test_(Sheet2).pdf') ) return true;
+ Return false;
+ });
+
+
+ $sheetNamed3 = $outputDirFiles->filter(function ($item) {
+ // echo $item . "\n";
+ if (str($item)->contains('Book1 MultiSheet Test_(Tab3).pdf') ) return true;
+
+ });
+
+ expect($sheetNamed->count())->tobe(0);
+ expect($sheetNamed3->count())->tobe(1);
+
+ // Storage::deleteDirectory($outputfiledir);
+ });
+
+
+ it('can pdf each sheet in a multi sheet xls', function () {
+
+ $inputfiledir = 'inputfilesxls';
+ $outputfiledir = 'outputfilesxls' . uniqid();
+ // setup
+ $testinputfilesdir_temp = Storage::path($inputfiledir);
+ $testoutputdir_temp = Storage::path($outputfiledir);
+
+ Storage::createDirectory($outputfiledir);
+
+ $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir);
+
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-XL')
+ ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' )
+ ->add('-o', $testoutputdir_temp .'\\Book1 MultiSheet Test.pdf')
+ ->add('-t', 'xlPDF')
+ ->add('--sheets', '1,2')
+ ->add('-L 10')
+ ->build();
+
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output);
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir));
+
+ expect($outputDirFiles->count())->toBeGreaterThan(0);
+ expect($outputDirFiles->count())->tobe(2);
+ // Sheet named
+ $sheetNamed = $outputDirFiles->filter(function ($item) {
+ // echo $item . "\n";
+ if (str($item)->contains('Book1 MultiSheet Test_(Sheet1).pdf') ) return true;
+ if (str($item)->contains('Book1 MultiSheet Test_(Sheet2).pdf') ) return true;
+ Return false;
+ });
+
+
+ $sheetNamed3 = $outputDirFiles->filter(function ($item) {
+ // echo $item . "\n";
+ if (str($item)->contains('Book1 MultiSheet Test_(Tab3).pdf') ) return true;
+
+ });
+
+ expect($sheetNamed->count())->tobe(2);
+ expect($sheetNamed3->count())->tobe(0);
+
+ Storage::deleteDirectory('outputtempxls2');
+ });
+
+
+ it('can pdf output all sheets multi sheet xls', function () {
+
+ $inputfiledir = 'inputfilesxls';
+ $outputfiledir = 'outputfilesxls' . uniqid();
+ // setup
+ $testinputfilesdir_temp = Storage::path($inputfiledir);
+ $testoutputdir_temp = Storage::path($outputfiledir);
+
+ Storage::createDirectory($outputfiledir);
+
+ $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir);
+
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-XL')
+ ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' )
+ ->add('-o', $testoutputdir_temp .'\\Book1 MultiSheet Test.pdf')
+ ->add('-t', 'xlPDF')
+ ->add('--allsheets')
+ ->add('-L 10')
+ ->build();
+
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output);
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir));
+
+ expect($outputDirFiles->count())->toBeGreaterThan(0);
+ expect($outputDirFiles->count())->tobe(3);
+ // Sheet named
+ $sheetNamed = $outputDirFiles->filter(function ($item) {
+ // echo $item . "\n";
+ if (str($item)->contains('Book1 MultiSheet Test_(Sheet1).pdf') ) return true;
+ if (str($item)->contains('Book1 MultiSheet Test_(Sheet2).pdf') ) return true;
+ if (str($item)->contains('Book1 MultiSheet Test_(Tab3).pdf') ) return true;
+ // this is not expected to match. Emtpy sheets dont output
+ if (str($item)->contains('Book1 MultiSheet Test_(Sheet4).pdf') ) return true;
+ Return false;
+ });
+
+ expect($sheetNamed->count())->tobe(3);
+
+
+ Storage::deleteDirectory($outputfiledir);
+ });
+
+ it('outputs correct all sheets multi sheet xls', function () {
+
+ $inputfiledir = 'inputfilesxls';
+ $outputfiledir = 'outputfilesxls' . uniqid();
+ // setup
+ $testinputfilesdir_temp = Storage::path($inputfiledir);
+ $testoutputdir_temp = Storage::path($outputfiledir);
+
+ Storage::createDirectory($outputfiledir);
+
+ $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir);
+
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-XL')
+ ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' )
+ ->add('-o', $testoutputdir_temp .'\\TabTest.csv')
+ ->add('-t', 'xlCSV')
+ ->add('--allsheets')
+ ->add('-L 10')
+ ->build();
+
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output->output());
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir));
+
+ expect($outputDirFiles->count())->toBeGreaterThan(0);
+ expect($outputDirFiles->count())->tobe(4);
+
+
+ // Sheet named
+ $fileText = file_get_contents(Storage::path($outputfiledir . '\\TabTest_(Tab3).csv'));
+ expect(str($fileText)->contains('This is Tab3'))->toBeTrue();
+ expect(str($fileText)->contains('This is Sheet 1'))->not()->toBeTrue();
+
+ // Sheet named
+ $fileText = file_get_contents(Storage::path($outputfiledir . '\\TabTest_(Sheet1).csv'));
+ expect(str($fileText)->contains('This is Sheet 1'))->toBeTrue();
+ expect(str($fileText)->contains('This is Tab3'))->not()->toBeTrue();
+
+
+
+ });
+
+
+
+ // these formats only output single sheet.
+ it('outputs correct single sheet multi sheet xls', function ($format, $ext) {
+
+ $inputfiledir = 'inputfilesxls';
+ $outputfiledir = 'outputfilesxls' . uniqid();
+ // setup
+ $testinputfilesdir_temp = Storage::path($inputfiledir);
+ $testoutputdir_temp = Storage::path($outputfiledir);
+
+ Storage::createDirectory($outputfiledir);
+
+ $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir);
+
+ $doctocmd = \App\Services\DocToCommandBuilder::docto()
+ ->add('-XL')
+ ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' )
+ ->add('-o', $testoutputdir_temp .'\\TabTest.' . $ext)
+ ->add('-t', $format)
+ ->add('--allsheets')
+ ->add('-L 10')
+ ->build();
+
+ $output = \Illuminate\Support\Facades\Process::run($doctocmd);
+ // print_r($output->output());
+ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir));
+
+ expect($outputDirFiles->count())->toBeGreaterThan(0);
+ expect($outputDirFiles->count())->tobe(1);
+
+
+
+ })->with([
+ ['xlUnicodeText', 'txt'],
+ ['xlCSVWindows', 'csv'],
+ ['xlTextWindows', 'txt'],
+ ]);
diff --git a/companion/tests/Feature/output/OutputDirCreationPestTest.php b/companion/tests/Feature/output/OutputDirCreationPestTest.php
index ba3a454..d1f40a7 100644
--- a/companion/tests/Feature/output/OutputDirCreationPestTest.php
+++ b/companion/tests/Feature/output/OutputDirCreationPestTest.php
@@ -9,7 +9,10 @@
$docto = config('services.docto.path');
$inputdir = \Illuminate\Support\Facades\Storage::path($gatherdir);
$fulloutputdir = \Illuminate\Support\Facades\Storage::path($outputdir);
- $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatHTML";
+ // $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatHTML";
+ $cmd = \App\Services\DocToCommandBuilder::docto()->add('-WD')->add('-f',$inputdir)
+ ->add('-o',$fulloutputdir)
+ ->add('-t wdFormatHTML')->build();
\Illuminate\Support\Facades\Log::debug($cmd);
\Illuminate\Support\Facades\Log::debug($fulloutputdir);
$output = Process::run($cmd);
@@ -17,7 +20,7 @@
});
- test('will not create extention directory', function () {
+ test('will not create extension directory', function () {
$gatherdir = uniqid();
$outputdir = uniqid();
$files = \App\Services\FileGatherService::GatherFiles(collect(['single']),$gatherdir);
@@ -26,7 +29,11 @@
$fulloutputdir = \Illuminate\Support\Facades\Storage::path($outputdir);
// a bug caused docto to create and ouput to extension directory.
$pdfdir = $fulloutputdir . '\\.pdf';
- $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatPDF";
+ // $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatPDF";
+ $cmd = \App\Services\DocToCommandBuilder::docto()->add('-WD')
+ ->add('-f',$inputdir)
+ ->add('-o',$fulloutputdir)
+ ->add('-t wdFormatPDF')->build();
\Illuminate\Support\Facades\Log::debug($cmd);
\Illuminate\Support\Facades\Log::debug($fulloutputdir);
$output = Process::run($cmd);
@@ -36,3 +43,22 @@
+
+ test('can create non existant directory with bulder', function () {
+ $gatherdir = uniqid();
+ $outputdir = uniqid();
+ $files = \App\Services\FileGatherService::GatherFiles(collect(['single']),$gatherdir);
+ $docto = config('services.docto.path');
+ $inputdir = \Illuminate\Support\Facades\Storage::path($gatherdir);
+ $fulloutputdir = \Illuminate\Support\Facades\Storage::path($outputdir);
+ $cmd = \App\Services\DocToCommandBuilder::docto()->add('-WD')
+ ->add('-f',$inputdir)
+ ->add('-o',$fulloutputdir)
+ ->add('-t wdFormatHTML')->build();
+ // $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatHTML";
+ \Illuminate\Support\Facades\Log::debug($cmd);
+ \Illuminate\Support\Facades\Log::debug($fulloutputdir);
+ $output = Process::run($cmd);
+ expect(\Illuminate\Support\Facades\Storage::exists($outputdir))->toBeTrue();
+
+});
diff --git a/pages/all/HelpLog.md b/pages/all/HelpLog.md
index 90790e7..fe0dc62 100644
--- a/pages/all/HelpLog.md
+++ b/pages/all/HelpLog.md
@@ -117,10 +117,15 @@ Long Parameters:
--PDF-no-BitmapMissingFonts
Do not bitmap missing fonts, fonts will be substituted.
--use-ISO190051
- Create PDF to the ISO 19005-1 standard.
+ Create PDF to the ISO 19005-1 standard.
+ --enable-macroautorun
--enable-wordvbaauto
- By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word Only.
-
+ --enable-xlvbaauto
+ By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only.
+ --sheets
+ Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. Unavailable for xlCSV
+ --allsheets
+ If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names
Experimental:
@@ -137,6 +142,7 @@ ERROR CODES:
203 : Unknown switch in command
204 : Input File does not exist
205 : Invalid Parameter Value
+210 : DocTo Error
220 : Word or COM Error
221 : Word not Installed
301 : Not Implemented
diff --git a/pages/all/HelpLog.txt.md b/pages/all/HelpLog.txt.md
index 6ecb041..e4be18a 100644
--- a/pages/all/HelpLog.txt.md
+++ b/pages/all/HelpLog.txt.md
@@ -112,10 +112,15 @@ Long Parameters:
--PDF-no-BitmapMissingFonts
Do not bitmap missing fonts, fonts will be substituted.
--use-ISO190051
- Create PDF to the ISO 19005-1 standard.
+ Create PDF to the ISO 19005-1 standard.
+ --enable-macroautorun
--enable-wordvbaauto
- By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word Only.
-
+ --enable-xlvbaauto
+ By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only.
+ --sheets
+ Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. Unavailable for xlCSV
+ --allsheets
+ If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names
Experimental:
@@ -132,6 +137,7 @@ ERROR CODES:
203 : Unknown switch in command
204 : Input File does not exist
205 : Invalid Parameter Value
+210 : DocTo Error
220 : Word or COM Error
221 : Word not Installed
301 : Not Implemented
diff --git a/readme.md b/readme.md
index cf1e421..1b978bb 100644
--- a/readme.md
+++ b/readme.md
@@ -128,8 +128,8 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u
## Command Line Help
Help
- Docto Version:%s
- Office Version : %s
+ DocTo Version: %s
+ Office Version: %s
Open Source: https://github.com/tobya/DocTo/
Description: DocTo converts Word Documents and Excel Spreadsheets to other formats.
@@ -140,19 +140,22 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u
-H This message
--HELP -?
- -WD Use Word for Converstion (Default). Help '-h -wd'
+ -WD Use Word for Conversion (Default). Help '-h -wd'
--word
-XL Use Excel for Conversion. Help '-h -xl'
--excel
-PP Use Powerpoint for Conversion. help '-h -pp'
--powerpoint
- -VS Use Visio for Conversion.
+ -VS Use Visio for Conversion.
--visio
-F Input File or Directory
--inputfile
- -FX Input file search for if -f is directory. Can use .rtf test*.txt etc
+ -FX Input Extension to search for if directory. (.rtf .txt etc)
Default ".doc*" (will find ".docx" also)
--inputextension
+ --inputfilter
+ Filter Files to input. Property*.doc will match Property1.doc,
+ Property2.doc etc
-O Output File or Directory to place converted Docs
--outputfile
-OX Output Extension if -F is Directory. Please include '.' eg. '.pdf' .
@@ -162,7 +165,6 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u
Available from
https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.word.wdsaveformat
or https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel.xlfileformat
- or https://docs.microsoft.com/en-us/office/vba/api/powerpoint.presentation.saveas
See current List Below.
--format
-TF Force Format. -T value if an integer, is checked against current list
@@ -219,9 +221,9 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u
--no-subdirs Only convert specified directory. Do not recurse sub directories
--ExportMarkup Value for wdExportItem - default wdExportDocumentContent.
use wdExportDocumentWithMarkup to export all word comments with pdf
- --no-IncludeDocProperties
+ --no-IncludeDocProperties
--no-DocProp
- Do not include Document Properties in the exported pdf file.
+ Do not include Document Properties in the exported pdf file.
--PDF-OpenAfterExport
If you wish for a converted PDF to be opened after creation. No value req.
--PDF-FromPage
@@ -237,11 +239,19 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u
--PDF-No-DocStructureTags
Do not include DocStructureTags to help screen readers.
--PDF-no-BitmapMissingFonts
- Do not bitmap missing fonts, fonts will be substituted.
- --use-ISO190051
+ Do not bitmap missing fonts, fonts will be substituted.
+ --use-ISO190051
Create PDF to the ISO 19005-1 standard.
+ --enable-macroautorun
+ --enable-wordvbaauto
+ --enable-xlvbaauto
+ By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only.
+ --sheets
+ Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only.
+ --allsheets
+ If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names
Experimental:
@@ -260,8 +270,9 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u
205 : Invalid Parameter Value
220 : Word or COM Error
221 : Word not Installed
+ 301 : Not Implemented
400 : Unknown Error
-
+
# Parameter Overview
## Usage
diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas
index eff9453..c11ba22 100644
--- a/src/ExcelUtils.pas
+++ b/src/ExcelUtils.pas
@@ -14,7 +14,10 @@
****************************************************************)
interface
-uses Classes,Sysutils, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants, Excel_TLB_Constants,StrUtils;
+uses Classes,Sysutils, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants,
+DynamicFileNameGenerator, DocToExceptions,
+
+ Excel_TLB_Constants,StrUtils;
type
@@ -23,11 +26,25 @@ interface
ExcelApp : OleVariant;
FExcelVersion : String;
+ olevar_FromPage, olevar_ToPage : OleVariant;
+
+ function SingleFileExecuteConversion(fileToConvert, OutputFilename: String; OutputFileFormat: Integer): TConversionInfo;
+ procedure SaveAsPDF(OutputFilename : string) ;
+ procedure SaveAsXPS(OutputFilename: string);
+ procedure SaveAsCSV(OutputFilename: string);
+ procedure ExportWorkSheetasPDF(ws :OleVariant; FileNameGen : TDynamicFileNameGenerator);
+ procedure ExportWorkbookasPDF(OutputFileName: String);
+
+ function isWorkSheetEmpty(WorkSheet : OleVariant): boolean;
+ procedure CheckWorkSheetIndexValid(index : integer);
+
public
constructor Create() ;
function CreateOfficeApp() : boolean; override;
function DestroyOfficeApp() : boolean; override;
+
function ExecuteConversion(fileToConvert: String; OutputFilename: String; OutputFileFormat : Integer): TConversionInfo; override;
+
function AvailableFormats() : TStringList; override;
function FormatsExtensions(): TStringList; override;
function OfficeAppVersion() : String; override;
@@ -54,6 +71,15 @@ function TExcelXLSConverter.AvailableFormats() : TStringList;
{ TWordDocConverter }
+procedure TExcelXLSConverter.CheckWorkSheetIndexValid(index: integer);
+begin
+
+ if (index = 0) then
+ begin
+ raise ESheetIndexOutOfBounds.Create('Excel Worksheets start at 1. 0 is not valid index');
+ end;
+end;
+
constructor TExcelXLSConverter.Create;
begin
inherited;
@@ -88,7 +114,10 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen
var
NonsensePassword :OleVariant;
FromPage, ToPage : OleVariant;
+ activeSheet, oldEnableEvents, oldAutoSecurity : OleVariant;
+ dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String;
ExitAction :TExitAction;
+ Sheet : integer;
begin
//Excel is particuarily sensitive to having \\ at end of filename, eg it won't create file.
//so we remove any double \\
@@ -97,7 +126,21 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen
ExitAction := aSave;
Result.InputFile := fileToConvert;
Result.Successful := false;
+
+
+ // disable Macros before opening file.
+ if (fDontUseAutoVBA) then
+ begin
+ oldEnableEvents := ExcelApp.EnableEvents;
+ ExcelApp.EnableEvents := false;
+ oldAutoSecurity := ExcelApp.AutomationSecurity;
+ ExcelApp.AutomationSecurity := 3; // msoAutomationSecurityForceDisable
+ end;
+
+ try
+
NonsensePassword := 'tfm554!ghAGWRDD';
+
try
ExcelApp.Workbooks.Open( FileToConvert, //FileName ,
EmptyParam, //UpdateLinks ,
@@ -155,53 +198,124 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen
aSave: // Go ahead and save
begin
+ Result := SingleFileExecuteConversion(fileToConvert, OutputFilename, OutputFileFormat);
- //Unlike Word, in Excel you must call a different function to save a pdf and XPS.
- if OutputFileFormat = xlTypePDF then
+ // To avoid pop ups it is important to save the sheet. However not if the macros have run.
+ if (fDontUseAutoVBA) then
begin
+ ExcelApp.ActiveWorkBook.save;
+ end ;
- if pdfPrintToPage > 0 then
- begin
- logdebug('PrintFromPage: ' + inttostr(pdfPrintFromPage),debug);
- logdebug('PrintToPage: ' + inttostr(pdfPrintToPage),debug);
+ ExcelApp.ActiveWorkBook.Saved := true;
+ // Saved has previously been set to true.
+ // should close without dialog.
+ ExcelApp.ActiveWorkbook.Close();
- FromPage := pdfPrintFromPage;
- ToPage := pdfPrintToPage;
- end else
- begin
- FromPage := EmptyParam;
- ToPage := EmptyParam;
- end ;
+ end;
+ end;
- ExcelApp.Application.DisplayAlerts := False ;
- ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF,
- OutputFilename,
- EmptyParam, //Quality
- IncludeDocProps, // IncludeDocProperties,
- False,// IgnorePrintAreas,
- FromPage , // From,
- ToPage, // To,
- pdfOpenAfterExport, // OpenAfterPublish, (default false);
- EmptyParam// FixedFormatExtClassPtr
- ) ;
+ finally
+ if (fDontUseAutoVBA) then
+ begin
+ ExcelApp.EnableEvents := oldEnableEvents;
+ ExcelApp.AutomationSecurity := oldAutoSecurity;
+ end;
+ end;
+
+end;
+
+
+procedure TExcelXLSConverter.ExportWorkbookasPDF(OutputFileName: String);
+var
+activeWkBk: OleVariant;
+begin
+
+ activeWkBk := ExcelApp.ActiveWorkbook;
+
+
+ ExcelApp.Application.DisplayAlerts := False ;
+ activeWkBk.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF,
+ OutputFileName,
+ EmptyParam, // Quality
+ IncludeDocProps, // IncludeDocProperties,
+ False, // IgnorePrintAreas,
+ olevar_FromPage , // From,
+ olevar_ToPage, // To,
+ pdfOpenAfterExport, // OpenAfterPublish, (default false);
+ EmptyParam // FixedFormatExtClassPtr
+ ) ;
+ fOutputFiles.Add(OutputFileName);
+
+end;
- ExcelApp.ActiveWorkBook.Saved := True
+procedure TExcelXLSConverter.ExportWorkSheetasPDF(ws: OleVariant; FileNameGen: TDynamicFileNameGenerator);
+begin
+ if self.isWorkSheetEmpty(ws) then
+ begin
+ logInfo('The worksheet "' + ws.Name + '" is Empty and will not be output', STANDARD);
+
+ end else
+ begin
+
+
+ ExcelApp.Application.DisplayAlerts := False ;
+ ws.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF,
+ FileNameGen.Generate(ws.Name),
+ EmptyParam, // Quality
+ IncludeDocProps, // IncludeDocProperties,
+ False, // IgnorePrintAreas,
+ olevar_FromPage , // From,
+ olevar_ToPage, // To,
+ pdfOpenAfterExport, // OpenAfterPublish, (default false);
+ EmptyParam // FixedFormatExtClassPtr
+ ) ;
+ end;
+
+ fOutputFiles.Add(FileNameGen.Generate(ws.Name));
+
+end;
+
+//Useful Links:
+// https://docs.microsoft.com/en-us/office/vba/api/excel.workbooks.open
+// https://docs.microsoft.com/en-us/office/vba/api/excel.workbook.exportasfixedformat
+
+function TExcelXLSConverter.SingleFileExecuteConversion(fileToConvert: String; OutputFilename: String; OutputFileFormat : Integer): TConversionInfo;
+var
+ NonsensePassword :OleVariant;
+ FromPage, ToPage : OleVariant;
+ activeSheet : OleVariant;
+ dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String;
+ ExitAction :TExitAction;
+ Sheet : integer;
+begin
+
+ logdebug('SingleFileExecuteConversion',VERBOSE);
+
+ //Unlike Word, in Excel you must call a different function to save a pdf and XPS.
+ if OutputFileFormat = xlTypePDF then
+ begin
+
+ SaveAsPDF(OutputFilename);
end
else if OutputFileFormat = xlTypeXPS then
begin
- ExcelApp.Application.DisplayAlerts := False ;
- ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypeXPS, OutputFilename );
- ExcelApp.ActiveWorkBook.save;
+ SaveAsXPS(OutputFilename);
end
else if OutputFileFormat = xlCSV then
begin
- //CSV pops up alert. must be hidden for automation
- ExcelApp.Application.DisplayAlerts := False ;
- ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat);
- ExcelApp.ActiveWorkBook.saved := true;
+
+
+
+ // to get sheets
+ // Sheets(Array("Sheet4", "Sheet5")) or Sheets(3) or Sheets(Array(1,2))
+ ExcelApp.Application.DisplayAlerts := False ;
+ SaveAsCSV( OutputFilename);
+
+// ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat);
+ // ExcelApp.ActiveWorkBook.saved := true;
end
else
begin
@@ -215,10 +329,8 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen
// Close Excel Sheet.
Result.Successful := true;
Result.OutputFile := OutputFilename;
- ExcelApp.ActiveWorkbook.Close();
- end;
- end;
+
end;
@@ -232,6 +344,16 @@ function TExcelXLSConverter.FormatsExtensions: TStringList;
result := Extensions;
end;
+function TExcelXLSConverter.isWorkSheetEmpty(WorkSheet: OleVariant): boolean;
+begin
+
+ // this will tell if a sheet is empty.
+ Result := ExcelApp.WorksheetFunction.CountA(WorkSheet.Cells) = 0;
+
+end;
+
+
+
function TExcelXLSConverter.OfficeAppVersion(): String;
begin
FExcelVersion := ReadOfficeAppVersion;
@@ -244,4 +366,226 @@ function TExcelXLSConverter.OfficeAppVersion(): String;
result := FExcelVersion;
end;
+
+procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ;
+var
+
+ FromPage, ToPage, SheetList, ExcelSheets : OleVariant;
+ Sheet1,Sheet2,Sheet3 , Workbook , SheetsArray: OleVariant;
+ activeSheet, WorkSheets, ws, wsName : OleVariant;
+ I,j, sheetNumber :integer;
+ sheetName : olevariant;
+ FileNameGen: TDynamicFileNameGenerator;
+begin
+
+
+ logdebug('Save as pdf',debug);
+
+ ExcelApp.Application.DisplayAlerts := False ;
+
+ if pdfPrintToPage > 0 then
+ begin
+ logdebug('PrintFromPage: ' + inttostr(pdfPrintFromPage),debug);
+ logdebug('PrintToPage: ' + inttostr(pdfPrintToPage),debug);
+
+ olevar_FromPage := pdfPrintFromPage;
+ olevar_ToPage := pdfPrintToPage;
+
+ end else
+ begin
+ olevar_FromPage := EmptyParam;
+ olevar_ToPage := EmptyParam;
+
+ end ;
+
+ WorkSheets := ExcelApp.Worksheets;
+
+
+ logDebug('count:' + inttostr(WorkSheets.Count), verbose);
+ FileNameGen := TDynamicFileNameGenerator.Create(OutputFilename);
+
+ if fSelectedSheets_All then
+ begin
+ logDebug('in fSelectedSheets_All');
+
+ for I := 1 to WorkSheets.Count do
+ begin
+
+
+ ws := WorkSheets.Item[I];
+
+ logDebug('worksheet:' + ws.Name, VERBOSE);
+
+ ExportWorkSheetasPDF(ws,FileNameGen);
+
+
+ end;
+
+ end else if SelectedSheets.Count > 0 then
+ begin
+ logdebug('SelectedSheets.Count:' + inttostr( SelectedSheets.Count), debug);
+
+ logDebug( SelectedSheets.Text,VERBOSE);
+
+
+
+
+
+ for j := 0 to SelectedSheets.Count -1 do
+ begin
+
+ sheetName := SelectedSheets[j];
+ logDebug( sheetName,VERBOSE);
+
+ if (TryStrToInt(sheetName,sheetNumber) )then
+ begin
+ logdebug( 'TryStrToInt',VERBOSE);
+ self.CheckWorkSheetIndexValid(sheetNumber);
+ ws := WorkSheets.Item[sheetNumber];
+ end else
+ begin
+ logdebug( 'not TryStrToInt',VERBOSE);
+ ws := WorkSheets.Item[sheetName];
+
+ end;
+
+
+
+
+
+
+
+ logDebug('worksheetxx:' + ws.Name, VERBOSE);
+
+ ExportWorkSheetasPDF(ws,FileNameGen);
+
+
+ end;
+
+ end else
+ begin
+
+ self.ExportWorkbookasPDF(OutputFileName);
+ end;
+
+
+
+
+
+ ExcelApp.ActiveWorkBook.Saved := True
+
+end;
+
+
+procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ;
+begin
+
+ if (SelectedSheets.Count > 0) or (fSelectedSheets_All = true) then
+ begin
+ raise ENotImplemented.Create('--sheets, --allsheets is not available for conversion to XPS');
+ end;
+
+ ExcelApp.Application.DisplayAlerts := False ;
+ ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypeXPS, OutputFilename );
+
+end;
+
+// Save to 1 or move csv files
+procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string);
+var
+ FromPage, ToPage : OleVariant;
+ activeSheet, sheetName : OleVariant;
+ sheetNumber : integer;
+ dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String;
+ ExitAction :TExitAction;
+ Sheet, ix : integer;
+ FileNameGen : TDynamicFileNameGenerator;
+begin
+ // LogDebug('output to csv format');
+
+
+ ExcelApp.Application.DisplayAlerts := False ;
+
+ if SelectedSheets.Count > 0 then
+ begin
+ raise EInvalidParameterCombination.Create('--sheet cannot be used with xlCSV. Use --allsheets instead');
+ end;
+
+
+ FileNameGen := TDynamicFileNameGenerator.Create(OutputFilename);
+
+// ********************************************************
+// Very Strange Behaviour
+//
+// When The sheets are output in order going from 1 to Worksheet.Count then each
+// sheet is output correctly as a CSV file. However if an attempt is made to
+// output a single sheet, either by index or sheet name the first sheet is
+// always output. It makes no sense, the code is identical. I have tried many
+// times. Therefore I am going to just leave it and always output all.
+
+
+
+ // output all sheets with seperate names
+ if (fSelectedSheets_All) or (SelectedSheets.Count > 0) then
+ begin
+
+
+
+ for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do
+ begin
+ // LogDebug('CSV Loop');
+ activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet];
+ dynamicSheetName := activeSheet.Name;
+
+ // LogDebug(dynamicSheetName);
+
+ dynamicOutputFilename := FileNameGen.Generate(dynamicSheetName);
+
+ // LogDebug(dynamicOutputFileName);
+
+ activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat);
+ fOutputFiles.Add(dynamicoutputFilename);
+ end;
+ end
+ (* end
+ // If we have been given Sheetnames or ids, just output them.
+ else if SelectedSheets.Count > 0 then
+
+ begin
+
+
+
+ // This code doesnt work, it should but it doesnt, it always outputs the
+ // first sheet.
+
+ for ix := 0 to SelectedSheets.Count -1 do
+ begin
+ LogDebug('CSV Loop:' + SelectedSheets[ix]);
+ sheetName := SelectedSheets[ix];
+
+ // Check if number requested and set sheetNumber
+ // -------------
+ activeSheet := ExcelApp.ActiveWorkbook.Sheets[sheetName];
+ dynamicSheetName := activeSheet.Name;
+
+ LogDebug(dynamicSheetName);
+
+ dynamicOutputFilename := FileNameGen.Generate(dynamicSheetName);
+
+ LogDebug(dynamicOutputFileName);
+
+ activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat);
+ end;
+
+ end else *)
+ // Do default which is usually first sheet, with name provided.
+ else
+ begin
+ ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat);
+ fOutputFiles.Add(OutputFilename);
+ end;
+
+
+end;
+
end.
diff --git a/src/Exceptions/DocToExceptions.pas b/src/Exceptions/DocToExceptions.pas
new file mode 100644
index 0000000..b091805
--- /dev/null
+++ b/src/Exceptions/DocToExceptions.pas
@@ -0,0 +1,14 @@
+unit DocToExceptions;
+
+interface
+uses Classes, ActiveX, ComObj, WinINet, Variants, sysutils, Types, StrUtils, TypInfo;
+
+type
+
+ EDocToException = class(Exception);
+ ESheetIndexOutOfBounds = class(EDocToException);
+ EInvalidParameterCombination = class(EDocToException);
+
+implementation
+
+end.
diff --git a/src/ExtraFiles.res b/src/ExtraFiles.res
index c334f37..c93bc94 100644
Binary files a/src/ExtraFiles.res and b/src/ExtraFiles.res differ
diff --git a/src/MainUtils.pas b/src/MainUtils.pas
index 1902b10..f793e98 100644
--- a/src/MainUtils.pas
+++ b/src/MainUtils.pas
@@ -9,17 +9,17 @@
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-Intereting article
+Interesting article
https://support.microsoft.com/en-gb/topic/considerations-for-server-side-automation-of-office-48bcfe93-8a89-47f1-0bce-017433ad79e2
****************************************************************)
interface
uses classes, Windows, sysutils, ActiveX, ComObj, WinINet, Variants, iduri,
- Types, ResourceUtils, StrUtils,
+ Types, ResourceUtils, StrUtils, DocToExceptions,
PathUtils, ShellAPI, datamodssl, Word_TLB_Constants;
Const
VERBOSE = 10;
- DEBUG = 9;
+ DEBUG = 9;
HELP = 8;
CHATTY = 5;
STANDARD = 2;
@@ -33,8 +33,8 @@ interface
MSVISIO = 4;
- DOCTO_VERSION = '1.15.45'; // dont use 0x - choco needs incrementing versions.
- DOCTO_VERSION_NOTE = ' x64 Release ';
+ DOCTO_VERSION = '1.16.45'; // dont use 0x - choco needs incrementing versions.
+ DOCTO_VERSION_NOTE = ' (Test Version XLS Multisheet B) ';
type
@@ -71,6 +71,9 @@ TDocumentConverter = class
FKeepIRM: boolean;
FDocStructureTags: boolean;
FBitmapMissingFonts: boolean;
+ fSelectedSheets: TStrings;
+
+
procedure SetCompatibilityMode(const Value: Integer);
@@ -95,6 +98,7 @@ TDocumentConverter = class
procedure SetKeepIRM(const Value: boolean);
procedure SetDocStructureTags(const Value: boolean);
procedure SetBitmapMissingFonts(const Value: boolean);
+ procedure Setsheets(const Value: TStrings);
protected
@@ -141,6 +145,10 @@ TDocumentConverter = class
FOutputIsFile: Boolean;
FOutputIsDir: Boolean;
+
+ fOutputFiles : TStrings;
+ fSelectedSheets_All : boolean;
+
procedure SetInputFile(const Value: String);
procedure SetOutputFile(const Value: String);
procedure SetOutputFileFormat(const Value: Integer);
@@ -184,6 +192,8 @@ TDocumentConverter = class
property pdfPrintToPage : integer read FpdfPrintToPage;
property useISO190051 : boolean read FuseISO190051;
property pdfOptimizeFor : integer read fpdfOptimizeFor write fpdfOptimizeFor;
+ property SelectedSheets : TStrings read fSelectedSheets write Setsheets;
+
property ExportMarkup : integer read fExportMarkup;
property IncludeDocProps : boolean read FIncludeDocProps write SetIncludeDocProps;
@@ -218,6 +228,7 @@ TDocumentConverter = class
function CheckShouldIgnore(DocumentPath : String): Boolean;
+
public
Constructor Create();
@@ -518,6 +529,9 @@ constructor TDocumentConverter.Create;
FBitmapMissingFonts := true;
FInputFiles := TStringList.Create;
fDontUseAutoVBA := true;
+ fSelectedSheets := TStringList.Create;
+ fSelectedSheets_All := false;
+ fOutputFiles := TStringlist.Create;
end;
@@ -539,6 +553,7 @@ destructor TDocumentConverter.Destroy;
FInputFiles.Free;
+ fSelectedSheets.Free;
if assigned(FNetHandle) then
begin
@@ -674,7 +689,8 @@ function TDocumentConverter.Execute: string;
if ConversionInfo.Successful then
begin
- logInfo('File Converted: ' + ConversionInfo.OutputFile);
+ // logInfo('File Converted: ' + ConversionInfo.OutputFile);
+ logInfo('Files Converted: ' + fOutputFiles.Text);
// Check if file needs to be deleted.
if RemoveFileOnConvert then
@@ -748,12 +764,41 @@ function TDocumentConverter.Execute: string;
end;
end;
+ on E: ENotImplemented do
+ begin
+ ErrorMessage := StringReplace(E.Message,#13,'--',[rfReplaceAll]);
+ if (HaltOnWordError) then
+ begin
+ LogError( FileToConvert );
+ HaltWithError(301,E.ClassName + ' ' + ErrorMessage );
+ end
+ else
+ begin
+ LogError(E.ClassName + ' ' + ErrorMessage + ' ' + FileToConvert + ':' + FileToCreate);
+
+ end;
+ end;
+ on E: EDocToException do
+ begin
+ ErrorMessage := StringReplace(E.Message,#13,'--',[rfReplaceAll]);
+ if (HaltOnWordError) then
+ begin
+ LogError( FileToConvert );
+ HaltWithError(210,E.ClassName + ' ' + ErrorMessage );
+ end
+ else
+ begin
+ LogError(E.ClassName + ' ' + ErrorMessage + ' ' + FileToConvert + ':' + FileToCreate);
+
+ end;
+ end;
on E: Exception do
begin
ErrorMessage := StringReplace(E.Message,#13,'--',[rfReplaceAll]);
if (HaltOnWordError) then
begin
- HaltWithError(220,E.ClassName + ' ' + ErrorMessage + ' ' + FileToConvert + ':' + FileToCreate);
+ LogError( FileToConvert );
+ HaltWithError(220,E.ClassName + ' ' + ErrorMessage );
end
else
begin
@@ -1243,6 +1288,20 @@ procedure TDocumentConverter.LoadConfig(Params: TStrings);
HaltWithConfigError(205,'Invalid value for --PDF-OPTIMIZEFOR :' + value);
end;
END
+ else if (id = '--SHEETS') then
+ begin
+ fSelectedSheets.DelimitedText := value;
+ if fSelectedSheets.Count = 0 then
+ begin
+ HaltWithConfigError(205,'Expecting > 0 selected sheets: ' + value);
+ end;
+ end
+ else if (id = '--ALLSHEETS') then
+ begin
+ fSelectedSheets_All := true;
+
+ dec(iParam);
+ end
else if (id = '--EXPORTMARKUP') then
begin
if (WordConstants.Exists(value)) then
@@ -1275,6 +1334,7 @@ procedure TDocumentConverter.LoadConfig(Params: TStrings);
FBitmapMissingFonts := false;
dec(iParam);
end
+
else if (id = '-W') or
(id = '--WEBHOOK') then
begin
@@ -1287,15 +1347,12 @@ procedure TDocumentConverter.LoadConfig(Params: TStrings);
end
else if (id = '--ENABLE-MACROAUTORUN') or
- (id = '--ENABLE-WORDVBAAUTO')
+ (id = '--ENABLE-WORDVBAAUTO') or
+ (id = '--ENABLE-XLVBAAUTO')
then
begin
fDontUseAutoVBA := false;
- if (OfficeAppName <> 'Word')then
- begin
- // Excel Application.EnableEvents = False
- // HaltWithError(301,'Parameter ' + id + ' not Implemented for ' + OfficeAppName );
- end;
+
end
else if (id = '-X') or
@@ -1642,6 +1699,8 @@ procedure TDocumentConverter.WriteOfficeAppVersion(Version: String);
LogDebug('Writing Version to File:' + ConfigFileName,VERBOSE);
end;
+
+
procedure TDocumentConverter.SetBitmapMissingFonts(const Value: boolean);
begin
FBitmapMissingFonts := Value;
@@ -1851,6 +1910,11 @@ procedure TDocumentConverter.SetRemoveFileOnConvert(const Value: boolean);
+procedure TDocumentConverter.Setsheets(const Value: TStrings);
+begin
+ fSelectedSheets := Value;
+end;
+
procedure TDocumentConverter.SetSkipDocsWithTOC(const Value: Boolean);
begin
FSkipDocsWithTOC := Value;
diff --git a/src/docto.dpr b/src/docto.dpr
index a880827..5b540d7 100644
--- a/src/docto.dpr
+++ b/src/docto.dpr
@@ -35,7 +35,9 @@ uses
Excel_TLB_Constants in 'Excel_TLB_Constants.pas',
PowerPoint_TLB_Constants in 'PowerPoint_TLB_Constants.pas',
VisioUtils in 'VisioUtils.pas',
- Visio_TLB in 'Visio_TLB.pas';
+ Visio_TLB in 'Visio_TLB.pas',
+ DynamicFileNameGenerator in 'shared\DynamicFileNameGenerator.pas',
+ DocToExceptions in 'Exceptions\DocToExceptions.pas';
var
i, Converter : integer;
diff --git a/src/docto.dproj b/src/docto.dproj
index cfaf3d7..a00d2dc 100644
--- a/src/docto.dproj
+++ b/src/docto.dproj
@@ -226,6 +226,7 @@
1033
CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.3.2.15;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
(None)
+ -XL -f "Book1WithMacros.xlsm" -o c:/DriveETemp/sheet222macdro.pdf -t xlPDF -l 10 --enable-xlvbaauto
../exe
@@ -297,6 +298,8 @@
+
+
@@ -387,56 +390,80 @@
True
-
+
.\
true
-
+
+
+ docto.exe
+ true
+
+
+
.\
true
-
+
.\
true
-
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
.\
true
+
+
+ .\
+ true
+
+
docto.exe
true
-
-
+
+
.\
true
-
+
.\
true
-
+
.\
true
-
-
+
+
.\
true
@@ -453,8 +480,8 @@
true
-
-
+
+
.\
true
@@ -465,8 +492,14 @@
true
-
-
+
+
+ .\
+ true
+
+
+
+
.\
true
@@ -477,6 +510,12 @@
true
+
+
+ .\
+ true
+
+
.\
@@ -495,12 +534,31 @@
true
-
-
+
+
+ .\
true
-
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ docto.exe
+ true
+
+
+
.\
true
@@ -517,6 +575,197 @@
true
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
.\
@@ -529,12 +778,30 @@
true
+
+
+ .\
+ true
+
+
.\
true
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
.\
diff --git a/src/docto.dproj.local b/src/docto.dproj.local
index 77c4153..ea67e01 100644
--- a/src/docto.dproj.local
+++ b/src/docto.dproj.local
@@ -6,12 +6,18 @@
2021/12/02 22:25:13.000.761,=D:\Development\GitHub\DocTo\src\New1.bat
2021/12/02 22:25:32.000.527,D:\Development\GitHub\DocTo\src\New1.bat=D:\Development\GitHub\DocTo\test\TestDocTo_Quiet.bat
2023/09/11 17:39:20.000.384,=C:\Development\github\docto\src\res\xlsFormats.txt
+ 2025/11/18 17:53:47.000.458,=C:\Development\github\docto\src\Unit1.pas
+ 2025/11/18 17:54:21.000.396,C:\Development\github\docto\src\shared\DynamicFileNameGenerator.pas=C:\Development\github\docto\src\Unit1.pas
+ 2025/11/19 14:43:02.000.361,=C:\Development\github\docto\src\Unit1.pas
+ 2025/11/19 14:43:31.000.175,C:\Development\github\docto\src\Exceptions\DocToExceptions.pas=C:\Development\github\docto\src\Unit1.pas
+
+
@@ -31,6 +37,8 @@
+
+
diff --git a/src/res/HelpLog.txt b/src/res/HelpLog.txt
index 6ecb041..eecaa26 100644
--- a/src/res/HelpLog.txt
+++ b/src/res/HelpLog.txt
@@ -112,10 +112,15 @@ Long Parameters:
--PDF-no-BitmapMissingFonts
Do not bitmap missing fonts, fonts will be substituted.
--use-ISO190051
- Create PDF to the ISO 19005-1 standard.
+ Create PDF to the ISO 19005-1 standard.
+ --enable-macroautorun
--enable-wordvbaauto
- By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word Only.
-
+ --enable-xlvbaauto
+ By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only.
+ --sheets
+ Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. PDF Only
+ --allsheets
+ If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names. PDF, CSV only
Experimental:
@@ -132,6 +137,7 @@ ERROR CODES:
203 : Unknown switch in command
204 : Input File does not exist
205 : Invalid Parameter Value
+210 : DocTo Error
220 : Word or COM Error
221 : Word not Installed
301 : Not Implemented
diff --git a/src/shared/DynamicFileNameGenerator.pas b/src/shared/DynamicFileNameGenerator.pas
new file mode 100644
index 0000000..5c808f6
--- /dev/null
+++ b/src/shared/DynamicFileNameGenerator.pas
@@ -0,0 +1,87 @@
+unit DynamicFileNameGenerator;
+
+interface
+
+uses Classes, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants, sysutils, Types, StrUtils;
+
+type
+
+TDynamicFileNameGenerator = Class(TObject)
+ private
+ FIgnoreTag: Boolean;
+ procedure SetIgnoreTag(const Value: Boolean);
+protected
+
+ fOrigionalFilename : string;
+ dynamicoutputDir :string;
+ dynamicoutputFile :string;
+ dynamicoutputExt :string;
+ fFilenameParts : TStringList;
+ procedure Deconstruct();
+public
+ Constructor Create(FileName: String);
+ function Generate(tag: String ) : String;
+ function SafeFileName(FileName: String ) : String;
+ property IgnoreTag : Boolean read FIgnoreTag write SetIgnoreTag;
+End;
+
+
+implementation
+
+{ TDynamicFileNameGenerator }
+
+constructor TDynamicFileNameGenerator.Create(FileName: String);
+begin
+
+ FIgnoreTag := false;
+ fOrigionalFilename := Filename;
+ self.Deconstruct;
+end;
+
+procedure TDynamicFileNameGenerator.Deconstruct;
+
+
+begin
+ dynamicoutputDir := ExtractFilePath(fOrigionalFilename); // includes last \
+ dynamicoutputFile := ChangefileExt ( ExtractFileName(fOrigionalFilename),'');
+ dynamicoutputExt := ExtractFileExt(fOrigionalFilename);
+
+
+end;
+
+function TDynamicFileNameGenerator.Generate(tag: String): String;
+var
+dynamicFileName : String;
+dynamicOutputFilename : string;
+
+begin
+ dynamicFileName := SafeFileName(tag);
+ if FIgnoreTag then
+ begin
+ result := fOrigionalFilename;
+ end else
+ begin
+ result := dynamicoutputDir + dynamicoutputFile + '_(' + tag + ')' + dynamicoutputExt;
+ end;
+
+end;
+
+function TDynamicFileNameGenerator.SafeFileName(FileName: String): String;
+begin
+ Filename := StringReplace(Filename,'&','_',[rfReplaceAll,rfIgnoreCase]);
+ Filename := StringReplace(Filename,'/','_',[rfReplaceAll,rfIgnoreCase]);
+ Filename := StringReplace(Filename,'\\','_',[rfReplaceAll,rfIgnoreCase]);
+ Filename := StringReplace(Filename,'<','_',[rfReplaceAll,rfIgnoreCase]);
+ Filename := StringReplace(Filename,'>','_',[rfReplaceAll,rfIgnoreCase]);
+ Filename := StringReplace(Filename,':','_',[rfReplaceAll,rfIgnoreCase]);
+ Filename := StringReplace(Filename,'?','_',[rfReplaceAll,rfIgnoreCase]);
+ Filename := StringReplace(Filename,'*','_',[rfReplaceAll,rfIgnoreCase]);
+ result := Filename;
+end;
+
+procedure TDynamicFileNameGenerator.SetIgnoreTag(const Value: Boolean);
+begin
+ FIgnoreTag := Value;
+end;
+
+end.
diff --git a/test/inputfilesxl/Book1 Single Sheet.xlsx b/test/inputfilesxl/Book1 Single Sheet.xlsx
new file mode 100644
index 0000000..591c871
Binary files /dev/null and b/test/inputfilesxl/Book1 Single Sheet.xlsx differ
diff --git a/test/inputfilesxl/Book1WithMacros.xlsm b/test/inputfilesxl/Book1WithMacros.xlsm
index e71827a..f94a4ac 100644
Binary files a/test/inputfilesxl/Book1WithMacros.xlsm and b/test/inputfilesxl/Book1WithMacros.xlsm differ
diff --git a/test/inputfilesxl/Week 1 Test.xls b/test/inputfilesxl/Week 1 Test.xls
index a10f1d6..0abb076 100644
Binary files a/test/inputfilesxl/Week 1 Test.xls and b/test/inputfilesxl/Week 1 Test.xls differ
diff --git a/test/inputfilesxl/wk1test-MultiSheet.xls b/test/inputfilesxl/wk1test-MultiSheet.xls
new file mode 100644
index 0000000..129dd4c
Binary files /dev/null and b/test/inputfilesxl/wk1test-MultiSheet.xls differ
diff --git a/test/inputfilesxl/wk1test.xls b/test/inputfilesxl/wk1test.xls
new file mode 100644
index 0000000..eaca836
Binary files /dev/null and b/test/inputfilesxl/wk1test.xls differ
diff --git a/test/testxlsfile.bat b/test/testxlsfile.bat
index d5bd189..9ee0855 100644
--- a/test/testxlsfile.bat
+++ b/test/testxlsfile.bat
@@ -1,2 +1,2 @@
REM Load csv files convert to xls
-"../exe/32/docto.exe" -XL -f "C:\dev\github\docto\test\inputfilesxl\Week 1 Test.xls" -o "C:\dev\github\docto\test\GeneratedFiles" -T xlPDF -l 10
\ No newline at end of file
+"../exe/32/docto.exe" -XL -f "C:\dev\github\docto\test\inputfilesxl\Week 1 Test.xls" -o "C:\dev\github\docto\test\GeneratedFiles" -T xlPDF -l 10
diff --git a/test/testxlspass.bat b/test/testxlspass.bat
index 5084bab..aab0e29 100644
--- a/test/testxlspass.bat
+++ b/test/testxlspass.bat
@@ -1,2 +1,3 @@
REM Load csv files convert to xls
-"../exe/32/docto.exe" -XL -f "C:\dev\github\docto\test\inputfilesxl\Book1 with password.xls" -o "C:\dev\github\docto\test\GeneratedFiles" -T xlpdf -l 10
\ No newline at end of file
+REM will skip password protected file
+"../exe/32/docto.exe" -XL -f "C:\development\github\docto\test\inputfilesxl\Book1 with password.xls" -o "C:\development\github\docto\test\GeneratedFiles" -T xlpdf -l 10
\ No newline at end of file