Skip to content

Instantly share code, notes, and snippets.

@dooman87
Created November 10, 2021 04:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dooman87/55c143892a853439e2c416957e3986d4 to your computer and use it in GitHub Desktop.
Save dooman87/55c143892a853439e2c416957e3986d4 to your computer and use it in GitHub Desktop.
// 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