orator-conversion 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/source/Conversion-Core.js +938 -0
- package/source/Orator-Conversion-BeaconProvider.js +726 -0
- package/source/Orator-File-Translation.js +9 -0
- package/source/endpoints/Endpoint-Image-Convert.js +33 -0
- package/source/endpoints/Endpoint-Image-Resize.js +49 -0
- package/source/endpoints/Endpoint-Image-Rotate.js +34 -0
- package/test/Conversion-Core_tests.js +442 -0
- package/test/Orator-File-Translation_basic_tests.js +10 -4
- package/test/Orator-File-Translation_tests.js +148 -0
|
@@ -8,6 +8,9 @@ const libOS = require('os');
|
|
|
8
8
|
|
|
9
9
|
const libEndpointImageJpgToPng = require('./endpoints/Endpoint-Image-JpgToPng.js');
|
|
10
10
|
const libEndpointImagePngToJpg = require('./endpoints/Endpoint-Image-PngToJpg.js');
|
|
11
|
+
const libEndpointImageResize = require('./endpoints/Endpoint-Image-Resize.js');
|
|
12
|
+
const libEndpointImageRotate = require('./endpoints/Endpoint-Image-Rotate.js');
|
|
13
|
+
const libEndpointImageConvert = require('./endpoints/Endpoint-Image-Convert.js');
|
|
11
14
|
const libEndpointPdfPageToPng = require('./endpoints/Endpoint-Pdf-PageToPng.js');
|
|
12
15
|
const libEndpointPdfPageToJpg = require('./endpoints/Endpoint-Pdf-PageToJpg.js');
|
|
13
16
|
const libEndpointPdfPageToPngSized = require('./endpoints/Endpoint-Pdf-PageToPng-Sized.js');
|
|
@@ -89,6 +92,9 @@ class OratorFileTranslation extends libFableServiceProviderBase
|
|
|
89
92
|
// Register endpoint service types with fable
|
|
90
93
|
this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImageJpgToPng', libEndpointImageJpgToPng);
|
|
91
94
|
this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImagePngToJpg', libEndpointImagePngToJpg);
|
|
95
|
+
this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImageResize', libEndpointImageResize);
|
|
96
|
+
this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImageRotate', libEndpointImageRotate);
|
|
97
|
+
this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-ImageConvert', libEndpointImageConvert);
|
|
92
98
|
this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-PdfPageToPng', libEndpointPdfPageToPng);
|
|
93
99
|
this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-PdfPageToJpg', libEndpointPdfPageToJpg);
|
|
94
100
|
this.fable.addServiceTypeIfNotExists('OratorFileTranslationEndpoint-PdfPageToPngSized', libEndpointPdfPageToPngSized);
|
|
@@ -100,6 +106,9 @@ class OratorFileTranslation extends libFableServiceProviderBase
|
|
|
100
106
|
[
|
|
101
107
|
'OratorFileTranslationEndpoint-ImageJpgToPng',
|
|
102
108
|
'OratorFileTranslationEndpoint-ImagePngToJpg',
|
|
109
|
+
'OratorFileTranslationEndpoint-ImageResize',
|
|
110
|
+
'OratorFileTranslationEndpoint-ImageRotate',
|
|
111
|
+
'OratorFileTranslationEndpoint-ImageConvert',
|
|
103
112
|
'OratorFileTranslationEndpoint-PdfPageToPng',
|
|
104
113
|
'OratorFileTranslationEndpoint-PdfPageToJpg',
|
|
105
114
|
'OratorFileTranslationEndpoint-PdfPageToPngSized',
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
2
|
+
|
|
3
|
+
const libConversionCore = require('../Conversion-Core.js');
|
|
4
|
+
|
|
5
|
+
class EndpointImageConvert extends libFableServiceProviderBase
|
|
6
|
+
{
|
|
7
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
8
|
+
{
|
|
9
|
+
super(pFable, pOptions, pServiceHash);
|
|
10
|
+
|
|
11
|
+
this.serviceType = 'OratorFileTranslationEndpoint-ImageConvert';
|
|
12
|
+
|
|
13
|
+
this.converterPath = 'image/convert/:Format';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
convert(pInputBuffer, pRequest, fCallback)
|
|
17
|
+
{
|
|
18
|
+
let tmpParams = pRequest.params || {};
|
|
19
|
+
let tmpQuery = pRequest.query || {};
|
|
20
|
+
|
|
21
|
+
let tmpCore = new libConversionCore();
|
|
22
|
+
|
|
23
|
+
let tmpOptions =
|
|
24
|
+
{
|
|
25
|
+
Format: tmpParams.Format,
|
|
26
|
+
Quality: tmpQuery.Quality ? parseInt(tmpQuery.Quality, 10) : undefined
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
tmpCore.imageConvert(pInputBuffer, tmpOptions, fCallback);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = EndpointImageConvert;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
2
|
+
const libURL = require('url');
|
|
3
|
+
|
|
4
|
+
const libConversionCore = require('../Conversion-Core.js');
|
|
5
|
+
|
|
6
|
+
class EndpointImageResize extends libFableServiceProviderBase
|
|
7
|
+
{
|
|
8
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
9
|
+
{
|
|
10
|
+
super(pFable, pOptions, pServiceHash);
|
|
11
|
+
|
|
12
|
+
this.serviceType = 'OratorFileTranslationEndpoint-ImageResize';
|
|
13
|
+
|
|
14
|
+
this.converterPath = 'image/resize';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
convert(pInputBuffer, pRequest, fCallback)
|
|
18
|
+
{
|
|
19
|
+
let tmpFileTranslation = this.options.FileTranslation;
|
|
20
|
+
|
|
21
|
+
let tmpCore = new libConversionCore({
|
|
22
|
+
MaxFileSize: tmpFileTranslation ? tmpFileTranslation.MaxFileSize : undefined
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
let tmpParams = pRequest.params || {};
|
|
26
|
+
// Parse query string from the URL if pRequest.query is not available
|
|
27
|
+
let tmpQuery = pRequest.query || {};
|
|
28
|
+
if (Object.keys(tmpQuery).length === 0 && pRequest.url)
|
|
29
|
+
{
|
|
30
|
+
let tmpParsed = libURL.parse(pRequest.url, true);
|
|
31
|
+
tmpQuery = tmpParsed.query || {};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let tmpOptions =
|
|
35
|
+
{
|
|
36
|
+
Width: tmpQuery.Width || tmpParams.Width,
|
|
37
|
+
Height: tmpQuery.Height || tmpParams.Height,
|
|
38
|
+
Format: tmpQuery.Format || tmpParams.Format,
|
|
39
|
+
Quality: tmpQuery.Quality || tmpParams.Quality,
|
|
40
|
+
Fit: tmpQuery.Fit || tmpParams.Fit,
|
|
41
|
+
Position: tmpQuery.Position || tmpParams.Position,
|
|
42
|
+
AutoOrient: tmpQuery.AutoOrient !== 'false'
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
tmpCore.imageResize(pInputBuffer, tmpOptions, fCallback);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = EndpointImageResize;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
2
|
+
|
|
3
|
+
const libConversionCore = require('../Conversion-Core.js');
|
|
4
|
+
|
|
5
|
+
class EndpointImageRotate extends libFableServiceProviderBase
|
|
6
|
+
{
|
|
7
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
8
|
+
{
|
|
9
|
+
super(pFable, pOptions, pServiceHash);
|
|
10
|
+
|
|
11
|
+
this.serviceType = 'OratorFileTranslationEndpoint-ImageRotate';
|
|
12
|
+
|
|
13
|
+
this.converterPath = 'image/rotate/:Angle';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
convert(pInputBuffer, pRequest, fCallback)
|
|
17
|
+
{
|
|
18
|
+
let tmpCore = new libConversionCore();
|
|
19
|
+
|
|
20
|
+
let tmpParams = pRequest.params || {};
|
|
21
|
+
let tmpQuery = pRequest.query || {};
|
|
22
|
+
|
|
23
|
+
let tmpOptions =
|
|
24
|
+
{
|
|
25
|
+
Angle: tmpParams.Angle,
|
|
26
|
+
Flip: (tmpQuery.Flip === 'true' || tmpQuery.Flip === '1'),
|
|
27
|
+
Flop: (tmpQuery.Flop === 'true' || tmpQuery.Flop === '1')
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
tmpCore.imageRotate(pInputBuffer, tmpOptions, fCallback);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = EndpointImageRotate;
|
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for Conversion-Core — Image, Video, Audio operations
|
|
3
|
+
*
|
|
4
|
+
* @license MIT
|
|
5
|
+
*
|
|
6
|
+
* @author Steven Velozo <steven@velozo.com>
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const Chai = require("chai");
|
|
10
|
+
const Expect = Chai.expect;
|
|
11
|
+
|
|
12
|
+
const libSharp = require('sharp');
|
|
13
|
+
|
|
14
|
+
const libConversionCore = require('../source/Conversion-Core.js');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate a minimal JPEG test image buffer (10x20 red).
|
|
18
|
+
*/
|
|
19
|
+
function createTestJpegBuffer(fCallback)
|
|
20
|
+
{
|
|
21
|
+
libSharp(
|
|
22
|
+
{
|
|
23
|
+
create:
|
|
24
|
+
{
|
|
25
|
+
width: 10,
|
|
26
|
+
height: 20,
|
|
27
|
+
channels: 3,
|
|
28
|
+
background: { r: 255, g: 0, b: 0 }
|
|
29
|
+
}
|
|
30
|
+
}).jpeg().toBuffer().then(
|
|
31
|
+
(pBuffer) => { return fCallback(null, pBuffer); },
|
|
32
|
+
(pError) => { return fCallback(pError); });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Generate a minimal PNG test image buffer.
|
|
37
|
+
*/
|
|
38
|
+
function createTestPngBuffer(fCallback)
|
|
39
|
+
{
|
|
40
|
+
libSharp(
|
|
41
|
+
{
|
|
42
|
+
create:
|
|
43
|
+
{
|
|
44
|
+
width: 10,
|
|
45
|
+
height: 20,
|
|
46
|
+
channels: 4,
|
|
47
|
+
background: { r: 0, g: 0, b: 255, alpha: 1 }
|
|
48
|
+
}
|
|
49
|
+
}).png().toBuffer().then(
|
|
50
|
+
(pBuffer) => { return fCallback(null, pBuffer); },
|
|
51
|
+
(pError) => { return fCallback(pError); });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
suite
|
|
55
|
+
(
|
|
56
|
+
'Conversion Core',
|
|
57
|
+
() =>
|
|
58
|
+
{
|
|
59
|
+
suite
|
|
60
|
+
(
|
|
61
|
+
'Image Rotate',
|
|
62
|
+
() =>
|
|
63
|
+
{
|
|
64
|
+
test
|
|
65
|
+
(
|
|
66
|
+
'should rotate an image 90 degrees and swap dimensions',
|
|
67
|
+
(fDone) =>
|
|
68
|
+
{
|
|
69
|
+
createTestJpegBuffer(
|
|
70
|
+
(pError, pJpegBuffer) =>
|
|
71
|
+
{
|
|
72
|
+
Expect(pError).to.equal(null);
|
|
73
|
+
|
|
74
|
+
let tmpCore = new libConversionCore();
|
|
75
|
+
|
|
76
|
+
tmpCore.imageRotate(pJpegBuffer,
|
|
77
|
+
{ Angle: 90 },
|
|
78
|
+
(pRotateError, pOutputBuffer, pContentType) =>
|
|
79
|
+
{
|
|
80
|
+
Expect(pRotateError).to.equal(null);
|
|
81
|
+
Expect(pOutputBuffer).to.be.an.instanceOf(Buffer);
|
|
82
|
+
Expect(pOutputBuffer.length).to.be.greaterThan(0);
|
|
83
|
+
Expect(pContentType).to.equal('image/jpeg');
|
|
84
|
+
|
|
85
|
+
// Verify dimensions are swapped (10x20 → 20x10)
|
|
86
|
+
libSharp(pOutputBuffer).metadata().then(
|
|
87
|
+
(pMetadata) =>
|
|
88
|
+
{
|
|
89
|
+
Expect(pMetadata.width).to.equal(20);
|
|
90
|
+
Expect(pMetadata.height).to.equal(10);
|
|
91
|
+
return fDone();
|
|
92
|
+
}).catch(
|
|
93
|
+
(pMetaError) => { return fDone(pMetaError); });
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
test
|
|
100
|
+
(
|
|
101
|
+
'should flip an image without error',
|
|
102
|
+
(fDone) =>
|
|
103
|
+
{
|
|
104
|
+
createTestJpegBuffer(
|
|
105
|
+
(pError, pJpegBuffer) =>
|
|
106
|
+
{
|
|
107
|
+
Expect(pError).to.equal(null);
|
|
108
|
+
|
|
109
|
+
let tmpCore = new libConversionCore();
|
|
110
|
+
|
|
111
|
+
tmpCore.imageRotate(pJpegBuffer,
|
|
112
|
+
{ Flip: true },
|
|
113
|
+
(pRotateError, pOutputBuffer, pContentType) =>
|
|
114
|
+
{
|
|
115
|
+
Expect(pRotateError).to.equal(null);
|
|
116
|
+
Expect(pOutputBuffer).to.be.an.instanceOf(Buffer);
|
|
117
|
+
Expect(pOutputBuffer.length).to.be.greaterThan(0);
|
|
118
|
+
return fDone();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
test
|
|
125
|
+
(
|
|
126
|
+
'should flop an image without error',
|
|
127
|
+
(fDone) =>
|
|
128
|
+
{
|
|
129
|
+
createTestJpegBuffer(
|
|
130
|
+
(pError, pJpegBuffer) =>
|
|
131
|
+
{
|
|
132
|
+
Expect(pError).to.equal(null);
|
|
133
|
+
|
|
134
|
+
let tmpCore = new libConversionCore();
|
|
135
|
+
|
|
136
|
+
tmpCore.imageRotate(pJpegBuffer,
|
|
137
|
+
{ Flop: true },
|
|
138
|
+
(pRotateError, pOutputBuffer, pContentType) =>
|
|
139
|
+
{
|
|
140
|
+
Expect(pRotateError).to.equal(null);
|
|
141
|
+
Expect(pOutputBuffer).to.be.an.instanceOf(Buffer);
|
|
142
|
+
Expect(pOutputBuffer.length).to.be.greaterThan(0);
|
|
143
|
+
return fDone();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
suite
|
|
152
|
+
(
|
|
153
|
+
'Image Convert',
|
|
154
|
+
() =>
|
|
155
|
+
{
|
|
156
|
+
test
|
|
157
|
+
(
|
|
158
|
+
'should convert JPEG to PNG',
|
|
159
|
+
(fDone) =>
|
|
160
|
+
{
|
|
161
|
+
createTestJpegBuffer(
|
|
162
|
+
(pError, pJpegBuffer) =>
|
|
163
|
+
{
|
|
164
|
+
Expect(pError).to.equal(null);
|
|
165
|
+
|
|
166
|
+
let tmpCore = new libConversionCore();
|
|
167
|
+
|
|
168
|
+
tmpCore.imageConvert(pJpegBuffer,
|
|
169
|
+
{ Format: 'png' },
|
|
170
|
+
(pConvertError, pOutputBuffer, pContentType) =>
|
|
171
|
+
{
|
|
172
|
+
Expect(pConvertError).to.equal(null);
|
|
173
|
+
Expect(pOutputBuffer).to.be.an.instanceOf(Buffer);
|
|
174
|
+
Expect(pContentType).to.equal('image/png');
|
|
175
|
+
|
|
176
|
+
// Verify PNG magic bytes
|
|
177
|
+
Expect(pOutputBuffer[0]).to.equal(137);
|
|
178
|
+
Expect(pOutputBuffer[1]).to.equal(80);
|
|
179
|
+
Expect(pOutputBuffer[2]).to.equal(78);
|
|
180
|
+
Expect(pOutputBuffer[3]).to.equal(71);
|
|
181
|
+
|
|
182
|
+
return fDone();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
test
|
|
189
|
+
(
|
|
190
|
+
'should convert PNG to WebP',
|
|
191
|
+
(fDone) =>
|
|
192
|
+
{
|
|
193
|
+
createTestPngBuffer(
|
|
194
|
+
(pError, pPngBuffer) =>
|
|
195
|
+
{
|
|
196
|
+
Expect(pError).to.equal(null);
|
|
197
|
+
|
|
198
|
+
let tmpCore = new libConversionCore();
|
|
199
|
+
|
|
200
|
+
tmpCore.imageConvert(pPngBuffer,
|
|
201
|
+
{ Format: 'webp' },
|
|
202
|
+
(pConvertError, pOutputBuffer, pContentType) =>
|
|
203
|
+
{
|
|
204
|
+
Expect(pConvertError).to.equal(null);
|
|
205
|
+
Expect(pOutputBuffer).to.be.an.instanceOf(Buffer);
|
|
206
|
+
Expect(pContentType).to.equal('image/webp');
|
|
207
|
+
Expect(pOutputBuffer.length).to.be.greaterThan(0);
|
|
208
|
+
|
|
209
|
+
return fDone();
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
test
|
|
216
|
+
(
|
|
217
|
+
'should convert PNG to JPEG with quality option',
|
|
218
|
+
(fDone) =>
|
|
219
|
+
{
|
|
220
|
+
createTestPngBuffer(
|
|
221
|
+
(pError, pPngBuffer) =>
|
|
222
|
+
{
|
|
223
|
+
Expect(pError).to.equal(null);
|
|
224
|
+
|
|
225
|
+
let tmpCore = new libConversionCore();
|
|
226
|
+
|
|
227
|
+
tmpCore.imageConvert(pPngBuffer,
|
|
228
|
+
{ Format: 'jpeg', Quality: 50 },
|
|
229
|
+
(pConvertError, pOutputBuffer, pContentType) =>
|
|
230
|
+
{
|
|
231
|
+
Expect(pConvertError).to.equal(null);
|
|
232
|
+
Expect(pOutputBuffer).to.be.an.instanceOf(Buffer);
|
|
233
|
+
Expect(pContentType).to.equal('image/jpeg');
|
|
234
|
+
|
|
235
|
+
// Verify JPEG magic bytes
|
|
236
|
+
Expect(pOutputBuffer[0]).to.equal(0xFF);
|
|
237
|
+
Expect(pOutputBuffer[1]).to.equal(0xD8);
|
|
238
|
+
Expect(pOutputBuffer[2]).to.equal(0xFF);
|
|
239
|
+
|
|
240
|
+
return fDone();
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
suite
|
|
249
|
+
(
|
|
250
|
+
'Enhanced Image Resize',
|
|
251
|
+
() =>
|
|
252
|
+
{
|
|
253
|
+
test
|
|
254
|
+
(
|
|
255
|
+
'should resize with contain fit mode',
|
|
256
|
+
(fDone) =>
|
|
257
|
+
{
|
|
258
|
+
createTestJpegBuffer(
|
|
259
|
+
(pError, pJpegBuffer) =>
|
|
260
|
+
{
|
|
261
|
+
Expect(pError).to.equal(null);
|
|
262
|
+
|
|
263
|
+
let tmpCore = new libConversionCore();
|
|
264
|
+
|
|
265
|
+
// 10x20 image, resize to fit within 5x5 with "inside" mode
|
|
266
|
+
tmpCore.imageResize(pJpegBuffer,
|
|
267
|
+
{ Width: 5, Height: 5, Fit: 'inside' },
|
|
268
|
+
(pResizeError, pOutputBuffer, pContentType) =>
|
|
269
|
+
{
|
|
270
|
+
Expect(pResizeError).to.equal(null);
|
|
271
|
+
Expect(pOutputBuffer).to.be.an.instanceOf(Buffer);
|
|
272
|
+
|
|
273
|
+
libSharp(pOutputBuffer).metadata().then(
|
|
274
|
+
(pMetadata) =>
|
|
275
|
+
{
|
|
276
|
+
// With 'inside' fit, the image should fit within 5x5
|
|
277
|
+
// The original is 10x20 (portrait), so height is dominant
|
|
278
|
+
// Scaled to fit: width=2 or 3, height=5
|
|
279
|
+
Expect(pMetadata.width).to.be.at.most(5);
|
|
280
|
+
Expect(pMetadata.height).to.be.at.most(5);
|
|
281
|
+
return fDone();
|
|
282
|
+
}).catch(
|
|
283
|
+
(pMetaError) => { return fDone(pMetaError); });
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
test
|
|
290
|
+
(
|
|
291
|
+
'should support avif output format',
|
|
292
|
+
(fDone) =>
|
|
293
|
+
{
|
|
294
|
+
createTestJpegBuffer(
|
|
295
|
+
(pError, pJpegBuffer) =>
|
|
296
|
+
{
|
|
297
|
+
Expect(pError).to.equal(null);
|
|
298
|
+
|
|
299
|
+
let tmpCore = new libConversionCore();
|
|
300
|
+
|
|
301
|
+
tmpCore.imageResize(pJpegBuffer,
|
|
302
|
+
{ Width: 5, Format: 'avif' },
|
|
303
|
+
(pResizeError, pOutputBuffer, pContentType) =>
|
|
304
|
+
{
|
|
305
|
+
Expect(pResizeError).to.equal(null);
|
|
306
|
+
Expect(pOutputBuffer).to.be.an.instanceOf(Buffer);
|
|
307
|
+
Expect(pContentType).to.equal('image/avif');
|
|
308
|
+
Expect(pOutputBuffer.length).to.be.greaterThan(0);
|
|
309
|
+
|
|
310
|
+
return fDone();
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
suite
|
|
319
|
+
(
|
|
320
|
+
'Tool Availability Checks',
|
|
321
|
+
() =>
|
|
322
|
+
{
|
|
323
|
+
test
|
|
324
|
+
(
|
|
325
|
+
'checkFfmpeg should return a result',
|
|
326
|
+
(fDone) =>
|
|
327
|
+
{
|
|
328
|
+
let tmpCore = new libConversionCore();
|
|
329
|
+
|
|
330
|
+
tmpCore.checkFfmpeg(
|
|
331
|
+
(pError, pAvailable) =>
|
|
332
|
+
{
|
|
333
|
+
// We don't require ffmpeg to be installed;
|
|
334
|
+
// just verify the check completes without throwing
|
|
335
|
+
Expect(typeof pAvailable).to.equal('boolean');
|
|
336
|
+
return fDone();
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
test
|
|
342
|
+
(
|
|
343
|
+
'checkFfprobe should return a result',
|
|
344
|
+
(fDone) =>
|
|
345
|
+
{
|
|
346
|
+
let tmpCore = new libConversionCore();
|
|
347
|
+
|
|
348
|
+
tmpCore.checkFfprobe(
|
|
349
|
+
(pError, pAvailable) =>
|
|
350
|
+
{
|
|
351
|
+
Expect(typeof pAvailable).to.equal('boolean');
|
|
352
|
+
return fDone();
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
test
|
|
358
|
+
(
|
|
359
|
+
'checkFfmpeg with invalid path should return not available',
|
|
360
|
+
(fDone) =>
|
|
361
|
+
{
|
|
362
|
+
let tmpCore = new libConversionCore({ FfmpegPath: '/nonexistent/ffmpeg' });
|
|
363
|
+
|
|
364
|
+
tmpCore.checkFfmpeg(
|
|
365
|
+
(pError, pAvailable) =>
|
|
366
|
+
{
|
|
367
|
+
Expect(pError).to.not.equal(null);
|
|
368
|
+
Expect(pAvailable).to.equal(false);
|
|
369
|
+
return fDone();
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
test
|
|
375
|
+
(
|
|
376
|
+
'checkFfprobe with invalid path should return not available',
|
|
377
|
+
(fDone) =>
|
|
378
|
+
{
|
|
379
|
+
let tmpCore = new libConversionCore({ FfprobePath: '/nonexistent/ffprobe' });
|
|
380
|
+
|
|
381
|
+
tmpCore.checkFfprobe(
|
|
382
|
+
(pError, pAvailable) =>
|
|
383
|
+
{
|
|
384
|
+
Expect(pError).to.not.equal(null);
|
|
385
|
+
Expect(pAvailable).to.equal(false);
|
|
386
|
+
return fDone();
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
suite
|
|
394
|
+
(
|
|
395
|
+
'Media Probe',
|
|
396
|
+
() =>
|
|
397
|
+
{
|
|
398
|
+
test
|
|
399
|
+
(
|
|
400
|
+
'should return an error when no file path is provided',
|
|
401
|
+
(fDone) =>
|
|
402
|
+
{
|
|
403
|
+
let tmpCore = new libConversionCore();
|
|
404
|
+
|
|
405
|
+
tmpCore.mediaProbe(null,
|
|
406
|
+
(pError, pMetadata) =>
|
|
407
|
+
{
|
|
408
|
+
Expect(pError).to.not.equal(null);
|
|
409
|
+
Expect(pError.message).to.include('No file path');
|
|
410
|
+
return fDone();
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
suite
|
|
418
|
+
(
|
|
419
|
+
'Audio Extract Segment',
|
|
420
|
+
() =>
|
|
421
|
+
{
|
|
422
|
+
test
|
|
423
|
+
(
|
|
424
|
+
'should require a Duration parameter',
|
|
425
|
+
(fDone) =>
|
|
426
|
+
{
|
|
427
|
+
let tmpCore = new libConversionCore();
|
|
428
|
+
|
|
429
|
+
tmpCore.audioExtractSegment('/tmp/input.mp3', '/tmp/output.mp3',
|
|
430
|
+
{ Start: '0' },
|
|
431
|
+
(pError, pResultPath) =>
|
|
432
|
+
{
|
|
433
|
+
Expect(pError).to.not.equal(null);
|
|
434
|
+
Expect(pError.message).to.include('Duration is required');
|
|
435
|
+
return fDone();
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
);
|
|
@@ -79,6 +79,12 @@ suite
|
|
|
79
79
|
Expect(tmpFileTranslation.converters['image/jpg-to-png']).to.be.a('function');
|
|
80
80
|
Expect(tmpFileTranslation.converters).to.have.a.property('image/png-to-jpg');
|
|
81
81
|
Expect(tmpFileTranslation.converters['image/png-to-jpg']).to.be.a('function');
|
|
82
|
+
Expect(tmpFileTranslation.converters).to.have.a.property('image/resize');
|
|
83
|
+
Expect(tmpFileTranslation.converters['image/resize']).to.be.a('function');
|
|
84
|
+
Expect(tmpFileTranslation.converters).to.have.a.property('image/rotate/:Angle');
|
|
85
|
+
Expect(tmpFileTranslation.converters['image/rotate/:Angle']).to.be.a('function');
|
|
86
|
+
Expect(tmpFileTranslation.converters).to.have.a.property('image/convert/:Format');
|
|
87
|
+
Expect(tmpFileTranslation.converters['image/convert/:Format']).to.be.a('function');
|
|
82
88
|
Expect(tmpFileTranslation.converters).to.have.a.property('pdf-to-page-png/:Page');
|
|
83
89
|
Expect(tmpFileTranslation.converters['pdf-to-page-png/:Page']).to.be.a('function');
|
|
84
90
|
Expect(tmpFileTranslation.converters).to.have.a.property('pdf-to-page-jpg/:Page');
|
|
@@ -270,13 +276,13 @@ suite
|
|
|
270
276
|
let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
|
|
271
277
|
let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation', {});
|
|
272
278
|
|
|
273
|
-
// Should have
|
|
274
|
-
Expect(Object.keys(tmpFileTranslation.converters).length).to.equal(
|
|
279
|
+
// Should have 9 default converters (jpg-to-png, png-to-jpg, resize, rotate, convert, pdf-to-page-png, pdf-to-page-jpg, pdf-to-page-png sized, pdf-to-page-jpg sized)
|
|
280
|
+
Expect(Object.keys(tmpFileTranslation.converters).length).to.equal(9);
|
|
275
281
|
|
|
276
282
|
tmpFileTranslation.addConverter('document/txt-to-html', (pInput, pReq, fCb) => { fCb(null, pInput, 'text/html'); });
|
|
277
283
|
|
|
278
|
-
// Should now have
|
|
279
|
-
Expect(Object.keys(tmpFileTranslation.converters).length).to.equal(
|
|
284
|
+
// Should now have 10
|
|
285
|
+
Expect(Object.keys(tmpFileTranslation.converters).length).to.equal(10);
|
|
280
286
|
|
|
281
287
|
return fDone();
|
|
282
288
|
}
|