Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| // Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan. | |
| // License: https://creativecommons.org/licenses/by-nc-sa/4.0/ | |
| // See page 234. | |
| // The thumbnail package produces thumbnail-size images from | |
| // larger images. Only JPEG images are currently supported. | |
| package thumbnail | |
| import ( | |
| "fmt" | |
| "image" | |
| "image/jpeg" | |
| "io" | |
| "os" | |
| "path/filepath" | |
| "strings" | |
| ) | |
| // Image returns a thumbnail-size version of src. | |
| func Image(src image.Image) image.Image { | |
| // Compute thumbnail size, preserving aspect ratio. | |
| xs := src.Bounds().Size().X | |
| ys := src.Bounds().Size().Y | |
| width, height := 128, 128 | |
| if aspect := float64(xs) / float64(ys); aspect < 1.0 { | |
| width = int(128 * aspect) // portrait | |
| } else { | |
| height = int(128 / aspect) // landscape | |
| } | |
| xscale := float64(xs) / float64(width) | |
| yscale := float64(ys) / float64(height) | |
| dst := image.NewRGBA(image.Rect(0, 0, width, height)) | |
| // a very crude scaling algorithm | |
| for x := 0; x < width; x++ { | |
| for y := 0; y < height; y++ { | |
| srcx := int(float64(x) * xscale) | |
| srcy := int(float64(y) * yscale) | |
| dst.Set(x, y, src.At(srcx, srcy)) | |
| } | |
| } | |
| return dst | |
| } | |
| // ImageStream reads an image from r and | |
| // writes a thumbnail-size version of it to w. | |
| func ImageStream(w io.Writer, r io.Reader) error { | |
| src, _, err := image.Decode(r) | |
| if err != nil { | |
| return err | |
| } | |
| dst := Image(src) | |
| return jpeg.Encode(w, dst, nil) | |
| } | |
| // ImageFile2 reads an image from infile and writes | |
| // a thumbnail-size version of it to outfile. | |
| func ImageFile2(outfile, infile string) (err error) { | |
| in, err := os.Open(infile) | |
| if err != nil { | |
| return err | |
| } | |
| defer in.Close() | |
| out, err := os.Create(outfile) | |
| if err != nil { | |
| return err | |
| } | |
| if err := ImageStream(out, in); err != nil { | |
| out.Close() | |
| return fmt.Errorf("scaling %s to %s: %s", infile, outfile, err) | |
| } | |
| return out.Close() | |
| } | |
| // ImageFile reads an image from infile and writes | |
| // a thumbnail-size version of it in the same directory. | |
| // It returns the generated file name, e.g. "foo.thumb.jpeg". | |
| func ImageFile(infile string) (string, error) { | |
| ext := filepath.Ext(infile) // e.g., ".jpg", ".JPEG" | |
| outfile := strings.TrimSuffix(infile, ext) + ".thumb" + ext | |
| return outfile, ImageFile2(outfile, infile) | |
| } |