Skip to content

Commit

Permalink
FEAT: more getters/setters for image! type
Browse files Browse the repository at this point in the history
implements: metaeducation/rebol-issues#2386

Could be optimized and enhanced later. For example it would be good to add also HSV, Hue, Saturation, Lightness etc. For these it would be good not to support only `binary!`, but also `vector!` as an input/output.
  • Loading branch information
Oldes committed Sep 23, 2019
1 parent 425fa56 commit 4f16809
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 24 deletions.
176 changes: 152 additions & 24 deletions src/core/t-image.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,28 +189,98 @@

/***********************************************************************
**
*/ void RGB_To_Bin(REBYTE *bin, REBYTE *rgba, REBINT len, REBOOL alpha)
*/ void Color_To_Bin(REBYTE *bin, REBYTE *rgba, REBINT len, REBCNT format)
/*
** Convert internal image (integer) to binary string according requested order
**
***********************************************************************/
{
// Convert internal image (integer) to RGB/A order binary string:
if (alpha) {
REBINT c0, c1, c2, c3;
REBINT alpha = 0;

switch(format) {
case SYM_RGB: c0 = C_R; c1 = C_G; c2 = C_B; c3 = C_A; break;
case SYM_RGBA: c0 = C_R; c1 = C_G; c2 = C_B; c3 = C_A; alpha = 1; break;
case SYM_RGBO: c0 = C_R; c1 = C_G; c2 = C_B; c3 = C_A; alpha = -1; break;
case SYM_ARGB: c0 = C_A; c1 = C_R; c2 = C_G; c3 = C_B; alpha = 1; break;
case SYM_ORGB: c0 = C_A; c1 = C_R; c2 = C_G; c3 = C_B; alpha = -1; break;

case SYM_BGRA: c0 = C_B; c1 = C_G; c2 = C_R; c3 = C_A; alpha = 1; break;
case SYM_BGRO: c0 = C_B; c1 = C_G; c2 = C_R; c3 = C_A; alpha = -1; break;
case SYM_ABGR: c0 = C_A; c1 = C_B; c2 = C_G; c3 = C_R; alpha = 1; break;
case SYM_OBGR: c0 = C_A; c1 = C_B; c2 = C_G; c3 = C_R; alpha = -1; break;
case SYM_BGR: c0 = C_B; c1 = C_G; c2 = C_R; c3 = C_A; break;
default: return;
}

if (alpha > 0) {
for (; len > 0; len--, rgba += 4, bin += 4) {
bin[0] = rgba[C_R];
bin[1] = rgba[C_G];
bin[2] = rgba[C_B];
bin[3] = rgba[C_A];
bin[0] = rgba[c0];
bin[1] = rgba[c1];
bin[2] = rgba[c2];
bin[3] = rgba[c3];
}
} else if (alpha < 0) {
if (c0 == C_A) {
for (; len > 0; len--, rgba += 4, bin += 4) {
bin[0] = 255 - rgba[c0];
bin[1] = rgba[c1];
bin[2] = rgba[c2];
bin[3] = rgba[c3];
}
} else {
for (; len > 0; len--, rgba += 4, bin += 4) {
bin[0] = rgba[c0];
bin[1] = rgba[c1];
bin[2] = rgba[c2];
bin[3] = 255 - rgba[c3];
}
}
} else {
// Only the RGB part:
// Result without alpha
for (; len > 0; len--, rgba += 4, bin += 3) {
bin[0] = rgba[C_R];
bin[1] = rgba[C_G];
bin[2] = rgba[C_B];
bin[0] = rgba[c0];
bin[1] = rgba[c1];
bin[2] = rgba[c2];
}
}
}

/***********************************************************************
**
*/ void Bin_To_Color(REBYTE *trg, REBYTE *src, REBINT len, REBCNT format)
/*
** Convert external binary is specified color format to internal image
**
***********************************************************************/
{
REBINT r, g, b, a;
REBINT alpha = 0;
REBCNT *clr = (REBCNT*)trg;

switch(format) {
case SYM_RGBA: r = 0; g = 1; b = 2; a = 3; alpha = 1; break;
case SYM_RGBO: r = 0; g = 1; b = 2; a = 3; alpha = -1; break;
case SYM_ARGB: a = 0; r = 1; g = 2; b = 3; alpha = 1; break;
case SYM_ORGB: a = 0; r = 1; g = 2; b = 3; alpha = -1; break;

case SYM_BGRA: b = 0; g = 1; r = 2; a = 3; alpha = 1; break;
case SYM_BGRO: b = 0; g = 1; r = 2; a = 3; alpha = -1; break;
case SYM_ABGR: a = 0; b = 1; g = 2; r = 3; alpha = 1; break;
case SYM_OBGR: a = 0; b = 1; g = 2; r = 3; alpha = -1; break;
default: return;
}

if (alpha > 0) {
for (; len > 0; len--, src += 4, clr++) {
clr[0] = TO_PIXEL_COLOR(src[r], src[g], src[b], src[a]);
}
} else {
for (; len > 0; len--, src += 4, clr++) {
clr[0] = TO_PIXEL_COLOR(src[r], src[g], src[b], 255 - src[a]);
}
}
}

/***********************************************************************
**
Expand Down Expand Up @@ -249,25 +319,34 @@

/***********************************************************************
**
*/ void Alpha_To_Bin(REBYTE *bin, REBYTE *rgba, REBINT len)
*/ void Alpha_To_Bin(REBYTE *bin, REBYTE *rgba, REBINT len, REBCNT type)
/*
***********************************************************************/
{
for (; len > 0; len--, rgba += 4)
*bin++ = rgba[C_A];
if (type == SYM_ALPHA) {
for (; len > 0; len--, rgba += 4)
*bin++ = rgba[C_A];
} else { // SYM_OPACITY
for (; len > 0; len--, rgba += 4)
*bin++ = 255 - rgba[C_A];
}
}


/***********************************************************************
**
*/ void Bin_To_Alpha(REBYTE *rgba, REBCNT size, REBYTE *bin, REBINT len)
*/ void Bin_To_Alpha(REBYTE *rgba, REBCNT size, REBYTE *bin, REBINT len, REBCNT type)
/*
***********************************************************************/
{
if (len > (REBINT)size) len = size; // avoid over-run

for (; len > 0; len--, rgba += 4)
rgba[C_A] = *bin++;
if (type == SYM_ALPHA) {
for (; len > 0; len--, rgba += 4)
rgba[C_A] = *bin++;
} else { // SYM_OPACITY
for (; len > 0; len--, rgba += 4)
rgba[C_A] = 255 - *bin++;
}
}


Expand All @@ -288,6 +367,14 @@
return 0;
}

/***********************************************************************
**
*/ void Tuple_To_Color(REBCNT format, REBVAL *tuple, REBCNT *rgba)
/*
***********************************************************************/
{
Bin_To_Color((REBYTE*)rgba, VAL_TUPLE(tuple), 1, format);
}

/***********************************************************************
**
Expand Down Expand Up @@ -474,7 +561,7 @@ INLINE REBCNT ARGB_To_BGR(REBCNT i)

// Load alpha channel data:
if (IS_BINARY(block)) {
Bin_To_Alpha(ip, size, VAL_BIN_DATA(block), VAL_LEN(block));
Bin_To_Alpha(ip, size, VAL_BIN_DATA(block), VAL_LEN(block), SYM_ALPHA);
// VAL_IMAGE_TRANSP(value)=VITT_ALPHA;
block++;
}
Expand Down Expand Up @@ -1182,6 +1269,7 @@ INLINE REBCNT ARGB_To_BGR(REBCNT i)
REBSER *nser;
REBSER *series = VAL_SERIES(data);
REBCNT *dp;
REBCNT sym;

len = VAL_TAIL(data) - index;
len = MAX(len, 0);
Expand All @@ -1192,9 +1280,10 @@ INLINE REBCNT ARGB_To_BGR(REBCNT i)
else if (IS_DECIMAL(sel)) n = (REBINT)VAL_DECIMAL(sel);
else if (IS_LOGIC(sel)) n = (VAL_LOGIC(sel) ? 1 : 2);
else if (IS_WORD(sel)) {
sym = VAL_WORD_CANON(sel);
if (val == 0) {
val = pvs->value = pvs->store;
switch (VAL_WORD_CANON(sel)) {
switch (sym) {

case SYM_SIZE:
VAL_SET(val, REB_PAIR);
Expand All @@ -1203,16 +1292,32 @@ INLINE REBCNT ARGB_To_BGR(REBCNT i)
break;

case SYM_RGB:
case SYM_BGR:
nser = Make_Binary(len * 3);
SERIES_TAIL(nser) = len * 3;
RGB_To_Bin(QUAD_HEAD(nser), src, len, FALSE);
Color_To_Bin(QUAD_HEAD(nser), src, len, sym);
Set_Binary(val, nser);
break;

case SYM_RGBA:
case SYM_RGBO:
case SYM_BGRA:
case SYM_BGRO:
case SYM_ARGB:
case SYM_ABGR:
case SYM_ORGB:
case SYM_OBGR:
nser = Make_Binary(len * 4);
SERIES_TAIL(nser) = len * 4;
Color_To_Bin(QUAD_HEAD(nser), src, len, sym);
Set_Binary(val, nser);
break;

case SYM_ALPHA:
case SYM_OPACITY:
nser = Make_Binary(len);
SERIES_TAIL(nser) = len;
Alpha_To_Bin(QUAD_HEAD(nser), src, len);
Alpha_To_Bin(QUAD_HEAD(nser), src, len, sym);
Set_Binary(val, nser);
break;

Expand All @@ -1223,7 +1328,7 @@ INLINE REBCNT ARGB_To_BGR(REBCNT i)

} else {

switch (VAL_WORD_CANON(sel)) {
switch (sym) {

case SYM_SIZE:
if (!IS_PAIR(val) || !VAL_PAIR_X(val)) return PE_BAD_SET;
Expand All @@ -1243,13 +1348,36 @@ INLINE REBCNT ARGB_To_BGR(REBCNT i)
} else return PE_BAD_SET;
break;

case SYM_RGBA:
case SYM_RGBO:
case SYM_BGRA:
case SYM_BGRO:
case SYM_ARGB:
case SYM_ABGR:
case SYM_ORGB:
case SYM_OBGR:
if (IS_TUPLE(val)) {
if (VAL_TUPLE_LEN(val) != 4) return PE_BAD_ARGUMENT;
REBCNT color = 0;
Tuple_To_Color(sym, val, &color);
Fill_Line((REBCNT *)src, color, len, FALSE);
} else if (IS_INTEGER(val)) {
n = VAL_INT32(val);
if (n < 0 || n > 255) return PE_BAD_RANGE;
Fill_Line((REBCNT *)src, TO_PIXEL_COLOR(n,n,n,n), len, FALSE);
} else if (IS_BINARY(val)) {
Bin_To_Color(src, VAL_BIN_DATA(val), VAL_LEN(val) / 4, sym);
} else return PE_BAD_SET;
break;

case SYM_ALPHA:
case SYM_OPACITY:
if (IS_INTEGER(val)) {
n = VAL_INT32(val);
if (n < 0 || n > 255) return PE_BAD_RANGE;
Fill_Alpha_Line(src, (REBYTE)n, len);
} else if (IS_BINARY(val)) {
Bin_To_Alpha(src, len, VAL_BIN_DATA(val), VAL_LEN(val));
Bin_To_Alpha(src, len, VAL_BIN_DATA(val), VAL_LEN(val), sym);
} else return PE_BAD_SET;
break;

Expand Down
31 changes: 31 additions & 0 deletions src/tests/units/image-test.r3
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,38 @@ Rebol [
--assert error? try [img/1: #"^(260)"]
===end-group===

===start-group=== "raw image data getters"
img: make image! 2x1 img/1: 1.2.3.100 img/2: 4.5.6.200
tests: [
rgba #{01020364040506C8}
rgbo #{0102039B04050637}
argb #{64010203C8040506}
orgb #{9B01020337040506}
bgra #{03020164060504C8}
bgro #{0302019B06050437}
abgr #{64030201C8060504}
obgr #{9B03020137060504}
opacity #{9B37}
alpha #{64C8}
]
foreach [format bin] tests [
--test-- reform ["get raw image" format "data"]
--assert img/:format = bin
]
===end-group===

===start-group=== "raw image data setters"
foreach [format bin] tests [
--test-- reform ["set raw image" format "data"]
img/1: 1.2.3
img/:format: bin
--assert img/1 = 1.2.3.100
]
===end-group===


===start-group=== "image pixel assignment validity"
img: make image! 2x2
--test-- "image pixel 3-tuple assignment"
--assert 255.255.255 = img/1: 255.255.255
--test-- "image pixel 4-tuple assignment"
Expand Down

0 comments on commit 4f16809

Please sign in to comment.