Skip to content

Commit

Permalink
chore: write some tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nd0ut committed Feb 16, 2024
1 parent ed20998 commit b6787d2
Show file tree
Hide file tree
Showing 19 changed files with 283 additions and 119 deletions.
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/image-shrink/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"signature"
],
"devDependencies": {
"@imagemagick/magick-wasm": "^0.0.28",
"@vitest/browser": "^1.2.2",
"playwright": "^1.41.2",
"ts-node": "^10.8.1",
Expand Down
11 changes: 0 additions & 11 deletions packages/image-shrink/src/test/helpers/blobToImage.ts

This file was deleted.

5 changes: 0 additions & 5 deletions packages/image-shrink/src/test/helpers/fileFromUrl.ts

This file was deleted.

12 changes: 12 additions & 0 deletions packages/image-shrink/src/test/helpers/getImageAttributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { readMagickImage } from './readMagickImage'

export const getImageAttributes = async (inputBlob: Blob) => {
return readMagickImage(inputBlob, (image) => {
return image.attributeNames.reduce((acc, name) => {
return {
...acc,
[name]: image.getAttribute(name)
}
}, {})
})
}
10 changes: 10 additions & 0 deletions packages/image-shrink/src/test/helpers/loadImageAsBlob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const loadImageAsBlob = async (
moduleResolver: () => Promise<{ default: string }>
) => {
const imageUrl = await moduleResolver().then((module) => module.default)
const response = await fetch(imageUrl)
const buffer = await response.arrayBuffer()
return new Blob([buffer], {
type: response.headers.get('content-type') ?? 'application/octet-stream'
})
}
17 changes: 17 additions & 0 deletions packages/image-shrink/src/test/helpers/loadImageMagick.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// <reference types="vite/client" />
import {
ImageMagick,
Magick,
MagickFormat,
Quantum,
initializeImageMagick
} from '@imagemagick/magick-wasm'
// eslint-disable-next-line import/no-unresolved
import wasmUrl from '@imagemagick/magick-wasm/magick.wasm?url'

export const loadImageMagick = async () => {
const wasmBytes = await fetch(wasmUrl).then((res) => res.arrayBuffer())
await initializeImageMagick(wasmBytes)

return { Magick, MagickFormat, Quantum, ImageMagick }
}
15 changes: 15 additions & 0 deletions packages/image-shrink/src/test/helpers/readMagickImage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { loadImageMagick } from './loadImageMagick'
import { type IMagickImage } from '@imagemagick/magick-wasm'

export const readMagickImage = async <T>(
inputBlob: Blob,
func: (image: IMagickImage) => T
): Promise<T> => {
const { ImageMagick } = await loadImageMagick()
const blobArray = new Uint8Array(await inputBlob.arrayBuffer())
return new Promise<T>((resolve) => {
ImageMagick.read(blobArray, (image) => {
resolve(func(image))
})
})
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 16 additions & 17 deletions packages/image-shrink/src/utils/IccProfile/getIccProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@ export const getIccProfile = async (blob: Blob) => {
const iccProfile: DataView[] = []
const { promiseReadJpegChunks, stack } = readJpegChunks()

return await promiseReadJpegChunks(blob)
.then(() => {
stack.forEach(({ marker, view }) => {
if (marker === 0xe2) {
if (
// check for "ICC_PROFILE\0"
view.getUint32(0) === 0x4943435f &&
view.getUint32(4) === 0x50524f46 &&
view.getUint32(8) === 0x494c4500
) {
iccProfile.push(view)
}
}
})
return iccProfile
})
.catch(() => iccProfile)
await promiseReadJpegChunks(blob)

stack.forEach(({ marker, view }) => {
if (marker === 0xe2) {
if (
// check for "ICC_PROFILE\0"
view.getUint32(0) === 0x4943435f &&
view.getUint32(4) === 0x50524f46 &&
view.getUint32(8) === 0x494c4500
) {
iccProfile.push(view)
}
}
})

return iccProfile
}
36 changes: 18 additions & 18 deletions packages/image-shrink/src/utils/exif/getExif.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ export const getExif = async (blob: Blob) => {
let exif: DataView | null = null

const { promiseReadJpegChunks, stack } = readJpegChunks()
return promiseReadJpegChunks(blob)
.then(() => {
stack.forEach(({ marker, view }) => {
if (!exif && marker === 0xe1) {
if (view.byteLength >= 14) {
if (
// check for "Exif\0"
view.getUint32(0) === 0x45786966 &&
view.getUint16(4) === 0
) {
exif = view
return
}
}

await promiseReadJpegChunks(blob)

stack.forEach(({ marker, view }) => {
if (!exif && marker === 0xe1) {
if (view.byteLength >= 14) {
if (
// check for "Exif\0"
view.getUint32(0) === 0x45786966 &&
view.getUint16(4) === 0
) {
exif = view
return
}
})
return exif
})
.catch(() => exif)
}
}
})

return exif
}
4 changes: 2 additions & 2 deletions packages/image-shrink/src/utils/image/JPEG/readJpegChunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ type TChunk = {
view: DataView
}

// TODO: unwrap promises
export const readJpegChunks = () => {
const stack: TChunk[] = []
const promiseReadJpegChunks = (blob: Blob) =>
Expand Down Expand Up @@ -37,7 +38,6 @@ export const readJpegChunks = () => {
break
}
}

readNextChunk()
})

Expand All @@ -50,7 +50,7 @@ export const readJpegChunks = () => {
return
}

const marker = view?.getUint8(1)
const marker = view.getUint8(1)

if (marker === 0xda) {
resolve(true)
Expand Down
75 changes: 35 additions & 40 deletions packages/image-shrink/src/utils/image/JPEG/replaceJpegChunk.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,47 @@
import { readJpegChunks } from './readJpegChunks'

export const replaceJpegChunk = (
export const replaceJpegChunk = async (
blob: Blob,
marker: number,
chunks: ArrayBuffer[]
) => {
return new Promise<Blob>((resolve, reject) => {
{
const oldChunkPos: number[] = []
const oldChunkLength: number[] = []

const { promiseReadJpegChunks, stack } = readJpegChunks()

return promiseReadJpegChunks(blob)
.then(() => {
stack.forEach((chunk) => {
if (chunk.marker === marker) {
oldChunkPos.push(chunk.startPos)
return oldChunkLength.push(chunk.length)
}
})
})
.then(() => {
const newChunks: (ArrayBuffer | Blob)[] = [blob.slice(0, 2)]

for (const chunk of chunks) {
const intro = new DataView(new ArrayBuffer(4))
intro.setUint16(0, 0xff00 + marker)
intro.setUint16(2, chunk.byteLength + 2)
newChunks.push(intro.buffer)
newChunks.push(chunk)
}

let pos = 2
for (let i = 0; i < oldChunkPos.length; i++) {
if (oldChunkPos[i] > pos) {
newChunks.push(blob.slice(pos, oldChunkPos[i]))
}
pos = oldChunkPos[i] + oldChunkLength[i] + 4
}

newChunks.push(blob.slice(pos, blob.size))

resolve(
new Blob(newChunks, {
type: blob.type
})
)
})
.catch(() => reject(blob))
}).catch(() => blob)
await promiseReadJpegChunks(blob)

stack.forEach((chunk) => {
if (chunk.marker === marker) {
oldChunkPos.push(chunk.startPos)
return oldChunkLength.push(chunk.length)
}
})

const newChunks: (ArrayBuffer | Blob)[] = [blob.slice(0, 2)]

for (const chunk of chunks) {
const intro = new DataView(new ArrayBuffer(4))
intro.setUint16(0, 0xff00 + marker)
intro.setUint16(2, chunk.byteLength + 2)
newChunks.push(intro.buffer)
newChunks.push(chunk)
}

let pos = 2
for (let i = 0; i < oldChunkPos.length; i++) {
if (oldChunkPos[i] > pos) {
newChunks.push(blob.slice(pos, oldChunkPos[i]))
}
pos = oldChunkPos[i] + oldChunkLength[i] + 4
}

newChunks.push(blob.slice(pos, blob.size))

return new Blob(newChunks, {
type: blob.type
})
}
}
Loading

0 comments on commit b6787d2

Please sign in to comment.