local player = require'cplayer' local cairo = require'cairo' local ffi = require'ffi' local bitmap = require'bitmap' function player:magnifier(t) local id = assert(t.id, 'id missing') local x, y, w, h = self:getbox(t) local zoom_level = math.max(1, math.floor(t.zoom_level or 2)) --by default, capture the box in the center of the magnifier local cx = t.cx or math.floor(x + w / 2 * (1 - 1 / zoom_level)) local cy = t.cy or math.floor(y + h / 2 * (1 - 1 / zoom_level)) local cw = math.floor(w / zoom_level) local ch = math.floor(h / zoom_level) w = cw * zoom_level h = ch * zoom_level local sr = self.cr:group_target() local sw = sr:width() local sh = sr:height() --store the pixels to be magnified in case they overlap with the magnifier itself assert(sr:format() == 'argb32') sr:flush() local getpixel, setpixel = bitmap.pixel_interface(sr:bitmap()) local bmp = ffi.new('uint8_t[?]', cw * ch * 4) local ofs = 0 for j = cy, cy + ch-1 do for i = cx, cx + cw-1 do if j >= 0 and j < sh and i >= 0 and i < sw then local r,g,b = getpixel(i, j) bmp[ofs+0] = r bmp[ofs+1] = g bmp[ofs+2] = b bmp[ofs+3] = 1 end ofs = ofs + 4 end end --draw the stored pixels as tiny filled rectangles local ofs = 0 for j = 0, ch-1 do for i = 0, cw-1 do local r = bmp[ofs+0] local g = bmp[ofs+1] local b = bmp[ofs+2] for jj = 0, zoom_level-1 do for ii = 0, zoom_level-1 do local x1 = x + i * zoom_level + ii local y1 = y + j * zoom_level + jj if x1 >= 0 and x1 < sw and y1 >= 0 and y1 < sh then setpixel(x1, y1, r, g, b, 1) end end end ofs = ofs + 4 end end self:rect(x, y, w, h, nil, 'selected_bg', 1) end if not ... then require'cplayer.widgets_demo' end