aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/Network.ts2
-rw-r--r--src/client/util/request-image-size.ts9
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx17
-rw-r--r--src/server/ApiManagers/UploadManager.ts14
-rw-r--r--src/server/DashUploadUtils.ts94
5 files changed, 73 insertions, 63 deletions
diff --git a/src/client/Network.ts b/src/client/Network.ts
index 204fcf0ac..9afdc844f 100644
--- a/src/client/Network.ts
+++ b/src/client/Network.ts
@@ -50,7 +50,7 @@ export namespace Networking {
if (!fileguidpairs.length) {
return [];
}
- const maxFileSize = 6000000;
+ const maxFileSize = 50000000;
if (fileguidpairs.some(f => f.file.size > maxFileSize)) {
return new Promise<Upload.FileResponse<T>[]>(res => res([{ source: { newFilename: '', mimetype: '' } as formidable.File, result: new Error(`max file size (${maxFileSize / 1000000}MB) exceeded`) }]));
}
diff --git a/src/client/util/request-image-size.ts b/src/client/util/request-image-size.ts
index 7a2ecd486..c619192ed 100644
--- a/src/client/util/request-image-size.ts
+++ b/src/client/util/request-image-size.ts
@@ -35,7 +35,11 @@ module.exports = function requestImageSize(url: string) {
res.on('data', chunk => {
buffer = Buffer.concat([buffer, chunk]);
+ });
+
+ res.on('error', reject);
+ res.on('end', () => {
try {
size = imageSize(buffer);
if (size) {
@@ -46,11 +50,6 @@ module.exports = function requestImageSize(url: string) {
/* empty */
console.log('Error: ', err);
}
- });
-
- res.on('error', reject);
-
- res.on('end', () => {
if (!size) {
reject(new Error('Image has no size'));
return;
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 61bd0241c..5c41fee37 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -9,7 +9,7 @@ import { emptyFunction } from '../../../../Utils';
import { Docs } from '../../../documents/Documents';
import { DragManager } from '../../../util/DragManager';
import { Transform } from '../../../util/Transform';
-import { undoBatch } from '../../../util/UndoManager';
+import { undoable, undoBatch } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
import { ContextMenuProps } from '../../ContextMenuItem';
import { DocumentView } from '../../nodes/DocumentView';
@@ -221,13 +221,13 @@ export class CollectionGridView extends CollectionSubView() {
});
if (this.Document.gridStartCompaction) {
- undoBatch(() => {
+ undoable(() => {
this.Document.gridCompaction = this.Document.gridStartCompaction;
this.setLayoutList(savedLayouts);
- })();
+ }, 'start grid compaction')();
this.Document.gridStartCompaction = undefined;
} else {
- undoBatch(() => this.setLayoutList(savedLayouts))();
+ undoable(() => this.setLayoutList(savedLayouts), 'start grid compaction')();
}
}
};
@@ -315,9 +315,9 @@ export class CollectionGridView extends CollectionSubView() {
e,
returnFalse,
action(() => {
- undoBatch(() => {
+ undoable(() => {
this.Document.gridRowHeight = this._rowHeight;
- })();
+ }, 'changing row height')();
this._rowHeight = undefined;
}),
emptyFunction,
@@ -360,13 +360,14 @@ export class CollectionGridView extends CollectionSubView() {
returnFalse,
(clickEv: PointerEvent, doubleTap?: boolean) => {
if (doubleTap && !clickEv.button) {
- undoBatch(
+ undoable(
action(() => {
const text = Docs.Create.TextDocument('', { _width: 150, _height: 50 });
Doc.SetSelectOnLoad(text); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
Doc.AddDocToList(this.Document, this._props.fieldKey, text);
this.setLayoutList(this.addLayoutItem(this.savedLayoutList, this.makeLayoutItem(text, this.screenToCell(clickEv.clientX, clickEv.clientY))));
- })
+ }),
+ 'create grid text'
)();
}
},
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index b2624f654..8ab27130b 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -3,7 +3,7 @@ import * as formidable from 'formidable';
import * as fs from 'fs';
import { createReadStream, createWriteStream, unlink } from 'fs';
import * as imageDataUri from 'image-data-uri';
-import Jimp from 'jimp';
+import { Jimp } from 'jimp';
import * as path from 'path';
import * as uuid from 'uuid';
import { retrocycle } from '../../decycler/decycler';
@@ -11,7 +11,7 @@ import { DashVersion } from '../../fields/DocSymbols';
import { DashUploadUtils, InjectSize, SizeSuffix } from '../DashUploadUtils';
import { Method, _success } from '../RouteManager';
import { AcceptableMedia, Upload } from '../SharedMediaTypes';
-import { clientPathToFile, Directory, pathToDirectory, publicDirectory, serverPathToFile } from '../SocketData';
+import { Directory, clientPathToFile, pathToDirectory, publicDirectory, serverPathToFile } from '../SocketData';
import { Database } from '../database';
import ApiManager, { Registration } from './ApiManager';
import { SolrManager } from './SearchManager';
@@ -203,12 +203,11 @@ export default class UploadManager extends ApiManager {
try {
zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
createReadStream(pathname).pipe(createWriteStream(targetname));
- Jimp.read(pathname).then(imgIn => {
- let img = imgIn;
+ Jimp.read(pathname).then(img => {
DashUploadUtils.imageResampleSizes(extension).forEach(({ width, suffix }) => {
const outputPath = InjectSize(targetname, suffix);
if (!width) createReadStream(pathname).pipe(createWriteStream(outputPath));
- else img = img.resize(width, Jimp.AUTO).write(outputPath);
+ else img.resize({ w: width }).write(outputPath as `${string}.${string}`);
});
unlink(pathname, () => {});
});
@@ -288,13 +287,12 @@ export default class UploadManager extends ApiManager {
imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => {
const ext = path.extname(savedName).toLowerCase();
if (AcceptableMedia.imageFormats.includes(ext)) {
- Jimp.read(savedName).then(imgIn => {
- let img = imgIn;
+ Jimp.read(savedName).then(img => {
(!origSuffix ? [{ width: 400, suffix: SizeSuffix.Medium }] : Object.values(DashUploadUtils.Sizes)) //
.forEach(({ width, suffix }) => {
const outputPath = serverPathToFile(Directory.images, InjectSize(filename, suffix) + ext);
if (!width) createReadStream(savedName).pipe(createWriteStream(outputPath));
- else img = img.resize(width, Jimp.AUTO).write(outputPath);
+ else img.resize({ w: width }).write(outputPath as `${string}.${string}`);
});
});
}
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 8f012f783..5cf86b2ae 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -1,5 +1,5 @@
import axios from 'axios';
-import { spawn, exec } from 'child_process';
+import { exec, spawn } from 'child_process';
import { green, red } from 'colors';
import { ExifData, ExifImage } from 'exif';
import * as exifr from 'exifr';
@@ -7,9 +7,8 @@ import * as ffmpeg from 'fluent-ffmpeg';
import * as formidable from 'formidable';
import { File } from 'formidable';
import * as fs from 'fs';
-import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs';
-import Jimp from 'jimp';
-import * as autorotate from 'jpeg-autorotate';
+import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs'; // import { Jimp } from "@jimp/core";
+import { Jimp } from 'jimp';
import * as md5File from 'md5-file';
import * as path from 'path';
import { basename } from 'path';
@@ -23,6 +22,38 @@ import { AcceptableMedia, Upload } from './SharedMediaTypes';
import { Directory, clientPathToFile, filesDirectory, pathToDirectory, publicDirectory, serverPathToFile } from './SocketData';
import { resolvedServerUrl } from './server_Initialization';
+import { Worker, isMainThread, parentPort } from 'worker_threads';
+
+// Create an array to store worker threads
+const workerThreads: Worker[] = [];
+if (isMainThread) {
+ // Main thread code
+ // Create worker threads -- just one right to do image resampling
+ workerThreads.push(new Worker(__filename));
+} else {
+ // Worker thread code - Listens for messages from the main thread
+ parentPort?.on('message', message => workerResampleImage(message.task));
+ async function workerResampleImage(task: string) {
+ const [sourcePath, outputFileName, outputDirectory, unlinkSource] = task.split('::');
+ const sizes = DashUploadUtils.imageResampleSizes(path.extname(sourcePath));
+ const imgBuffer = await fs.readFileSync(sourcePath);
+ const outputPath = (suffix: SizeSuffix) => {
+ const writtenFile = InjectSize(outputFileName, suffix);
+ return path.resolve(outputDirectory, writtenFile);
+ };
+ await Jimp.fromBuffer(imgBuffer)
+ .then(img => sizes.filter(({ width }) => width).map(({ width, suffix }) => img.resize({ w: width }).write(outputPath(suffix) as `${string}.${string}`)))
+ .catch(e => {
+ console.log('ERROR' + e);
+ });
+ if (unlinkSource === 'true') {
+ unlinkSync(sourcePath);
+ }
+
+ // … operations to be performed to execute the task
+ }
+}
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
const requestImageSize = require('../client/util/request-image-size');
@@ -277,15 +308,6 @@ export namespace DashUploadUtils {
}
};
- async function correctRotation(imgSourcePath: string) {
- const buffer = fs.readFileSync(imgSourcePath);
- try {
- return (await autorotate.rotate(buffer, { quality: 30 })).buffer;
- } catch (e) {
- return buffer;
- }
- }
-
/**
* define the resizers to use
* @param ext the extension
@@ -310,38 +332,29 @@ export namespace DashUploadUtils {
* @param outputDirectory the directory to output to, usually Directory.Images
* @returns a map with suffixes as keys and resized filenames as values.
*/
- export async function outputResizedImages(imgSourcePath: string, outputFileName: string, outputDirectory: string) {
+ export async function outputResizedImages(imgSourcePath: string, outputFileName: string, outputDirectory: string, unlinkSource: boolean) {
const writtenFiles: { [suffix: string]: string } = {};
- const sizes = imageResampleSizes(path.extname(outputFileName));
- const imgBuffer = await correctRotation(imgSourcePath);
- const imgReadStream = new Duplex();
- imgReadStream.push(imgBuffer);
- imgReadStream.push(null);
const outputPath = (suffix: SizeSuffix) => {
writtenFiles[suffix] = InjectSize(outputFileName, suffix);
return path.resolve(outputDirectory, writtenFiles[suffix]);
};
+
+ const sizes = imageResampleSizes(path.extname(outputFileName));
+ const imgBuffer = fs.readFileSync(imgSourcePath);
+ const imgReadStream = new Duplex();
+ imgReadStream.push(imgBuffer);
+ imgReadStream.push(null);
await Promise.all(
- sizes.filter(({ width }) => !width).map(({ suffix }) =>
- new Promise<void>(res => {
- imgReadStream.pipe(createWriteStream(outputPath(suffix))).on('close', res);
- })
+ sizes.map(({ suffix }) =>
+ new Promise<unknown>(res =>
+ imgReadStream.pipe(createWriteStream(outputPath(suffix))).on('close', res)
+ )
)); // prettier-ignore
- return Jimp.read(imgBuffer)
- .then(async imgIn => {
- let img = imgIn;
- await Promise.all( sizes.filter(({ width }) => width).map(({ width, suffix }) => {
- img = img.resize(width, Jimp.AUTO).write(outputPath(suffix));
- return img;
- } )); // prettier-ignore
- return writtenFiles;
- })
- .catch(e => {
- console.log('ERROR' + e);
- return writtenFiles;
- });
+ // Send a message to worker thread to resample image
+ workerThreads[0].postMessage({ task: imgSourcePath + '::' + outputFileName + '::' + outputDirectory + '::' + unlinkSource });
+ return writtenFiles;
}
/**
@@ -387,8 +400,9 @@ export namespace DashUploadUtils {
writtenFiles = {};
}
} else {
+ const unlinkSrcWhenFinished = isLocal().test(source) && cleanUp;
try {
- writtenFiles = await outputResizedImages(metadata.source, resolved, pathToDirectory(Directory.images));
+ writtenFiles = await outputResizedImages(metadata.source, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished);
} catch (e) {
// input is a blob or other, try reading it to create a metadata source file.
const reqSource = request(metadata.source);
@@ -400,16 +414,14 @@ export namespace DashUploadUtils {
.on('close', () => res())
.on('error', () => rej());
});
- writtenFiles = await outputResizedImages(readSource, resolved, pathToDirectory(Directory.images));
+ writtenFiles = await outputResizedImages(readSource, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished);
fs.unlink(readSource, err => console.log("Couldn't unlink temporary image file:" + readSource, err));
}
}
Array.from(Object.keys(writtenFiles)).forEach(suffix => {
information.accessPaths[suffix] = getAccessPaths(images, writtenFiles[suffix]);
});
- if (isLocal().test(source) && cleanUp) {
- unlinkSync(source);
- }
+
return information;
};