From 8e262104c25d1c2578f683109e1b373aade3a17c Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Sat, 5 Jun 2021 14:32:19 +0200 Subject: Add Image Diff for SVG files (#14867) * Added type sniffer. * Switched content detection from base to typesniffer. * Added GuessContentType to Blob. * Moved image info logic to client. Added support for SVG images in diff. * Restore old blocked svg behaviour. * Added missing image formats. * Execute image diff only when container is visible. * add margin to spinner * improve BIN tag on image diffs * Default to render view. * Show image diff on incomplete diff. Co-authored-by: silverwind Co-authored-by: Lunny Xiao Co-authored-by: Lauris BH --- web_src/js/features/imagediff.js | 74 +++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 8 deletions(-) (limited to 'web_src/js/features') diff --git a/web_src/js/features/imagediff.js b/web_src/js/features/imagediff.js index ce7ce8d2af..67e9548596 100644 --- a/web_src/js/features/imagediff.js +++ b/web_src/js/features/imagediff.js @@ -1,3 +1,34 @@ +function getDefaultSvgBoundsIfUndefined(svgXml, src) { + const DefaultSize = 300; + const MaxSize = 99999; + + const svg = svgXml.rootElement; + + const width = svg.width.baseVal; + const height = svg.height.baseVal; + if (width.unitType === SVGLength.SVG_LENGTHTYPE_PERCENTAGE || height.unitType === SVGLength.SVG_LENGTHTYPE_PERCENTAGE) { + const img = new Image(); + img.src = src; + if (img.width > 1 && img.width < MaxSize && img.height > 1 && img.height < MaxSize) { + return { + width: img.width, + height: img.height + }; + } + if (svg.hasAttribute('viewBox')) { + const viewBox = svg.viewBox.baseVal; + return { + width: DefaultSize, + height: DefaultSize * viewBox.width / viewBox.height + }; + } + return { + width: DefaultSize, + height: DefaultSize + }; + } +} + export default async function initImageDiff() { function createContext(image1, image2) { const size1 = { @@ -30,34 +61,50 @@ export default async function initImageDiff() { $('.image-diff').each(function() { const $container = $(this); + + const diffContainerWidth = $container.width() - 300; const pathAfter = $container.data('path-after'); const pathBefore = $container.data('path-before'); const imageInfos = [{ loaded: false, path: pathAfter, - $image: $container.find('img.image-after') + $image: $container.find('img.image-after'), + $boundsInfo: $container.find('.bounds-info-after') }, { loaded: false, path: pathBefore, - $image: $container.find('img.image-before') + $image: $container.find('img.image-before'), + $boundsInfo: $container.find('.bounds-info-before') }]; for (const info of imageInfos) { if (info.$image.length > 0) { - info.$image.on('load', () => { - info.loaded = true; - setReadyIfLoaded(); + $.ajax({ + url: info.path, + success: (data, _, jqXHR) => { + info.$image.on('load', () => { + info.loaded = true; + setReadyIfLoaded(); + }); + info.$image.attr('src', info.path); + + if (jqXHR.getResponseHeader('Content-Type') === 'image/svg+xml') { + const bounds = getDefaultSvgBoundsIfUndefined(data, info.path); + if (bounds) { + info.$image.attr('width', bounds.width); + info.$image.attr('height', bounds.height); + info.$boundsInfo.hide(); + } + } + } }); - info.$image.attr('src', info.path); } else { info.loaded = true; setReadyIfLoaded(); } } - const diffContainerWidth = $container.width() - 300; - function setReadyIfLoaded() { if (imageInfos[0].loaded && imageInfos[1].loaded) { initViews(imageInfos[0].$image, imageInfos[1].$image); @@ -81,6 +128,17 @@ export default async function initImageDiff() { factor = (diffContainerWidth - 24) / 2 / sizes.max.width; } + const widthChanged = sizes.image1.length !== 0 && sizes.image2.length !== 0 && sizes.image1[0].naturalWidth !== sizes.image2[0].naturalWidth; + const heightChanged = sizes.image1.length !== 0 && sizes.image2.length !== 0 && sizes.image1[0].naturalHeight !== sizes.image2[0].naturalHeight; + if (sizes.image1.length !== 0) { + $container.find('.bounds-info-after .bounds-info-width').text(`${sizes.image1[0].naturalWidth}px`).addClass(widthChanged ? 'green' : ''); + $container.find('.bounds-info-after .bounds-info-height').text(`${sizes.image1[0].naturalHeight}px`).addClass(heightChanged ? 'green' : ''); + } + if (sizes.image2.length !== 0) { + $container.find('.bounds-info-before .bounds-info-width').text(`${sizes.image2[0].naturalWidth}px`).addClass(widthChanged ? 'red' : ''); + $container.find('.bounds-info-before .bounds-info-height').text(`${sizes.image2[0].naturalHeight}px`).addClass(heightChanged ? 'red' : ''); + } + sizes.image1.css({ width: sizes.size1.width * factor, height: sizes.size1.height * factor -- cgit v1.2.3