Skip to content

Commit b4bf149

Browse files
author
Pierre Massat
committed
Merge pull request #30 from gotsunami/text-annotate
Text annotate + canvas.Fit()
2 parents c878013 + a364624 commit b4bf149

File tree

3 files changed

+278
-26
lines changed

3 files changed

+278
-26
lines changed

canvas.go

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ type Canvas struct {
6262
height string
6363

6464
quantumRange uint
65+
66+
text *TextProperties
6567
}
6668

6769
func init() {
@@ -346,16 +348,31 @@ func (self *Canvas) Thumbnail(width uint, height uint) error {
346348

347349
ratio = math.Min(float64(self.Width())/float64(width), float64(self.Height())/float64(height))
348350

351+
return self.thumbnail(width, height, ratio)
352+
}
353+
354+
// Creates a thumbnail that fits within the given dimensions
355+
func (self *Canvas) Fit(width uint, height uint) error {
356+
357+
var ratio float64
358+
359+
// Normalizing image.
360+
361+
ratio = math.Max(float64(self.Width())/float64(width), float64(self.Height())/float64(height))
362+
363+
return self.thumbnail(width, height, ratio)
364+
}
365+
366+
func (self *Canvas) thumbnail(width uint, height uint, ratio float64) error {
367+
349368
if ratio < 1.0 {
350369
// Origin image is smaller than the thumbnail image.
351-
max := uint(math.Max(float64(width), float64(height)))
352-
353370
// Empty replacement buffer with transparent background.
354371
replacement := New()
355372

356373
replacement.SetBackgroundColor("none")
357374

358-
replacement.Blank(max, max)
375+
replacement.Blank(width, height)
359376

360377
// Putting original image in the center of the replacement canvas.
361378
replacement.AppendCanvas(self, int(int(width-self.Width())/2), int(int(height-self.Height())/2))
@@ -539,16 +556,14 @@ func (self *Canvas) Quality() uint {
539556
return uint(C.MagickGetImageCompressionQuality(self.wand))
540557
}
541558

542-
/*
543559
// Sets canvas's foreground color.
544-
func (self *Canvas) SetColor(color string) (bool) {
545-
status := C.PixelSetColor(self.fg, C.CString(color))
546-
if status == C.MagickFalse {
547-
return false
548-
}
549-
return true
560+
func (self *Canvas) SetColor(color string) bool {
561+
status := C.PixelSetColor(self.fg, C.CString(color))
562+
if status == C.MagickFalse {
563+
return false
564+
}
565+
return true
550566
}
551-
*/
552567

553568
// Sets canvas' background color.
554569
func (self *Canvas) SetBackgroundColor(color string) error {
@@ -773,6 +788,11 @@ func (self *Canvas) Destroy() error {
773788
self.wand = nil
774789
}
775790

791+
if self.text != nil && self.text.UnderColor != nil {
792+
C.DestroyPixelWand(self.text.UnderColor)
793+
self.text.UnderColor = nil
794+
}
795+
776796
return nil
777797
}
778798

@@ -998,21 +1018,6 @@ func (self *Canvas) QuantumRange() uint {
9981018
return self.quantumRange
9991019
}
10001020

1001-
func (self *Canvas) SetFontFamily(name string) error {
1002-
family := C.CString(name)
1003-
defer C.free(unsafe.Pointer(family))
1004-
1005-
if C.MagickSetFont(self.wand, family) == C.MagickFalse {
1006-
return fmt.Errorf("Could not set font family: %s", self.Error())
1007-
}
1008-
1009-
return nil
1010-
}
1011-
1012-
func (self *Canvas) SetFontSize(size float64) {
1013-
C.MagickSetPointsize(self.wand, C.double(size))
1014-
}
1015-
10161021
func (self *Canvas) SetGravity(gravity uint) {
10171022
C.MagickSetGravity(self.wand, C.GravityType(gravity))
10181023
}
@@ -1045,5 +1050,7 @@ func New() *Canvas {
10451050

10461051
self.SetFillColor("#888888")
10471052

1053+
self.text = self.NewTextProperties(true)
1054+
10481055
return self
10491056
}

canvas_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,23 @@ func TestThumbnail(t *testing.T) {
103103
canvas.Destroy()
104104
}
105105

106+
func TestFit(t *testing.T) {
107+
canvas := New()
108+
109+
err := canvas.Open("_examples/input/example.png")
110+
111+
if err == nil {
112+
canvas.AutoOrientate()
113+
114+
canvas.Fit(100, 100)
115+
116+
canvas.Write("_examples/output/example-fit.png")
117+
} else {
118+
t.Errorf("Error: %s\n", err)
119+
}
120+
121+
canvas.Destroy()
122+
}
106123
// https://github.com/gosexy/canvas/issues/3
107124
func TestThumbnailIssue3(t *testing.T) {
108125
canvas := New()

text.go

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/* text.go contains functions for text annotation
2+
TODO:
3+
getters and setters for
4+
- Stretch (redefine C type)
5+
- Style (redefine C type)
6+
- Resolution (two doubles)
7+
- Decoration (redefine C type)
8+
- Encoding (string)
9+
- DrawSetTextInterlineSpacing(DrawingWand *,const double),
10+
- DrawSetTextInterwordSpacing(DrawingWand *,const double),
11+
- DrawSetGravity(DrawingWand *wand,const GravityType gravity)
12+
*/
13+
14+
package canvas
15+
16+
/*
17+
#cgo CFLAGS: -fopenmp -I./_include
18+
#cgo LDFLAGS: -lMagickWand -lMagickCore
19+
20+
#include <wand/magick_wand.h>
21+
*/
22+
import "C"
23+
24+
import (
25+
"unsafe"
26+
)
27+
28+
type Alignment uint
29+
30+
const (
31+
UndefinedAlign Alignment = Alignment(C.UndefinedAlign)
32+
LeftAlign = Alignment(C.LeftAlign)
33+
CenterAlign = Alignment(C.CenterAlign)
34+
RightAlign = Alignment(C.RightAlign)
35+
)
36+
37+
// structure containing all text properties for an annotation
38+
// except the colors that are defined by FillColor and StrokeColor
39+
type TextProperties struct {
40+
Font string
41+
Family string
42+
Size float64
43+
// Stretch C.StretchType
44+
Weight uint
45+
// Style C.StyleType
46+
// Resolution [2]C.double
47+
Alignment Alignment
48+
Antialias bool
49+
// Decoration C.DecorationType
50+
// Encoding string
51+
Kerning float64
52+
// Interline float64
53+
// Interword float64
54+
UnderColor *C.PixelWand
55+
}
56+
57+
// Returns a TextProperties structure.
58+
// Parameters:
59+
// readDefault: if false, returns an empty structure.
60+
// if true, returns a structure set with current canvas settings
61+
func (self *Canvas) NewTextProperties(readDefault bool) *TextProperties {
62+
if readDefault {
63+
cfont := C.DrawGetFont(self.drawing)
64+
defer C.free(unsafe.Pointer(cfont))
65+
cfamily := C.DrawGetFontFamily(self.drawing)
66+
defer C.free(unsafe.Pointer(cfamily))
67+
csize := C.DrawGetFontSize(self.drawing)
68+
cweight := C.DrawGetFontWeight(self.drawing)
69+
calignment := C.DrawGetTextAlignment(self.drawing)
70+
cantialias := C.DrawGetTextAntialias(self.drawing)
71+
ckerning := C.DrawGetTextKerning(self.drawing)
72+
antialias := cantialias == C.MagickTrue
73+
74+
underColor := C.NewPixelWand()
75+
C.DrawGetTextUnderColor(self.drawing, underColor)
76+
return &TextProperties{
77+
Font: C.GoString(cfont),
78+
Family: C.GoString(cfamily),
79+
Size: float64(csize),
80+
Weight: uint(cweight),
81+
Alignment: Alignment(calignment),
82+
Antialias: antialias,
83+
Kerning: float64(ckerning),
84+
UnderColor: underColor,
85+
}
86+
}
87+
return &TextProperties{
88+
UnderColor: C.NewPixelWand(),
89+
}
90+
}
91+
92+
// Sets canvas' default TextProperties
93+
func (self *Canvas) SetTextProperties(def *TextProperties) {
94+
if def != nil {
95+
self.text = def
96+
self.SetFontFamily(def.Family)
97+
self.SetFont(def.Font, def.Size)
98+
self.SetFontWeight(def.Weight)
99+
self.SetTextAlignment(def.Alignment)
100+
self.SetTextAntialias(def.Antialias)
101+
self.SetTextKerning(def.Kerning)
102+
}
103+
}
104+
105+
// Gets a copy of canvas' current TextProperties
106+
func (self *Canvas) TextProperties() *TextProperties {
107+
if self.text == nil {
108+
return nil
109+
}
110+
cpy := *self.text
111+
return &cpy
112+
}
113+
114+
// Sets canvas' default font name
115+
func (self *Canvas) SetFontName(font string) {
116+
self.text.Font = font
117+
cfont := C.CString(font)
118+
defer C.free(unsafe.Pointer(cfont))
119+
C.DrawSetFont(self.drawing, cfont)
120+
}
121+
122+
// Returns canvas' current font name
123+
func (self *Canvas) FontName() string {
124+
return self.text.Font
125+
}
126+
127+
// Sets canvas' default font family
128+
func (self *Canvas) SetFontFamily(family string) {
129+
self.text.Family = family
130+
cfamily := C.CString(family)
131+
defer C.free(unsafe.Pointer(cfamily))
132+
C.DrawSetFontFamily(self.drawing, cfamily)
133+
}
134+
135+
// Returns canvas' current font family
136+
func (self *Canvas) FontFamily() string {
137+
return self.text.Family
138+
}
139+
140+
// Sets canvas' default font size
141+
func (self *Canvas) SetFontSize(size float64) {
142+
self.text.Size = size
143+
C.DrawSetFontSize(self.drawing, C.double(size))
144+
}
145+
146+
// Returns canvas' current font size
147+
func (self *Canvas) FontSize() float64 {
148+
return self.text.Size
149+
}
150+
151+
// Sets canvas' default font weight
152+
func (self *Canvas) SetFontWeight(weight uint) {
153+
self.text.Weight = weight
154+
C.DrawSetFontWeight(self.drawing, C.size_t(weight))
155+
}
156+
157+
// Returns canvas' current font weight
158+
func (self *Canvas) FontWeight() uint {
159+
return self.text.Weight
160+
}
161+
162+
// Sets canvas' font name and size.
163+
// If font is 0-length, the current font family is not changed
164+
// If size is <= 0, the current font size is not changed
165+
func (self *Canvas) SetFont(font string, size float64) {
166+
if len(font) > 0 {
167+
self.SetFontName(font)
168+
}
169+
if size > 0 {
170+
self.SetFontSize(size)
171+
}
172+
}
173+
174+
// Returns canvas' current font name and size
175+
func (self *Canvas) Font() (string, float64) {
176+
return self.text.Font, self.text.Size
177+
}
178+
179+
// Sets canvas' default text alignment. Available values are:
180+
// UndefinedAlign (?), LeftAlign, CenterAlign, RightAlign
181+
func (self *Canvas) SetTextAlignment(a Alignment) {
182+
self.text.Alignment = a
183+
C.DrawSetTextAlignment(self.drawing, C.AlignType(a))
184+
}
185+
186+
// Returns the canvas' current text aligment
187+
func (self *Canvas) TextAlignment() Alignment {
188+
return self.text.Alignment
189+
}
190+
191+
// Sets canvas' default text antialiasing option.
192+
func (self *Canvas) SetTextAntialias(b bool) {
193+
self.text.Antialias = b
194+
C.DrawSetTextAntialias(self.drawing, magickBoolean(b))
195+
}
196+
197+
// Returns the canvas' current text aligment
198+
func (self *Canvas) TextAntialias() bool {
199+
return self.text.Antialias
200+
}
201+
202+
// Sets canvas' default text antialiasing option.
203+
func (self *Canvas) SetTextKerning(k float64) {
204+
self.text.Kerning = k
205+
C.DrawSetTextKerning(self.drawing, C.double(k))
206+
}
207+
208+
// Returns the canvas' current text aligment
209+
func (self *Canvas) TextKerning() float64 {
210+
return self.text.Kerning
211+
}
212+
213+
// Draws a string at the specified coordinates and using the current canvas
214+
// Alignment.
215+
func (self *Canvas) Annotate(text string, x, y float64) {
216+
c_text := C.CString(text)
217+
defer C.free(unsafe.Pointer(c_text))
218+
C.DrawAnnotation(self.drawing, C.double(x), C.double(y), (*C.uchar)(unsafe.Pointer(c_text)))
219+
}
220+
221+
// Draws a string at the specified coordinates and using the specified Text Properties
222+
// Does not modify the canvas' default TextProperties
223+
func (self *Canvas) AnnotateWithProperties(text string, x, y float64, prop *TextProperties) {
224+
tmp := self.TextProperties()
225+
self.SetTextProperties(prop)
226+
self.Annotate(text, x, y)
227+
self.SetTextProperties(tmp)
228+
}

0 commit comments

Comments
 (0)