[The Go Programming Language] 1장 튜토리얼 - 1.4 애니메이션 GIF
안녕하세요. 개발자 모도리입니다.
The Go Programming Language 라는 책으로 Go를 공부하고 있으며, 해당 책의 내용을 요약 정리해서 올리려고 합니다. 저는 번역본을 구매해서 공부하고 있습니다.
지난 게시물
- [Go] Mac에서 Atom으로 Go 개발 환경 구축하기
- [The Go Programming Language] 1장 튜토리얼 - 1.1 Hello, World
- [The Go Programming Language] 1장 튜토리얼 - 1.2 커맨드라인 인수
- [The Go Programming Language] 1장 튜토리얼 - 1.3 중복 줄 찾기
1장 튜토리얼
1.4 애니메이션 GIF
// Lissajous는 임의의 리사주 형태의 애니메이션 GIF를 생성한다.
package main
import (
"image"
"image/color"
"image/gif"
"io"
"math"
"math/rand"
"os"
)
var palette = []color.Color{color.White, color.Black}
const (
whiteIndex = 0 // 팔레트의 첫 번째 색상
blackIndex = 1 // 팔레트의 다음 색상
)
func main() {
lissajous(os.Stdout)
}
func lissajous(out io.Writer) {
const (
cycles = 5 // x 진동자의 회전수
res = 0.001 // 회전각
size = 100 // 이미지 캔버스 크기 [-size..+size]
nframes = 64 // 애니메이션 프레임 수
delay = 8 // 10ms 단위의 프레임 간 지연
)
freq := rand.Float64() * 3.0 // y 진동자의 상대적 진동수
anim := gif.GIF{LoopCount: nframes}
phase := 0.0 // 위상 차이
for i := 0; i < nframes; i++ {
rect := image.Rect(0, 0, 2*size+1, 2*size+1)
img := image.NewPaletted(rect, palette)
for t := 0.0; t < cycles*2*math.Pi; t += res {
x := math.Sin(t)
y := math.Sin(t*freq + phase)
img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), blackIndex)
}
phase += 0.1
anim.Delay = append(anim.Delay, delay)
anim.Image = append(anim.Image, img)
}
gif.EncodeAll(out, &anim) // NOTE: 인코딩 오류 무시
}
예제코드 [ch1/lissajous.go]
실행결과
$ go run ch1/lissajous.go > out.gif
out.gif 파일을 확인하면 아래와 같습니다.
- 경로에 여러 구성 요소가 포함된 패키지 (line 6, 7)
image/color
는color
를 참조하여color.White
처럼 사용하고,image/gif
는gif
를 참조하여gif.GIF
처럼 사용합니다.
- const 선언 (line 16, 26)
- import 와 마찬가지로 단독으로 선언도 가능하고 목록 형태로 선언도 가능합니다.
- 상수에 이름을 붙이며,
cycle, frame, delay
등의 수치형 파라미터는 컴파일 시 고정된 값을 갖습니다. - const 선언은 var 선언처럼 패키지 수준(line 16)에서, 또는 함수 내( line 26)에서 사용할 수 있습니다.
- 상수의 값은 숫자, 문자열, 불리언 이어야 합니다.
- 복합 리터럴 (line 14, 34)
- Go의 복합 타입을 원소 값의 나열로 초기화하는 간결한 표기법입니다.
[]color.Color{...}
: 슬라이스gif.GIF{...}
: 구조체
- 구조체 타입 (line 34, line 45)
- 구조체는 필드라고 불리는 값의 그룹이며, 보통 서로 다른 타입들을 하나의 객체로 묶어 단일 객체로 취급할 수 있습니다.
anim
변수는gif.GIF
타입의 구조체입니다.- 이 구조체 리터럴은 LoopCount 필드의 값이 nframes로 설정 된 구조체 값을 생성합니다.
- 구조체의 개별 필드는 명시적으로 점 표기법으로 사용할 수 있습니다. (
anim.Delay, anim.Image
)
- 그 외 코드 설명
- 코드에 이중 루프가 존재합니다.
- 외부 루프는 64회의 반복에 걸쳐 매 반복 마다 애니메이션의 단일 프레임을 생성합니다.
- 이 루프는 흰색과 검은색 두 가지 색상의 팔레트로 새로운 201 x 201 이미지를 만듭니다.
- 모든 픽셀은 최초 흰색으로 지정한 팔레트의 제로 값으로 설정됩니다.
- 일부 픽셀을 검은색으로 설정해 새로운 이미지를 생성하고, 그 결과를 내장 함수
append
를 통해서 지정된 80ms 지연과 함께 anim의 프레임 목록에 추가합니다.- 마지막으로 프레임과 지연의 시퀀스들은 GIF 포맷으로 인코딩되고 출력 스트림 out에 기록됩니다.
- out의 타입은 다양한 대상으로 출력할 수 있는
io.Writer
입니다.- 내부 루프는 두 개의 진동자를 실행합니다.
- x 진동자는 사인 함수입니다. y 진동자도 사인 함수지만 주파수가 x 진동자의 진동수에 상대적인 0 ~ 3 사이의 임의의 수이고, x 진동자에 상대적인 위상차는 처음에는 0이지만 애니메이션의 각 프레임에 따라 증가합니다.
- 이 루프는 x 진동자가 다섯 번의 전체 주기를 완료할 때까지 실행됩니다.
- 각 단계에서
setColorIndex
를 호출해 (x, y) 좌표의 픽셀을 팔레트 1번에 위치한 검은색으로 칠합니다.
이어보기
[The Go Programming Language] 1장 튜토리얼 - 1.5, 1.6 URL 반입(Fetching)