• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cshum / imagor / 15488577405

06 Jun 2025 10:35AM UTC coverage: 90.768% (-1.7%) from 92.43%
15488577405

Pull #562

github

cshum
reset arm64 golden
Pull Request #562: build: libvips 8.17.0, vipsgen 1.1.1

4808 of 5297 relevant lines covered (90.77%)

1.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.33
/processor/vipsprocessor/filter.go
1
package vipsprocessor
2

3
import (
4
        "context"
5
        "fmt"
6
        "github.com/cshum/vipsgen/vips"
7
        "image/color"
8
        "math"
9
        "net/url"
10
        "strconv"
11
        "strings"
12

13
        "github.com/cshum/imagor"
14
        "github.com/cshum/imagor/imagorpath"
15
        "golang.org/x/image/colornames"
16
)
17

18
func (v *Processor) watermark(ctx context.Context, img *vips.Image, load imagor.LoadFunc, args ...string) (err error) {
1✔
19
        ln := len(args)
1✔
20
        if ln < 1 {
1✔
21
                return
×
22
        }
×
23
        image := args[0]
1✔
24
        if unescape, e := url.QueryUnescape(args[0]); e == nil {
2✔
25
                image = unescape
1✔
26
        }
1✔
27
        var blob *imagor.Blob
1✔
28
        if blob, err = load(image); err != nil {
1✔
29
                return
×
30
        }
×
31
        var x, y, w, h int
1✔
32
        var across = 1
1✔
33
        var down = 1
1✔
34
        var overlay *vips.Image
1✔
35
        var n = 1
1✔
36
        if isAnimated(img) {
2✔
37
                n = -1
1✔
38
        }
1✔
39
        // w_ratio h_ratio
40
        if ln >= 6 {
2✔
41
                w = img.Width()
1✔
42
                h = img.PageHeight()
1✔
43
                if args[4] != "none" {
2✔
44
                        w, _ = strconv.Atoi(args[4])
1✔
45
                        w = img.Width() * w / 100
1✔
46
                }
1✔
47
                if args[5] != "none" {
2✔
48
                        h, _ = strconv.Atoi(args[5])
1✔
49
                        h = img.PageHeight() * h / 100
1✔
50
                }
1✔
51
                if overlay, err = v.NewThumbnail(
1✔
52
                        ctx, blob, w, h, vips.InterestingNone, vips.SizeBoth, n, 1, 0,
1✔
53
                ); err != nil {
1✔
54
                        return
×
55
                }
×
56
        } else {
1✔
57
                if overlay, err = v.NewThumbnail(
1✔
58
                        ctx, blob, v.MaxWidth, v.MaxHeight, vips.InterestingNone, vips.SizeDown, n, 1, 0,
1✔
59
                ); err != nil {
1✔
60
                        return
×
61
                }
×
62
        }
63
        var overlayN = overlay.Height() / overlay.PageHeight()
1✔
64
        contextDefer(ctx, overlay.Close)
1✔
65
        if overlay.Bands() < 3 {
2✔
66
                if err = overlay.Colourspace(vips.InterpretationSrgb, nil); err != nil {
1✔
67
                        return
×
68
                }
×
69
        }
70
        if !overlay.HasAlpha() {
2✔
71
                if err = overlay.Addalpha(); err != nil {
1✔
72
                        return
×
73
                }
×
74
        }
75
        w = overlay.Width()
1✔
76
        h = overlay.PageHeight()
1✔
77
        // alpha
1✔
78
        if ln >= 4 {
2✔
79
                alpha, _ := strconv.ParseFloat(args[3], 64)
1✔
80
                alpha = 1 - alpha/100
1✔
81
                if alpha != 1 {
2✔
82
                        if err = overlay.Linear([]float64{1, 1, 1, alpha}, []float64{0, 0, 0, 0}, nil); err != nil {
1✔
83
                                return
×
84
                        }
×
85
                }
86
        }
87
        // x y
88
        if ln >= 3 {
2✔
89
                if args[1] == "center" {
2✔
90
                        x = (img.Width() - overlay.Width()) / 2
1✔
91
                } else if args[1] == imagorpath.HAlignLeft {
3✔
92
                        x = 0
1✔
93
                } else if args[1] == imagorpath.HAlignRight {
3✔
94
                        x = img.Width() - overlay.Width()
1✔
95
                } else if args[1] == "repeat" {
3✔
96
                        x = 0
1✔
97
                        across = img.Width()/overlay.Width() + 1
1✔
98
                } else if strings.HasPrefix(strings.TrimPrefix(args[1], "-"), "0.") {
3✔
99
                        pec, _ := strconv.ParseFloat(args[1], 64)
1✔
100
                        x = int(pec * float64(img.Width()))
1✔
101
                } else if strings.HasSuffix(args[1], "p") {
3✔
102
                        x, _ = strconv.Atoi(strings.TrimSuffix(args[1], "p"))
1✔
103
                        x = x * img.Width() / 100
1✔
104
                } else {
2✔
105
                        x, _ = strconv.Atoi(args[1])
1✔
106
                }
1✔
107
                if args[2] == "center" {
2✔
108
                        y = (img.PageHeight() - overlay.PageHeight()) / 2
1✔
109
                } else if args[2] == imagorpath.VAlignTop {
3✔
110
                        y = 0
1✔
111
                } else if args[2] == imagorpath.VAlignBottom {
3✔
112
                        y = img.PageHeight() - overlay.PageHeight()
1✔
113
                } else if args[2] == "repeat" {
3✔
114
                        y = 0
1✔
115
                        down = img.PageHeight()/overlay.PageHeight() + 1
1✔
116
                } else if strings.HasPrefix(strings.TrimPrefix(args[2], "-"), "0.") {
3✔
117
                        pec, _ := strconv.ParseFloat(args[2], 64)
1✔
118
                        y = int(pec * float64(img.PageHeight()))
1✔
119
                } else if strings.HasSuffix(args[2], "p") {
3✔
120
                        y, _ = strconv.Atoi(strings.TrimSuffix(args[2], "p"))
1✔
121
                        y = y * img.PageHeight() / 100
1✔
122
                } else {
2✔
123
                        y, _ = strconv.Atoi(args[2])
1✔
124
                }
1✔
125
                if x < 0 {
2✔
126
                        x += img.Width() - overlay.Width()
1✔
127
                }
1✔
128
                if y < 0 {
2✔
129
                        y += img.PageHeight() - overlay.PageHeight()
1✔
130
                }
1✔
131
        }
132
        if across*down > 1 {
2✔
133
                if err = overlay.EmbedMultiPage(0, 0, across*w, down*h,
1✔
134
                        &vips.EmbedMultiPageOptions{Extend: vips.ExtendRepeat}); err != nil {
1✔
135
                        return
×
136
                }
×
137
        }
138
        if err = overlay.EmbedMultiPage(
1✔
139
                x, y, img.Width(), img.PageHeight(), nil,
1✔
140
        ); err != nil {
1✔
141
                return
×
142
        }
×
143
        if n := img.Height() / img.PageHeight(); n > overlayN {
2✔
144
                cnt := n / overlayN
1✔
145
                if n%overlayN > 0 {
2✔
146
                        cnt++
1✔
147
                }
1✔
148
                if err = overlay.Replicate(1, cnt); err != nil {
1✔
149
                        return
×
150
                }
×
151
        }
152
        if err = img.Composite2(overlay, vips.BlendModeOver, nil); err != nil {
1✔
153
                return
×
154
        }
×
155
        return
1✔
156
}
157

158
func (v *Processor) fill(ctx context.Context, img *vips.Image, w, h int, pLeft, pTop, pRight, pBottom int, colour string) (err error) {
1✔
159
        if isRotate90(ctx) {
2✔
160
                tmpW := w
1✔
161
                w = h
1✔
162
                h = tmpW
1✔
163
                tmpPLeft := pLeft
1✔
164
                pLeft = pTop
1✔
165
                pTop = tmpPLeft
1✔
166
                tmpPRight := pRight
1✔
167
                pRight = pBottom
1✔
168
                pBottom = tmpPRight
1✔
169
        }
1✔
170
        c := getColor(img, colour)
1✔
171
        left := (w-img.Width())/2 + pLeft
1✔
172
        top := (h-img.PageHeight())/2 + pTop
1✔
173
        width := w + pLeft + pRight
1✔
174
        height := h + pTop + pBottom
1✔
175
        if colour != "blur" || v.DisableBlur || isAnimated(img) {
2✔
176
                // fill color
1✔
177
                isTransparent := colour == "none" || colour == "transparent"
1✔
178
                if img.HasAlpha() && !isTransparent {
2✔
179
                        c := getColor(img, colour)
1✔
180
                        if err = img.Flatten(&vips.FlattenOptions{Background: c}); err != nil {
1✔
181
                                return
×
182
                        }
×
183
                }
184
                if isTransparent {
2✔
185
                        if img.Bands() < 3 {
2✔
186
                                if err = img.Colourspace(vips.InterpretationSrgb, nil); err != nil {
1✔
187
                                        return
×
188
                                }
×
189
                        }
190
                        if !img.HasAlpha() {
2✔
191
                                if err = img.Addalpha(); err != nil {
1✔
192
                                        return
×
193
                                }
×
194
                        }
195
                        if err = img.EmbedMultiPage(left, top, width, height, &vips.EmbedMultiPageOptions{Extend: vips.ExtendBlack}); err != nil {
1✔
196
                                return
×
197
                        }
×
198
                } else if isBlack(c) {
2✔
199
                        if err = img.EmbedMultiPage(left, top, width, height, &vips.EmbedMultiPageOptions{Extend: vips.ExtendBlack}); err != nil {
1✔
200
                                return
×
201
                        }
×
202
                } else if isWhite(c) {
2✔
203
                        if err = img.EmbedMultiPage(left, top, width, height, &vips.EmbedMultiPageOptions{Extend: vips.ExtendWhite}); err != nil {
1✔
204
                                return
×
205
                        }
×
206
                } else {
1✔
207
                        if err = img.EmbedMultiPage(left, top, width, height, &vips.EmbedMultiPageOptions{
1✔
208
                                Extend:     vips.ExtendBackground,
1✔
209
                                Background: c,
1✔
210
                        }); err != nil {
1✔
211
                                return
×
212
                        }
×
213
                }
214
        } else {
1✔
215
                // fill blur
1✔
216
                var cp *vips.Image
1✔
217
                if cp, err = img.Copy(nil); err != nil {
1✔
218
                        return
×
219
                }
×
220
                contextDefer(ctx, cp.Close)
1✔
221
                if err = img.ThumbnailImage(
1✔
222
                        width, &vips.ThumbnailImageOptions{
1✔
223
                                Height: height,
1✔
224
                                Crop:   vips.InterestingNone,
1✔
225
                                Size:   vips.SizeForce,
1✔
226
                        },
1✔
227
                ); err != nil {
1✔
228
                        return
×
229
                }
×
230
                if err = img.Gaussblur(50, nil); err != nil {
1✔
231
                        return
×
232
                }
×
233
                if err = img.Composite2(
1✔
234
                        cp, vips.BlendModeOver,
1✔
235
                        &vips.Composite2Options{X: left, Y: top}); err != nil {
1✔
236
                        return
×
237
                }
×
238
        }
239
        return
1✔
240
}
241

242
func roundCorner(ctx context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
243
        var rx, ry int
1✔
244
        var c []float64
1✔
245
        if len(args) == 0 {
2✔
246
                return
1✔
247
        }
1✔
248
        if a, e := url.QueryUnescape(args[0]); e == nil {
2✔
249
                args[0] = a
1✔
250
        }
1✔
251
        if len(args) == 3 {
2✔
252
                // rx,ry,color
1✔
253
                c = getColor(img, args[2])
1✔
254
                args = args[:2]
1✔
255
        }
1✔
256
        rx, _ = strconv.Atoi(args[0])
1✔
257
        ry = rx
1✔
258
        if len(args) > 1 {
2✔
259
                ry, _ = strconv.Atoi(args[1])
1✔
260
        }
1✔
261

262
        var rounded *vips.Image
1✔
263
        var w = img.Width()
1✔
264
        var h = img.PageHeight()
1✔
265
        if rounded, err = vips.NewSvgloadBuffer([]byte(fmt.Sprintf(`
1✔
266
                <svg viewBox="0 0 %d %d">
1✔
267
                        <rect rx="%d" ry="%d" 
1✔
268
                         x="0" y="0" width="%d" height="%d" 
1✔
269
                         fill="#fff"/>
1✔
270
                </svg>
1✔
271
        `, w, h, rx, ry, w, h)), nil); err != nil {
1✔
272
                return
×
273
        }
×
274
        contextDefer(ctx, rounded.Close)
1✔
275
        if n := img.Height() / img.PageHeight(); n > 1 {
2✔
276
                if err = rounded.Replicate(1, n); err != nil {
1✔
277
                        return
×
278
                }
×
279
        }
280
        if err = img.Composite2(rounded, vips.BlendModeDestIn, nil); err != nil {
1✔
281
                return
×
282
        }
×
283
        if c != nil {
2✔
284
                if err = img.Flatten(&vips.FlattenOptions{Background: c}); err != nil {
1✔
285
                        return
×
286
                }
×
287
        }
288
        return nil
1✔
289
}
290

291
func label(_ context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
292
        ln := len(args)
1✔
293
        if ln == 0 {
1✔
294
                return
×
295
        }
×
296
        if a, e := url.QueryUnescape(args[0]); e == nil {
2✔
297
                args[0] = a
1✔
298
        }
1✔
299
        var text = args[0]
1✔
300
        var font = "tahoma"
1✔
301
        var x, y int
1✔
302
        var c []float64
1✔
303
        var alpha float64
1✔
304
        var align = vips.AlignLow
1✔
305
        var size = 20
1✔
306
        var width = img.Width()
1✔
307
        if ln > 3 {
2✔
308
                size, _ = strconv.Atoi(args[3])
1✔
309
        }
1✔
310
        if ln > 1 {
2✔
311
                if args[1] == "center" {
2✔
312
                        align = vips.AlignCentre
1✔
313
                        x = width / 2
1✔
314
                } else if args[1] == imagorpath.HAlignRight {
3✔
315
                        align = vips.AlignHigh
1✔
316
                        x = width
1✔
317
                } else if strings.HasPrefix(strings.TrimPrefix(args[1], "-"), "0.") {
3✔
318
                        pec, _ := strconv.ParseFloat(args[1], 64)
1✔
319
                        x = int(pec * float64(width))
1✔
320
                } else if strings.HasSuffix(args[1], "p") {
3✔
321
                        x, _ = strconv.Atoi(strings.TrimSuffix(args[1], "p"))
1✔
322
                        x = x * width / 100
1✔
323
                } else {
2✔
324
                        x, _ = strconv.Atoi(args[1])
1✔
325
                }
1✔
326
                if x < 0 {
2✔
327
                        align = vips.AlignHigh
1✔
328
                        x += width
1✔
329
                }
1✔
330
        }
331
        if ln > 2 {
2✔
332
                if args[2] == "center" {
2✔
333
                        y = (img.PageHeight() - size) / 2
1✔
334
                } else if args[2] == imagorpath.VAlignTop {
3✔
335
                        y = 0
1✔
336
                } else if args[2] == imagorpath.VAlignBottom {
3✔
337
                        y = img.PageHeight() - size
1✔
338
                } else if strings.HasPrefix(strings.TrimPrefix(args[2], "-"), "0.") {
3✔
339
                        pec, _ := strconv.ParseFloat(args[2], 64)
1✔
340
                        y = int(pec * float64(img.PageHeight()))
1✔
341
                } else if strings.HasSuffix(args[2], "p") {
3✔
342
                        y, _ = strconv.Atoi(strings.TrimSuffix(args[2], "p"))
1✔
343
                        y = y * img.PageHeight() / 100
1✔
344
                } else {
2✔
345
                        y, _ = strconv.Atoi(args[2])
1✔
346
                }
1✔
347
                if y < 0 {
2✔
348
                        y += img.PageHeight() - size
1✔
349
                }
1✔
350
        }
351
        if ln > 4 {
2✔
352
                c = getColor(img, args[4])
1✔
353
        }
1✔
354
        if ln > 5 {
2✔
355
                alpha, _ = strconv.ParseFloat(args[5], 64)
1✔
356
                alpha /= 100
1✔
357
        }
1✔
358
        if ln > 6 {
2✔
359
                if a, e := url.QueryUnescape(args[6]); e == nil {
2✔
360
                        font = a
1✔
361
                } else {
1✔
362
                        font = args[6]
×
363
                }
×
364
        }
365
        if img.Bands() < 3 {
2✔
366
                if err = img.Colourspace(vips.InterpretationSrgb, nil); err != nil {
1✔
367
                        return
×
368
                }
×
369
        }
370
        if !img.HasAlpha() {
2✔
371
                if err = img.Addalpha(); err != nil {
1✔
372
                        return
×
373
                }
×
374
        }
375
        return img.Label(text, x, y, &vips.LabelOptions{
1✔
376
                Font:    font,
1✔
377
                Size:    size,
1✔
378
                Align:   align,
1✔
379
                Opacity: 1 - alpha,
1✔
380
                Color:   c,
1✔
381
        })
1✔
382
}
383

384
func (v *Processor) padding(ctx context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) error {
1✔
385
        ln := len(args)
1✔
386
        if ln < 2 {
2✔
387
                return nil
1✔
388
        }
1✔
389
        var (
1✔
390
                c       = args[0]
1✔
391
                left, _ = strconv.Atoi(args[1])
1✔
392
                top     = left
1✔
393
                right   = left
1✔
394
                bottom  = left
1✔
395
        )
1✔
396
        if ln > 2 {
2✔
397
                top, _ = strconv.Atoi(args[2])
1✔
398
                bottom = top
1✔
399
        }
1✔
400
        if ln > 4 {
2✔
401
                right, _ = strconv.Atoi(args[3])
1✔
402
                bottom, _ = strconv.Atoi(args[4])
1✔
403
        }
1✔
404
        return v.fill(ctx, img, img.Width(), img.PageHeight(), left, top, right, bottom, c)
1✔
405
}
406

407
func backgroundColor(_ context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
408
        if len(args) == 0 {
2✔
409
                return
1✔
410
        }
1✔
411
        if !img.HasAlpha() {
2✔
412
                return
1✔
413
        }
1✔
414
        c := getColor(img, args[0])
1✔
415
        return img.Flatten(&vips.FlattenOptions{
1✔
416
                Background: c,
1✔
417
        })
1✔
418
}
419

420
func rotate(ctx context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
421
        if len(args) == 0 {
2✔
422
                return
1✔
423
        }
1✔
424
        if angle, _ := strconv.Atoi(args[0]); angle > 0 {
2✔
425
                switch angle {
1✔
426
                case 90, 270:
1✔
427
                        setRotate90(ctx)
1✔
428
                }
429
                if err = img.RotMultiPage(getAngle(angle)); err != nil {
1✔
430
                        return err
×
431
                }
×
432
        }
433
        return
1✔
434
}
435

436
func getAngle(angle int) vips.Angle {
1✔
437
        switch angle {
1✔
438
        case 90:
1✔
439
                return vips.AngleD270
1✔
440
        case 180:
1✔
441
                return vips.AngleD180
1✔
442
        case 270:
1✔
443
                return vips.AngleD90
1✔
444
        default:
×
445
                return vips.AngleD0
×
446
        }
447
}
448

449
func proportion(_ context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
450
        if len(args) == 0 {
2✔
451
                return
1✔
452
        }
1✔
453
        scale, _ := strconv.ParseFloat(args[0], 64)
1✔
454
        if scale <= 0 {
2✔
455
                return // no ops
1✔
456
        }
1✔
457
        if scale > 100 {
2✔
458
                scale = 100
1✔
459
        }
1✔
460
        if scale > 1 {
2✔
461
                scale /= 100
1✔
462
        }
1✔
463
        width := int(float64(img.Width()) * scale)
1✔
464
        height := int(float64(img.PageHeight()) * scale)
1✔
465
        if width <= 0 || height <= 0 {
2✔
466
                return // op ops
1✔
467
        }
1✔
468
        return img.ThumbnailImage(width, &vips.ThumbnailImageOptions{
1✔
469
                Height: height,
1✔
470
                Crop:   vips.InterestingNone,
1✔
471
        })
1✔
472
}
473

474
func grayscale(_ context.Context, img *vips.Image, _ imagor.LoadFunc, _ ...string) (err error) {
1✔
475
        return img.Colourspace(vips.InterpretationBW, nil)
1✔
476
}
1✔
477

478
func brightness(_ context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
479
        if len(args) == 0 {
1✔
480
                return
×
481
        }
×
482
        b, _ := strconv.ParseFloat(args[0], 64)
1✔
483
        b = b * 255 / 100
1✔
484
        return linearRGB(img, []float64{1, 1, 1}, []float64{b, b, b})
1✔
485
}
486

487
func contrast(_ context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
488
        if len(args) == 0 {
1✔
489
                return
×
490
        }
×
491
        a, _ := strconv.ParseFloat(args[0], 64)
1✔
492
        a = a * 255 / 100
1✔
493
        a = math.Min(math.Max(a, -255), 255)
1✔
494
        a = (259 * (a + 255)) / (255 * (259 - a))
1✔
495
        b := 128 - a*128
1✔
496
        return linearRGB(img, []float64{a, a, a}, []float64{b, b, b})
1✔
497
}
498

499
func hue(_ context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
500
        if len(args) == 0 {
1✔
501
                return
×
502
        }
×
503
        h, _ := strconv.ParseFloat(args[0], 64)
1✔
504
        return img.Modulate(1, 1, h)
1✔
505
}
506

507
func saturation(_ context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
508
        if len(args) == 0 {
1✔
509
                return
×
510
        }
×
511
        s, _ := strconv.ParseFloat(args[0], 64)
1✔
512
        s = 1 + s/100
1✔
513
        return img.Modulate(1, s, 0)
1✔
514
}
515

516
func rgb(_ context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
517
        if len(args) != 3 {
1✔
518
                return
×
519
        }
×
520
        r, _ := strconv.ParseFloat(args[0], 64)
1✔
521
        g, _ := strconv.ParseFloat(args[1], 64)
1✔
522
        b, _ := strconv.ParseFloat(args[2], 64)
1✔
523
        r = r * 255 / 100
1✔
524
        g = g * 255 / 100
1✔
525
        b = b * 255 / 100
1✔
526
        return linearRGB(img, []float64{1, 1, 1}, []float64{r, g, b})
1✔
527
}
528

529
func modulate(_ context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
530
        if len(args) != 3 {
1✔
531
                return
×
532
        }
×
533
        b, _ := strconv.ParseFloat(args[0], 64)
1✔
534
        s, _ := strconv.ParseFloat(args[1], 64)
1✔
535
        h, _ := strconv.ParseFloat(args[2], 64)
1✔
536
        b = 1 + b/100
1✔
537
        s = 1 + s/100
1✔
538
        return img.Modulate(b, s, h)
1✔
539
}
540

541
func blur(ctx context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
542
        if isAnimated(img) {
1✔
543
                // skip animation support
×
544
                return
×
545
        }
×
546
        var sigma float64
1✔
547
        switch len(args) {
1✔
548
        case 2:
1✔
549
                sigma, _ = strconv.ParseFloat(args[1], 64)
1✔
550
                break
1✔
551
        case 1:
1✔
552
                sigma, _ = strconv.ParseFloat(args[0], 64)
1✔
553
                break
1✔
554
        }
555
        sigma /= 2
1✔
556
        if sigma > 0 {
2✔
557
                return img.Gaussblur(sigma, nil)
1✔
558
        }
1✔
559
        return
×
560
}
561

562
func sharpen(ctx context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) (err error) {
1✔
563
        if isAnimated(img) {
1✔
564
                // skip animation support
×
565
                return
×
566
        }
×
567
        var sigma float64
1✔
568
        switch len(args) {
1✔
569
        case 1:
1✔
570
                sigma, _ = strconv.ParseFloat(args[0], 64)
1✔
571
                break
1✔
572
        case 2, 3:
1✔
573
                sigma, _ = strconv.ParseFloat(args[1], 64)
1✔
574
                break
1✔
575
        }
576
        sigma = 1 + sigma*2
1✔
577
        if sigma > 0 {
2✔
578
                return img.Sharpen(&vips.SharpenOptions{
1✔
579
                        Sigma: sigma,
1✔
580
                        X1:    1,
1✔
581
                        M2:    2,
1✔
582
                })
1✔
583
        }
1✔
584
        return
1✔
585
}
586

587
func stripIcc(_ context.Context, img *vips.Image, _ imagor.LoadFunc, _ ...string) (err error) {
×
588
        return img.RemoveICCProfile()
×
589
}
×
590

591
func stripExif(_ context.Context, img *vips.Image, _ imagor.LoadFunc, _ ...string) (err error) {
1✔
592
        return img.RemoveExif()
1✔
593
}
1✔
594

595
func trim(ctx context.Context, img *vips.Image, _ imagor.LoadFunc, args ...string) error {
×
596
        var (
×
597
                ln        = len(args)
×
598
                pos       string
×
599
                tolerance int
×
600
        )
×
601
        if ln > 0 {
×
602
                tolerance, _ = strconv.Atoi(args[0])
×
603
        }
×
604
        if ln > 1 {
×
605
                pos = args[1]
×
606
        }
×
607
        if l, t, w, h, err := findTrim(ctx, img, pos, tolerance); err == nil {
×
608
                return img.ExtractAreaMultiPage(l, t, w, h)
×
609
        }
×
610
        return nil
×
611
}
612

613
func linearRGB(img *vips.Image, a, b []float64) error {
1✔
614
        if img.HasAlpha() {
2✔
615
                a = append(a, 1)
1✔
616
                b = append(b, 0)
1✔
617
        }
1✔
618
        return img.Linear(a, b, nil)
1✔
619
}
620

621
func isBlack(c []float64) bool {
1✔
622
        if len(c) < 3 {
1✔
623
                return false
×
624
        }
×
625
        return c[0] == 0x00 && c[1] == 0x00 && c[2] == 0x00
1✔
626
}
627

628
func isWhite(c []float64) bool {
1✔
629
        if len(c) < 3 {
1✔
630
                return false
×
631
        }
×
632
        return c[0] == 0xff && c[1] == 0xff && c[2] == 0xff
1✔
633
}
634

635
func getColor(img *vips.Image, color string) []float64 {
1✔
636
        var vc = make([]float64, 3)
1✔
637
        args := strings.Split(strings.ToLower(color), ",")
1✔
638
        mode := ""
1✔
639
        name := strings.TrimPrefix(args[0], "#")
1✔
640
        if len(args) > 1 {
2✔
641
                mode = args[1]
1✔
642
        }
1✔
643
        if name == "auto" {
2✔
644
                if img != nil {
2✔
645
                        x := 0
1✔
646
                        y := 0
1✔
647
                        if mode == "bottom-right" {
2✔
648
                                x = img.Width() - 1
1✔
649
                                y = img.PageHeight() - 1
1✔
650
                        }
1✔
651
                        p, _ := img.Getpoint(x, y, nil)
1✔
652
                        if len(p) >= 3 {
2✔
653
                                vc[0] = p[0]
1✔
654
                                vc[1] = p[1]
1✔
655
                                vc[2] = p[2]
1✔
656
                        }
1✔
657
                }
658
        } else if c, ok := colornames.Map[name]; ok {
2✔
659
                vc[0] = float64(c.R)
1✔
660
                vc[1] = float64(c.G)
1✔
661
                vc[2] = float64(c.B)
1✔
662
        } else if c, ok := parseHexColor(name); ok {
3✔
663
                vc[0] = float64(c.R)
1✔
664
                vc[1] = float64(c.G)
1✔
665
                vc[2] = float64(c.B)
1✔
666
        }
1✔
667
        return vc
1✔
668
}
669

670
func parseHexColor(s string) (c color.RGBA, ok bool) {
1✔
671
        c.A = 0xff
1✔
672
        switch len(s) {
1✔
673
        case 6:
1✔
674
                c.R = hexToByte(s[0])<<4 + hexToByte(s[1])
1✔
675
                c.G = hexToByte(s[2])<<4 + hexToByte(s[3])
1✔
676
                c.B = hexToByte(s[4])<<4 + hexToByte(s[5])
1✔
677
                ok = true
1✔
678
        case 3:
1✔
679
                c.R = hexToByte(s[0]) * 17
1✔
680
                c.G = hexToByte(s[1]) * 17
1✔
681
                c.B = hexToByte(s[2]) * 17
1✔
682
                ok = true
1✔
683
        }
684
        return
1✔
685
}
686

687
func hexToByte(b byte) byte {
1✔
688
        switch {
1✔
689
        case b >= '0' && b <= '9':
1✔
690
                return b - '0'
1✔
691
        case b >= 'a' && b <= 'f':
1✔
692
                return b - 'a' + 10
1✔
693
        }
694
        return 0
1✔
695
}
696

697
func isAnimated(img *vips.Image) bool {
1✔
698
        return img.Height() > img.PageHeight()
1✔
699
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc