Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
73dccae
one1
Dec 21, 2022
01ad688
output multisheets to multiple files
Dec 21, 2022
8ebabf3
version
Dec 21, 2022
5b1c93c
config
Dec 21, 2022
d0d0a8c
update
Jun 1, 2023
b0b988a
Merge branch 'main' into Excelmultipage#192
Jun 22, 2025
24481b0
Move To sub methods
Jun 22, 2025
7e9a344
ver
Jun 22, 2025
7e5f121
new t est file with multiple sheets
Jun 22, 2025
a1ea1cf
add xps
Jun 22, 2025
44b7f42
Move csv
Jun 22, 2025
0769d3e
add param
Jun 22, 2025
ad7310f
named
Jun 22, 2025
d83db6c
working with selected tabs (selected manually)
Jun 22, 2025
e719651
using active sheet pdf manually selected sheets. not selected sheets
Jun 22, 2025
d1de629
update
Jun 22, 2025
0fc2f4d
sheets
Oct 11, 2025
20af806
MWE
Nov 18, 2025
bdb7bfc
save csv files
Nov 18, 2025
1c804e7
Export all worksheets
Nov 18, 2025
5a28a71
further tests
Nov 18, 2025
4994708
tidy
Nov 18, 2025
7c329f8
export worksheet
Nov 18, 2025
9751e46
output correct filename
Nov 18, 2025
eeb23e8
res
Nov 18, 2025
c1c65b1
sheet selection
Nov 19, 2025
5fcec77
ignore
Nov 19, 2025
a0b80e9
save sheets as pdf, error xps
Nov 19, 2025
5e6993c
halt error
Nov 19, 2025
d7eb72f
not implemented
Nov 19, 2025
0bae300
note
Nov 19, 2025
7b5b72b
xl macros
Nov 19, 2025
1bf44af
switch off auto vba for excel
Nov 19, 2025
513a3a1
tidy
Nov 19, 2025
62e22d3
update help
Nov 19, 2025
907fb38
update
Nov 19, 2025
d50cc59
check for 0 index
Nov 19, 2025
0c779d6
files
Nov 19, 2025
ce8be0d
Disable Excel Auto Macros (#241)
tobya Nov 19, 2025
463787c
update
Nov 19, 2025
9210be2
Merge branch 'excelmacro' into Excelmultipage#192
Nov 19, 2025
81cea49
Merge remote-tracking branch 'origin/Excelmultipage#192' into Excelmu…
Nov 19, 2025
70bf414
Move files for file gather
Nov 19, 2025
1c807c2
Required Test .doc
Nov 19, 2025
ec80daa
fix tests
Nov 19, 2025
d44f499
ver
Nov 19, 2025
f5119e8
try to output csv
Nov 19, 2025
dc20103
New parameter notes
Nov 19, 2025
bc49cfa
New details
Nov 19, 2025
b5a2674
multi
Nov 19, 2025
7846bfc
spelling
Nov 20, 2025
60517f4
param
Nov 20, 2025
508238f
test
Nov 22, 2025
12d97d2
reset
Nov 22, 2025
4d264ce
Extra tests
Nov 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ test/Generated*
test/InputFiles3*
test/test1/*
newdir2/
src/__recovery

/releases
src/docto.exe
Expand Down
5 changes: 4 additions & 1 deletion companion/app/Services/CommandInfoService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)'],



];
Expand Down
29 changes: 29 additions & 0 deletions companion/app/Services/DocToCommandBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Services;

class DocToCommandBuilder
{
public $params = [];

public static function docto()
{
return (new static())->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;
}
}
20 changes: 15 additions & 5 deletions companion/app/Services/FileGatherService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
3 changes: 3 additions & 0 deletions companion/app/Services/ResourceFileService.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
class ResourceFileService
{
public static function LoadResourceFile($fn) {


$fullfn = docto_path('\\src\\res\\' . $fn);
return file_get_contents($fullfn);

Expand All @@ -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)];
Expand Down
6 changes: 6 additions & 0 deletions companion/config/filesystems.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
'throw' => false,
],

'inputfiles' => [
'driver' => 'local',
'root' => resource_path('inputfiles'),
'throw' => false,
],


'public' => [
'driver' => 'local',
Expand Down
3 changes: 2 additions & 1 deletion companion/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' => [
Expand Down
21 changes: 21 additions & 0 deletions companion/resources/generator_templates/AllParameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
Binary file added companion/resources/inputfiles/docx/DocXFile.docx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
141 changes: 141 additions & 0 deletions companion/tests/Feature/DocX/CompatibilityPestTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

it ('can read docx files',function (){

$inputfiledir = 'inputfilesxls'. uniqid();
$outputfiledir = 'outputfilesxls' . uniqid();
// setup
$testinputfilesdir_temp = Storage::path($inputfiledir);
$testoutputdir_temp = Storage::path($outputfiledir);

Storage::createDirectory($outputfiledir);

$dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['docx']), $inputfiledir);

$doctocmd = \App\Services\DocToCommandBuilder::docto()
->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],
]);
72 changes: 68 additions & 4 deletions companion/tests/Feature/Remove/RemoveInputFilePestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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('\\');
});
Loading