mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 11:28:24 +00:00 
			
		
		
		
	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>
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user