-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwarp.go
142 lines (127 loc) · 3.85 KB
/
warp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// This file provides functions for warping images.
package xmorph
/*
#include <xmorph/mesh.h>
#include <xmorph/mesh_t.h>
#include <xmorph/warp2.h>
#include <xmorph/resample.h>
*/
import "C"
import (
"fmt"
"image"
)
// AAKernel indicates the type of antialiasing to perform.
type AAKernel int
// These are the values that an AAKernel variable can accept.
const (
NearestNeighbor AAKernel = iota // No antialiasing. Fastest.
Bilinear
Lanczos
Lanczos4 // Best antialiasing. Slowest.
)
// Antialiasing indicates the type of antialiasing to perform when warping an
// image.
var Antialiasing = Lanczos
// warpUint8Slice warps any image type that's representable as a slice of
// alternating channel values, each of which is of type uint8.
func warpUint8Slice(pix []uint8, ystr, nchan int, bnds image.Rectangle, src, dst *Mesh) []uint8 {
// Select an antialiasing kernel.
C.mesh_resample_choose_aa(C.int(Antialiasing))
// Warp the image.
wd := bnds.Max.X - bnds.Min.X
ht := bnds.Max.Y - bnds.Min.Y
out := make([]uint8, len(pix))
C.warp_image_versatile(
// Source information
(*C.PIXEL_TYPE)(&pix[0]),
C.int(wd), C.int(ht), C.int(nchan), C.int(ystr), C.int(nchan),
// Destination information
(*C.PIXEL_TYPE)(&out[0]),
C.int(wd), C.int(ht), C.int(nchan), C.int(ystr), C.int(nchan),
// Mesh information
src.mesh.x, src.mesh.y,
dst.mesh.x, dst.mesh.y,
C.int(src.mesh.nx), C.int(src.mesh.ny))
return out
}
// warpAlpha warps an Alpha image.
func warpAlpha(img *image.Alpha, src, dst *Mesh) *image.Alpha {
out := warpUint8Slice(img.Pix, img.Stride, 1, img.Rect, src, dst)
return &image.Alpha{
Pix: out,
Stride: img.Stride,
Rect: img.Rect,
}
}
// warpNRGBA warps an NRGBA image.
func warpNRGBA(img *image.NRGBA, src, dst *Mesh) *image.NRGBA {
out := warpUint8Slice(img.Pix, img.Stride, 4, img.Rect, src, dst)
return &image.NRGBA{
Pix: out,
Stride: img.Stride,
Rect: img.Rect,
}
}
// warpCMYK warps a CMYK image.
func warpCMYK(img *image.CMYK, src, dst *Mesh) *image.CMYK {
out := warpUint8Slice(img.Pix, img.Stride, 4, img.Rect, src, dst)
return &image.CMYK{
Pix: out,
Stride: img.Stride,
Rect: img.Rect,
}
}
// warpGray warps a Gray image.
func warpGray(img *image.Gray, src, dst *Mesh) *image.Gray {
out := warpUint8Slice(img.Pix, img.Stride, 1, img.Rect, src, dst)
return &image.Gray{
Pix: out,
Stride: img.Stride,
Rect: img.Rect,
}
}
// warpAny warps any image type by first converting it to NRGBA and then
// invoking warpNRGBA.
func warpAny(img image.Image, src, dst *Mesh) *image.NRGBA {
bnds := img.Bounds()
nrgba := image.NewNRGBA(bnds)
cm := nrgba.ColorModel()
for y := bnds.Min.Y; y < bnds.Max.Y; y++ {
for x := bnds.Min.X; x < bnds.Max.X; x++ {
c := img.At(x, y)
nrgba.Set(x, y, cm.Convert(c))
}
}
return warpNRGBA(nrgba, src, dst)
}
// warpCompletely distorts an image by warping an input mesh to an output mesh.
func warpCompletely(img image.Image, src, dst *Mesh) (image.Image, error) {
if C.meshCompatibilityCheck(src.mesh, dst.mesh) != 0 {
return nil, fmt.Errorf("incompatible meshes passed to InterpolateMeshes")
}
switch img := img.(type) {
case *image.NRGBA:
return warpNRGBA(img, src, dst), nil
case *image.Gray:
return warpGray(img, src, dst), nil
case *image.CMYK:
return warpCMYK(img, src, dst), nil
case *image.Alpha:
return warpAlpha(img, src, dst), nil
default:
return warpAny(img, src, dst), nil
}
}
// Warp distorts an image by warping a source mesh some fraction of the way to
// a destination mesh.
func Warp(img image.Image, src, dst *Mesh, t float64) (image.Image, error) {
// Distort the source mesh a fraction of the way towards the
// destination mesh to produce a target mesh.
target, err := InterpolateMeshes(src, dst, t)
if err != nil {
return nil, err
}
// Warp from the source mesh to the target (not destination) mesh.
return warpCompletely(img, src, target)
}