pptx-automizer
Version:
A template based pptx generator
153 lines • 8.32 kB
JavaScript
;
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 };
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../types/types");
const slugify_1 = __importDefault(require("slugify"));
const image_size_1 = require("image-size");
const fs_1 = __importDefault(require("fs"));
const xml_helper_1 = require("./xml-helper");
const compute_src_rect_1 = require("./compute-src-rect");
class ModifyImageHelper {
}
_a = ModifyImageHelper;
/**
* Update the "Target" attribute of a created image relation.
* This will change the image itself. Load images with Automizer.loadMedia
* @param filename name of target image in root template media folder.
*/
ModifyImageHelper.setRelationTarget = (filename) => {
return (element, arg1) => {
arg1.setAttribute('Target', xml_helper_1.XmlHelper.sanitizeAttr('../media/' + (0, slugify_1.default)(filename)));
};
};
/**
* Update the "Target" attribute of a created image relation.
* This will change the image itself. Load images with Automizer.loadMedia
* This will also auto-crop the image to the new width and height,
* based on the container aspect ratio, derived from the original image
* and using the new image width and height based on the files loaded into
* the presentation media folder using .loadMedia()
* @param filename name of target image in root template media folder.
* @param pres presentation properties (to access the root template archive)
*/
ModifyImageHelper.setRelationTargetCover = (filename, pres) => {
return (element, arg1) => __awaiter(void 0, void 0, void 0, function* () {
const newTarget = '../media/' + (0, slugify_1.default)(filename);
const originalTarget = arg1.getAttribute('Target');
const originalTargetPath = originalTarget.replace('../', 'ppt/');
const originalImageDimensions = { width: 100, height: 100 };
const newImageDimensions = { width: 100, height: 100 };
// Get the new image dimensions, using the rootTemplate mediafiles array,
// since we have it loaded into the presentation media folder using .loadMedia()
// If we don't find the media file, we warn, but continue
try {
const mediaFile = pres.rootTemplate.mediaFiles.find((file) => file.file === filename);
if (!mediaFile) {
throw new Error('Media file not found in template archive in path: ' + filename);
}
const buffer = (0, types_1.getMediaBuffer)(mediaFile, fs_1.default.readFileSync);
const _dimensions = (0, image_size_1.imageSize)(buffer);
newImageDimensions.width = _dimensions.width;
newImageDimensions.height = _dimensions.height;
}
catch (error) {
console.warn("Couldn't find media file in template archive in path.");
}
// Find the original image dimensions using the original target path from the original slide
// using the rootTemplate archive file system and get the image dimensions.
// If we don't find the original image, we warn, but continue
// If we find the original image, we get the image dimensions and use this to reverse calculate
// the aspect ratio and then use the new image dimensions to calculate and set the new crop on srcRect.
// This results in the image being cropped in the image container to match the aspect ratio of the new image.
try {
if (pres.rootTemplate.archive.fileExists(originalTargetPath)) {
const originalImage = yield pres.rootTemplate.archive.read(originalTargetPath, 'nodebuffer');
const _dimensions = (0, image_size_1.imageSize)(originalImage);
originalImageDimensions.width = _dimensions.width;
originalImageDimensions.height = _dimensions.height;
}
else {
throw new Error('Original image not found from template archive in path: ' +
originalTargetPath);
}
const srcRect = element.getElementsByTagName('a:srcRect')[0];
const srcRectLeft = srcRect.getAttribute('l');
const srcRectTop = srcRect.getAttribute('t');
const srcRectRight = srcRect.getAttribute('r');
const srcRectBottom = srcRect.getAttribute('b');
const currentSrcRect = {
l: srcRectLeft ? Number(srcRectLeft) : 0,
t: srcRectTop ? Number(srcRectTop) : 0,
r: srcRectRight ? Number(srcRectRight) : 0,
b: srcRectBottom ? Number(srcRectBottom) : 0,
};
const containerAr = (0, compute_src_rect_1.inferContainerAr)(originalImageDimensions.width, originalImageDimensions.height, currentSrcRect);
const newSrcRect = (0, compute_src_rect_1.computeSrcRectForNewImage)(containerAr, newImageDimensions.width, newImageDimensions.height);
srcRect.setAttribute('l', String(newSrcRect.l));
srcRect.setAttribute('t', String(newSrcRect.t));
srcRect.setAttribute('r', String(newSrcRect.r));
srcRect.setAttribute('b', String(newSrcRect.b));
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.warn('Skipped setting relation target cropped due to an error: ' +
errorMessage);
}
arg1.setAttribute('Target', xml_helper_1.XmlHelper.sanitizeAttr(newTarget));
});
};
/*
Update an existing duotone image overlay element (WIP)
Apply a duotone color to an image p:blipFill -> a:blip fill element.
Works best on white icons, see __tests__/media/feather.png
*/
ModifyImageHelper.setDuotoneFill = (duotoneParams) => (element) => {
const blipFill = element.getElementsByTagName('p:blipFill');
if (!blipFill) {
return;
}
const duotone = blipFill.item(0).getElementsByTagName('a:duotone')[0];
if (duotone) {
if (duotoneParams === null || duotoneParams === void 0 ? void 0 : duotoneParams.color) {
const srgbClr = duotone.getElementsByTagName('a:srgbClr')[0];
if (srgbClr) {
// Only sRgb supported
srgbClr.setAttribute('val', String(duotoneParams.color.value));
if ((duotoneParams === null || duotoneParams === void 0 ? void 0 : duotoneParams.tint) !== undefined) {
// tint needs to be 0 - 100000
const tint = srgbClr.getElementsByTagName('a:tint')[0];
if (tint) {
tint.setAttribute('val', String(duotoneParams.tint));
}
}
if ((duotoneParams === null || duotoneParams === void 0 ? void 0 : duotoneParams.satMod) !== undefined) {
const satMod = srgbClr.getElementsByTagName('a:satMod')[0];
if (satMod) {
satMod.setAttribute('val', String(duotoneParams.satMod));
}
}
}
}
if (duotoneParams === null || duotoneParams === void 0 ? void 0 : duotoneParams.prstClr) {
const prstClr = duotone.getElementsByTagName('a:prstClr')[0];
if (prstClr) {
// Only tested with "black" and "white"
prstClr.setAttribute('val', String(duotoneParams.prstClr));
}
}
}
};
exports.default = ModifyImageHelper;
//# sourceMappingURL=modify-image-helper.js.map