1package bimg
2
3// Image provides a simple method DSL to transform a given image as byte buffer.
4type Image struct {
5	buffer []byte
6}
7
8// NewImage creates a new Image struct with method DSL.
9func NewImage(buf []byte) *Image {
10	return &Image{buf}
11}
12
13// Resize resizes the image to fixed width and height.
14func (i *Image) Resize(width, height int) ([]byte, error) {
15	options := Options{
16		Width:  width,
17		Height: height,
18		Embed:  true,
19	}
20	return i.Process(options)
21}
22
23// ForceResize resizes with custom size (aspect ratio won't be maintained).
24func (i *Image) ForceResize(width, height int) ([]byte, error) {
25	options := Options{
26		Width:  width,
27		Height: height,
28		Force:  true,
29	}
30	return i.Process(options)
31}
32
33// ResizeAndCrop resizes the image to fixed width and height with additional crop transformation.
34func (i *Image) ResizeAndCrop(width, height int) ([]byte, error) {
35	options := Options{
36		Width:  width,
37		Height: height,
38		Embed:  true,
39		Crop:   true,
40	}
41	return i.Process(options)
42}
43
44// SmartCrop produces a thumbnail aiming at focus on the interesting part.
45func (i *Image) SmartCrop(width, height int) ([]byte, error) {
46	options := Options{
47		Width:   width,
48		Height:  height,
49		Crop:    true,
50		Gravity: GravitySmart,
51	}
52	return i.Process(options)
53}
54
55// Extract area from the by X/Y axis in the current image.
56func (i *Image) Extract(top, left, width, height int) ([]byte, error) {
57	options := Options{
58		Top:        top,
59		Left:       left,
60		AreaWidth:  width,
61		AreaHeight: height,
62	}
63
64	if top == 0 && left == 0 {
65		options.Top = -1
66	}
67
68	return i.Process(options)
69}
70
71// Enlarge enlarges the image by width and height. Aspect ratio is maintained.
72func (i *Image) Enlarge(width, height int) ([]byte, error) {
73	options := Options{
74		Width:   width,
75		Height:  height,
76		Enlarge: true,
77	}
78	return i.Process(options)
79}
80
81// EnlargeAndCrop enlarges the image by width and height with additional crop transformation.
82func (i *Image) EnlargeAndCrop(width, height int) ([]byte, error) {
83	options := Options{
84		Width:   width,
85		Height:  height,
86		Enlarge: true,
87		Crop:    true,
88	}
89	return i.Process(options)
90}
91
92// Crop crops the image to the exact size specified.
93func (i *Image) Crop(width, height int, gravity Gravity) ([]byte, error) {
94	options := Options{
95		Width:   width,
96		Height:  height,
97		Gravity: gravity,
98		Crop:    true,
99	}
100	return i.Process(options)
101}
102
103// CropByWidth crops an image by width only param (auto height).
104func (i *Image) CropByWidth(width int) ([]byte, error) {
105	options := Options{
106		Width: width,
107		Crop:  true,
108	}
109	return i.Process(options)
110}
111
112// CropByHeight crops an image by height (auto width).
113func (i *Image) CropByHeight(height int) ([]byte, error) {
114	options := Options{
115		Height: height,
116		Crop:   true,
117	}
118	return i.Process(options)
119}
120
121// Thumbnail creates a thumbnail of the image by the a given width by aspect ratio 4:4.
122func (i *Image) Thumbnail(pixels int) ([]byte, error) {
123	options := Options{
124		Width:   pixels,
125		Height:  pixels,
126		Crop:    true,
127		Quality: 95,
128	}
129	return i.Process(options)
130}
131
132// Watermark adds text as watermark on the given image.
133func (i *Image) Watermark(w Watermark) ([]byte, error) {
134	options := Options{Watermark: w}
135	return i.Process(options)
136}
137
138// WatermarkImage adds image as watermark on the given image.
139func (i *Image) WatermarkImage(w WatermarkImage) ([]byte, error) {
140	options := Options{WatermarkImage: w}
141	return i.Process(options)
142}
143
144// Zoom zooms the image by the given factor.
145// You should probably call Extract() before.
146func (i *Image) Zoom(factor int) ([]byte, error) {
147	options := Options{Zoom: factor}
148	return i.Process(options)
149}
150
151// Rotate rotates the image by given angle degrees (0, 90, 180 or 270).
152func (i *Image) Rotate(a Angle) ([]byte, error) {
153	options := Options{Rotate: a}
154	return i.Process(options)
155}
156
157// AutoRotate automatically rotates the image with no additional transformation based on the EXIF oritentation metadata, if available.
158func (i *Image) AutoRotate() ([]byte, error) {
159	return i.Process(Options{autoRotateOnly: true})
160}
161
162// Flip flips the image about the vertical Y axis.
163func (i *Image) Flip() ([]byte, error) {
164	options := Options{Flip: true}
165	return i.Process(options)
166}
167
168// Flop flops the image about the horizontal X axis.
169func (i *Image) Flop() ([]byte, error) {
170	options := Options{Flop: true}
171	return i.Process(options)
172}
173
174// Convert converts image to another format.
175func (i *Image) Convert(t ImageType) ([]byte, error) {
176	options := Options{Type: t}
177	return i.Process(options)
178}
179
180// Colourspace performs a color space conversion bsaed on the given interpretation.
181func (i *Image) Colourspace(c Interpretation) ([]byte, error) {
182	options := Options{Interpretation: c}
183	return i.Process(options)
184}
185
186// Trim removes the background from the picture. It can result in a 0x0 output
187// if the image is all background.
188func (i *Image) Trim() ([]byte, error) {
189	options := Options{Trim: true}
190	return i.Process(options)
191}
192
193// Gamma returns the gamma filtered image buffer.
194func (i *Image) Gamma(exponent float64) ([]byte, error) {
195	options := Options{Gamma: exponent}
196	return i.Process(options)
197}
198
199// Process processes the image based on the given transformation options,
200// talking with libvips bindings accordingly and returning the resultant
201// image buffer.
202func (i *Image) Process(o Options) ([]byte, error) {
203	image, err := Resize(i.buffer, o)
204	if err != nil {
205		return nil, err
206	}
207	i.buffer = image
208	return image, nil
209}
210
211// Metadata returns the image metadata (size, alpha channel, profile, EXIF rotation).
212func (i *Image) Metadata() (ImageMetadata, error) {
213	return Metadata(i.buffer)
214}
215
216// Interpretation gets the image interpretation type.
217// See: https://libvips.github.io/libvips/API/current/VipsImage.html#VipsInterpretation
218func (i *Image) Interpretation() (Interpretation, error) {
219	return ImageInterpretation(i.buffer)
220}
221
222// ColourspaceIsSupported checks if the current image
223// color space is supported.
224func (i *Image) ColourspaceIsSupported() (bool, error) {
225	return ColourspaceIsSupported(i.buffer)
226}
227
228// Type returns the image type format (jpeg, png, webp, tiff).
229func (i *Image) Type() string {
230	return DetermineImageTypeName(i.buffer)
231}
232
233// Size returns the image size as form of width and height pixels.
234func (i *Image) Size() (ImageSize, error) {
235	return Size(i.buffer)
236}
237
238// Image returns the current resultant image buffer.
239func (i *Image) Image() []byte {
240	return i.buffer
241}
242
243// Length returns the size in bytes of the image buffer.
244func (i *Image) Length() int {
245	return len(i.buffer)
246}
247