diff options
author | KN4CK3R <KN4CK3R@users.noreply.github.com> | 2021-06-05 14:32:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-05 15:32:19 +0300 |
commit | 8e262104c25d1c2578f683109e1b373aade3a17c (patch) | |
tree | 04b8fda8516498b74350bb695f230e0e1089a48d /web_src | |
parent | 7979c3654eb91adce4fd9717d9ff891496a56ff3 (diff) | |
download | gitea-8e262104c25d1c2578f683109e1b373aade3a17c.tar.gz gitea-8e262104c25d1c2578f683109e1b373aade3a17c.zip |
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 <me@silverwind.io>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Lauris BH <lauris@nix.lv>
Diffstat (limited to 'web_src')
-rw-r--r-- | web_src/js/features/imagediff.js | 74 |
1 files changed, 66 insertions, 8 deletions
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 |