mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08: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:
		@@ -12,10 +12,8 @@ import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
@@ -30,15 +28,6 @@ import (
 | 
			
		||||
	"github.com/dustin/go-humanize"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Use at most this many bytes to determine Content Type.
 | 
			
		||||
const sniffLen = 512
 | 
			
		||||
 | 
			
		||||
// SVGMimeType MIME type of SVG images.
 | 
			
		||||
const SVGMimeType = "image/svg+xml"
 | 
			
		||||
 | 
			
		||||
var svgTagRegex = regexp.MustCompile(`(?si)\A\s*(?:(<!--.*?-->|<!DOCTYPE\s+svg([\s:]+.*?>|>))\s*)*<svg[\s>\/]`)
 | 
			
		||||
var svgTagInXMLRegex = regexp.MustCompile(`(?si)\A<\?xml\b.*?\?>\s*(?:(<!--.*?-->|<!DOCTYPE\s+svg([\s:]+.*?>|>))\s*)*<svg[\s>\/]`)
 | 
			
		||||
 | 
			
		||||
// EncodeMD5 encodes string to md5 hex value.
 | 
			
		||||
func EncodeMD5(str string) string {
 | 
			
		||||
	m := md5.New()
 | 
			
		||||
@@ -276,63 +265,6 @@ func IsLetter(ch rune) bool {
 | 
			
		||||
	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DetectContentType extends http.DetectContentType with more content types.
 | 
			
		||||
func DetectContentType(data []byte) string {
 | 
			
		||||
	ct := http.DetectContentType(data)
 | 
			
		||||
 | 
			
		||||
	if len(data) > sniffLen {
 | 
			
		||||
		data = data[:sniffLen]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if setting.UI.SVG.Enabled &&
 | 
			
		||||
		((strings.Contains(ct, "text/plain") || strings.Contains(ct, "text/html")) && svgTagRegex.Match(data) ||
 | 
			
		||||
			strings.Contains(ct, "text/xml") && svgTagInXMLRegex.Match(data)) {
 | 
			
		||||
 | 
			
		||||
		// SVG is unsupported.  https://github.com/golang/go/issues/15888
 | 
			
		||||
		return SVGMimeType
 | 
			
		||||
	}
 | 
			
		||||
	return ct
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsRepresentableAsText returns true if file content can be represented as
 | 
			
		||||
// plain text or is empty.
 | 
			
		||||
func IsRepresentableAsText(data []byte) bool {
 | 
			
		||||
	return IsTextFile(data) || IsSVGImageFile(data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsTextFile returns true if file content format is plain text or empty.
 | 
			
		||||
func IsTextFile(data []byte) bool {
 | 
			
		||||
	if len(data) == 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Contains(DetectContentType(data), "text/")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsImageFile detects if data is an image format
 | 
			
		||||
func IsImageFile(data []byte) bool {
 | 
			
		||||
	return strings.Contains(DetectContentType(data), "image/")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsSVGImageFile detects if data is an SVG image format
 | 
			
		||||
func IsSVGImageFile(data []byte) bool {
 | 
			
		||||
	return strings.Contains(DetectContentType(data), SVGMimeType)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsPDFFile detects if data is a pdf format
 | 
			
		||||
func IsPDFFile(data []byte) bool {
 | 
			
		||||
	return strings.Contains(DetectContentType(data), "application/pdf")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsVideoFile detects if data is an video format
 | 
			
		||||
func IsVideoFile(data []byte) bool {
 | 
			
		||||
	return strings.Contains(DetectContentType(data), "video/")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsAudioFile detects if data is an video format
 | 
			
		||||
func IsAudioFile(data []byte) bool {
 | 
			
		||||
	return strings.Contains(DetectContentType(data), "audio/")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EntryIcon returns the octicon class for displaying files/directories
 | 
			
		||||
func EntryIcon(entry *git.TreeEntry) string {
 | 
			
		||||
	switch {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user