Created
November 10, 2021 04:05
-
-
Save dooman87/55c143892a853439e2c416957e3986d4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// isIllustration returns true if image is cartoon like, including | |
// icons, logos, illustrations. | |
// | |
// It returns false for banners, product images, photos. | |
// | |
// We use this function to decide on lossy or lossless conversion for PNG when converting | |
// to the next generation format. | |
// | |
// The initial idea is from here: https://legacy.imagemagick.org/Usage/compare/#type_reallife | |
func (p *ImageMagick) isIllustration(src *img.Image, info *img.Info) (bool, error) { | |
if len(src.Data) < 20*1024 { | |
return true, nil | |
} | |
if len(src.Data) > 1024*1024 { | |
return false, nil | |
} | |
if float32(len(src.Data))/float32(info.Width*info.Height) > 1.0 { | |
return false, nil | |
} | |
var ( | |
colors []*imagick.PixelWand | |
colorsCnt uint | |
) | |
mw := imagick.NewMagickWand() | |
err := mw.ReadImageBlob(src.Data) | |
if err != nil { | |
return false, err | |
} | |
if info.Width*info.Height > 500*500 { | |
aspectRatio := float32(info.Width) / float32(info.Height) | |
err = mw.ScaleImage(500, uint(500/aspectRatio)) | |
if err != nil { | |
return false, err | |
} | |
} | |
colorsCnt, colors = mw.GetImageHistogram() | |
if colorsCnt > 30000 { | |
return false, nil | |
} | |
colorsCounts := make([]int, colorsCnt) | |
for i, c := range colors { | |
colorsCounts[i] = int(c.GetColorCount()) | |
} | |
sort.Sort(sort.Reverse(sort.IntSlice(colorsCounts))) | |
var ( | |
colorIdx int | |
count int | |
imageWidth = mw.GetImageWidth() | |
imageHeight = mw.GetImageHeight() | |
pixelsCount = 0 | |
totalPixelsCount = float32(imageHeight * imageWidth) | |
tenPercent = int(totalPixelsCount * 0.1) | |
fiftyPercent = int(totalPixelsCount * 0.5) | |
hasBackground = false | |
) | |
for colorIdx, count = range colorsCounts { | |
if colorIdx == 0 && count >= tenPercent { | |
hasBackground = true | |
fiftyPercent = int((totalPixelsCount - float32(count)) * 0.5) | |
continue | |
} | |
if pixelsCount > fiftyPercent { | |
break | |
} | |
pixelsCount += count | |
} | |
colorsCntIn50Pct := colorIdx + 1 | |
if hasBackground { | |
colorsCntIn50Pct-- | |
} | |
return colorsCntIn50Pct < 10 || (float32(colorsCntIn50Pct)/float32(colorsCnt)) <= 0.02, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment