Skip to content

Commit

Permalink
Add RGB Highlights
Browse files Browse the repository at this point in the history
  • Loading branch information
smasher816 committed Oct 28, 2023
1 parent 16a856a commit c610c9a
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 17 deletions.
135 changes: 135 additions & 0 deletions blitbuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,89 @@ void BB_fill_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsi
}
}

void BB_fill_rect_color(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, ColorRGB32 * restrict color) {
const int rotation = GET_BB_ROTATION(bb);
unsigned int rx, ry, rw, rh;
// Compute rotated rectangle coordinates & size
switch (rotation) {
case 0:
rx = x;
ry = y;
rw = w;
rh = h;
break;
case 1:
rx = bb->w - (y + h);
ry = x;
rw = h;
rh = w;
break;
case 2:
rx = bb->w - (x + w);
ry = bb->h - (y + h);
rw = w;
rh = h;
break;
case 3:
rx = y;
ry = bb->h - (x + w);
rw = h;
rh = w;
break;
}

// Handle any target pitch properly
const int bb_type = GET_BB_TYPE(bb);
switch (bb_type) {
case TYPE_BBRGB16:
// we want to preserve the alpha byte
if (rx == 0 && rw == bb->w) {
// Single step for contiguous scanlines
const uint16_t src = *((uint16_t*) &ColorRGB32_To_Color16(color));
uint16_t * restrict p = (uint16_t *) (bb->data + bb->stride*ry);
size_t px_count = bb->pixel_stride*rh;
while (px_count--) {
*p++ = src;
}
} else {
// Scanline per scanline
const uint16_t src = *((uint16_t*) &ColorRGB32_To_Color16(color));
for (unsigned int j = ry; j < ry+rh; j++) {
uint16_t * restrict p = (uint16_t *) (bb->data + bb->stride*j) + rx;
size_t px_count = rw;
while (px_count--) {
*p++ = src;
}
}
}
break;
case TYPE_BBRGB24:
{
// Scanline per scanline
const ColorRGB24 src = ColorRGB32_To_Color24(color);
for (unsigned int j = ry; j < ry+rh; j++) {
for (unsigned int k = rx; k < rx+rw; k++) {
uint8_t * restrict p = bb->data + bb->stride*j + (k * 3U);
memcpy(p, &src, 3);
}
}
}
break;
case TYPE_BBRGB32:
{
// Scanline per scanline
const uint32_t* src = (uint32_t*) &color;
for (unsigned int j = ry; j < ry+rh; j++) {
for (unsigned int k = rx; k < rx+rw; k++) {
uint8_t * restrict p = bb->data + bb->stride*j + (k * 3U);
memcpy(p, src, 3);
}
}
}
break;
}
}

void BB_blend_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, Color8A * restrict color) {
const int bb_type = GET_BB_TYPE(bb);
const int bb_rotation = GET_BB_ROTATION(bb);
Expand Down Expand Up @@ -477,6 +560,58 @@ void BB_blend_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, uns
}
}

void BB_blend_rect_color(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, ColorRGB32 * restrict color) {
const int bb_type = GET_BB_TYPE(bb);
const int bb_rotation = GET_BB_ROTATION(bb);
const uint8_t alpha = color->alpha;
const uint8_t ainv = alpha ^ 0xFF;
switch (bb_type) {
case TYPE_BBRGB16:
for (unsigned int j = y; j < y + h; j++) {
for (unsigned int i = x; i < x + w; i++) {
ColorRGB16 * restrict dstptr;
BB_GET_PIXEL(bb, bb_rotation, ColorRGB16, i, j, &dstptr);
if (ColorRGB16_GetR(dstptr->v) > 30 && ColorRGB16_GetG(dstptr->v) > 30 && ColorRGB16_GetB(dstptr->v) > 30) {
// Only edit light colors and leave blacks alone. This avoids whitewashing text.
const uint8_t r = (uint8_t) DIV_255(ColorRGB16_GetR(dstptr->v) * ainv + color->r * alpha);
const uint8_t g = (uint8_t) DIV_255(ColorRGB16_GetG(dstptr->v) * ainv + color->g * alpha);
const uint8_t b = (uint8_t) DIV_255(ColorRGB16_GetB(dstptr->v) * ainv + color->b * alpha);
dstptr->v = (uint16_t) RGB_To_RGB16(r, g, b);
}
}
}
break;
case TYPE_BBRGB24:
for (unsigned int j = y; j < y + h; j++) {
for (unsigned int i = x; i < x + w; i++) {
ColorRGB24 * restrict dstptr;
BB_GET_PIXEL(bb, bb_rotation, ColorRGB24, i, j, &dstptr);
if (dstptr->r > 30 && dstptr->g > 30 && dstptr->b > 30) {
// Only edit light colors and leave blacks alone. This avoids whitewashing text.
dstptr->r = (uint8_t) DIV_255(dstptr->r * ainv + color->r * alpha);
dstptr->g = (uint8_t) DIV_255(dstptr->g * ainv + color->r * alpha);
dstptr->b = (uint8_t) DIV_255(dstptr->b * ainv + color->r * alpha);
}
}
}
break;
case TYPE_BBRGB32:
for (unsigned int j = y; j < y + h; j++) {
for (unsigned int i = x; i < x + w; i++) {
ColorRGB32 * restrict dstptr;
BB_GET_PIXEL(bb, bb_rotation, ColorRGB32, i, j, &dstptr);
if (dstptr->r > 30 && dstptr->g > 30 && dstptr->b > 30) {
// Only edit light colors and leave blacks alone. This avoids whitewashing text.
dstptr->r = (uint8_t) DIV_255(dstptr->r * ainv + color->r * alpha);
dstptr->g = (uint8_t) DIV_255(dstptr->g * ainv + color->g * alpha);
dstptr->b = (uint8_t) DIV_255(dstptr->b * ainv + color->b * alpha);
}
}
}
break;
}
}

void BB_invert_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h) {
const int rotation = GET_BB_ROTATION(bb);
unsigned int rx, ry, rw, rh;
Expand Down
2 changes: 2 additions & 0 deletions blitbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ typedef struct BlitBufferRGB32 {

DLL_PUBLIC void BB_fill(BlitBuffer * restrict bb, uint8_t v);
DLL_PUBLIC void BB_fill_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint8_t v);
DLL_PUBLIC void BB_fill_rect_color(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, ColorRGB32 * restrict color);
DLL_PUBLIC void BB_blend_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, Color8A * restrict color);
DLL_PUBLIC void BB_blend_rect_color(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, ColorRGB32 * restrict color);
DLL_PUBLIC void BB_invert_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h);
DLL_PUBLIC void BB_hatch_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int stripe_width, Color8 * restrict color, uint8_t alpha);
DLL_PUBLIC void BB_blit_to_BB8(const BlitBuffer * restrict src, BlitBuffer * restrict dst,
Expand Down
60 changes: 53 additions & 7 deletions ffi/blitbuffer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ typedef struct BlitBufferRGB32 {

void BB_fill(BlitBuffer * restrict bb, uint8_t v);
void BB_fill_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint8_t v);
void BB_fill_rect_color(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, ColorRGB32 * restrict color);
void BB_blend_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, Color8A * restrict color);
void BB_blend_rect_color(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, ColorRGB32 * restrict color);
void BB_invert_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h);
void BB_hatch_rect(BlitBuffer * restrict bb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int stripe_width, Color8 * restrict color, uint8_t alpha);
void BB_blit_to(const BlitBuffer * restrict source, BlitBuffer * restrict dest, unsigned int dest_x, unsigned int dest_y,
Expand Down Expand Up @@ -1497,8 +1499,13 @@ function BB_mt.__index:paintRect(x, y, w, h, value, setter)
h, y = BB.checkBounds(h, y, 0, self:getHeight(), 0xFFFF)
if w <= 0 or h <= 0 then return end
if self:canUseCbb() and setter == self.setPixel then
cblitbuffer.BB_fill_rect(ffi.cast(P_BlitBuffer, self),
x, y, w, h, value:getColor8().a)
if ffi.istype(ColorRGB32, value) then
cblitbuffer.BB_fill_rect_color(ffi.cast(P_BlitBuffer, self),
x, y, w, h, value:getColorRGB32())
else
cblitbuffer.BB_fill_rect(ffi.cast(P_BlitBuffer, self),
x, y, w, h, value:getColor8().a)
end
else
-- We can only do fast filling when there's no complex processing involved (i.e., simple setPixel only)
if setter == self.setPixel then
Expand Down Expand Up @@ -1926,16 +1933,21 @@ lighten color values in rectangular area
@param y Y coordinate
@param w width
@param h height
@param by lighten by this factor (default: 0.5)
@param color color to overlay (default: 0x80, 50% gray)
--]]
function BB_mt.__index:lightenRect(x, y, w, h, by)
local color = Color8A(0, 0xFF*(by or 0.5))
function BB_mt.__index:lightenRect(x, y, w, h, color)
color = color or Color8A(0xFF, 0x80)
if self:canUseCbb() then
w, x = BB.checkBounds(w, x, 0, self:getWidth(), 0xFFFF)
h, y = BB.checkBounds(h, y, 0, self:getHeight(), 0xFFFF)
if w <= 0 or h <= 0 then return end
cblitbuffer.BB_blend_rect(ffi.cast(P_BlitBuffer, self),
x, y, w, h, color)
if ffi.istype(ColorRGB32, color) then
cblitbuffer.BB_blend_rect_color(ffi.cast(P_BlitBuffer, self),
x, y, w, h, color)
else
cblitbuffer.BB_blend_rect(ffi.cast(P_BlitBuffer, self),
x, y, w, h, color)
end
else
self:paintRect(x, y, w, h, color, self.setPixelBlend)
end
Expand Down Expand Up @@ -2220,6 +2232,40 @@ function BB.gray(level)
return Color8(bxor(floor(0xFF * level), 0xFF))
end

--[[
return a Color value resembling a given hex string
---]]
function BB.colorFromString(value)
value = value:gsub('#','')
-- #rrggbbaa
if(string.len(value) == 8) then
return ColorRGB32(
tonumber(value:sub(1,2), 16),
tonumber(value:sub(3,4), 16),
tonumber(value:sub(5,6), 16),
tonumber(value:sub(7,8), 16)
)
-- #rrggbb
elseif(string.len(value) == 6) then
return ColorRGB32(
tonumber(value:sub(1,2), 16),
tonumber(value:sub(3,4), 16),
tonumber(value:sub(5,6), 16),
0xFF
)
-- #vv
elseif(string.len(value) == 2) then
return ColorRGB32(
tonumber(value:sub(1,2), 16),
tonumber(value:sub(1,2), 16),
tonumber(value:sub(1,2), 16),
0xFF
)
else
return nil
end
end

-- the full eInk palette:
BB.COLOR_WHITE = Color8(0xFF)
BB.COLOR_GRAY_E = Color8(0xEE)
Expand Down
41 changes: 31 additions & 10 deletions ffi/mupdf.lua
Original file line number Diff line number Diff line change
Expand Up @@ -682,27 +682,48 @@ end
mupdf.STRIKE_HEIGHT = 0.375
mupdf.UNDERLINE_HEIGHT = 0
mupdf.LINE_THICKNESS = 0.05
mupdf.HIGHLIGHT_COLOR = {1.0, 1.0, 0.0}
mupdf.UNDERLINE_COLOR = {0.0, 0.0, 1.0}
mupdf.STRIKE_OUT_COLOR = {1.0, 0.0, 0.0}

function page_mt.__index:addMarkupAnnotation(points, n, type)
function page_mt.__index:addMarkupAnnotation(points, n, type, bb_color)
local color = ffi.new("float[3]")
local alpha = 1.0
local line_height = 0.5
local line_thickness = 1.0
if type == M.PDF_ANNOT_HIGHLIGHT then
color[0] = 1.0
color[1] = 1.0
color[2] = 0.0
if bb_color then
color[0] = bb_color.r / 255
color[1] = bb_color.g / 255
color[2] = bb_color.b / 255
else
color[0] = mupdf.HIGHLIGHT_COLOR[1]
color[1] = mupdf.HIGHLIGHT_COLOR[2]
color[2] = mupdf.HIGHLIGHT_COLOR[3]
end
alpha = 0.5
elseif type == M.PDF_ANNOT_UNDERLINE then
color[0] = 0.0
color[1] = 0.0
color[2] = 1.0
if bb_color then
color[0] = bb_color.r / 255
color[1] = bb_color.g / 255
color[2] = bb_color.b / 255
else
color[0] = mupdf.UNDERLINE_COLOR[1]
color[1] = mupdf.UNDERLINE_COLOR[2]
color[2] = mupdf.UNDERLINE_COLOR[3]
end
line_thickness = mupdf.LINE_THICKNESS
line_height = mupdf.UNDERLINE_HEIGHT
elseif type == M.PDF_ANNOT_STRIKE_OUT then
color[0] = 1.0
color[1] = 0.0
color[2] = 0.0
if bb_color then
color[0] = bb_color.r / 255
color[1] = bb_color.g / 255
color[2] = bb_color.b / 255
else
color[0] = mupdf.STRIKE_OUT_COLOR[1]
color[1] = mupdf.STRIKE_OUT_COLOR[2]
color[2] = mupdf.STRIKE_OUT_COLOR[3]
end
line_thickness = mupdf.LINE_THICKNESS
line_height = mupdf.STRIKE_HEIGHT
else
Expand Down

0 comments on commit c610c9a

Please sign in to comment.