Closed demotomohiro closed 2 years ago
Yes that does cause some trouble sadly. I tries this out myself and here is what I ran into:
The image[x, y]
accessor is a safe way to access image data that returns rgbx(0, 0, 0, 0) if you attempt to read outside the bounds of the image.
We must check if image.inside(x, y)
first, not just assert as shown in your example. Further, asserts are not run in release so we'd need doAssert. But the point is to not crash and just get transparent black, so asserts are not an option.
Since we need to branch and cannot guarantee we have an addressable heap memory thing to return a pointer to (var type), we cannot return a var ColorRGBX.
If you want to swap I suggest using swap image.data[image.dataIndex(x, y)], image.data[image.dataIndex(x, y)]
and accept your program will crash if you attempt to swap out of bounds.
Thank you for your reply.
So image[x, y]
works differently from seq[T]
when it got out of bound coordinate.
myseq[idx]
always raise exception when idx
is out of bound unless -d:danger
is set.
But image[x, y]
returns transparent black, and image[x, y] = v
does nothing instead of raising an exception.
And there is no way to image[x, y]
returns var ColorRGBX
safely in that case.
Adding new procedure that raises exception in the same way as myseq[idx]
allows returning var ColorRGBX
safely.
And I can add it to my code.
import std/strformat
import pixie
proc `{}`(image: var Image, x, y: int): var ColorRGBX {.inline.} =
## Accessing any pixels outside the bounds of the image is error
when not defined(danger):
if not image.inside(x, y):
raise newException(IndexDefect, &"({x}, {y}) not in range ({image.width - 1}, {image.height - 1})")
image.unsafe[x, y]
var image = newImage(10, 10)
image[0, 0] = rgba(0, 255, 255, 255)
image[0, 1] = rgba(255, 255, 0, 255)
swap(image{0, 0}, image{0, 1})
doAssert image[0, 0] == rgba(255, 255, 0, 255)
doAssert image[0, 1] == rgba(0, 255, 255, 255)
doAssertRaises(IndexDefect):
echo image{11, 0}
This is sort of true. You should be careful about the exception from seq[] though / IndexDefect. They are not considered catchable.
IndexDefect is a Defect and Defects are "Abstract base class for all exceptions that Nim's runtime raises but that are strictly uncatchable as they can also be mapped to a quit / trap / exit operation."
So counting on seq[] access exceptions to manage your control flow (using try catch) could be troublesome.
I have another suggestion and change we can make here:
It should work to use:
swap image.unsafe[x, y], image.unsafe[x + 1,y]
To enable this we can make image.unsafe[x, y] return a var ColorRGBX since it will segfault if you ask for something out of bounds.
I guess as templates they already work / the var or not part of the return doesnt matter.
When we use seq[T]
, we avoid accessing it with out of bounds index.
But when we accidentally access it with out of bound index, it is a bug need to be fixed.
If seq[T]
returns default(T)
instead of raising IndexDefect
, it is hard to find the bug.
There are cases you want image[x, y]
returns transparent black when x
and/or y
are outside the bounds of the image.
But when you write code so that x
and y
are always inside the bound of the image, bound check helps to find the bug.
swap(image.unsafe[0, 0], image.unsafe[0, 1])
works.
But there is only bound check in Image.data.
It doesn't check for x >= image.width
.
import std/strformat
import pixie
var image = newImage(10, 10)
image[0, 0] = rgba(0, 255, 255, 255)
image[0, 1] = rgba(255, 255, 0, 255)
swap(image.unsafe[0, 0], image.unsafe[0, 1])
doAssert image[0, 0] == rgba(255, 255, 0, 255)
doAssert image[0, 1] == rgba(0, 255, 255, 255)
doAssertRaises(IndexDefect):
echo image.unsafe[10, 10]
# This assert fails because IndexDefect is not raised.
# doAssertRaises(IndexDefect):
# echo image.unsafe[11, 0]
Compiling following code is compile error:
Error message:
Adding
proc `[]`(image: var Image, x, y: int): var ColorRGBX
allows passingimage[x, y]
to var parameters. Following code compiles and runs:Another workaround is copy
image[x, y]
to temporal variable, pass it to var parameter and copy back toimage[x, y]
.Can adding
proc `[]`(image: var Image, x, y: int): var ColorRGBX
to pixie/images.nim cause any problems?