www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - color library

reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
I've been working on a submission for a std.color library.
I'm starting to become happy with it. I'd like to get API
criticism/review, such that if there are no more major changes, then
I'll start the fine-details and documenting.

https://github.com/D-Programming-Language/phobos/pull/2845
Jun 21 2015
parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 21/06/2015 9:11 p.m., Manu via Digitalmars-d wrote:
 I've been working on a submission for a std.color library.
 I'm starting to become happy with it. I'd like to get API
 criticism/review, such that if there are no more major changes, then
 I'll start the fine-details and documenting.

 https://github.com/D-Programming-Language/phobos/pull/2845
Following PR comments. Yeah I'm serious about you (Manu) watching me write a image library using it tonight. I've had quite a bit of success live streaming and it would work well for this and not just for publicizing D. Generally it makes you act out your emotions more. Making them far more visible. Usability testing and emotions being visible are quite useful for whoever is doing the testing. Just a thought.
Jun 21 2015
parent reply "Rikki Cattermole" <alphaglosined gmail.com> writes:
On Sunday, 21 June 2015 at 10:10:14 UTC, Rikki Cattermole wrote:
 On 21/06/2015 9:11 p.m., Manu via Digitalmars-d wrote:
 I've been working on a submission for a std.color library.
 I'm starting to become happy with it. I'd like to get API
 criticism/review, such that if there are no more major 
 changes, then
 I'll start the fine-details and documenting.

 https://github.com/D-Programming-Language/phobos/pull/2845
Following PR comments. Yeah I'm serious about you (Manu) watching me write a image library using it tonight. I've had quite a bit of success live streaming and it would work well for this and not just for publicizing D. Generally it makes you act out your emotions more. Making them far more visible. Usability testing and emotions being visible are quite useful for whoever is doing the testing. Just a thought.
I did end up streaming, although Manu did not make it. Had pretty good turn out though! Had quite a lot of questions about D code. Attributes and even comments (introduced DDOC). Comments before code. Here is what I learnt. - Image storage is not the same as the file format storage - Optimisations on the storage type are pretty easy - The only thing that cannot be nogc is constructors + file parsers - Can we make GCAllocator (or what ever its name is) which Andrei is working on, you know, nogc? I know I know, seems odd. But it would be _nice_ to make file parsers nogc. That reminds me about other allocators? It just seems you know, a good idea here. - The state of the color api is fine. As long as I can convert easily and access the values. Manu there is nothing so far which says ewww bad job! But really would be nice to see some actual code usage such as flipHorizontal and friends. Would be nice to see what happens with them. Especially there optimised versions. Okay there is one thing (next point), a function to determine if during conversion it 'leaks' information aka RGBA8 to RGB8 would. But not RGB8 to RGBA8. - It's not hard to make an image storage type that wraps another so as long as you know what color type you need to be able to use, it can auto convert to whatever you want. Oh and look ma no allocation! - There may be only a few image storage types implemented at _all_. Like I said previously image storage type != image file format. Struct + alias this works wonders here! I'm genuinely quite excited by this. I think it could very well be a winner. It's very prone to no allocations and highly optimisable. Manu you've done a great job so far. I can't fault you on it. I can only suggest one addition. Which is pretty amazing. Considering I haven't got to the point with this, where it is actually needed. Also I can't stress this enough. Image storage type must and SHOULD be a different type to the file format struct. The file format struct should operate on the generic type. Which uses the color definition. Anyway here is the code I wrote during the stream: ```D import std.stdio; import std.experimental.color; import std.traits : ReturnType; import std.typecons : tuple; void main() { writeln("Edit source/app.d to start your project."); } /* * What does this solve? * - A general definition, get + set + width + height * - Memory allocation strategies * - File format support * - Range support * - Optimisation support per image storage for mutating functions e.g. flip * - Offset for image support * - General image storage wrapper * - Auto conversion of colors * - Adds offset support if not supported by original image storage type * - No allocating except in constructors! * - Similar to std.ranges in concept */ /* * Image definitions */ interface IImage(COLOR) { property { size_t width() nogc nothrow; size_t height() nogc nothrow; void* storage() nogc nothrow; } COLOR pixelAt(size_t x, size_t y) nogc; void pixelStoreAt(size_t x, size_t y, COLOR value) nogc; // COLOR opIndex(size_t x, size_t y) // void opIndexAssign(COLOR value, size_t x, size_t y) } // adds pixel offset capabilities to an image, useful for small images/embedded interface IImagePixelOffset(COLOR) : IImage!COLOR { property { size_t count() nogc nothrow; } COLOR pixelAtOffset(size_t offset) nogc; void pixelStoreAtOffset(size_t offset, COLOR value) nogc; // COLOR opIndex(size_t offset) // void opIndexAssign(COLOR value, size_t offset) } /* * Traits for images */ bool isAnImage(T)() pure { static if (__traits(hasMember, T, "pixelAt")) { static if (!isColor!(ReturnType!(T.pixelAt))) return false; } static if (is(T == class) || is(T == struct)) { return __traits(hasMember, T, "width") && __traits(hasMember, T, "height") && __traits(hasMember, T, "pixelStoreAt") && __traits(hasMember, T, "storage"); } else { return false; } } bool supportsPixelOffset(T)() pure { static if (!isAnImage!T) return false; static if (__traits(hasMember, T, "pixelAtOffset")) { static if (!is(ReturnType!(T.pixelAt) == ReturnType!(T.pixelAtOffset))) return false; } static if (is(T == class) || is(T == struct)) { return __traits(hasMember, T, "count") && __traits(hasMember, T, "pixelStoreAtOffset"); } else { return false; } } /* * Some dummy images with different storage types + support for offset */ final class DummyImage(COLOR) { private { COLOR[][] data; } this(size_t width, size_t height, COLOR init = COLOR.init) { data.length = width; foreach(ref datem; data) { datem.length = height; datem[0 .. height] = init; } } property { size_t width() nogc nothrow { return data.length; } size_t height() nogc nothrow in { assert(width > 0); } body { return data[0].length; } void* storage() nogc nothrow { return cast(void*)data.ptr; } } COLOR pixelAt(size_t x, size_t y) nogc in { assert(x < data.length); assert(y < data[0].length); } body { return data[x][y]; } void pixelStoreAt(size_t x, size_t y, COLOR value) nogc in { assert(x < data.length); assert(y < data[0].length); } body { data[x][y] = value; } } static assert(isAnImage!(DummyImage!RGB8)); static assert(!supportsPixelOffset!(DummyImage!RGB8)); final class DummyImage2(COLOR) { private { COLOR[][] data; } this(size_t width, size_t height, COLOR init) in { assert(width > 0); assert(height > 0); } body { data.length = width; foreach(ref datem; data) { datem.length = height; datem[0 .. height] = init; } } property { size_t width() nogc nothrow { return data.length; } size_t height() nogc nothrow { return data[0].length; } size_t count() nogc nothrow { return width * height; } void* storage() nogc nothrow { return cast(void*)data.ptr; } } COLOR pixelAtOffset(size_t offset) nogc { // width == 2 // height == 3 // offset == 3 // x = 1 // y = 0 return pixelAt(offset % height, offset / (height + 1)); } COLOR pixelAt(size_t x, size_t y) nogc in { assert(x < data.length); assert(y < data[0].length); } body { return data[x][y]; } void pixelStoreAt(size_t x, size_t y, COLOR value) nogc in { assert(x < data.length); assert(y < data[0].length); } body { data[x][y] = value; } void pixelStoreAtOffset(size_t offset, COLOR value) nogc { pixelStoreAt(offset % height, offset / (height + 1), value); } } static assert(isAnImage!(DummyImage2!RGB8)); static assert(supportsPixelOffset!(DummyImage2!RGB8)); final class DummyImage3(COLOR, size_t width_, size_t height_) { private { COLOR[height_][width_] data; } this(COLOR init) { foreach(ref datem; data) { datem[0 .. height_] = init; } } property { size_t width() nogc nothrow { return width_; } size_t height() nogc nothrow { return height_; } void* storage() nogc nothrow { return cast(void*)data.ptr; } } COLOR pixelAt(size_t x, size_t y) nogc in { assert(x < width_); assert(y < height_); } body { return data[x][y]; } } final class DummyImage4(COLOR, size_t width_, size_t height_) { private { COLOR[width_ * height_] data; } this(COLOR init) { datem[0 .. width_ * height_] = init; } property { size_t width() nogc nothrow { return width_; } size_t height() nogc nothrow { return height_; } void* storage() nogc nothrow { return cast(void*)data.ptr; } } COLOR pixelAt(size_t x, size_t y) nogc in { assert(x < width_); assert(y < height_); } body { return data[(height_ * x) + y]; } void pixelStoreAt(size_t x, size_t y, COLOR value) nogc in { assert(x < width_); assert(y < height_); } body { data[(height_ * x) + y] = value; } } /* * Useful code */ // An image type that wraps others // Auto converts to specified type struct ImageOperable(COLOR) { disable this(); this(T)(T from) nogc if (isAnImage!T) in { static if (is(T == class)) assert(from !is null); } body { width = &from.width; height = &from.height; storage = &from.storage; static if (is(T == struct)) origin_ = &from; else origin_ = cast(void*)from; auto tpixelAt = &from.pixelAt; pixelAt_ = &tpixelAt; pixelAt = &pixelAtCompatFunc!(ReturnType!(T.pixelAt)); auto tpixelStoreAt = &pixelStoreAt; pixelStoreAt_ = &tpixelStoreAt; pixelStoreAt = &pixelStoreAtCompatFunc!(ReturnType!(T.pixelAt)); static if (supportsPixelOffset!T) { count = &from.count; auto tpixelAtOffset = &from.pixelAtOffset; pixelAtOffset_ = &tpixelAtOffset; pixelAtOffset = &pixelAtOffsetCompatFunc!(ReturnType!(T.pixelAt)); auto tpixelStoreAtOffset = &pixelStoreAtOffset; pixelStoreAtOffset_ = &tpixelStoreAt; pixelStoreAtOffset = &pixelStoreAtOffsetCompatFunc!(ReturnType!(T.pixelAt)); } else { count = &countNotSupported; pixelAtOffset = &pixelAtOffsetNotSupported; pixelStoreAtOffset = &pixelStoreAtOffsetNotSupported; } } property { size_t delegate() nogc nothrow width; size_t delegate() nogc nothrow height; size_t delegate() nogc nothrow count; void* delegate() nogc nothrow storage; void* original() nogc nothrow { return origin_; } } COLOR delegate(size_t x, size_t y) nogc pixelAt; void delegate(size_t x, size_t y, COLOR value) nogc pixelStoreAt; COLOR delegate(size_t offset) nogc pixelAtOffset; void delegate(size_t offset, COLOR value) nogc pixelStoreAtOffset; private { void* origin_; void* pixelAt_; void* pixelStoreAt_; void* pixelAtOffset_; void* pixelStoreAtOffset_; COLOR pixelAtCompatFunc(FROM)(size_t x, size_t y) nogc { auto del = *cast(FROM delegate(size_t x, size_t y) nogc*) pixelAt_; static if (is(FROM == COLOR)) { return del(x, y); } else { return convertColor!COLOR(del(x, y)); } } void pixelStoreAtCompatFunc(FROM)(size_t x, size_t y, COLOR value) nogc { auto del = *cast(void delegate(size_t x, size_t y, FROM value) nogc*) pixelStoreAt_; static if (is(FROM == COLOR)) { del(x, y, value); } else { del(x, y, convertColor!FROM(value)); } } COLOR pixelAtOffsetCompatFunc(FROM)(size_t offset) nogc { auto del = *cast(FROM delegate(size_t offset) nogc*) pixelAtOffset_; static if (is(FROM == COLOR)) { return del(offset); } else { return convertColor!COLOR(del(offset)); } } void pixelStoreAtOffsetCompatFunc(FROM)(size_t offset, COLOR value) nogc { auto del = *cast(void delegate(size_t offset, FROM value) nogc*) pixelStoreAtOffset_; static if (is(FROM == COLOR)) { del(offset, value); } else { del(offset, convertColor!FROM(value)); } } size_t countNotSupported() nogc nothrow { return width() * height(); } COLOR pixelAtOffsetNotSupported(size_t offset) nogc { return pixelAt(offset % height(), offset / (height() + 1)); } void pixelStoreAtOffsetNotSupported(size_t offset, COLOR value) nogc { pixelStoreAt(offset % height(), offset / (height() + 1), value); } } } // Constructs an input range over an image // For every pixel get x + y and the color value // Scan line version of this? auto rangeOf(IMAGE)(IMAGE from) nogc nothrow if (isAnImage!IMAGE) { struct RangeOf(IMAGE) { private { IMAGE input; size_t offsetX; size_t offsetY; } property { auto front() nogc { return tuple!("x", "y", "value")(offsetX, offsetY, input.pixelAt(offsetX, offsetY)); } bool empty() nogc nothrow { return offsetX == 0 && offsetY == input.height(); } } auto save() nogc nothrow { return RangeOf!IMAGE(input, offsetX, offsetY); } void popFront() nogc nothrow { if (offsetX == input.width() - 1) { offsetY++; offsetX = 0; } else { offsetX++; } } } return RangeOf!IMAGE(from); } /* * Some random thoughts on image formats */ struct ImageFormatPNG(COLOR) { ImageOperable!COLOR imageStorage; alias imageStorage this; string comment; } struct GCAllocator {} // ImageStorage is the image storage e.g. DummyImage // Image storage type != image format common misconception in implementations ImageFormatPNG!COLOR readPNG(ImageStorage)(ubyte[] file) { return readPNG!(ImageStorage)(file, GCAllocator()); } ImageFormatPNG!COLOR readPNG(ImageStorage, ALLOCATOR)(ubyte[] file, ALLOCATOR allocatorInstance) { alias COLOR = ReturnType!(ImageStorage.pixelAt); assert(0); } /* * Optimisation random thoughts */ void flipHorizontal(IMAGE)(IMAGE image, size_t maxRecursion = size_t.max) if (isAnImage!IMAGE) { doFrom(image); size_t recursionDone; void doFrom(IMAGE2)(IMAGE2 image2) { if (ImageOperable actualImage = cast(ImageOperable)image2 && recursionDone < maxRecursion) { alias COLOR = ReturnType!(typeof(actualImage).pixelAt); // unknown type irk doFrom(actualImage.actual); recursionDone++; } else if (DummyImage actualImage = cast(DummyImage)image2) { alias COLOR = ReturnType!(typeof(actualImage).pixelAt); // do something with actual.storage! } else { alias actualImage = image; alias COLOR = ReturnType!(typeof(actualImage).pixelAt); // do some generic algo using width, height, pixelAt and pixelStoreAt } } } /* * Unittests */ unittest { ImageOperable!RGB8 workaround = void; workaround = ImageOperable!(RGB8)(new DummyImage!RGB8(8, 3)); } unittest { ImageOperable!RGBA8 workaround = void; workaround = ImageOperable!(RGBA8)(new DummyImage!RGB8(8, 3)); } unittest { ImageOperable!RGBA8 workaround = void; workaround = ImageOperable!(RGBA8)(new DummyImage!RGB8(8, 3, RGB8(77, 82, 31))); size_t count = workaround.countNotSupported(); } unittest { foreach(pixel; new DummyImage!RGB8(2, 2, RGB8(82, 32, 11)).rangeOf) { assert(pixel.value == RGB8(82, 32, 11)); } auto aRange = new DummyImage!RGB8(2, 2, RGB8(82, 32, 11)).rangeOf; auto pixel = aRange.front; assert(pixel.x == 0); assert(pixel.y == 0); aRange.popFront; auto anotherRange = aRange.save(); pixel = aRange.front; assert(aRange.front == anotherRange.front); aRange.popFront; assert(anotherRange.front == pixel); } ```
Jun 21 2015
parent reply "Andrea Fontana" <nospam example.com> writes:
On Sunday, 21 June 2015 at 15:42:39 UTC, Rikki Cattermole wrote:
 interface IImage(COLOR) {
      property {
         size_t width()  nogc nothrow;
         size_t height()  nogc nothrow;
         void* storage()  nogc nothrow;
     }

     COLOR pixelAt(size_t x, size_t y)  nogc;
     void pixelStoreAt(size_t x, size_t y, COLOR value)  nogc;

     // COLOR opIndex(size_t x, size_t y)
     // void opIndexAssign(COLOR value, size_t x, size_t y)
 }
What about alpha? I don't see it on "color" or "IImage". Anyway I always hope to have something like antigrain (heavily template based library for c++, really really fast!), implemented in D. Maybe you should check it for some ideas.
Jun 22 2015
next sibling parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 22/06/2015 7:55 p.m., Andrea Fontana wrote:
 On Sunday, 21 June 2015 at 15:42:39 UTC, Rikki Cattermole wrote:
 interface IImage(COLOR) {
      property {
         size_t width()  nogc nothrow;
         size_t height()  nogc nothrow;
         void* storage()  nogc nothrow;
     }

     COLOR pixelAt(size_t x, size_t y)  nogc;
     void pixelStoreAt(size_t x, size_t y, COLOR value)  nogc;

     // COLOR opIndex(size_t x, size_t y)
     // void opIndexAssign(COLOR value, size_t x, size_t y)
 }
What about alpha? I don't see it on "color" or "IImage". Anyway I always hope to have something like antigrain (heavily template based library for c++, really really fast!), implemented in D. Maybe you should check it for some ideas.
Why would IImage support alpha? Shouldn't that be on the color? If so, the PR does support it see RGBA8 and friends. I just had a look at antigrain. It really is beyond this code. Well and truly out of scope.
Jun 22 2015
next sibling parent reply "Andrea Fontana" <nospam example.com> writes:
On Monday, 22 June 2015 at 08:08:42 UTC, Rikki Cattermole wrote:
 Why would IImage support alpha? Shouldn't that be on the color?
 If so, the PR does support it see RGBA8 and friends.
I said "on color or IImage". Anyway transparency is a property (mask) of an image ("material") rather than of the color itself. A color has no transparency, there's no transparency on gamut. It doesn't make sense for a color: transparency is used only when you add an image over another in order to sum the *colors* of two pixels. They used to pack alpha informations with other pixel infos (color) just for simplicity and to have a convenient way to store info inside a file, I guess.
 I just had a look at antigrain. It really is beyond this code. 
 Well and truly out of scope.
I mean it would be useful to grab some ideas from it. And that it would really wonderful to have something like this. However I think it is useful to build the library and interfaces thinking also to possible future developments. Andrea
Jun 22 2015
next sibling parent "Kagamin" <spam here.lot> writes:
On Monday, 22 June 2015 at 08:45:38 UTC, Andrea Fontana wrote:
 I said "on color or IImage". Anyway transparency is a property 
 (mask) of an image ("material") rather than of the color itself.
That would be a pair of images: Image!RGB8, Image!A8.
Jun 22 2015
prev sibling next sibling parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 22/06/2015 8:45 p.m., Andrea Fontana wrote:
 On Monday, 22 June 2015 at 08:08:42 UTC, Rikki Cattermole wrote:
 Why would IImage support alpha? Shouldn't that be on the color?
 If so, the PR does support it see RGBA8 and friends.
I said "on color or IImage". Anyway transparency is a property (mask) of an image ("material") rather than of the color itself. A color has no transparency, there's no transparency on gamut. It doesn't make sense for a color: transparency is used only when you add an image over another in order to sum the *colors* of two pixels. They used to pack alpha informations with other pixel infos (color) just for simplicity and to have a convenient way to store info inside a file, I guess.
 I just had a look at antigrain. It really is beyond this code. Well
 and truly out of scope.
I mean it would be useful to grab some ideas from it. And that it would really wonderful to have something like this. However I think it is useful to build the library and interfaces thinking also to possible future developments. Andrea
Humm, I can add it as an optional part of the interface like pixel offset. Maybe. But it does feel a little less like other libraries out there. The main reason I'm put off of antigrain is it feels a little too much unwieldy to me. But of course, I can't dismiss your guys suggestions so of course I'll dig more deeper into it! Even if I do drag my heels a little bit.
Jun 22 2015
parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
Hey cool. Glad to hear you had no problems.
Sorry, I missed it. I had an early night last night (sunday night >_<)
.. Are there recordings to review?

It's an interesting idea; knowing if a colour is convertible to some
other colour without loss... it sounds like it leads to implicit
conversion, but I don't think we want that here.
I'll think on how to do it. It's not really trivial.

On 22 June 2015 at 18:55, Rikki Cattermole via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 22/06/2015 8:45 p.m., Andrea Fontana wrote:
 On Monday, 22 June 2015 at 08:08:42 UTC, Rikki Cattermole wrote:
 Why would IImage support alpha? Shouldn't that be on the color?
 If so, the PR does support it see RGBA8 and friends.
I said "on color or IImage". Anyway transparency is a property (mask) of an image ("material") rather than of the color itself. A color has no transparency, there's no transparency on gamut. It doesn't make sense for a color: transparency is used only when you add an image over another in order to sum the *colors* of two pixels. They used to pack alpha informations with other pixel infos (color) just for simplicity and to have a convenient way to store info inside a file, I guess.
 I just had a look at antigrain. It really is beyond this code. Well
 and truly out of scope.
I mean it would be useful to grab some ideas from it. And that it would really wonderful to have something like this. However I think it is useful to build the library and interfaces thinking also to possible future developments. Andrea
Humm, I can add it as an optional part of the interface like pixel offset. Maybe. But it does feel a little less like other libraries out there. The main reason I'm put off of antigrain is it feels a little too much unwieldy to me. But of course, I can't dismiss your guys suggestions so of course I'll dig more deeper into it! Even if I do drag my heels a little bit.
Jun 22 2015
parent Rikki Cattermole <alphaglosined gmail.com> writes:
On 22/06/2015 9:11 p.m., Manu via Digitalmars-d wrote:
 Hey cool. Glad to hear you had no problems.
 Sorry, I missed it. I had an early night last night (sunday night >_<)
 .. Are there recordings to review?
There is indeed! I'll be streaming again tonight FYI.
 It's an interesting idea; knowing if a colour is convertible to some
 other colour without loss... it sounds like it leads to implicit
 conversion, but I don't think we want that here.
 I'll think on how to do it. It's not really trivial.
It shouldn't be implicit. Never implicit. Always must be asked for. I just want functions to tell me if it is loosing or gaining precision in the conversion. That way it can be e.g. logged.
 On 22 June 2015 at 18:55, Rikki Cattermole via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 22/06/2015 8:45 p.m., Andrea Fontana wrote:
 On Monday, 22 June 2015 at 08:08:42 UTC, Rikki Cattermole wrote:
 Why would IImage support alpha? Shouldn't that be on the color?
 If so, the PR does support it see RGBA8 and friends.
I said "on color or IImage". Anyway transparency is a property (mask) of an image ("material") rather than of the color itself. A color has no transparency, there's no transparency on gamut. It doesn't make sense for a color: transparency is used only when you add an image over another in order to sum the *colors* of two pixels. They used to pack alpha informations with other pixel infos (color) just for simplicity and to have a convenient way to store info inside a file, I guess.
 I just had a look at antigrain. It really is beyond this code. Well
 and truly out of scope.
I mean it would be useful to grab some ideas from it. And that it would really wonderful to have something like this. However I think it is useful to build the library and interfaces thinking also to possible future developments. Andrea
Humm, I can add it as an optional part of the interface like pixel offset. Maybe. But it does feel a little less like other libraries out there. The main reason I'm put off of antigrain is it feels a little too much unwieldy to me. But of course, I can't dismiss your guys suggestions so of course I'll dig more deeper into it! Even if I do drag my heels a little bit.
Jun 22 2015
prev sibling next sibling parent "Tofu Ninja" <emmons0 purdue.edu> writes:
On Monday, 22 June 2015 at 08:45:38 UTC, Andrea Fontana wrote:
 On Monday, 22 June 2015 at 08:08:42 UTC, Rikki Cattermole wrote:
 I said "on color or IImage". Anyway transparency is a property 
 (mask) of an image ("material") rather than of the color 
 itself. A color has no transparency, there's no transparency on 
 gamut. It doesn't make sense for a color: transparency is used 
 only when you add an image over another in order to sum the 
 *colors* of two pixels. They used to pack alpha informations 
 with other pixel infos (color) just for simplicity and to have 
 a convenient way to store info inside a file, I guess.
I think alpha being part of the color make perfect sense in many contexts, seems kinda silly to try and separate them...
Jun 22 2015
prev sibling parent reply "Kagamin" <spam here.lot> writes:
On Monday, 22 June 2015 at 08:45:38 UTC, Andrea Fontana wrote:
 They used to pack alpha informations with other pixel infos 
 (color) just for simplicity and to have a convenient way to 
 store info inside a file, I guess.
Separate mask has an advantage of lower memory consumption: it can have 1-bit depth. It was important in 90s when you didn't have lots of RAM and HDD and didn't need transparency deeper than 1 bit, masks were used to only outline a crop region, which worked with RLE compression well further decreasing mask size, so it made no sense to waste space on 8-bit alpha channel.
Jun 22 2015
parent Rikki Cattermole <alphaglosined gmail.com> writes:
On 22/06/2015 9:15 p.m., Kagamin wrote:
 On Monday, 22 June 2015 at 08:45:38 UTC, Andrea Fontana wrote:
 They used to pack alpha informations with other pixel infos (color)
 just for simplicity and to have a convenient way to store info inside
 a file, I guess.
Separate mask has an advantage of lower memory consumption: it can have 1-bit depth. It was important in 90s when you didn't have lots of RAM and HDD and didn't need transparency deeper than 1 bit, masks were used to only outline a crop region, which worked with RLE compression well further decreasing mask size, so it made no sense to waste space on 8-bit alpha channel.
Thank you. That use case does make sense. I think I might add it as an optional feature anyway. For e.g. embedded devices. The mutation algorithms can reasonably easily handle this specific case in image storage.
Jun 22 2015
prev sibling parent "Kagamin" <spam here.lot> writes:
On Monday, 22 June 2015 at 08:08:42 UTC, Rikki Cattermole wrote:
 I just had a look at antigrain. It really is beyond this code. 
 Well and truly out of scope.
I thought the color module is the first step to write AGG. Think of it as sort of std.graphics.algorithm.
Jun 22 2015
prev sibling parent reply "Mike" <none none.com> writes:
On Monday, 22 June 2015 at 07:55:16 UTC, Andrea Fontana wrote:

 Anyway I always hope to have something like antigrain (heavily 
 template based library for c++, really really fast!), 
 implemented in D. Maybe you should check it for some ideas.
I agree, AGG (Anti-Grain Geometry) is an excellent model to follow, specifically for D. I've been using it in embedded systems running at 168MHz with less than 4MB of RAM. And that RAM is also running a lot of other stuff (libPNG, FreeType, Modbus, and even embedded TrueType fonts. Crazy! I was actually shocked when I got it working, and saw it perform so well. From http://www.antigrain.com/doc/introduction/introduction.agdoc.html "AGG allows you to replace any part of the library, if, for example, it doesn't fit performance requirements. Or you can add another color space if needed. All of it is possible because of extensive using of C++ template mechanism. Anti-Grain Geometry is not a solid graphic library and it's not very easy to use. I consider AGG as a “tool to create other tools”. It means that there's no “Graphics” object or something like that, instead, AGG consists of a number of loosely coupled algorithms that can be used together or separately. All of them have well defined interfaces and absolute minimum of implicit or explicit dependencies." It's architecture is what makes it so beautiful. You can configure your own graphics pipeline simply by passing the right template arguments. It would be an excellent showcase for D. Mike
Jun 22 2015
parent reply "ponce" <contact gam3sfrommars.fr> writes:
On Monday, 22 June 2015 at 08:21:44 UTC, Mike wrote:
 Anti-Grain Geometry is not a solid graphic library and it's not 
 very easy to use. I consider AGG as a “tool to create other 
 tools”. It means that there's no “Graphics” object or something 
 like that, instead, AGG consists of a number of loosely coupled 
 algorithms that can be used together or separately. All of them 
 have well defined interfaces and absolute minimum of implicit 
 or explicit dependencies."

 It's architecture is what makes it so beautiful.  You can 
 configure your own graphics pipeline simply by passing the 
 right template arguments.  It would be an excellent showcase 
 for D.

 Mike
Thankfully we already have it: http://blog.thecybershadow.net/2014/03/21/functional-image-processing-in-d/ Data structures separated from algorithms with lazy range-like computations. It's just a matter of using it and improving on it.
Jun 22 2015
parent reply "ZombineDev" <valid_email he.re> writes:
On Monday, 22 June 2015 at 12:52:36 UTC, ponce wrote:
 On Monday, 22 June 2015 at 08:21:44 UTC, Mike wrote:
 Anti-Grain Geometry is not a solid graphic library and it's 
 not very easy to use. I consider AGG as a “tool to create 
 other tools”. It means that there's no “Graphics” object or 
 something like that, instead, AGG consists of a number of 
 loosely coupled algorithms that can be used together or 
 separately. All of them have well defined interfaces and 
 absolute minimum of implicit or explicit dependencies."

 It's architecture is what makes it so beautiful.  You can 
 configure your own graphics pipeline simply by passing the 
 right template arguments.  It would be an excellent showcase 
 for D.

 Mike
Thankfully we already have it: http://blog.thecybershadow.net/2014/03/21/functional-image-processing-in-d/ Data structures separated from algorithms with lazy range-like computations. It's just a matter of using it and improving on it.
Another cool library that separates images from algorithms (ala STL) is Boost GIL (Generic Image Library) [1]. It was developed internally by Adobe and then they open-sourced it and moved it to Boost. They used concepts quite extensively in their code (emulated with C++03/11 features, eww) so leveraging D's features to the same will be much more natural. I haven't used it, so I am not sure how featured it is, but key point is that the abstractions are really solid and generic/algorithmic (not some inflexible java-style OOP). Like many good designs in D it tries to use as much as possiple of the types system to propagate information about the properties of the types (like color spaces, iterator categories, etc) at compile-time. I wanted to make a D image library, based on the same ideas, but so far I haven't had enogh time to do this. The ae.graphics library design is quite effective (flexible and easy to use/apply) and is all about getting the job done. On the other hand Boost GIL is more about systematic abstraction of the domain area, i.e. more academic. I'm not sure if a more pragmatic or more theoretical approach is better, but even only porting GIL to D would be great showcase of D's modeling power. Here's a video [2] and a design guide [3] that exaplain the motivation behind GIL: [1]: http://www.boost.org/doc/libs/1_58_0/libs/gil/doc/index.html [2]: http://www.boost.org/doc/libs/1_58_0/libs/gil/doc/html/gildesignguide.html [3]: http://stlab.adobe.com/gil/presentation/index.htm (video, requires Flash, couldn't find one that's Flash-free)
Jun 23 2015
parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Wednesday, 24 June 2015 at 01:47:11 UTC, ZombineDev wrote:
 I wanted to make a D image library, based on the same ideas, 
 but so far I haven't had enogh time to do this.
 The ae.graphics library design is quite effective (flexible and 
 easy to use/apply) and is all about getting the job done. On 
 the other hand Boost GIL is more about systematic abstraction 
 of the domain area, i.e. more academic. I'm not sure if a more 
 pragmatic or more theoretical approach is better, but even only 
 porting GIL to D would be great showcase of D's modeling power.

 Here's a video [2] and a design guide [3] that exaplain the 
 motivation behind GIL:
I watched the first half of the video, and although I did get a few good ideas for ae.utils.graphics, I wouldn't say it's all that different. Why do you say GIL takes a more academic approach? One thing I noticed is just how much GIL works around C++ language limitations. I think a direct translation wouldn't be suitable for D.
Jun 24 2015