Initial QSfera import
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package thumbnail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
_resolutionSeparator = "x"
|
||||
)
|
||||
|
||||
// ParseResolution returns an image.Rectangle representing the resolution given as a string
|
||||
func ParseResolution(s string) (image.Rectangle, error) {
|
||||
parts := strings.Split(s, _resolutionSeparator)
|
||||
if len(parts) != 2 {
|
||||
return image.Rectangle{}, fmt.Errorf("failed to parse resolution: %s. Expected format <width>x<height>", s)
|
||||
}
|
||||
width, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return image.Rectangle{}, fmt.Errorf("width: %s has an invalid value. Expected an integer", parts[0])
|
||||
}
|
||||
height, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return image.Rectangle{}, fmt.Errorf("height: %s has an invalid value. Expected an integer", parts[1])
|
||||
}
|
||||
return image.Rect(0, 0, width, height), nil
|
||||
}
|
||||
|
||||
// Resolutions is a list of image.Rectangle representing resolutions.
|
||||
type Resolutions []image.Rectangle
|
||||
|
||||
// ParseResolutions creates an instance of Resolutions from resolution strings.
|
||||
func ParseResolutions(strs []string) (Resolutions, error) {
|
||||
rs := make(Resolutions, 0, len(strs))
|
||||
for _, s := range strs {
|
||||
r, err := ParseResolution(s)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse resolutions")
|
||||
}
|
||||
rs = append(rs, r)
|
||||
}
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
// ClosestMatch returns the resolution which is closest to the provided resolution.
|
||||
// If there is no exact match the resolution will be the next higher one.
|
||||
// If the given resolution is bigger than all available resolutions the biggest available one is used.
|
||||
func (rs Resolutions) ClosestMatch(requested image.Rectangle, sourceSize image.Rectangle) image.Rectangle {
|
||||
isLandscape := sourceSize.Dx() > sourceSize.Dy()
|
||||
sourceLen := dimensionLength(sourceSize, isLandscape)
|
||||
requestedLen := dimensionLength(requested, isLandscape)
|
||||
isSourceSmaller := sourceLen < requestedLen
|
||||
|
||||
// We don't want to scale images up.
|
||||
if isSourceSmaller {
|
||||
return sourceSize
|
||||
}
|
||||
|
||||
if len(rs) == 0 {
|
||||
return requested
|
||||
}
|
||||
|
||||
var match image.Rectangle
|
||||
// Since we want to search for the smallest difference we start with the highest possible number
|
||||
minDiff := math.MaxInt32
|
||||
|
||||
for _, current := range rs {
|
||||
cLen := dimensionLength(current, isLandscape)
|
||||
diff := requestedLen - cLen
|
||||
if diff > 0 {
|
||||
// current is smaller
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert diff to positive value
|
||||
// Multiplying by -1 is safe since we aren't getting positive numbers here
|
||||
// because of the check above
|
||||
absDiff := diff * -1
|
||||
if absDiff < minDiff {
|
||||
minDiff = absDiff
|
||||
match = current
|
||||
}
|
||||
}
|
||||
|
||||
if (match == image.Rectangle{}) {
|
||||
match = rs[len(rs)-1]
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
func dimensionLength(rect image.Rectangle, isLandscape bool) int {
|
||||
if isLandscape {
|
||||
return rect.Dx()
|
||||
}
|
||||
return rect.Dy()
|
||||
}
|
||||
Reference in New Issue
Block a user