John1561's picture
Upload 47 files
791db78
package utils
import (
"bytes"
"errors"
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
"net/http"
"strings"
)
type Photo struct {
Width int
Height int
Type string
Bytes []byte
}
func CompressImageResource(data []byte, quality uint) (*Photo, error) {
var imgSrc image.Image
dataType, err := GetType(data)
if err != nil {
return nil, err
}
rowPhoto := bytes.NewReader(data)
switch dataType {
case "image/png":
imgSrc, err = png.Decode(rowPhoto)
if err != nil {
return nil, err
}
case "image/jpeg":
imgSrc, err = jpeg.Decode(rowPhoto)
if err != nil {
return nil, err
}
default:
imgSrc, _, err = image.Decode(rowPhoto)
if err != nil {
return nil, err
}
}
newImg := image.NewRGBA(imgSrc.Bounds())
draw.Draw(newImg, newImg.Bounds(), &image.Uniform{C: color.White}, image.Point{}, draw.Src)
draw.Draw(newImg, newImg.Bounds(), imgSrc, imgSrc.Bounds().Min, draw.Over)
buf := bytes.NewBuffer(nil)
err = jpeg.Encode(buf, newImg, &jpeg.Options{Quality: int(quality)})
if err != nil {
return nil, err
}
jp := new(Photo)
jp.Type = "image/jpeg"
jp.Width = newImg.Bounds().Max.X
jp.Height = newImg.Bounds().Max.Y
if buf.Len() > rowPhoto.Len() {
jp.Bytes = data
} else {
jp.Bytes = buf.Bytes()
}
return jp, nil
}
func GetPhotoSize(photo []byte) (width, hight int, err error) {
var imgSrc image.Image
dataType, err := GetType(photo)
if err != nil {
return 0, 0, err
}
rowPhoto := bytes.NewReader(photo)
switch dataType {
case "image/png":
imgSrc, err = png.Decode(rowPhoto)
if err != nil {
return 0, 0, err
}
return imgSrc.Bounds().Max.X, imgSrc.Bounds().Max.Y, nil
case "image/jpeg":
imgSrc, err = jpeg.Decode(rowPhoto)
if err != nil {
return 0, 0, err
}
return imgSrc.Bounds().Max.X, imgSrc.Bounds().Max.Y, nil
default:
imgSrc, _, err = image.Decode(rowPhoto)
if err != nil {
return 0, 0, err
}
return imgSrc.Bounds().Max.X, imgSrc.Bounds().Max.Y, nil
}
}
func PhotoColorInvert(photo []byte) (InvertPhoto []byte, Err error) {
var imgSrc image.Image
dataType, err := GetType(photo)
if err != nil {
return nil, err
}
rowPhoto := bytes.NewReader(photo)
switch dataType {
case "image/png":
imgSrc, err = png.Decode(rowPhoto)
if err != nil {
return nil, err
}
case "image/jpeg":
imgSrc, err = jpeg.Decode(rowPhoto)
if err != nil {
return nil, err
}
default:
imgSrc, _, err = image.Decode(rowPhoto)
if err != nil {
return nil, err
}
}
bounds := imgSrc.Bounds()
newImg := image.NewRGBA(bounds)
for x := bounds.Min.X; x < bounds.Max.X; x++ {
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
originalColor := imgSrc.At(x, y)
r, g, b, a := originalColor.RGBA()
newColor := color.RGBA{uint8(255 - r), uint8(255 - g), uint8(255 - b), uint8(a)}
newImg.Set(x, y, newColor)
}
}
buffer := bytes.NewBuffer(nil)
err = jpeg.Encode(buffer, newImg, &jpeg.Options{Quality: 100})
return buffer.Bytes(), err
}
func CompressImageResourceToSize(data []byte, maxSize uint) (*Photo, error) {
if maxSize == 0 {
return nil, errors.New("max size is zero")
}
var imgSrc image.Image
dataType, err := GetType(data)
if err != nil {
return nil, err
}
jp := new(Photo)
rowPhoto := bytes.NewReader(data)
switch dataType {
case "image/png":
imgSrc, err = png.Decode(rowPhoto)
if err != nil {
return nil, err
}
if rowPhoto.Size() < int64(maxSize) {
jp.Width = imgSrc.Bounds().Max.X
jp.Height = imgSrc.Bounds().Max.Y
jp.Type = "image/png"
jp.Bytes = data
return jp, nil
}
case "image/jpeg":
imgSrc, err = jpeg.Decode(rowPhoto)
if err != nil {
return nil, err
}
if rowPhoto.Size() < int64(maxSize) {
jp.Width = imgSrc.Bounds().Max.X
jp.Height = imgSrc.Bounds().Max.Y
jp.Type = "image/jpeg"
jp.Bytes = data
return jp, nil
}
default:
imgSrc, _, err = image.Decode(rowPhoto)
if err != nil {
return nil, err
}
}
newImg := image.NewRGBA(imgSrc.Bounds())
draw.Draw(newImg, newImg.Bounds(), &image.Uniform{C: color.White}, image.Point{}, draw.Src)
draw.Draw(newImg, newImg.Bounds(), imgSrc, imgSrc.Bounds().Min, draw.Over)
newPhoto := bytes.NewBuffer(nil)
for quality := 100; quality > 0; quality -= 5 {
newPhoto.Reset()
err = jpeg.Encode(newPhoto, newImg, &jpeg.Options{Quality: quality})
if err != nil {
return nil, err
}
if newPhoto.Len() <= int(maxSize) {
break
}
}
if newPhoto.Len() > int(maxSize) {
return nil, errors.New("unable to compress within the maximum limit")
}
jp.Width = newImg.Bounds().Max.X
jp.Height = newImg.Bounds().Max.Y
jp.Bytes = newPhoto.Bytes()
jp.Type = "image/jpeg"
return jp, nil
}
func GetType(data []byte) (string, error) {
filetype := http.DetectContentType(data)
for i := 0; i < len(ext); i++ {
if strings.Contains(ext[i], filetype[6:]) {
return filetype, nil
}
}
return "", errors.New("invalid image type")
}
var ext = []string{
"ase",
"art",
"bmp",
"blp",
"cd5",
"cit",
"cpt",
"cr2",
"cut",
"dds",
"dib",
"djvu",
"egt",
"exif",
"gif",
"gpl",
"grf",
"icns",
"ico",
"iff",
"jng",
"jpeg",
"jpg",
"jfif",
"jp2",
"jps",
"lbm",
"max",
"miff",
"mng",
"msp",
"nitf",
"ota",
"pbm",
"pc1",
"pc2",
"pc3",
"pcf",
"pcx",
"pdn",
"pgm",
"PI1",
"PI2",
"PI3",
"pict",
"pct",
"pnm",
"pns",
"ppm",
"psb",
"psd",
"pdd",
"psp",
"px",
"pxm",
"pxr",
"qfx",
"raw",
"rle",
"sct",
"sgi",
"rgb",
"int",
"bw",
"tga",
"tiff",
"tif",
"vtf",
"xbm",
"xcf",
"xpm",
"3dv",
"amf",
"ai",
"awg",
"cgm",
"cdr",
"cmx",
"dxf",
"e2d",
"egt",
"eps",
"fs",
"gbr",
"odg",
"svg",
"stl",
"vrml",
"x3d",
"sxd",
"v2d",
"vnd",
"wmf",
"emf",
"art",
"xar",
"png",
"webp",
"jxr",
"hdp",
"wdp",
"cur",
"ecw",
"iff",
"lbm",
"liff",
"nrrd",
"pam",
"pcx",
"pgf",
"sgi",
"rgb",
"rgba",
"bw",
"int",
"inta",
"sid",
"ras",
"sun",
"tga",
}