Esempio n. 1
0
File: sample.go Progetto: eryx/go-gd
func main() {
	// http://www.php.net/manual/en/function.imagecreatefromjpeg.php
	pict := gd.CreateFromJpeg("source.jpg")

	// http://www.php.net/manual/en/function.imagedestroy.php
	defer pict.Destroy()

	pict.Sharpen(10)
	pict.Brightness(50)

	// http://www.php.net/manual/en/function.imagecolorallocate.php
	black := pict.ColorAllocate(0, 0, 0)
	white := pict.ColorAllocate(255, 255, 255)

	pict.SmoothFilledEllipse(20, 20, 32, 32, white)

	// http://www.php.net/manual/en/function.imagefilledellipse.php
	pict.FilledEllipse(100, 100, 40, 50, white)

	// http://www.php.net/manual/en/function.imagecopyresampled.php
	pict.CopyResampled(pict, 40, 40, pict.Sx()-41, pict.Sy()-41, 20, 20, 40, 40)

	// Non-Unicode font
	font := gd.GetFont(gd.FONTGIANT)

	// http://www.php.net/manual/en/function.imagechar.php
	pict.Char(font, 100, 100, "B", black)
	// http://www.php.net/manual/en/function.imagestring.php
	pict.String(font, 100, 120, "bolknote.ru", black)

	// Unicode font
	fonts := gd.GetFonts()
	fmt.Printf("Found %d X11 TTF font(s)\n", len(fonts))

	if l := len(fonts); l > 0 {
		pict.StringFT(black, fonts[l-1], 12, 0, 100, 150, "Hello! Привет!")
	}

	// http://www.php.net/Imagejpeg
	pict.Jpeg("out.jpg", 95)
}
Esempio n. 2
0
func main() {
	options := parseoptions()

	// Показываем силу му-у-у-у-у?
	if v, ok := options["moo"]; ok && v == "1" {
		moo()
	}

	if runtime.GOMAXPROCS(-1) > 1 {
		runtime.GOMAXPROCS(3)
	}

	// Преобразование маски файлов в более традиционный для Go формат
	regexp, _ := r.Compile(`(\{[^\}]+\})`)

	oMask := regexp.ReplaceAllStringFunc(options["mask"], func(m string) string {
		return "[" + s.Join(s.Split(m[1:len(m)-1], ","), "") + "]"
	})

	// Первоначальное значение out-dir
	wd, _ := os.Getwd()
	oOutDir := path.Clean(path.Join(wd, options["out-dir"]))

	// Составляем список файлов, по которому будем двигаться
	var oFileList []string

	if options["recursive"] == "1" {
		if path.IsAbs(options["out-dir"]) {
			oOutDir = path.Clean(options["out-dir"])
		}

		oFileList = getrecurlist(oMask, oOutDir)
	} else {
		oFileList, _ = fp.Glob(oMask)
	}

	// Создаём директорий для результата, если он нужен
	if options["keep-name"] == "0" && !fileexists(oOutDir) {
		os.MkdirAll(oOutDir, 0777)
	}

	// Сколько файлов получилось?
	oLen := len(oFileList)

	if oLen < 1 {
		os.Stdout.WriteString("Файлы не найдены\n")
		os.Exit(1)
	}

	// Маска для нового имени
	now := time.Now().Format("2006.01.02")
	oNameMask := path.Join(options["out-dir"], now)
	if oLen > 1 {
		prec := strconv.Itoa(len(strconv.Itoa(oLen)))
		oNameMask += ".%0" + prec + "d.jpg"

		fmt.Printf("Found %d JPEG files.\n", oLen)
	} else {
		oNameMask += ".jpg"
		fmt.Println("Found 1 JPEG file.")
	}

	// Нормализация background, должны получиться три hex числа
	// в Go очень примитивные regexp :(
	if re := r.MustCompile(`^#[0-9a-fA-F]+`); len(options["background"]) == 7 && !re.MatchString(options["background"]) {
		options["background"] = "#ffffff"
	}

	// И переводим background компоненты
	oBgColor := [3]int{}

	for i := 1; i < len(options["background"]); i += 2 {
		c, _ := strconv.ParseInt(options["background"][i:i+2], 16, 0)
		oBgColor[i>>1] = int(c)
	}

	// Уголки для скруглений
	var corner *gd.Image
	defer corner.Destroy()

	coready := make(chan *gd.Image)

	oRadius, _ := strconv.Atoi(options["radius"])
	if oRadius > 0 {
		go func() {
			oRadius, _ := strconv.Atoi(options["radius"])

			// важно, что это локальная переменная, иначе будет
			// баг — указатель будет уже не пустой, а уголки ещё
			// не будут готовы
			corner := gd.CreateTrueColor(oRadius<<1+2, oRadius<<1+2)
			corner.AlphaBlending(false)
			corner.SaveAlpha(true)
			trans := corner.ColorAllocateAlpha(oBgColor[0], oBgColor[1], oBgColor[2], 127)
			back := corner.ColorAllocate(oBgColor[0], oBgColor[1], oBgColor[2])

			corner.Fill(0, 0, trans)
			smoothellipse(corner, oRadius, oRadius+1, oRadius, back)

			// инвертируем прозрачность пикселей
			for x := 0; x < corner.Sx(); x++ {
				for y := 0; y < corner.Sy(); y++ {
					c := corner.ColorsForIndex(corner.ColorAt(x, y))
					c["alpha"] = 127 - c["alpha"]

					nc := corner.ColorAllocateAlpha(c["red"], c["green"], c["blue"], c["alpha"])
					corner.SetPixel(x, y, nc)
				}
			}

			coready <- corner
		}()
	}

	// Качество сохраняемой картинки
	oQuality, _ := strconv.Atoi(options["quality"])

	// проверяем, доступен ли jpegtran
	// пробуем найти jpegtran
	oJtname, oJt := func() (string, bool) {
		if jpegtran != "" {
			if fileexists(jpegtran) {
				return jpegtran, true
			}

			jtname := fp.Base(jpegtran)
			paths := bytes.Split([]byte(os.Getenv("PATH")), []byte{fp.ListSeparator})

			for _, p := range paths {
				if name := fp.Join(string(p), jtname); fileexists(name) {
					return name, true
				}
			}
		}

		return "", false
	}()

	// Временное имя для ч/б профиля
	oProfile := fp.Join(os.TempDir(), "cornet-bolk-bw.txt")
	defer os.Remove(oProfile)

	// Пишем профайл для ч/б изображения, профиль цветного не поддерживается «Оперой»
	profile, e := os.OpenFile(oProfile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0777)
	if e == nil {
		defer profile.Close()
		profile.WriteString("0:   0  0 0 0 ;\n0:   1  8 0 2 ;\n0:   9 63 0 2 ;\n0:   1 63 2 1 ;\n0:   1 63 1 0;")
	}

	oTmpName := fp.Join(os.TempDir(), "cornet-bolk-"+strconv.Itoa(os.Getpid())+"-")
	oSaved := int64(0)

	// Цикл обработки файлов
	for num, name := range oFileList {
		fmt.Printf("Processing %s ... ", name)

		im := gd.CreateFromJpeg(name)
		im.AlphaBlending(true)

		sx := im.Sx()
		sy := im.Sy()
		var w, h int

		// Если указана какая-то разумная ширина, то уменьшим до этой
		// ширины
		if w, _ = strconv.Atoi(options["width"]); w > 0 {
			h = int(float32(sy) * (float32(w) / float32(sx)))
			imresized := gd.CreateTrueColor(w, h)
			im.CopyResampled(imresized, 0, 0, 0, 0, w, h, sx, sy)
			im.Destroy()

			im = imresized
		} else {
			w, h = sx, sy
		}

		if oRadius > 0 {
			if corner == nil {
				corner = <-coready
			}

			if R := oRadius + 1; R > 1 {
				corner.Copy(im, 0, 0, 0, 0, R, R)
				corner.Copy(im, 0, h-R, 0, R, R, R)
				corner.Copy(im, w-R, 0, R, 0, R, R)
				corner.Copy(im, w-R, h-R, R, R, R, R)
			}
		}

		// Если имена не сохраняем, то заменяем на сгенерированное имя
		if options["keep-name"] == "0" {
			if oLen > 1 {
				name = fmt.Sprintf(oNameMask, num+1)
			} else {
				name = oNameMask
			}
		}

		// Jpegtran доступен
		if oJt {
			tmpname := oTmpName + fp.Base(name)
			gray := isgray(im)

			im.Jpeg(tmpname, oQuality)
			im.Destroy()
			im = nil

			// Оптимизация jpeg
			stat, _ := os.Stat(tmpname)
			cmdkeys := []string{"-copy", "none"}

			// Для файлов > 10КБ с вероятностью 94% лучшие результаты даёт progressive
			if stat.Size() > 10*1024 {
				cmdkeys = append(cmdkeys, "-progressive")
			}

			// Если файл серый, то оптимизируем его как серый
			if gray {
				cmdkeys = append(cmdkeys, "-grayscale", "-scans", oProfile)
			}

			cmdkeys = append(cmdkeys, "-optimize", tmpname)
			cmd := exec.Command(oJtname, cmdkeys...)

			buf := make([]byte, 2048)

			fp, _ := os.Create(name)
			out, _ := cmd.StdoutPipe()
			cmd.Start()

			for {
				n, _ := out.Read(buf)

				if n == 0 {
					break
				}

				fp.Write(buf[0:n])
			}

			fp.Close()
			cmd.Wait()

			// TODO: идея такая — stdout замыкаем на Writer, берём с него данные, следим за EXIF
			// не забыть прочитать EXIF из файла

			outstat, _ := os.Stat(name)

			oSaved += stat.Size() - outstat.Size()

			os.Remove(tmpname)
		} else {
			// Jpegtran нам недоступен
			im.Jpeg(name, oQuality)
			im.Destroy()
			im = nil
		}
		fmt.Println("done")
	}

	if oSaved > 0 {
		fmt.Printf("Saved %d bytes after optimization.\n", oSaved)
	}
}