Skip to content

Commit

Permalink
add .maskPixel for Icon in paint mode and DeviceBitmap
Browse files Browse the repository at this point in the history
  • Loading branch information
dk committed Sep 26, 2023
1 parent 0a8cc89 commit 0bb8cf3
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 37 deletions.
3 changes: 3 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
Revision history for Perl module Prima

1.71 20XX-XX-XX
- Add DeviceBitmap.maskPixel

1.70 2023-09-03
- Use fading effects in widgets
- Solidify emulated 2D transformations with images
Expand Down
23 changes: 23 additions & 0 deletions class/DeviceBitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,29 @@ DeviceBitmap_get_paint_state( Handle self)
return psEnabled;
}

int
DeviceBitmap_maskPixel( Handle self, Bool set, int x, int y, int pixel)
{
Point pt;

if ( var->type != dbtLayered )
return 0;

pt = prima_matrix_apply_to_int( var->current_state.matrix, x, y );
x = pt.x;
y = pt.y;
if (x >= var->w || x < 0 || y >= var->h || y < 0)
return clInvalid;

if (set) {
if ( pixel < 0 ) pixel = 0;
if ( pixel > 255 ) pixel = 255;
return apc_gp_set_mask_pixel( self, x, y, pixel );
} else {
return apc_gp_get_mask_pixel( self, x, y );
}
}

#ifdef __cplusplus
}
#endif
1 change: 1 addition & 0 deletions class/DeviceBitmap.cls
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ object Prima::DeviceBitmap( Prima::Drawable)
{
int type;
property int type;
property int maskPixel(int x, int y);
method Bool begin_paint();
method Bool begin_paint_info();
method void done();
Expand Down
66 changes: 31 additions & 35 deletions class/Icon.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,68 +487,64 @@ Icon_maskIndex( Handle self, Bool set, int index)
return -1;
}

SV *
Icon_maskPixel( Handle self, Bool set, int x, int y, SV * pixel)
int
Icon_maskPixel( Handle self, Bool set, int x, int y, int pixel)
{
Point pt;

if (!set) {
if ( opt_InPaint)
return inherited pixel(self,false,x,y,pixel);

pt = prima_matrix_apply_to_int( VAR_MATRIX, x, y );
x = pt.x;
y = pt.y;
pt = prima_matrix_apply_to_int( VAR_MATRIX, x, y );
x = pt.x;
y = pt.y;
if (x >= var->w || x < 0 || y >= var->h || y < 0)
return clInvalid;

if (x >= var->w || x < 0 || y >= var->h || y < 0)
return newSViv(clInvalid);
if (!set) {
if ( is_opt( optInDraw) ) {
if ( var-> maskType == imbpp8 )
return apc_gp_get_mask_pixel( self, x, y );
}

switch (var->maskType) {
case imbpp1: {
Byte p = var->mask[ var->maskLine * y + ( x>>3 )];
Byte p = var->mask[ var->maskLine * y + ( x >> 3 )];
p = (p >> (7 - (x & 7))) & 1;
return newSViv(p);
return p ? 0xff : 0;
}
case imbpp8: {
Byte p = var->mask[ var->lineSize * y + x];
return newSViv(p);
Byte p = var->mask[ var->maskLine * y + x];
return p;
}
default:
return newSViv(clInvalid);
return clInvalid;
}
} else {
IV color;
if ( is_opt( optInDraw))
return inherited pixel(self,true,x,y,pixel);

pt = prima_matrix_apply_to_int( VAR_MATRIX, x, y );
x = pt.x;
y = pt.y;


if ( x >= var->w || x < 0 || y >= var->h || y < 0)
return NULL_SV;
Bool do_update = true;
if ( pixel < 0 ) pixel = 0;
if ( pixel > 255 ) pixel = 255;
if ( is_opt( optInDraw)) {
if ( var-> maskType == imbpp8 )
return apc_gp_set_mask_pixel( self, x, y, pixel );
else
do_update = false;
}

color = SvIV( pixel);
if ( color < 0 ) color = 0;
if ( color > 255 ) color = 255;
switch (var->maskType) {
case imbpp1 : {
int x1 = 7 - ( x & 7 );
Byte p = (color > 0) ? 1 : 0;
Byte p = (pixel > 0) ? 1 : 0;
Byte *pd = var->mask + (var->maskLine * y + ( x >> 3));
*pd &= ~(1 << x1);
*pd |= p << x1;
break;
}
case imbpp8:
var->mask[var->maskLine * y + x] = color;
var->mask[var->maskLine * y + x] = pixel & 0xff;
break;
default:
return NULL_SV;
return 0;
}
my->update_change( self);
return NULL_SV;
if ( do_update ) my->update_change( self);
return 0;
}
}

Expand Down
2 changes: 1 addition & 1 deletion class/Icon.cls
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ object Prima::Icon( Prima::Image)
property int maskType;
property Color maskColor;
property int maskIndex;
property SV * maskPixel( int x, int y);
property int maskPixel( int x, int y);
property int autoMasking;
method Handle bitmap();
method void init( HV * profile);
Expand Down
2 changes: 1 addition & 1 deletion class/Image/primitive.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Image_pixel( Handle self, Bool set, int x, int y, SV * pixel)

#define BGRto32(pal) ((var->palette[pal].r<<16) | (var->palette[pal].g<<8) | (var->palette[pal].b))
if (!set) {
if ( opt_InPaint)
if ( is_opt( optInDraw))
return inherited pixel(self,false,x,y,pixel);

pt = prima_matrix_apply_to_int( VAR_MATRIX, x, y );
Expand Down
6 changes: 6 additions & 0 deletions include/apricot.h
Original file line number Diff line number Diff line change
Expand Up @@ -3668,6 +3668,9 @@ END_TABLE(ggo,UV)
extern int
apc_gp_get_glyph_outline( Handle self, int index, int flags, int ** buffer);

extern Byte
apc_gp_get_mask_pixel( Handle self, int x, int y);

extern Color
apc_gp_get_pixel( Handle self, int x, int y);

Expand All @@ -3680,6 +3683,9 @@ apc_gp_put_image( Handle self, Handle image, int x, int y,
extern Bool
apc_gp_rectangle( Handle self, int x1, int y1, int x2, int y2);

extern Bool
apc_gp_set_mask_pixel( Handle self, int x, int y, Byte pixel);

extern Bool
apc_gp_set_pixel( Handle self, int x, int y, Color color);

Expand Down
15 changes: 15 additions & 0 deletions pod/Prima/Image.pod
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,16 @@ A read-only property, returning the length of the mask row in bytes, as
represented internally in memory. Data returned by the C<::mask> property is
aligned with C<::maskLineSize> bytes per row.

=item maskPixel ( X_OFFSET, Y_OFFSET ) PIXEL

Provides per-pixel access to the icon mask.

In the disabled mode, gets and sets the value directly from the mask memory.
In the paint mode, and if (and only if) the mask depth is 8 bits, queries the
alpha pixel value from the system paint surface. Pixel values for all mask
depths are treated uniformly, their values range from 0 to 255. For example,
values for 1-bit mask pixels are 0 and 255, not 0 and 1.

=item maskType INTEGER

Is either C<im::bpp1> (1) or C<im::bpp8> (8). The latter can be used
Expand All @@ -720,6 +730,11 @@ that correspond to alpha values lesser than 255 will be reset to 0.

=over

=item maskPixel ( X_OFFSET, Y_OFFSET ) PIXEL

Provides per-pixel access to the alpha component of the layered device bitmap.
If the bitmap is not layered, the property does not do anything.

=item type INTEGER

A read-only property that can only be set during creation, reflects whether the
Expand Down
33 changes: 33 additions & 0 deletions t/Object/GPExtra.t
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,37 @@ my $jj = $ii->data;
$ii->begin_paint;
$ii->end_paint;
is(unpack('H*',$ii->data), unpack('H*',$jj), "begin/end paint preserves data");

if ( $can_argb ) {
my $j = Prima::Icon->new(
size => [1,1],
type => im::RGB,
maskType => 8,
autoMasking => am::None,
);
$j->pixel(0,0,0x102030);
$j->maskPixel(0,0,0x40);
is( $j->pixel(0,0), 0x102030, "icon.pixel(1)");
is( $j->maskPixel(0,0), 0x40, "icon.maskPixel(1)");
$j->begin_paint;
is( $j->pixel(0,0), 0x102030, "icon.pixel(2)");
is( $j->maskPixel(0,0), 0x40, "icon.maskPixel(2)");
$j->pixel(0,0,0x203040);
$j->maskPixel(0,0,0x50);
is( $j->pixel(0,0), 0x203040, "icon.pixel(3)");
is( $j->maskPixel(0,0), 0x50, "icon.maskPixel(3)");
$j->end_paint;
is( $j->pixel(0,0), 0x203040, "icon.pixel(4)");
is( $j->maskPixel(0,0), 0x50, "icon.maskPixel(4)");

$j = Prima::DeviceBitmap->new(
size => [1,1],
type => dbt::Layered,
);
$j->pixel(0,0,0x102030);
$j->maskPixel(0,0,0x40);
is( $j->pixel(0,0), 0x102030, "dbm.pixel");
is( $j->maskPixel(0,0), 0x40, "dbm.maskPixel");
}

done_testing;
78 changes: 78 additions & 0 deletions unix/graphics.c
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,59 @@ apc_gp_flood_fill( Handle self, int x, int y, Color color, Bool singleBorder)
return ret;
}

Byte
apc_gp_get_mask_pixel( Handle self, int x, int y)
{
DEFXX;
XImage *im;
uint32_t p32 = 0;
int a, amax;
PRGBABitDescription bd;

if ( !opt_InPaint) return clInvalid;
SHIFT( x, y);
XRENDER_SYNC;

if ( x < 0 || x >= XX-> size.x || y < 0 || y >= XX-> size.y)
return 0;
if ( !((XT_IS_ICON(XX) || XT_IS_DBM(XX)) && XF_LAYERED(XX)))
return 0;

im = XGetImage( DISP, XX-> gdrawable, x, XX-> size.y - y - 1, 1, 1, AllPlanes, ZPixmap);
XCHECKPOINT;
if ( !im) return clInvalid;

bd = GET_RGBA_DESCRIPTION;
amax = 0xff;

switch ( guts.argb_visual.depth ) {
case 16:
p32 = *(( uint16_t*)(im-> data));
if ( guts.machine_byte_order != guts.byte_order)
p32 = REVERSE_BYTES_16(p32);
amax = 0xff & ( 0xff << ( 8 - bd-> alpha_range));
goto COMP;
case 24:
p32 = (im-> data[0] << 16) | (im-> data[1] << 8) | im-> data[2];
if ( guts.machine_byte_order != guts.byte_order)
p32 = REVERSE_BYTES_24(p32);
goto COMP;
case 32:
p32 = *(( uint32_t*)(im-> data));
if ( guts.machine_byte_order != guts.byte_order)
p32 = REVERSE_BYTES_32(p32);
COMP:
a = ((((p32 & bd-> alpha_mask) >> bd->alpha_shift) << 8) >> bd-> alpha_range) & 0xff;
if ( a == amax ) a = 0xff;
break;
default:
warn("UAG_009: get_mask_pixel not implemented for %d depth", guts.argb_visual.depth);
}

XDestroyImage( im);
return c;
}

Color
apc_gp_get_pixel( Handle self, int x, int y)
{
Expand Down Expand Up @@ -1324,6 +1377,31 @@ apc_gp_set_palette( Handle self)
return prima_palette_replace( self, false);
}

Bool
apc_gp_set_mask_pixel( Handle self, int x, int y, int pixel)
{
DEFXX;

if ( PObject( self)-> options. optInDrawInfo)
return false;
if ( !XF_IN_PAINT(XX))
return false;
if ( x < 0 || x >= XX-> size.x || y < 0 || y >= XX-> size.y)
return false;
if ( !((XT_IS_ICON(XX) || XT_IS_DBM(XX)) && XF_LAYERED(XX)))
return false;
XRENDER_SYNC;

SHIFT(x, y);
XSetPlaneMask( DISP, XX-> gc, guts.argb_bits.alpha_mask);
XSetForeground( DISP, XX-> gc, DEV_A(&guts.argb_bits,pixel));
XDrawPoint( DISP, XX-> gdrawable, XX-> gc, x, REVERT( y));
XSetPlaneMask( DISP, XX-> gc, AllPlanes);
XFLUSH;

return true;
}

Bool
apc_gp_set_pixel( Handle self, int x, int y, Color color)
{
Expand Down
37 changes: 37 additions & 0 deletions win32/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,43 @@ apc_dbm_get_handle( Handle self)
return ( ApiHandle) sys ps;
}

Byte
apc_gp_get_mask_pixel( Handle self, int x, int y)
{
uint32_t *p;
PDrawable d = ( PDrawable ) self;
objCheck 0;

if ( !((is_apt(aptIcon) || is_apt(aptDeviceBitmap)) && is_apt(aptLayered)))
return false;
select_world_transform(self, false);
SHIFT_XY(x,y);
if ( x < 0 || x >= d-> w || y < 0 || y > d-> h) return 0;

p = sys s. image. argb_bits + d-> h * y + x;
return (*p) >> 24;
}

Bool
apc_gp_set_mask_pixel( Handle self, int x, int y, Byte pixel)
{
uint32_t *p;
PDrawable d = ( PDrawable ) self;
objCheck false;

if ( !((is_apt(aptIcon) || is_apt(aptDeviceBitmap)) && is_apt(aptLayered)))
return false;
select_world_transform(self, false);
SHIFT_XY(x,y);
if ( x < 0 || x >= d-> w || y < 0 || y > d-> h) return false;

p = sys s. image. argb_bits + d-> h * y + x;
*p &= 0x00ffffff;
*p |= ((uint32_t) pixel) << 24;

return true;
}


#ifdef __cplusplus
}
Expand Down

0 comments on commit 0bb8cf3

Please sign in to comment.