Merge pull request #310 from guzba/master
3.0.1, minifyBy2 fix for non-even src dimens
|
@ -1,4 +1,4 @@
|
||||||
version = "3.0.0"
|
version = "3.0.1"
|
||||||
author = "Andre von Houck and Ryan Oldenburg"
|
author = "Andre von Houck and Ryan Oldenburg"
|
||||||
description = "Full-featured 2d graphics library for Nim."
|
description = "Full-featured 2d graphics library for Nim."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT"
|
||||||
srcDir = "src"
|
srcDir = "src"
|
||||||
|
|
||||||
requires "nim >= 1.4.0"
|
requires "nim >= 1.4.0"
|
||||||
requires "vmath >= 1.0.11"
|
requires "vmath >= 1.1.0"
|
||||||
requires "chroma >= 0.2.5"
|
requires "chroma >= 0.2.5"
|
||||||
requires "zippy >= 0.6.2"
|
requires "zippy >= 0.6.2"
|
||||||
requires "flatty >= 0.2.2"
|
requires "flatty >= 0.2.2"
|
||||||
|
|
|
@ -256,14 +256,24 @@ proc minifyBy2*(image: Image, power = 1): Image {.raises: [PixieError].} =
|
||||||
|
|
||||||
var src = image
|
var src = image
|
||||||
for _ in 1 .. power:
|
for _ in 1 .. power:
|
||||||
result = newImage(src.width div 2, src.height div 2)
|
# When minifying an image of odd size, round the result image size up
|
||||||
for y in 0 ..< result.height:
|
# so a 99 x 99 src image returns a 50 x 50 image.
|
||||||
|
let
|
||||||
|
srcWidthIsOdd = (src.width mod 2) != 0
|
||||||
|
srcHeightIsOdd = (src.height mod 2) != 0
|
||||||
|
resultEvenWidth = src.width div 2
|
||||||
|
resultEvenHeight = src.height div 2
|
||||||
|
result = newImage(
|
||||||
|
if srcWidthIsOdd: resultEvenWidth + 1 else: resultEvenWidth,
|
||||||
|
if srcHeightIsOdd: resultEvenHeight + 1 else: resultEvenHeight
|
||||||
|
)
|
||||||
|
for y in 0 ..< resultEvenHeight:
|
||||||
var x: int
|
var x: int
|
||||||
when defined(amd64) and not defined(pixieNoSimd):
|
when defined(amd64) and not defined(pixieNoSimd):
|
||||||
let
|
let
|
||||||
oddMask = mm_set1_epi16(cast[int16](0xff00))
|
oddMask = mm_set1_epi16(cast[int16](0xff00))
|
||||||
first32 = cast[M128i]([uint32.high, 0, 0, 0])
|
first32 = cast[M128i]([uint32.high, 0, 0, 0])
|
||||||
for _ in countup(0, result.width - 4, 2):
|
for _ in countup(0, resultEvenWidth - 4, 2):
|
||||||
let
|
let
|
||||||
top = mm_loadu_si128(src.data[src.dataIndex(x * 2, y * 2 + 0)].addr)
|
top = mm_loadu_si128(src.data[src.dataIndex(x * 2, y * 2 + 0)].addr)
|
||||||
btm = mm_loadu_si128(src.data[src.dataIndex(x * 2, y * 2 + 1)].addr)
|
btm = mm_loadu_si128(src.data[src.dataIndex(x * 2, y * 2 + 1)].addr)
|
||||||
|
@ -303,7 +313,7 @@ proc minifyBy2*(image: Image, power = 1): Image {.raises: [PixieError].} =
|
||||||
mm_storeu_si128(result.data[result.dataIndex(x, y)].addr, zeroTwo)
|
mm_storeu_si128(result.data[result.dataIndex(x, y)].addr, zeroTwo)
|
||||||
x += 2
|
x += 2
|
||||||
|
|
||||||
for x in x ..< result.width:
|
for x in x ..< resultEvenWidth:
|
||||||
let
|
let
|
||||||
a = src.getRgbaUnsafe(x * 2 + 0, y * 2 + 0)
|
a = src.getRgbaUnsafe(x * 2 + 0, y * 2 + 0)
|
||||||
b = src.getRgbaUnsafe(x * 2 + 1, y * 2 + 0)
|
b = src.getRgbaUnsafe(x * 2 + 1, y * 2 + 0)
|
||||||
|
@ -318,6 +328,32 @@ proc minifyBy2*(image: Image, power = 1): Image {.raises: [PixieError].} =
|
||||||
|
|
||||||
result.setRgbaUnsafe(x, y, rgba)
|
result.setRgbaUnsafe(x, y, rgba)
|
||||||
|
|
||||||
|
if srcWidthIsOdd:
|
||||||
|
let rgbx = mix(
|
||||||
|
src.getRgbaUnsafe(src.width - 1, y * 2 + 0),
|
||||||
|
src.getRgbaUnsafe(src.width - 1, y * 2 + 1),
|
||||||
|
0.5
|
||||||
|
) * 0.5
|
||||||
|
result.setRgbaUnsafe(result.width - 1, y, rgbx)
|
||||||
|
|
||||||
|
if srcHeightIsOdd:
|
||||||
|
let y = result.height - 1
|
||||||
|
|
||||||
|
for x in 0 ..< resultEvenWidth:
|
||||||
|
let rgbx = mix(
|
||||||
|
src.getRgbaUnsafe(x * 2 + 0, y),
|
||||||
|
src.getRgbaUnsafe(x * 2 + 1, y),
|
||||||
|
0.5
|
||||||
|
) * 0.5
|
||||||
|
result.setRgbaUnsafe(x, y, rgbx)
|
||||||
|
|
||||||
|
if srcWidthIsOdd:
|
||||||
|
result.setRgbaUnsafe(
|
||||||
|
result.width - 1,
|
||||||
|
result.height - 1,
|
||||||
|
src.getRgbaUnsafe(src.width - 1, src.height - 1) * 0.25
|
||||||
|
)
|
||||||
|
|
||||||
# Set src as this result for if we do another power
|
# Set src as this result for if we do another power
|
||||||
src = result
|
src = result
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ proc gaussianKernel*(radius: int): seq[uint16] {.raises: [].} =
|
||||||
for i, f in floats:
|
for i, f in floats:
|
||||||
result[i] = round(f * 255 * 256).uint16
|
result[i] = round(f * 255 * 256).uint16
|
||||||
|
|
||||||
proc applyOpacity*(color: ColorRGBX, opacity: float32): ColorRGBX {.raises: [].} =
|
proc `*`*(color: ColorRGBX, opacity: float32): ColorRGBX {.raises: [].} =
|
||||||
if opacity == 0:
|
if opacity == 0:
|
||||||
rgbx(0, 0, 0, 0)
|
rgbx(0, 0, 0, 0)
|
||||||
else:
|
else:
|
||||||
|
|
BIN
tests/images/diffs/minify_odd.png
Normal file
After Width: | Height: | Size: 326 B |
Before Width: | Height: | Size: 353 B After Width: | Height: | Size: 411 B |
Before Width: | Height: | Size: 408 B After Width: | Height: | Size: 479 B |
BIN
tests/images/masters/minify_odd.png
Normal file
After Width: | Height: | Size: 381 B |
Before Width: | Height: | Size: 194 B After Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 179 B |
BIN
tests/images/rendered/minify_odd.png
Normal file
After Width: | Height: | Size: 378 B |
|
@ -1,5 +1,13 @@
|
||||||
import pixie, strformat
|
import pixie, strformat
|
||||||
|
|
||||||
|
proc doDiff(rendered: Image, name: string) =
|
||||||
|
rendered.writeFile(&"tests/images/rendered/{name}.png")
|
||||||
|
let
|
||||||
|
master = readImage(&"tests/images/masters/{name}.png")
|
||||||
|
(diffScore, diffImage) = diff(master, rendered)
|
||||||
|
echo &"{name} score: {diffScore}"
|
||||||
|
diffImage.writeFile(&"tests/images/diffs/{name}.png")
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let
|
let
|
||||||
a = newImage(1000, 1000)
|
a = newImage(1000, 1000)
|
||||||
|
@ -128,14 +136,6 @@ block:
|
||||||
a.draw(b, translate(vec2(250, 250)) * scale(vec2(0.5, 0.5)))
|
a.draw(b, translate(vec2(250, 250)) * scale(vec2(0.5, 0.5)))
|
||||||
a.writeFile("tests/images/scaleHalf.png")
|
a.writeFile("tests/images/scaleHalf.png")
|
||||||
|
|
||||||
proc doDiff(rendered: Image, name: string) =
|
|
||||||
rendered.writeFile(&"tests/images/rendered/{name}.png")
|
|
||||||
let
|
|
||||||
master = readImage(&"tests/images/masters/{name}.png")
|
|
||||||
(diffScore, diffImage) = diff(master, rendered)
|
|
||||||
echo &"{name} score: {diffScore}"
|
|
||||||
diffImage.writeFile(&"tests/images/diffs/{name}.png")
|
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let
|
let
|
||||||
a = newImage(100, 100)
|
a = newImage(100, 100)
|
||||||
|
@ -249,3 +249,12 @@ block:
|
||||||
a.draw(b, m * translate(vec2(-40,-40)))
|
a.draw(b, m * translate(vec2(-40,-40)))
|
||||||
a.draw(b, m * translate(vec2(0,-40)))
|
a.draw(b, m * translate(vec2(0,-40)))
|
||||||
doDiff(a, "smooth12")
|
doDiff(a, "smooth12")
|
||||||
|
|
||||||
|
block:
|
||||||
|
let
|
||||||
|
a = newImage(100, 100)
|
||||||
|
b = newImage(99, 99)
|
||||||
|
a.fill(rgba(255, 255, 255, 255))
|
||||||
|
b.fill(rgba(0, 0, 0, 255))
|
||||||
|
a.draw(b, scale(vec2(0.5, 0.5)))
|
||||||
|
doDiff(a, "minify_odd")
|
||||||
|
|