Reputation: 151
i am trying to fetch a series of pixel colors at different offsets using this function,
_getColor(ByteData rgbaImageData, int x, int y) {
var byteOffset = x * 4 + y * imageWidth * 4;
var r = rgbaImageData.getUint8(byteOffset);
var g = rgbaImageData.getUint8(byteOffset + 1);
var b = rgbaImageData.getUint8(byteOffset + 2);
var a = rgbaImageData.getUint8(byteOffset + 3);
return Color.fromARGB(a, r, g, b);
}
but the it is taking long time to execute, any solution for this?
Upvotes: 3
Views: 717
Reputation: 71693
It shouldn't be that slow, but you could reduce the number of reads:
Color getColor(ByteData rgbaData, int x, int y) {
var byteOffset = (x + y * imageWidth) * 4;
var rgba = rgbaImageData.getUint32(byteOffset);
return Color(argb);
}
That only performs one (potentially unaligned) read per color, and doesn't have to recombine the bytes.
Alternatively, you can change the type of your typed data to Uint8List
:
var bytes = Uint8List.view(
rgbaImageData.buffer, rgbaImageData.offsetInBytes, rgbaImageData.lengthInBytes);
...
var color = _getColor(bytes, x, y);
...
Color _getColor(Uint8List bytes, int x, int y) {
var byteOffset = (x + y * imageWith) * 4;
var r = bytes[byteOffset];
var g = bytes[byteOffset + 1];
var b = bytes[byteOffset + 2];
var a = bytes[byteOffset + 3];
return Color.fromARGB(a, r, g, b);
}
This might be more efficient than the original, but likely not a lot.
You can even interpret the original buffer as a Uint32List
, but that only works if offsetInBytes
is a multiple of four, since a Uint32List
requires data to be 32-bit aligned (which is also why it maybe be slightly more efficient than ByteData
). If offsetInBytes
is always zero anyway, this may work for you too.
Example:
var words = Uint32List.view(
rgbaImageData.buffer,
rgbaImageData.offsetInBytes,
rgbaImageData.lengthInBytes ~/ Uint32List.bytesPerElement);
...
var color = _getColor(words, x, y);
...
Color _getColor(Uint32List words, int x, int y) {
var offset = x + y * imageWith;
return Color(words[offset]);
}
Another reason this may be slow is that you are allocating a lots of Color
objects if you traverse the entire image. If the image doesn't have that many different colors, you can choose to reuse existing color objects. If the image has a lot of different colors, caching them may just cause even more memory churn.
Example:
Map<int, Color> _colorCache = {};
const int _maxCacheSize = 1024;
Color createColor(int argb) {
var result = _colorCache[argb];
if (result != null) return result;
result = Color(argb);
if (_colorCache.length == _maxCacheSize) {
_colorCache.remove(_colorCache.keys.first);
}
_colorCache[argb] = result;
return result;
}
then use createColor(argb)
instead of Color(argb)
. Again, if your image has lots of different varying colors, and no large patches of the same color, then this is most likely just overhead.
Upvotes: 3