-
Notifications
You must be signed in to change notification settings - Fork 181
/
magick_wand.go
196 lines (169 loc) · 7.21 KB
/
magick_wand.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright 2013 Herbert G. Fischer. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package imagick
/*
#include <wand/MagickWand.h>
*/
import "C"
import (
"fmt"
"runtime"
"sync"
"sync/atomic"
"unsafe"
)
// This struct represents the MagickWand C API of ImageMagick
type MagickWand struct {
mw *C.MagickWand
init sync.Once
}
func newMagickWand(cmw *C.MagickWand) *MagickWand {
mw := &MagickWand{mw: cmw}
runtime.SetFinalizer(mw, Destroy)
mw.IncreaseCount()
return mw
}
// Returns a wand required for all other methods in the API. A fatal exception is thrown if there is not enough memory to allocate the wand.
func NewMagickWand() *MagickWand {
return newMagickWand(C.NewMagickWand())
}
// Returns a wand with an image
func NewMagickWandFromImage(img *Image) *MagickWand {
return newMagickWand(C.NewMagickWandFromImage(img.img))
}
// Clear resources associated with the wand, leaving the wand blank, and ready to be used for a new set of images.
func (mw *MagickWand) Clear() {
C.ClearMagickWand(mw.mw)
}
// Makes an exact copy of the MagickWand object
func (mw *MagickWand) Clone() *MagickWand {
return newMagickWand(C.CloneMagickWand(mw.mw))
}
// Deallocates memory associated with an MagickWand
func (mw *MagickWand) Destroy() {
if mw.mw == nil {
return
}
mw.init.Do(func() {
mw.mw = C.DestroyMagickWand(mw.mw)
relinquishMemory(unsafe.Pointer(mw.mw))
mw.mw = nil
mw.DecreaseCount()
})
}
// Returns true if the wand is a verified magick wand
func (mw *MagickWand) IsVerified() bool {
if mw.mw != nil {
return 1 == C.int(C.IsMagickWand(mw.mw))
}
return false
}
// Increase MagickWand ref counter and set according "can`t be terminated status"
func (mw *MagickWand) IncreaseCount() {
atomic.AddInt64(&magickWandCounter, int64(1))
unsetCanTerminate()
}
// Decrease MagickWand ref counter and set according "can be terminated status"
func (mw *MagickWand) DecreaseCount() {
atomic.AddInt64(&magickWandCounter, int64(-1))
setCanTerminate()
}
// Returns the position of the iterator in the image list
func (mw *MagickWand) GetIteratorIndex() uint {
return uint(C.MagickGetIteratorIndex(mw.mw))
}
// Returns the value associated with the specified configure option
func (mw *MagickWand) QueryConfigureOption(option string) (string, error) {
csoption := C.CString(option)
defer C.free(unsafe.Pointer(csoption))
availableOptions := mw.QueryConfigureOptions(option)
for _, availableOption := range availableOptions {
if availableOption == option {
return C.GoString(C.MagickQueryConfigureOption(csoption)), nil
}
}
return "", fmt.Errorf("Unknown option \"%s\"", option)
}
// Returns any configure options that match the specified pattern (e.g. "*" for all). Options include NAME, VERSION, LIB_VERSION, etc
func (mw *MagickWand) QueryConfigureOptions(pattern string) (options []string) {
cspattern := C.CString(pattern)
defer C.free(unsafe.Pointer(cspattern))
var num C.size_t
copts := C.MagickQueryConfigureOptions(cspattern, &num)
defer relinquishMemoryCStringArray(copts)
options = sizedCStringArrayToStringSlice(copts, num)
return
}
// Returns a FontMetrics struct
func (mw *MagickWand) QueryFontMetrics(dw *DrawingWand, textLine string) *FontMetrics {
cstext := C.CString(textLine)
defer C.free(unsafe.Pointer(cstext))
cdoubles := C.MagickQueryFontMetrics(mw.mw, dw.dw, cstext)
defer relinquishMemory(unsafe.Pointer(cdoubles))
doubles := sizedDoubleArrayToFloat64Slice(cdoubles, 13)
return NewFontMetricsFromArray(doubles)
}
// Returns a FontMetrics struct related to the multiline text
func (mw *MagickWand) QueryMultilineFontMetrics(dw *DrawingWand, textParagraph string) *FontMetrics {
cstext := C.CString(textParagraph)
defer C.free(unsafe.Pointer(cstext))
cdoubles := C.MagickQueryMultilineFontMetrics(mw.mw, dw.dw, cstext)
defer relinquishMemory(unsafe.Pointer(cdoubles))
doubles := sizedDoubleArrayToFloat64Slice(cdoubles, 13)
return NewFontMetricsFromArray(doubles)
}
// Returns any font that match the specified pattern (e.g. "*" for all)
func (mw *MagickWand) QueryFonts(pattern string) (fonts []string) {
cspattern := C.CString(pattern)
defer C.free(unsafe.Pointer(cspattern))
var num C.size_t
copts := C.MagickQueryFonts(cspattern, &num)
defer relinquishMemoryCStringArray(copts)
fonts = sizedCStringArrayToStringSlice(copts, num)
return
}
// Returns any supported image format that match the specified pattern (e.g. "*" for all)
func (mw *MagickWand) QueryFormats(pattern string) (formats []string) {
cspattern := C.CString(pattern)
defer C.free(unsafe.Pointer(cspattern))
var num C.size_t
copts := C.MagickQueryFormats(cspattern, &num)
defer relinquishMemoryCStringArray(copts)
formats = sizedCStringArrayToStringSlice(copts, num)
return
}
// This method resets the wand iterator.
// It is typically used either before iterating though images, or before calling specific methods such as AppendImages()
// to append all images together.
// Afterward you can use NextImage() to iterate over all the images in a wand container, starting with the first image.
// Using this before AddImages() or ReadImages() will cause new images to be inserted between the first and second image.
func (mw *MagickWand) ResetIterator() {
C.MagickResetIterator(mw.mw)
}
// This method sets the wand iterator to the first image.
// After using any images added to the wand using AddImage() or ReadImage() will be prepended before any image in the wand.
// Also the current image has been set to the first image (if any) in the MagickWand. Using NextImage() will then set the
// current image to the second image in the list (if present).
// This operation is similar to ResetIterator() but differs in how AddImage(), ReadImage(), and NextImage() behaves afterward.
func (mw *MagickWand) SetFirstIterator() {
C.MagickSetFirstIterator(mw.mw)
}
// This method set the iterator to the given position in the image list specified with the index parameter.
// A zero index will set the first image as current, and so on. Negative indexes can be used to specify an
// image relative to the end of the images in the wand, with -1 being the last image in the wand.
// If the index is invalid (range too large for number of images in wand) the function will return false.
// In that case the current image will not change.
// After using any images added to the wand using AddImage() or ReadImage() will be added after the image indexed,
// regardless of if a zero (first image in list) or negative index (from end) is used.
// Jumping to index 0 is similar to ResetIterator() but differs in how NextImage() behaves afterward.
func (mw *MagickWand) SetIteratorIndex(index int) bool {
return 1 == C.int(C.MagickSetIteratorIndex(mw.mw, C.ssize_t(index)))
}
// SetLastIterator() sets the wand iterator to the last image.
// The last image is actually the current image, and the next use of PreviousImage() will not change this allowing this function
// to be used to iterate over the images in the reverse direction. In this sense it is more like ResetIterator() than SetFirstIterator().
// Typically this function is used before AddImage(), ReadImage() functions to ensure new images are appended to the very end of wand's image list.
func (mw *MagickWand) SetLastIterator() {
C.MagickSetLastIterator(mw.mw)
}