Files
image-processing/electron/main/image-processor.spec.ts
T

107 lines
3.7 KiB
TypeScript

import { promises as fs } from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import sharp from 'sharp'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import type { ProcessOptions } from '../../src/shared/types'
import {
ImageProcessor,
processSingleImage,
readSofHeight,
} from './image-processor'
describe('image processing algorithm', () => {
let temporaryDirectory: string
let inputPath: string
beforeEach(async () => {
temporaryDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'genuine-qingquwang-'))
inputPath = path.join(temporaryDirectory, 'sample.jpg')
await sharp({
create: {
width: 18,
height: 12,
channels: 3,
background: { r: 23, g: 105, b: 224 },
},
}).jpeg({ quality: 90 }).toFile(inputPath)
})
afterEach(async () => {
await fs.rm(temporaryDirectory, { recursive: true, force: true })
})
it('writes a .file without EOI while restoring original SOF height', async () => {
const outputPath = await processSingleImage(inputPath, options('file', 0))
const output = await fs.readFile(outputPath)
expect(outputPath).toBe(path.join(temporaryDirectory, 'sample.file'))
expect(readSofHeight(output)).toBe(12)
expect(output.subarray(-2).equals(Buffer.from([0xff, 0xd9]))).toBe(false)
})
it('supports .file.jpg and appends the configured random byte count', async () => {
const baselinePath = await processSingleImage(inputPath, options('file', 0))
const baselineSize = (await fs.stat(baselinePath)).size
const outputPath = await processSingleImage(inputPath, options('file-jpg', 0.01))
const outputSize = (await fs.stat(outputPath)).size
expect(outputPath).toBe(path.join(temporaryDirectory, 'sample.file.jpg'))
expect(outputSize - baselineSize).toBe(Math.floor(0.01 * 1024 * 1024))
})
it('discovers and converts supported non-JPEG inputs into JPEG delivery files', async () => {
const source = sharp({
create: {
width: 18,
height: 12,
channels: 4,
background: { r: 23, g: 105, b: 224, alpha: 0.5 },
},
})
const inputs = [
path.join(temporaryDirectory, 'sample.png'),
path.join(temporaryDirectory, 'sample.webp'),
path.join(temporaryDirectory, 'sample.gif'),
path.join(temporaryDirectory, 'sample.tiff'),
path.join(temporaryDirectory, 'sample.avif'),
]
await Promise.all([
source.clone().png().toFile(inputs[0]),
source.clone().webp().toFile(inputs[1]),
source.clone().gif().toFile(inputs[2]),
source.clone().tiff().toFile(inputs[3]),
source.clone().avif().toFile(inputs[4]),
fs.writeFile(path.join(temporaryDirectory, 'sample.svg'), '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="12"><rect width="18" height="12" fill="#1769e0"/></svg>'),
fs.writeFile(path.join(temporaryDirectory, 'ignored.bmp'), 'not-supported'),
])
const processor = new ImageProcessor()
const inspected = await processor.inspect([temporaryDirectory])
const inspectedNames = inspected.map((item) => item.name)
expect(inspectedNames).toEqual([
'sample.avif',
'sample.gif',
'sample.jpg',
'sample.png',
'sample.svg',
'sample.tiff',
'sample.webp',
])
for (const input of [...inputs, path.join(temporaryDirectory, 'sample.svg')]) {
const outputPath = await processSingleImage(input, options('file', 0))
expect(readSofHeight(await fs.readFile(outputPath))).toBe(12)
}
})
function options(outputFormat: 'file' | 'file-jpg', junkSizeMb: number): ProcessOptions {
return {
paths: [inputPath],
useSourceDirectory: true,
outputFormat,
junkSizeMb,
}
}
})