fix: replace github.com/disintegration/imaging with github.com/kovidgoyal/imaging
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
Bugfix: Crash when processing crafted TIFF files
|
||||||
|
|
||||||
|
Fix for a vulnerability with low severity in disintegration/imaging.
|
||||||
|
|
||||||
|
https://github.com/advisories/GHSA-q7pp-wcgr-pffx
|
||||||
|
https://github.com/owncloud/ocis/pull/8981
|
||||||
|
|
||||||
@@ -17,7 +17,6 @@ require (
|
|||||||
github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781
|
github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781
|
||||||
github.com/cs3org/reva/v2 v2.19.2-0.20240426071117-7ed0671f9e0b
|
github.com/cs3org/reva/v2 v2.19.2-0.20240426071117-7ed0671f9e0b
|
||||||
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
|
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
|
||||||
github.com/disintegration/imaging v1.6.2
|
|
||||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||||
github.com/egirna/icap-client v0.1.1
|
github.com/egirna/icap-client v0.1.1
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3
|
github.com/gabriel-vasile/mimetype v1.4.3
|
||||||
@@ -56,6 +55,7 @@ require (
|
|||||||
github.com/jellydator/ttlcache/v3 v3.2.0
|
github.com/jellydator/ttlcache/v3 v3.2.0
|
||||||
github.com/jinzhu/now v1.1.5
|
github.com/jinzhu/now v1.1.5
|
||||||
github.com/justinas/alice v1.2.0
|
github.com/justinas/alice v1.2.0
|
||||||
|
github.com/kovidgoyal/imaging v1.6.3
|
||||||
github.com/leonelquinteros/gotext v1.6.0
|
github.com/leonelquinteros/gotext v1.6.0
|
||||||
github.com/libregraph/idm v0.5.0
|
github.com/libregraph/idm v0.5.0
|
||||||
github.com/libregraph/lico v0.61.3-0.20240322112242-72cf9221d3a7
|
github.com/libregraph/lico v0.61.3-0.20240322112242-72cf9221d3a7
|
||||||
|
|||||||
@@ -1056,8 +1056,6 @@ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8
|
|||||||
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 h1:simG0vMYFvNriGhaaat7QVVkaVkXzvqcohaBoLZl9Hg=
|
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 h1:simG0vMYFvNriGhaaat7QVVkaVkXzvqcohaBoLZl9Hg=
|
||||||
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25/go.mod h1:Z3Lomva4pyMWYezjMAU5QWRh0p1VvO4199OHlFnyKkM=
|
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25/go.mod h1:Z3Lomva4pyMWYezjMAU5QWRh0p1VvO4199OHlFnyKkM=
|
||||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
|
||||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
|
||||||
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
|
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
|
||||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||||
@@ -1613,6 +1611,8 @@ github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXH
|
|||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kovidgoyal/imaging v1.6.3 h1:iNPpv7ygiaB/NOztc6APMT7yr9UwBS+rOZwIbAdtyY8=
|
||||||
|
github.com/kovidgoyal/imaging v1.6.3/go.mod h1:sHvcLOOVhJuto2IoNdPLEqnAUoL5ZfHEF0PpNH+882g=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -2200,7 +2200,6 @@ golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86h
|
|||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"mime"
|
"mime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/disintegration/imaging"
|
"github.com/kovidgoyal/imaging"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/image/font"
|
"golang.org/x/image/font"
|
||||||
"golang.org/x/image/font/opentype"
|
"golang.org/x/image/font/opentype"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"image/gif"
|
"image/gif"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/disintegration/imaging"
|
"github.com/kovidgoyal/imaging"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generator generates a web friendly file version.
|
// Generator generates a web friendly file version.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/disintegration/imaging"
|
"github.com/kovidgoyal/imaging"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Processor processes the thumbnail by applying different transformations to it.
|
// Processor processes the thumbnail by applying different transformations to it.
|
||||||
@@ -13,7 +13,7 @@ type Processor interface {
|
|||||||
Process(img image.Image, width, height int, filter imaging.ResampleFilter) *image.NRGBA
|
Process(img image.Image, width, height int, filter imaging.ResampleFilter) *image.NRGBA
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefinableProcessor is the most simple processor, it holds a replaceable image converter function.
|
// DefinableProcessor is the simplest processor, it holds a replaceable image converter function.
|
||||||
type DefinableProcessor struct {
|
type DefinableProcessor struct {
|
||||||
Slug string
|
Slug string
|
||||||
Converter func(img image.Image, width, height int, filter imaging.ResampleFilter) *image.NRGBA
|
Converter func(img image.Image, width, height int, filter imaging.ResampleFilter) *image.NRGBA
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package thumbnail_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/disintegration/imaging"
|
"github.com/kovidgoyal/imaging"
|
||||||
tAssert "github.com/stretchr/testify/assert"
|
tAssert "github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/owncloud/ocis/v2/services/thumbnails/pkg/thumbnail"
|
"github.com/owncloud/ocis/v2/services/thumbnails/pkg/thumbnail"
|
||||||
|
|||||||
-12
@@ -1,12 +0,0 @@
|
|||||||
language: go
|
|
||||||
go:
|
|
||||||
- "1.10.x"
|
|
||||||
- "1.11.x"
|
|
||||||
- "1.12.x"
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
|
|
||||||
script:
|
|
||||||
- go test -v -race -cover
|
|
||||||
- $GOPATH/bin/goveralls -service=travis-ci
|
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
dist/
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||||
|
# Make sure to check the documentation at https://goreleaser.com
|
||||||
|
|
||||||
|
# The lines below are called `modelines`. See `:help modeline`
|
||||||
|
# Feel free to remove those if you don't want/need to use them.
|
||||||
|
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||||
|
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||||
|
|
||||||
|
version: 1
|
||||||
|
|
||||||
|
before:
|
||||||
|
hooks:
|
||||||
|
# You may remove this if you don't use go modules.
|
||||||
|
- go mod tidy
|
||||||
|
# you may remove this if you don't need go generate
|
||||||
|
- go generate ./...
|
||||||
|
|
||||||
|
builds:
|
||||||
|
- skip: true
|
||||||
|
|
||||||
|
archives:
|
||||||
|
- format: tar.gz
|
||||||
|
# this name template makes the OS and Arch compatible with the results of `uname`.
|
||||||
|
name_template: >-
|
||||||
|
{{ .ProjectName }}_
|
||||||
|
{{- title .Os }}_
|
||||||
|
{{- if eq .Arch "amd64" }}x86_64
|
||||||
|
{{- else if eq .Arch "386" }}i386
|
||||||
|
{{- else }}{{ .Arch }}{{ end }}
|
||||||
|
{{- if .Arm }}v{{ .Arm }}{{ end }}
|
||||||
|
# use zip for windows archives
|
||||||
|
format_overrides:
|
||||||
|
- goos: windows
|
||||||
|
format: zip
|
||||||
|
|
||||||
|
changelog:
|
||||||
|
sort: asc
|
||||||
|
filters:
|
||||||
|
exclude:
|
||||||
|
- "^docs:"
|
||||||
|
- "^test:"
|
||||||
Generated
Vendored
Generated
Vendored
+231
-226
@@ -1,226 +1,231 @@
|
|||||||
# Imaging
|
# Imaging
|
||||||
|
|
||||||
[](https://godoc.org/github.com/disintegration/imaging)
|
Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.).
|
||||||
[](https://travis-ci.org/disintegration/imaging)
|
|
||||||
[](https://coveralls.io/github/disintegration/imaging?branch=master)
|
All the image processing functions provided by the package accept any image type that implements `image.Image` interface
|
||||||
[](https://goreportcard.com/report/github.com/disintegration/imaging)
|
as an input, and return a new image of `*image.NRGBA` type (32bit RGBA colors, non-premultiplied alpha).
|
||||||
|
|
||||||
Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.).
|
## Installation
|
||||||
|
|
||||||
All the image processing functions provided by the package accept any image type that implements `image.Image` interface
|
go get -u github.com/kovidgoyal/imaging
|
||||||
as an input, and return a new image of `*image.NRGBA` type (32bit RGBA colors, non-premultiplied alpha).
|
|
||||||
|
## Documentation
|
||||||
## Installation
|
|
||||||
|
https://pkg.go.dev/github.com/kovidgoyal/imaging
|
||||||
go get -u github.com/disintegration/imaging
|
|
||||||
|
## Usage examples
|
||||||
## Documentation
|
|
||||||
|
A few usage examples can be found below. See the documentation for the full list of supported functions.
|
||||||
http://godoc.org/github.com/disintegration/imaging
|
|
||||||
|
### Image resizing
|
||||||
## Usage examples
|
|
||||||
|
```go
|
||||||
A few usage examples can be found below. See the documentation for the full list of supported functions.
|
// Resize srcImage to size = 128x128px using the Lanczos filter.
|
||||||
|
dstImage128 := imaging.Resize(srcImage, 128, 128, imaging.Lanczos)
|
||||||
### Image resizing
|
|
||||||
|
// Resize srcImage to width = 800px preserving the aspect ratio.
|
||||||
```go
|
dstImage800 := imaging.Resize(srcImage, 800, 0, imaging.Lanczos)
|
||||||
// Resize srcImage to size = 128x128px using the Lanczos filter.
|
|
||||||
dstImage128 := imaging.Resize(srcImage, 128, 128, imaging.Lanczos)
|
// Scale down srcImage to fit the 800x600px bounding box.
|
||||||
|
dstImageFit := imaging.Fit(srcImage, 800, 600, imaging.Lanczos)
|
||||||
// Resize srcImage to width = 800px preserving the aspect ratio.
|
|
||||||
dstImage800 := imaging.Resize(srcImage, 800, 0, imaging.Lanczos)
|
// Resize and crop the srcImage to fill the 100x100px area.
|
||||||
|
dstImageFill := imaging.Fill(srcImage, 100, 100, imaging.Center, imaging.Lanczos)
|
||||||
// Scale down srcImage to fit the 800x600px bounding box.
|
```
|
||||||
dstImageFit := imaging.Fit(srcImage, 800, 600, imaging.Lanczos)
|
|
||||||
|
Imaging supports image resizing using various resampling filters. The most notable ones:
|
||||||
// Resize and crop the srcImage to fill the 100x100px area.
|
- `Lanczos` - A high-quality resampling filter for photographic images yielding sharp results.
|
||||||
dstImageFill := imaging.Fill(srcImage, 100, 100, imaging.Center, imaging.Lanczos)
|
- `CatmullRom` - A sharp cubic filter that is faster than Lanczos filter while providing similar results.
|
||||||
```
|
- `MitchellNetravali` - A cubic filter that produces smoother results with less ringing artifacts than CatmullRom.
|
||||||
|
- `Linear` - Bilinear resampling filter, produces smooth output. Faster than cubic filters.
|
||||||
Imaging supports image resizing using various resampling filters. The most notable ones:
|
- `Box` - Simple and fast averaging filter appropriate for downscaling. When upscaling it's similar to NearestNeighbor.
|
||||||
- `Lanczos` - A high-quality resampling filter for photographic images yielding sharp results.
|
- `NearestNeighbor` - Fastest resampling filter, no antialiasing.
|
||||||
- `CatmullRom` - A sharp cubic filter that is faster than Lanczos filter while providing similar results.
|
|
||||||
- `MitchellNetravali` - A cubic filter that produces smoother results with less ringing artifacts than CatmullRom.
|
The full list of supported filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. Custom filters can be created using ResampleFilter struct.
|
||||||
- `Linear` - Bilinear resampling filter, produces smooth output. Faster than cubic filters.
|
|
||||||
- `Box` - Simple and fast averaging filter appropriate for downscaling. When upscaling it's similar to NearestNeighbor.
|
**Resampling filters comparison**
|
||||||
- `NearestNeighbor` - Fastest resampling filter, no antialiasing.
|
|
||||||
|
Original image:
|
||||||
The full list of supported filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. Custom filters can be created using ResampleFilter struct.
|
|
||||||
|

|
||||||
**Resampling filters comparison**
|
|
||||||
|
The same image resized from 600x400px to 150x100px using different resampling filters.
|
||||||
Original image:
|
From faster (lower quality) to slower (higher quality):
|
||||||
|
|
||||||

|
Filter | Resize result
|
||||||
|
--------------------------|---------------------------------------------
|
||||||
The same image resized from 600x400px to 150x100px using different resampling filters.
|
`imaging.NearestNeighbor` | 
|
||||||
From faster (lower quality) to slower (higher quality):
|
`imaging.Linear` | 
|
||||||
|
`imaging.CatmullRom` | 
|
||||||
Filter | Resize result
|
`imaging.Lanczos` | 
|
||||||
--------------------------|---------------------------------------------
|
|
||||||
`imaging.NearestNeighbor` | 
|
|
||||||
`imaging.Linear` | 
|
### Gaussian Blur
|
||||||
`imaging.CatmullRom` | 
|
|
||||||
`imaging.Lanczos` | 
|
```go
|
||||||
|
dstImage := imaging.Blur(srcImage, 0.5)
|
||||||
|
```
|
||||||
### Gaussian Blur
|
|
||||||
|
Sigma parameter allows to control the strength of the blurring effect.
|
||||||
```go
|
|
||||||
dstImage := imaging.Blur(srcImage, 0.5)
|
Original image | Sigma = 0.5 | Sigma = 1.5
|
||||||
```
|
-----------------------------------|----------------------------------------|---------------------------------------
|
||||||
|
 |  | 
|
||||||
Sigma parameter allows to control the strength of the blurring effect.
|
|
||||||
|
### Sharpening
|
||||||
Original image | Sigma = 0.5 | Sigma = 1.5
|
|
||||||
-----------------------------------|----------------------------------------|---------------------------------------
|
```go
|
||||||
 |  | 
|
dstImage := imaging.Sharpen(srcImage, 0.5)
|
||||||
|
```
|
||||||
### Sharpening
|
|
||||||
|
`Sharpen` uses gaussian function internally. Sigma parameter allows to control the strength of the sharpening effect.
|
||||||
```go
|
|
||||||
dstImage := imaging.Sharpen(srcImage, 0.5)
|
Original image | Sigma = 0.5 | Sigma = 1.5
|
||||||
```
|
-----------------------------------|-------------------------------------------|------------------------------------------
|
||||||
|
 |  | 
|
||||||
`Sharpen` uses gaussian function internally. Sigma parameter allows to control the strength of the sharpening effect.
|
|
||||||
|
### Gamma correction
|
||||||
Original image | Sigma = 0.5 | Sigma = 1.5
|
|
||||||
-----------------------------------|-------------------------------------------|------------------------------------------
|
```go
|
||||||
 |  | 
|
dstImage := imaging.AdjustGamma(srcImage, 0.75)
|
||||||
|
```
|
||||||
### Gamma correction
|
|
||||||
|
Original image | Gamma = 0.75 | Gamma = 1.25
|
||||||
```go
|
-----------------------------------|------------------------------------------|-----------------------------------------
|
||||||
dstImage := imaging.AdjustGamma(srcImage, 0.75)
|
 |  | 
|
||||||
```
|
|
||||||
|
### Contrast adjustment
|
||||||
Original image | Gamma = 0.75 | Gamma = 1.25
|
|
||||||
-----------------------------------|------------------------------------------|-----------------------------------------
|
```go
|
||||||
 |  | 
|
dstImage := imaging.AdjustContrast(srcImage, 20)
|
||||||
|
```
|
||||||
### Contrast adjustment
|
|
||||||
|
Original image | Contrast = 15 | Contrast = -15
|
||||||
```go
|
-----------------------------------|--------------------------------------------|-------------------------------------------
|
||||||
dstImage := imaging.AdjustContrast(srcImage, 20)
|
 |  | 
|
||||||
```
|
|
||||||
|
### Brightness adjustment
|
||||||
Original image | Contrast = 15 | Contrast = -15
|
|
||||||
-----------------------------------|--------------------------------------------|-------------------------------------------
|
```go
|
||||||
 |  | 
|
dstImage := imaging.AdjustBrightness(srcImage, 20)
|
||||||
|
```
|
||||||
### Brightness adjustment
|
|
||||||
|
Original image | Brightness = 10 | Brightness = -10
|
||||||
```go
|
-----------------------------------|----------------------------------------------|---------------------------------------------
|
||||||
dstImage := imaging.AdjustBrightness(srcImage, 20)
|
 |  | 
|
||||||
```
|
|
||||||
|
### Saturation adjustment
|
||||||
Original image | Brightness = 10 | Brightness = -10
|
|
||||||
-----------------------------------|----------------------------------------------|---------------------------------------------
|
```go
|
||||||
 |  | 
|
dstImage := imaging.AdjustSaturation(srcImage, 20)
|
||||||
|
```
|
||||||
### Saturation adjustment
|
|
||||||
|
Original image | Saturation = 30 | Saturation = -30
|
||||||
```go
|
-----------------------------------|----------------------------------------------|---------------------------------------------
|
||||||
dstImage := imaging.AdjustSaturation(srcImage, 20)
|
 |  | 
|
||||||
```
|
|
||||||
|
### Hue adjustment
|
||||||
Original image | Saturation = 30 | Saturation = -30
|
|
||||||
-----------------------------------|----------------------------------------------|---------------------------------------------
|
```go
|
||||||
 |  | 
|
dstImage := imaging.AdjustHue(srcImage, 20)
|
||||||
|
```
|
||||||
## FAQ
|
|
||||||
|
Original image | Hue = 60 | Hue = -60
|
||||||
### Incorrect image orientation after processing (e.g. an image appears rotated after resizing)
|
-----------------------------------|----------------------------------------------|---------------------------------------------
|
||||||
|
 |  | 
|
||||||
Most probably, the given image contains the EXIF orientation tag.
|
|
||||||
The stadard `image/*` packages do not support loading and saving
|
## FAQ
|
||||||
this kind of information. To fix the issue, try opening images with
|
|
||||||
the `AutoOrientation` decode option. If this option is set to `true`,
|
### Incorrect image orientation after processing (e.g. an image appears rotated after resizing)
|
||||||
the image orientation is changed after decoding, according to the
|
|
||||||
orientation tag (if present). Here's the example:
|
Most probably, the given image contains the EXIF orientation tag.
|
||||||
|
The standard `image/*` packages do not support loading and saving
|
||||||
```go
|
this kind of information. To fix the issue, try opening images with
|
||||||
img, err := imaging.Open("test.jpg", imaging.AutoOrientation(true))
|
the `AutoOrientation` decode option. If this option is set to `true`,
|
||||||
```
|
the image orientation is changed after decoding, according to the
|
||||||
|
orientation tag (if present). Here's the example:
|
||||||
### What's the difference between `imaging` and `gift` packages?
|
|
||||||
|
```go
|
||||||
[imaging](https://github.com/disintegration/imaging)
|
img, err := imaging.Open("test.jpg", imaging.AutoOrientation(true))
|
||||||
is designed to be a lightweight and simple image manipulation package.
|
```
|
||||||
It provides basic image processing functions and a few helper functions
|
|
||||||
such as `Open` and `Save`. It consistently returns *image.NRGBA image
|
### What's the difference between `imaging` and `gift` packages?
|
||||||
type (8 bits per channel, RGBA).
|
|
||||||
|
[imaging](https://github.com/kovidgoyal/imaging)
|
||||||
[gift](https://github.com/disintegration/gift)
|
is designed to be a lightweight and simple image manipulation package.
|
||||||
supports more advanced image processing, for example, sRGB/Linear color
|
It provides basic image processing functions and a few helper functions
|
||||||
space conversions. It also supports different output image types
|
such as `Open` and `Save`. It consistently returns *image.NRGBA image
|
||||||
(e.g. 16 bits per channel) and provides easy-to-use API for chaining
|
type (8 bits per channel, RGBA).
|
||||||
multiple processing steps together.
|
|
||||||
|
[gift](https://github.com/disintegration/gift)
|
||||||
## Example code
|
supports more advanced image processing, for example, sRGB/Linear color
|
||||||
|
space conversions. It also supports different output image types
|
||||||
```go
|
(e.g. 16 bits per channel) and provides easy-to-use API for chaining
|
||||||
package main
|
multiple processing steps together.
|
||||||
|
|
||||||
import (
|
## Example code
|
||||||
"image"
|
|
||||||
"image/color"
|
```go
|
||||||
"log"
|
package main
|
||||||
|
|
||||||
"github.com/disintegration/imaging"
|
import (
|
||||||
)
|
"image"
|
||||||
|
"image/color"
|
||||||
func main() {
|
"log"
|
||||||
// Open a test image.
|
|
||||||
src, err := imaging.Open("testdata/flowers.png")
|
"github.com/kovidgoyal/imaging"
|
||||||
if err != nil {
|
)
|
||||||
log.Fatalf("failed to open image: %v", err)
|
|
||||||
}
|
func main() {
|
||||||
|
// Open a test image.
|
||||||
// Crop the original image to 300x300px size using the center anchor.
|
src, err := imaging.Open("testdata/flowers.png")
|
||||||
src = imaging.CropAnchor(src, 300, 300, imaging.Center)
|
if err != nil {
|
||||||
|
log.Fatalf("failed to open image: %v", err)
|
||||||
// Resize the cropped image to width = 200px preserving the aspect ratio.
|
}
|
||||||
src = imaging.Resize(src, 200, 0, imaging.Lanczos)
|
|
||||||
|
// Crop the original image to 300x300px size using the center anchor.
|
||||||
// Create a blurred version of the image.
|
src = imaging.CropAnchor(src, 300, 300, imaging.Center)
|
||||||
img1 := imaging.Blur(src, 5)
|
|
||||||
|
// Resize the cropped image to width = 200px preserving the aspect ratio.
|
||||||
// Create a grayscale version of the image with higher contrast and sharpness.
|
src = imaging.Resize(src, 200, 0, imaging.Lanczos)
|
||||||
img2 := imaging.Grayscale(src)
|
|
||||||
img2 = imaging.AdjustContrast(img2, 20)
|
// Create a blurred version of the image.
|
||||||
img2 = imaging.Sharpen(img2, 2)
|
img1 := imaging.Blur(src, 5)
|
||||||
|
|
||||||
// Create an inverted version of the image.
|
// Create a grayscale version of the image with higher contrast and sharpness.
|
||||||
img3 := imaging.Invert(src)
|
img2 := imaging.Grayscale(src)
|
||||||
|
img2 = imaging.AdjustContrast(img2, 20)
|
||||||
// Create an embossed version of the image using a convolution filter.
|
img2 = imaging.Sharpen(img2, 2)
|
||||||
img4 := imaging.Convolve3x3(
|
|
||||||
src,
|
// Create an inverted version of the image.
|
||||||
[9]float64{
|
img3 := imaging.Invert(src)
|
||||||
-1, -1, 0,
|
|
||||||
-1, 1, 1,
|
// Create an embossed version of the image using a convolution filter.
|
||||||
0, 1, 1,
|
img4 := imaging.Convolve3x3(
|
||||||
},
|
src,
|
||||||
nil,
|
[9]float64{
|
||||||
)
|
-1, -1, 0,
|
||||||
|
-1, 1, 1,
|
||||||
// Create a new image and paste the four produced images into it.
|
0, 1, 1,
|
||||||
dst := imaging.New(400, 400, color.NRGBA{0, 0, 0, 0})
|
},
|
||||||
dst = imaging.Paste(dst, img1, image.Pt(0, 0))
|
nil,
|
||||||
dst = imaging.Paste(dst, img2, image.Pt(0, 200))
|
)
|
||||||
dst = imaging.Paste(dst, img3, image.Pt(200, 0))
|
|
||||||
dst = imaging.Paste(dst, img4, image.Pt(200, 200))
|
// Create a new image and paste the four produced images into it.
|
||||||
|
dst := imaging.New(400, 400, color.NRGBA{0, 0, 0, 0})
|
||||||
// Save the resulting image as JPEG.
|
dst = imaging.Paste(dst, img1, image.Pt(0, 0))
|
||||||
err = imaging.Save(dst, "testdata/out_example.jpg")
|
dst = imaging.Paste(dst, img2, image.Pt(0, 200))
|
||||||
if err != nil {
|
dst = imaging.Paste(dst, img3, image.Pt(200, 0))
|
||||||
log.Fatalf("failed to save image: %v", err)
|
dst = imaging.Paste(dst, img4, image.Pt(200, 200))
|
||||||
}
|
|
||||||
}
|
// Save the resulting image as JPEG.
|
||||||
```
|
err = imaging.Save(dst, "testdata/out_example.jpg")
|
||||||
|
if err != nil {
|
||||||
Output:
|
log.Fatalf("failed to save image: %v", err)
|
||||||
|
}
|
||||||

|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|

|
||||||
Generated
Vendored
+44
@@ -62,6 +62,10 @@ func Invert(img image.Image) *image.NRGBA {
|
|||||||
// dstImage = imaging.AdjustSaturation(srcImage, -10) // Decrease image saturation by 10%.
|
// dstImage = imaging.AdjustSaturation(srcImage, -10) // Decrease image saturation by 10%.
|
||||||
//
|
//
|
||||||
func AdjustSaturation(img image.Image, percentage float64) *image.NRGBA {
|
func AdjustSaturation(img image.Image, percentage float64) *image.NRGBA {
|
||||||
|
if percentage == 0 {
|
||||||
|
return Clone(img)
|
||||||
|
}
|
||||||
|
|
||||||
percentage = math.Min(math.Max(percentage, -100), 100)
|
percentage = math.Min(math.Max(percentage, -100), 100)
|
||||||
multiplier := 1 + percentage/100
|
multiplier := 1 + percentage/100
|
||||||
|
|
||||||
@@ -76,6 +80,34 @@ func AdjustSaturation(img image.Image, percentage float64) *image.NRGBA {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdjustHue changes the hue of the image using the shift parameter (measured in degrees) and returns the adjusted image.
|
||||||
|
// The shift = 0 (or 360 / -360 / etc.) gives the original image.
|
||||||
|
// The shift = 180 (or -180) corresponds to a 180° degree rotation of the color wheel and thus gives the image with its hue inverted for each pixel.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// dstImage = imaging.AdjustHue(srcImage, 90) // Shift Hue by 90°.
|
||||||
|
// dstImage = imaging.AdjustHue(srcImage, -30) // Shift Hue by -30°.
|
||||||
|
//
|
||||||
|
func AdjustHue(img image.Image, shift float64) *image.NRGBA {
|
||||||
|
if math.Mod(shift, 360) == 0 {
|
||||||
|
return Clone(img)
|
||||||
|
}
|
||||||
|
|
||||||
|
summand := shift / 360
|
||||||
|
|
||||||
|
return AdjustFunc(img, func(c color.NRGBA) color.NRGBA {
|
||||||
|
h, s, l := rgbToHSL(c.R, c.G, c.B)
|
||||||
|
h += summand
|
||||||
|
h = math.Mod(h, 1)
|
||||||
|
//Adding 1 because Golang's Modulo function behaves differently to similar operators in most other languages.
|
||||||
|
if h < 0 {
|
||||||
|
h++
|
||||||
|
}
|
||||||
|
r, g, b := hslToRGB(h, s, l)
|
||||||
|
return color.NRGBA{r, g, b, c.A}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// AdjustContrast changes the contrast of the image using the percentage parameter and returns the adjusted image.
|
// AdjustContrast changes the contrast of the image using the percentage parameter and returns the adjusted image.
|
||||||
// The percentage must be in range (-100, 100). The percentage = 0 gives the original image.
|
// The percentage must be in range (-100, 100). The percentage = 0 gives the original image.
|
||||||
// The percentage = -100 gives solid gray image.
|
// The percentage = -100 gives solid gray image.
|
||||||
@@ -86,6 +118,10 @@ func AdjustSaturation(img image.Image, percentage float64) *image.NRGBA {
|
|||||||
// dstImage = imaging.AdjustContrast(srcImage, 20) // Increase image contrast by 20%.
|
// dstImage = imaging.AdjustContrast(srcImage, 20) // Increase image contrast by 20%.
|
||||||
//
|
//
|
||||||
func AdjustContrast(img image.Image, percentage float64) *image.NRGBA {
|
func AdjustContrast(img image.Image, percentage float64) *image.NRGBA {
|
||||||
|
if percentage == 0 {
|
||||||
|
return Clone(img)
|
||||||
|
}
|
||||||
|
|
||||||
percentage = math.Min(math.Max(percentage, -100.0), 100.0)
|
percentage = math.Min(math.Max(percentage, -100.0), 100.0)
|
||||||
lut := make([]uint8, 256)
|
lut := make([]uint8, 256)
|
||||||
|
|
||||||
@@ -114,6 +150,10 @@ func AdjustContrast(img image.Image, percentage float64) *image.NRGBA {
|
|||||||
// dstImage = imaging.AdjustBrightness(srcImage, 10) // Increase image brightness by 10%.
|
// dstImage = imaging.AdjustBrightness(srcImage, 10) // Increase image brightness by 10%.
|
||||||
//
|
//
|
||||||
func AdjustBrightness(img image.Image, percentage float64) *image.NRGBA {
|
func AdjustBrightness(img image.Image, percentage float64) *image.NRGBA {
|
||||||
|
if percentage == 0 {
|
||||||
|
return Clone(img)
|
||||||
|
}
|
||||||
|
|
||||||
percentage = math.Min(math.Max(percentage, -100.0), 100.0)
|
percentage = math.Min(math.Max(percentage, -100.0), 100.0)
|
||||||
lut := make([]uint8, 256)
|
lut := make([]uint8, 256)
|
||||||
|
|
||||||
@@ -134,6 +174,10 @@ func AdjustBrightness(img image.Image, percentage float64) *image.NRGBA {
|
|||||||
// dstImage = imaging.AdjustGamma(srcImage, 0.7)
|
// dstImage = imaging.AdjustGamma(srcImage, 0.7)
|
||||||
//
|
//
|
||||||
func AdjustGamma(img image.Image, gamma float64) *image.NRGBA {
|
func AdjustGamma(img image.Image, gamma float64) *image.NRGBA {
|
||||||
|
if gamma == 1 {
|
||||||
|
return Clone(img)
|
||||||
|
}
|
||||||
|
|
||||||
e := 1.0 / math.Max(gamma, 0.0001)
|
e := 1.0 / math.Max(gamma, 0.0001)
|
||||||
lut := make([]uint8, 256)
|
lut := make([]uint8, 256)
|
||||||
|
|
||||||
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
+29
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# License: GPLv3 Copyright: 2024, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def run(*args: str):
|
||||||
|
cp = subprocess.run(args)
|
||||||
|
if cp.returncode != 0:
|
||||||
|
raise SystemExit(cp.returncode)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
version = input('Enter the version to publish: ')
|
||||||
|
try:
|
||||||
|
ans = input(f'Publish version \033[91m{version}\033[m (y/n): ')
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
ans = 'n'
|
||||||
|
if ans.lower() != 'y':
|
||||||
|
return
|
||||||
|
os.environ['GITHUB_TOKEN'] = open(os.path.join(os.environ['PENV'], 'github-token')).read().strip()
|
||||||
|
run('git', 'tag', '-a', 'v' + version, '-m', f'version {version}')
|
||||||
|
run('git', 'push')
|
||||||
|
run('goreleaser', 'release')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Generated
Vendored
+6
-4
@@ -87,6 +87,10 @@ func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NR
|
|||||||
dstH = int(math.Max(1.0, math.Floor(tmpH+0.5)))
|
dstH = int(math.Max(1.0, math.Floor(tmpH+0.5)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if srcW == dstW && srcH == dstH {
|
||||||
|
return Clone(img)
|
||||||
|
}
|
||||||
|
|
||||||
if filter.Support <= 0 {
|
if filter.Support <= 0 {
|
||||||
// Nearest-neighbor special case.
|
// Nearest-neighbor special case.
|
||||||
return resizeNearest(img, dstW, dstH)
|
return resizeNearest(img, dstW, dstH)
|
||||||
@@ -98,10 +102,8 @@ func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NR
|
|||||||
if srcW != dstW {
|
if srcW != dstW {
|
||||||
return resizeHorizontal(img, dstW, filter)
|
return resizeHorizontal(img, dstW, filter)
|
||||||
}
|
}
|
||||||
if srcH != dstH {
|
return resizeVertical(img, dstH, filter)
|
||||||
return resizeVertical(img, dstH, filter)
|
|
||||||
}
|
|
||||||
return Clone(img)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func resizeHorizontal(img image.Image, width int, filter ResampleFilter) *image.NRGBA {
|
func resizeHorizontal(img image.Image, width int, filter ResampleFilter) *image.NRGBA {
|
||||||
Generated
Vendored
+1
-1
@@ -18,7 +18,7 @@ func newScanner(img image.Image) *scanner {
|
|||||||
h: img.Bounds().Dy(),
|
h: img.Bounds().Dy(),
|
||||||
}
|
}
|
||||||
if img, ok := img.(*image.Paletted); ok {
|
if img, ok := img.(*image.Paletted); ok {
|
||||||
s.palette = make([]color.NRGBA, len(img.Palette))
|
s.palette = make([]color.NRGBA, max(256, len(img.Palette)))
|
||||||
for i := 0; i < len(img.Palette); i++ {
|
for i := 0; i < len(img.Palette); i++ {
|
||||||
s.palette[i] = color.NRGBAModel.Convert(img.Palette[i]).(color.NRGBA)
|
s.palette[i] = color.NRGBAModel.Convert(img.Palette[i]).(color.NRGBA)
|
||||||
}
|
}
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
" Empty for the moment
|
||||||
|
|
||||||
Generated
Vendored
+8
@@ -96,6 +96,10 @@ func Crop(img image.Image, rect image.Rectangle) *image.NRGBA {
|
|||||||
if r.Empty() {
|
if r.Empty() {
|
||||||
return &image.NRGBA{}
|
return &image.NRGBA{}
|
||||||
}
|
}
|
||||||
|
if r.Eq(img.Bounds().Sub(img.Bounds().Min)) {
|
||||||
|
return Clone(img)
|
||||||
|
}
|
||||||
|
|
||||||
src := newScanner(img)
|
src := newScanner(img)
|
||||||
dst := image.NewNRGBA(image.Rect(0, 0, r.Dx(), r.Dy()))
|
dst := image.NewNRGBA(image.Rect(0, 0, r.Dx(), r.Dy()))
|
||||||
rowSize := r.Dx() * 4
|
rowSize := r.Dx() * 4
|
||||||
@@ -133,6 +137,10 @@ func Paste(background, img image.Image, pos image.Point) *image.NRGBA {
|
|||||||
if interRect.Empty() {
|
if interRect.Empty() {
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
|
if interRect.Eq(dst.Bounds()) {
|
||||||
|
return Clone(img)
|
||||||
|
}
|
||||||
|
|
||||||
src := newScanner(img)
|
src := newScanner(img)
|
||||||
parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) {
|
parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) {
|
||||||
for y := range ys {
|
for y := range ys {
|
||||||
Generated
Vendored
Generated
Vendored
+13
@@ -5,8 +5,17 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var maxProcs int64
|
||||||
|
|
||||||
|
// SetMaxProcs limits the number of concurrent processing goroutines to the given value.
|
||||||
|
// A value <= 0 clears the limit.
|
||||||
|
func SetMaxProcs(value int) {
|
||||||
|
atomic.StoreInt64(&maxProcs, int64(value))
|
||||||
|
}
|
||||||
|
|
||||||
// parallel processes the data in separate goroutines.
|
// parallel processes the data in separate goroutines.
|
||||||
func parallel(start, stop int, fn func(<-chan int)) {
|
func parallel(start, stop int, fn func(<-chan int)) {
|
||||||
count := stop - start
|
count := stop - start
|
||||||
@@ -15,6 +24,10 @@ func parallel(start, stop int, fn func(<-chan int)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
procs := runtime.GOMAXPROCS(0)
|
procs := runtime.GOMAXPROCS(0)
|
||||||
|
limit := int(atomic.LoadInt64(&maxProcs))
|
||||||
|
if procs > limit && limit > 0 {
|
||||||
|
procs = limit
|
||||||
|
}
|
||||||
if procs > count {
|
if procs > count {
|
||||||
procs = count
|
procs = count
|
||||||
}
|
}
|
||||||
Vendored
+3
-3
@@ -758,9 +758,6 @@ github.com/dgryski/go-rendezvous
|
|||||||
# github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
|
# github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/dhowden/tag
|
github.com/dhowden/tag
|
||||||
# github.com/disintegration/imaging v1.6.2
|
|
||||||
## explicit
|
|
||||||
github.com/disintegration/imaging
|
|
||||||
# github.com/dlclark/regexp2 v1.4.0
|
# github.com/dlclark/regexp2 v1.4.0
|
||||||
## explicit
|
## explicit
|
||||||
github.com/dlclark/regexp2
|
github.com/dlclark/regexp2
|
||||||
@@ -1256,6 +1253,9 @@ github.com/klauspost/compress/s2
|
|||||||
# github.com/klauspost/cpuid/v2 v2.2.6
|
# github.com/klauspost/cpuid/v2 v2.2.6
|
||||||
## explicit; go 1.15
|
## explicit; go 1.15
|
||||||
github.com/klauspost/cpuid/v2
|
github.com/klauspost/cpuid/v2
|
||||||
|
# github.com/kovidgoyal/imaging v1.6.3
|
||||||
|
## explicit; go 1.21
|
||||||
|
github.com/kovidgoyal/imaging
|
||||||
# github.com/leodido/go-urn v1.4.0
|
# github.com/leodido/go-urn v1.4.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/leodido/go-urn
|
github.com/leodido/go-urn
|
||||||
|
|||||||
Reference in New Issue
Block a user