@ngageoint/mage.image.service
Version:
Orient images attached to MAGE observations according to EXIF meta-data and generate configurable size thumbnails.
178 lines • 9.71 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const adapters_images_sharp_1 = require("./adapters.images.sharp");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const stream_1 = __importDefault(require("stream"));
const sharp_1 = __importDefault(require("sharp"));
const jimp_1 = __importDefault(require("jimp"));
const util_spec_1 = require("./util.spec");
const imageBasePath = path_1.default.resolve(__dirname, '..', 'spec');
const unorientedPath = path_1.default.resolve(imageBasePath, 'majestic_ram.orient.raw-6.tag-6.jpg');
describe('sharp image service', () => {
describe('auto-orient', () => {
it('rotates the image to the correct orientation', () => __awaiter(void 0, void 0, void 0, function* () {
const service = (0, adapters_images_sharp_1.SharpImageService)();
const source = {
mediaType: 'image/jpeg',
bytes: fs_1.default.createReadStream(unorientedPath)
};
const dest = new util_spec_1.BufferWriteable();
const oriented = yield service.autoOrient(source, dest);
if (oriented instanceof Error) {
return fail(oriented);
}
const expectedPixels = yield (0, sharp_1.default)(path_1.default.resolve(imageBasePath, 'majestic_ram.oriented.jpg')).toBuffer();
const orientedByServiceJimp = yield jimp_1.default.read(dest.content);
const expectedJimp = yield jimp_1.default.read(expectedPixels);
const percentDifferent = jimp_1.default.diff(orientedByServiceJimp, expectedJimp).percent;
expect(percentDifferent).toBeLessThan(1);
expect(oriented.sizeInBytes).toEqual(dest.content.length);
expect(Math.abs(oriented.sizeInBytes - expectedPixels.length)).toBeLessThanOrEqual(1000);
expect(oriented).toEqual(jasmine.objectContaining({
mediaType: 'image/jpeg',
dimensions: {
width: 720,
height: 720
}
}));
}));
});
describe('scaling', () => {
const service = (0, adapters_images_sharp_1.SharpImageService)();
it('scales the height to the target when height is less than width', () => __awaiter(void 0, void 0, void 0, function* () {
const source = {
bytes: fs_1.default.createReadStream(path_1.default.resolve(imageBasePath, 'tumbeasts-1800x1140.png')),
dimensions: {
width: 1800,
height: 1140
}
};
const dest = new util_spec_1.BufferWriteable();
const scaled = yield service.scaleToDimension(76, source, dest);
if (scaled instanceof Error) {
return fail(scaled);
}
const expectedPixels = yield (0, sharp_1.default)(path_1.default.resolve(imageBasePath, 'tumbeasts-120x76.png')).toBuffer();
const scaledJimp = yield jimp_1.default.read(dest.content);
const expectedJimp = yield jimp_1.default.read(expectedPixels);
const percentDifferent = jimp_1.default.diff(scaledJimp, expectedJimp).percent;
expect(scaled).toEqual(jasmine.objectContaining({
mediaType: 'image/png',
dimensions: {
width: 120,
height: 76
}
}));
expect(scaled.sizeInBytes).toEqual(dest.content.length);
expect(Math.abs(scaled.sizeInBytes - expectedPixels.length)).toBeLessThanOrEqual(1200);
expect(percentDifferent).toBeLessThan(1);
}));
it('scales the width to the target when width is less than height', () => __awaiter(void 0, void 0, void 0, function* () {
const source = {
bytes: fs_1.default.createReadStream(path_1.default.resolve(imageBasePath, 'tumbeasts-1140x1800.png')),
dimensions: {
width: 1140,
height: 1800
}
};
const dest = new util_spec_1.BufferWriteable();
const scaled = yield service.scaleToDimension(76, source, dest);
if (scaled instanceof Error) {
return fail(scaled);
}
const expectedPixels = yield (0, sharp_1.default)(path_1.default.resolve(imageBasePath, 'tumbeasts-76x120.png')).toBuffer();
const scaledJimp = yield jimp_1.default.read(dest.content);
const expectedJimp = yield jimp_1.default.read(expectedPixels);
const percentDifferent = jimp_1.default.diff(scaledJimp, expectedJimp).percent;
expect(scaled).toEqual(jasmine.objectContaining({
mediaType: 'image/png',
dimensions: {
width: 76,
height: 120
}
}));
expect(scaled.sizeInBytes).toEqual(dest.content.length);
expect(Math.abs(scaled.sizeInBytes - expectedPixels.length)).toBeLessThanOrEqual(1000);
expect(percentDifferent).toBeLessThan(2);
}));
it('uses the given dimension even when they are not accurate', () => __awaiter(void 0, void 0, void 0, function* () {
const source = {
bytes: fs_1.default.createReadStream(path_1.default.resolve(imageBasePath, 'tumbeasts-1140x1800.png')),
dimensions: {
width: 1800,
height: 1140
}
};
const dest = new util_spec_1.BufferWriteable();
const scaled = yield service.scaleToDimension(76, source, dest);
if (scaled instanceof Error) {
return fail(scaled);
}
const expectedPixels = yield (0, sharp_1.default)(path_1.default.resolve(imageBasePath, 'tumbeasts-48x76.png')).toBuffer();
const scaledJimp = yield jimp_1.default.read(dest.content);
const expectedJimp = yield jimp_1.default.read(expectedPixels);
const percentDifferent = jimp_1.default.diff(scaledJimp, expectedJimp).percent;
expect(scaled).toEqual(jasmine.objectContaining({
mediaType: 'image/png',
dimensions: {
width: 48,
height: 76
}
}));
expect(scaled.sizeInBytes).toEqual(dest.content.length);
expect(Math.abs(scaled.sizeInBytes - expectedPixels.length)).toBeLessThanOrEqual(1000);
expect(percentDifferent).toBeLessThan(2);
}));
it('scales the height to the target size when the source has no dimensions', () => __awaiter(void 0, void 0, void 0, function* () {
const source = {
bytes: fs_1.default.createReadStream(path_1.default.resolve(imageBasePath, 'tumbeasts-1140x1800.png')),
};
const dest = new util_spec_1.BufferWriteable();
const scaled = yield service.scaleToDimension(76, source, dest);
if (scaled instanceof Error) {
return fail(scaled);
}
const expectedPixels = yield (0, sharp_1.default)(path_1.default.resolve(imageBasePath, 'tumbeasts-48x76.png')).toBuffer();
const scaledJimp = yield jimp_1.default.read(dest.content);
const expectedJimp = yield jimp_1.default.read(expectedPixels);
const percentDifferent = jimp_1.default.diff(scaledJimp, expectedJimp).percent;
expect(scaled).toEqual(jasmine.objectContaining({
mediaType: 'image/png',
dimensions: {
width: 48,
height: 76
}
}));
expect(scaled.sizeInBytes).toEqual(dest.content.length);
expect(Math.abs(scaled.sizeInBytes - expectedPixels.length)).toBeLessThanOrEqual(1000);
expect(percentDifferent).toBeLessThan(2);
}));
});
describe('corrupted image tolerance', () => {
it('returns an error loading this test image found on a demo server', () => __awaiter(void 0, void 0, void 0, function* () {
const service = (0, adapters_images_sharp_1.SharpImageService)();
const corruptedBytes = fs_1.default.readFileSync(path_1.default.join(imageBasePath, 'corrupted.jpeg'));
const corruptedSource = {
mediaType: 'image/jpeg',
bytes: stream_1.default.Readable.from(corruptedBytes)
};
const corruptedDest = new util_spec_1.BufferWriteable();
const err = yield service.autoOrient(corruptedSource, corruptedDest);
expect(err).toBeInstanceOf(Error);
}));
});
});
//# sourceMappingURL=adapters.images.sharp.spec.js.map