Skip to content

Commit

Permalink
Merge pull request #162 from TonyBrobston/add-fix-image-orientation-o…
Browse files Browse the repository at this point in the history
…ption

feat: add fixImageOrientation option
  • Loading branch information
TonyBrobston authored Jul 27, 2020
2 parents cb212ea + b9c8dc5 commit 8007a67
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 13 deletions.
25 changes: 19 additions & 6 deletions src/services/canvasService.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import {Options} from '../types/Options';
import exifService from './exifService';

const setCanvasDimensions =
(canvas: HTMLCanvasElement, orientation: number, scaledHeight: number, scaledWidth: number): void => {
if (orientation > 4 && orientation < 9) {
const setCanvasDimensions = (
canvas: HTMLCanvasElement,
orientation: number,
fixImageOrientation: boolean,
scaledHeight: number,
scaledWidth: number,
): void => {
if (orientation > 4 && orientation < 9 && fixImageOrientation) {
canvas.width = scaledHeight;
canvas.height = scaledWidth;
} else {
Expand Down Expand Up @@ -39,15 +45,22 @@ const correctExifRotation = (context: CanvasTransform, orientation: number, heig
}
};

const create = async (file: File, image: HTMLImageElement, scale: number): Promise<HTMLCanvasElement> => {
const create = async (
file: File,
image: HTMLImageElement,
scale: number,
{fixImageOrientation}: Options,
): Promise<HTMLCanvasElement> => {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
if (context) {
const scaledHeight = image.height * scale;
const scaledWidth = image.width * scale;
const orientation = await exifService.determineOrientation(file);
setCanvasDimensions(canvas, orientation, scaledHeight, scaledWidth);
correctExifRotation(context, orientation, scaledHeight, scaledWidth);
setCanvasDimensions(canvas, orientation, fixImageOrientation, scaledHeight, scaledWidth);
if (fixImageOrientation) {
correctExifRotation(context, orientation, scaledHeight, scaledWidth);
}
context.drawImage(image, 0, 0, scaledWidth, scaledHeight);
return canvas;
} else {
Expand Down
1 change: 1 addition & 0 deletions src/services/optionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {Options} from '../types/Options';
const override = (inputOptions: InputOptions): Options => {
return {
allowCrossOriginResourceSharing: false,
fixImageOrientation: true,
quality: 0.5,
returnOriginalIfCompressedFileIsLarger: false,
returnOriginalOnFailure: true,
Expand Down
2 changes: 1 addition & 1 deletion src/services/scaleService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const determineScale = ({height, width}: HTMLImageElement, {maxHeight, maxWidth,
const toCanvas = async (file: File, options: Options): Promise<HTMLCanvasElement> => {
const image = await imageService.create(file, options);
const scale = determineScale(image, options);
return canvasService.create(file, image, scale);
return canvasService.create(file, image, scale, options);
};

export default {
Expand Down
1 change: 1 addition & 0 deletions src/types/InputOptions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface InputOptions {
readonly allowCrossOriginResourceSharing?: boolean;
readonly fixImageOrientation?: boolean;
readonly quality?: number;
readonly returnOriginalOnFailure?: boolean;
readonly returnOriginalIfCompressedFileIsLarger?: boolean;
Expand Down
1 change: 1 addition & 0 deletions src/types/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {InputOptions} from './InputOptions';

export interface Options extends InputOptions {
readonly allowCrossOriginResourceSharing: boolean;
readonly fixImageOrientation: boolean;
readonly quality: number;
readonly returnOriginalOnFailure: boolean;
readonly returnOriginalIfCompressedFileIsLarger: boolean;
Expand Down
31 changes: 26 additions & 5 deletions tests/services/canvasService.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Chance} from 'chance';
import {Options} from '../../src/types/Options';

import canvasService from '../../src/services/canvasService';
import exifService from '../../src/services/exifService';
Expand All @@ -19,6 +20,9 @@ describe('canvasService', () => {
});
const scaledHeight = image.height * scale;
const scaledWidth = image.width * scale;
const options = {
fixImageOrientation: true,
} as Options;

const expectedOrientation = 1;

Expand All @@ -28,7 +32,7 @@ describe('canvasService', () => {

describe('create', () => {
beforeAll(async () => {
actualCanvas = await canvasService.create(file, image, scale);
actualCanvas = await canvasService.create(file, image, scale, options);
});

it('should determine orientation', () => {
Expand All @@ -43,6 +47,10 @@ describe('canvasService', () => {
});

describe('correctExifRotation', () => {
afterEach(() => {
transform.mockClear();
});

const transform = jest.fn();
const canvas = document.createElement('canvas');
canvas.getContext = jest.fn().mockReturnValue({
Expand Down Expand Up @@ -103,10 +111,9 @@ describe('canvasService', () => {
width: number,
}) => {
it(`should correct orientation ${scenario.exifOrientation}`, async () => {
transform.mockClear();
exifService.determineOrientation = jest.fn(() => Promise.resolve(scenario.exifOrientation));

actualCanvas = await canvasService.create(file, image, scale);
actualCanvas = await canvasService.create(file, image, scale, options);

expect(actualCanvas.height).toBe(Math.floor(scenario.height));
expect(actualCanvas.width).toBe(Math.floor(scenario.width));
Expand All @@ -115,6 +122,20 @@ describe('canvasService', () => {
expect(transform).toHaveBeenCalledWith(...scenario.parameters);
});
});

it('should NOT correct orientation', async () => {
const exifOrientation = 6;
exifService.determineOrientation = jest.fn(() => Promise.resolve(exifOrientation));

actualCanvas = await canvasService.create(file, image, scale, {
fixImageOrientation: false,
} as Options);

expect(actualCanvas.height).toBe(Math.floor(scaledHeight));
expect(actualCanvas.width).toBe(Math.floor(scaledWidth));

expect(transform).not.toHaveBeenCalled();
});
});

describe('cannot read context', () => {
Expand All @@ -124,7 +145,7 @@ describe('canvasService', () => {
document.createElement = jest.fn(() => canvas);

try {
await canvasService.create(file, image, scale);
await canvasService.create(file, image, scale, options);
} catch (error) {
expect(error.message).toBe('Could not get CanvasRenderingContext2D from HTMLCanvasElement.');
}
Expand All @@ -135,7 +156,7 @@ describe('canvasService', () => {
canvas.getContext = jest.fn(() => null);
document.createElement = jest.fn(() => canvas);

await expect(canvasService.create(file, image, scale)).rejects.toThrow();
await expect(canvasService.create(file, image, scale, options)).rejects.toThrow();
});
});
});
4 changes: 4 additions & 0 deletions tests/services/optionService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('optionService', () => {
{
expectedOptions: {
allowCrossOriginResourceSharing: false,
fixImageOrientation: true,
quality: 0.5,
returnOriginalIfCompressedFileIsLarger: false,
returnOriginalOnFailure: true,
Expand All @@ -18,6 +19,7 @@ describe('optionService', () => {
{
expectedOptions: {
allowCrossOriginResourceSharing: true,
fixImageOrientation: false,
maxHeight: 5,
maxWidth: 4,
quality: 0.75,
Expand All @@ -27,6 +29,7 @@ describe('optionService', () => {
} as Options,
inputOptions: {
allowCrossOriginResourceSharing: true,
fixImageOrientation: false,
maxHeight: 5,
maxWidth: 4,
quality: 0.75,
Expand All @@ -39,6 +42,7 @@ describe('optionService', () => {
{
expectedOptions: {
allowCrossOriginResourceSharing: true,
fixImageOrientation: true,
quality: 0.5,
returnOriginalIfCompressedFileIsLarger: false,
returnOriginalOnFailure: true,
Expand Down
2 changes: 1 addition & 1 deletion tests/services/scaleService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ describe('scaleService', () => {
it('should create a canvas', () => {
expect(canvasService.create).toHaveBeenCalledTimes(1);
expect(canvasService.create).toHaveBeenCalledWith(
file, image, scenario.scale);
file, image, scenario.scale, scenario.options);
});

it('should return a scaled canvasService', () => {
Expand Down

0 comments on commit 8007a67

Please sign in to comment.