feat: Initial clean release of CHM
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
这个提交包含在:
@@ -0,0 +1,99 @@
|
||||
import shim from '@joplin/lib/shim';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { ImageManipulator, SaveFormat } from 'expo-image-manipulator';
|
||||
import fileToImage from './fileToImage.web';
|
||||
import FsDriverWeb from '../fs-driver/fs-driver-rn.web';
|
||||
import getImageDimensions from './getImageDimensions';
|
||||
|
||||
const logger = Logger.create('resizeImage');
|
||||
|
||||
type OutputFormat = 'PNG' | 'JPEG';
|
||||
|
||||
interface Options {
|
||||
inputPath: string;
|
||||
outputPath: string;
|
||||
maxWidth: number;
|
||||
maxHeight: number;
|
||||
format: OutputFormat;
|
||||
// A number from 0 to 1, where 1 is least compressed.
|
||||
quality: number;
|
||||
}
|
||||
|
||||
const resizeImage = async (options: Options) => {
|
||||
type Sized = { width: number; height: number };
|
||||
const computeScale = (image: Sized) => {
|
||||
// Choose a scale factor such that the resized image fits within a
|
||||
// maxWidth x maxHeight box.
|
||||
const scale = Math.min(
|
||||
options.maxWidth / image.width,
|
||||
options.maxHeight / image.height,
|
||||
);
|
||||
return scale;
|
||||
};
|
||||
|
||||
if (shim.mobilePlatform() === 'web') {
|
||||
const image = await fileToImage(options.inputPath);
|
||||
try {
|
||||
const canvas = document.createElement('canvas');
|
||||
|
||||
const scale = computeScale(image.image);
|
||||
canvas.width = image.image.width * scale;
|
||||
canvas.height = image.image.height * scale;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(image.image, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
const blob = await new Promise<Blob>((resolve, reject) => {
|
||||
try {
|
||||
canvas.toBlob(
|
||||
(blob) => resolve(blob),
|
||||
`image/${options.format.toLowerCase()}`,
|
||||
options.quality,
|
||||
);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
await (shim.fsDriver() as FsDriverWeb).writeFile(
|
||||
options.outputPath, await blob.arrayBuffer(), 'Buffer',
|
||||
);
|
||||
} finally {
|
||||
image.free();
|
||||
}
|
||||
} else {
|
||||
const originalSize = await getImageDimensions(options.inputPath);
|
||||
logger.debug('Processing image with size', originalSize.width, 'x', originalSize.height);
|
||||
|
||||
let context = ImageManipulator.manipulate(options.inputPath);
|
||||
|
||||
// Only rescale the image if it's bigger than the maximum size:
|
||||
if (originalSize.width > options.maxWidth || originalSize.height > options.maxHeight) {
|
||||
const scale = computeScale(originalSize);
|
||||
context = context.resize({
|
||||
width: originalSize.width * scale,
|
||||
height: originalSize.height * scale,
|
||||
});
|
||||
}
|
||||
|
||||
const final = await context.renderAsync();
|
||||
const saved = await final.saveAsync({
|
||||
format: options.format === 'PNG' ? SaveFormat.PNG : SaveFormat.JPEG,
|
||||
compress: options.quality,
|
||||
});
|
||||
|
||||
const resizedImagePath = saved.uri;
|
||||
logger.info('Resized image ', resizedImagePath);
|
||||
logger.info(`Moving ${resizedImagePath} => ${options.outputPath}`);
|
||||
|
||||
await shim.fsDriver().copy(resizedImagePath, options.outputPath);
|
||||
|
||||
try {
|
||||
await shim.fsDriver().unlink(resizedImagePath);
|
||||
} catch (error) {
|
||||
logger.warn('Error when unlinking cached file: ', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default resizeImage;
|
||||
在新工单中引用
屏蔽一个用户