Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test: add set orientation #16

Merged
merged 4 commits into from
Jul 13, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 70 additions & 6 deletions src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import * as fs from 'fs';
import { getOrientation } from './index';
import { getOrientation, OrientationCode, updateOrientationCode } from './index';

describe('imageUtil', () => {
const readFile = (name: string) => {
const buffer = fs.readFileSync(`test/${name}`);
return buffer.buffer;
};

describe('getOrientation()', () => {
it('accepts Buffer', async () => {
const buffer = fs.readFileSync(`test/000-1.jpg`);
Expand All @@ -23,11 +28,6 @@ describe('imageUtil', () => {
});

describe('recognize orientation from file of', () => {
const readFile = (name: string) => {
const buffer = fs.readFileSync(`test/${name}`);
return buffer.buffer;
};

it('original image', async () => {
const arr = readFile('000-1.jpg');
const orientation = await getOrientation(arr);
Expand Down Expand Up @@ -95,4 +95,68 @@ describe('imageUtil', () => {
});
});
});

describe('updateOrientationCode()', () => {
it('accepts Buffer', async () => {
const buffer = fs.readFileSync('test/000-flipped-2.jpg');
await updateOrientationCode(buffer.buffer, OrientationCode.original);
const orientation = await getOrientation(buffer.buffer);
expect(orientation).toEqual({ rotation: 0, flipped: false });
});

it('accepts ArrayBuffer', async () => {
const buffer = fs.readFileSync('test/000-flipped-2.jpg');
const arrayBuffer = new ArrayBuffer(buffer.byteLength);
const view = new DataView(arrayBuffer);
buffer.forEach((value, index) => {
view.setUint8(index, value);
});
await updateOrientationCode(arrayBuffer, OrientationCode.original);

const orientation = await getOrientation(arrayBuffer);
expect(orientation).toEqual({ rotation: 0, flipped: false });
});

describe('update orientation from file of', () => {
it('flipped image update orientation', async () => {
const arr = readFile('000-flipped-2.jpg');
await updateOrientationCode(arr, OrientationCode.original);
const orientation = await getOrientation(arr);
expect(orientation).toEqual({ rotation: 0, flipped: false });
});

it('image without Exif', async () => {
const arr = readFile('no-exif.jpg');
const errorMessage = 'The File you are trying to update has no exif data';

try {
await updateOrientationCode(arr, OrientationCode.original);
} catch (error) {
expect(error.message).toBe(errorMessage);
}
});

it('non-JPEG image', async () => {
const arr = readFile('png.png');
const errorMessage = 'The File you are trying to update is not a jpeg';

try {
await updateOrientationCode(arr, OrientationCode.original);
} catch (error) {
expect(error.message).toBe(errorMessage);
}
});

it('empty file', async () => {
const arr = readFile('empty.txt');
const errorMessage = 'The File you are trying to update is not a jpeg';

try {
await updateOrientationCode(arr, OrientationCode.original);
} catch (error) {
expect(error.message).toBe(errorMessage);
}
});
});
});
});
56 changes: 46 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,8 @@ export async function readOrientationCode (
return OrientationCode.unknown;
}

const tiffHeaderOffset =
segmentOffset + statics.offsets.tiffHeader.fromSegment;
const littleEndian = isLittleEndian(view, tiffHeaderOffset);
const ifdPosition = findIfdPosition(view, tiffHeaderOffset, littleEndian);
const ifdFieldOffset = ifdPosition + statics.ifdFieldCountLength;
const {littleEndian, orientationOffset} = getOrientationOffsetAndLittleEndian(view, segmentOffset);

const orientationOffset = findOrientationOffset(
view,
ifdFieldOffset,
littleEndian,
);
if (orientationOffset < 0) {
console.warn('Rotation information was not found');
return OrientationCode.unknown;
Expand All @@ -116,6 +107,42 @@ export async function readOrientationCode (
return orientation;
}

export async function updateOrientationCode (
input: File | Buffer | ArrayBuffer,
orientation: OrientationCode,
): Promise<void> {
const view = await prepareDataView(input);
if (!isValidJpeg(view)) {
throw new Error('The File you are trying to update is not a jpeg');
}

const segmentOffset = await findExifSegmentOffset(view);
if (segmentOffset < 0) {
throw new Error('The File you are trying to update has no exif data');
}

const {littleEndian, orientationOffset} = getOrientationOffsetAndLittleEndian(view, segmentOffset);
setOrientationValueAt(
view,
orientationOffset,
orientation,
littleEndian,
);
}

function getOrientationOffsetAndLittleEndian (view: DataView, segmentOffset: number) {
const tiffHeaderOffset = segmentOffset + statics.offsets.tiffHeader.fromSegment;
const littleEndian = isLittleEndian(view, tiffHeaderOffset);
const ifdPosition = findIfdPosition(view, tiffHeaderOffset, littleEndian);
const ifdFieldOffset = ifdPosition + statics.ifdFieldCountLength;
const orientationOffset = findOrientationOffset(
view,
ifdFieldOffset,
littleEndian,
);
return {littleEndian, orientationOffset};
}
Comment on lines +133 to +144
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love this. Trying to reduce duplication.


async function prepareDataView (
input: File | Buffer | ArrayBuffer,
): Promise<DataView> {
Expand Down Expand Up @@ -300,6 +327,15 @@ function readOrientationValueAt (
return orientation;
}

function setOrientationValueAt (
view: DataView,
offset: number,
orientation: OrientationCode,
littleEndian: boolean,
) {
view.setUint16(offset, orientation, littleEndian);
}

/**
* Converts orientation code specified in Exif to readable information.
* @param input JPEG file data.
Expand Down