diff --git a/images/bamse_skorsten_1.png b/images/bamse_skorsten_1.png new file mode 100644 index 0000000..256c4bb Binary files /dev/null and b/images/bamse_skorsten_1.png differ diff --git a/main.lua b/main.lua index cc9979c..819cf3d 100644 --- a/main.lua +++ b/main.lua @@ -20,8 +20,8 @@ if CONFIG.LUA_EXTRA_CPATH then package.cpath = package.cpath .. CONFIG.LUA_EXTR -------------------------------------------------------------------------------- -- Constants -local FARVEL_INTERVAL = 60 -local MEME_INTERVAL = 30 +local FARVEL_INTERVAL = 120 +local MEME_INTERVAL = 30 -------------------------------------------------------------------------------- -- Make sure all required modules can be loaded @@ -75,6 +75,22 @@ local function generate_bait_link() return 'https://dcav.pw/jbait' end +local function fit_font_to_line_height (font_name, height) + local size_min, size_max = 1, 50 + while true do + local size_guess = math.floor((size_max + size_min)/2) + assert(size_min <= size_guess and size_guess <= size_max) + local font = assert(imlib.font.load(font_name..'/'..size_guess)) + if size_guess == size_min then return font end + local text_w, text_h = font:get_size 'k' + -- + if text_h <= height then size_min = size_guess + else size_max = size_guess + end + end + return nil +end + local function determine_required_font_size (font_name, text, width) local size_min, size_max = 1, 50 while true do @@ -82,7 +98,7 @@ local function determine_required_font_size (font_name, text, width) assert(size_min <= size_guess and size_guess <= size_max) local font = assert(imlib.font.load(font_name..'/'..size_guess)) if size_guess == size_min then return font end - local text_w = font:get_size(text) + local text_w, text_h = font:get_size(text) -- if text_w <= width then size_min = size_guess else size_max = size_guess @@ -91,18 +107,82 @@ local function determine_required_font_size (font_name, text, width) return nil end +local function wrap_lines (font, text, width) + local lines, current, x = {}, {}, 0 + local SPACE_ADVANCE = font:get_advance ' ' + for word in text:gmatch '[^%s]+' do + assert(type(word) == 'string') + local word_w = font:get_advance(word) + local next_x = x + word_w + SPACE_ADVANCE + if word == '' then + -- Do nothing + elseif next_x <= width then + current[#current+1], x = word, next_x + else + lines[#lines+1], current = table.concat(current, ' '), { word } + x = word_w + end + end + -- Færdiggør sidste linje + lines[#lines+1] = table.concat(current, ' ') + -- Ret + return lines +end + local COLOR_WHITE = imlib.color.new(255, 255, 255) local COLOR_BLACK = imlib.color.new( 0, 0, 0) -local function draw_centered_text_in_box (font_name, draw_onto, text, x0, y0, width, height, bg_color) +local function draw_centered_lines (draw_onto, lines, x0, y0, width, font, font_color) + assert(type(lines) == 'table') + local y = y0 + for i, line in ipairs(lines) do + local text_w, text_h = font:get_size(line) + local x = x0 + (width - text_w) / 2 + draw_onto:draw_text(font, line, x, y, font_color or COLOR_BLACK) + -- + y = y + text_h + end +end + +local function determine_font_and_lines_for_box (font_name, text, width, height) + local num_lines, last_actual, actual_lines = 1, nil, nil + for iteration = 1, 10 do + local estimate_font = determine_required_font_size(font_name, text, width * num_lines) + local line_height = select(2, estimate_font:get_size(text)) + + local estimate_num_lines = height / select(2, estimate_font:get_size(text)) + local lines = wrap_lines(estimate_font, text, width) + local actual_num_lines = #lines + print(require'pretty'(lines)) + --local estimate_num_lines = #lines + if #lines * line_height >= height then + estimate_num_lines = estimate_num_lines - 1 + end + print(num_lines, estimate_num_lines) + -- Test for convergence + if last_actual == actual_num_lines then + actual_lines = lines + break + end + num_lines = (estimate_num_lines + actual_num_lines) / 2 + last_actual = actual_num_lines + end + + assert(actual_lines) + local actual_font = fit_font_to_line_height(font_name, height / #actual_lines) + + assert(#actual_lines * select(2, actual_font:get_size(text)) < height) + return actual_font, actual_lines +end + +local function draw_centered_text_in_box (font_name, draw_onto, text, x0, y0, width, height, bg_color, font_color) assert(type(font_name) == 'string') - font = determine_required_font_size(font_name, text, width) + local font, lines = determine_font_and_lines_for_box(font_name, text, width, height) -- - local text_w, text_h = font:get_size(text) - local x, y = x0 + (width - text_w) / 2, y0 + (height - text_h) / 2 + local y = y0 + (height - #lines * select(2, font:get_size(text))) / 2 -- if bg_color then draw_onto:fill_rectangle(x0, y0, width, height, bg_color) end - draw_onto:draw_text(font, text, x, y, COLOR_BLACK) + draw_centered_lines(draw_onto, lines, x0, y, width, font, font_color) end local function choose_random_font () @@ -161,7 +241,7 @@ local function fill_in_topics_information (topics) return new_topics end -local function paste_topic_onto_image (target, topic, x, y, w, h, bg_color, font_name) +local function paste_topic_onto_image (target, topic, x, y, w, h, bg_color, font_name, font_color) assert(target) assert(type(topic) == 'table') assert(type(font_name) == 'string') @@ -186,7 +266,7 @@ local function paste_topic_onto_image (target, topic, x, y, w, h, bg_color, font --os.remove(filename) elseif topic.type == 'text' then local text = topic.text - draw_centered_text_in_box(font_name, target, text, x, y, w, h, bg_color) + draw_centered_text_in_box(font_name, target, text, x, y, w, h, bg_color, font_color) elseif topic.type == 'droste' then target:fill_rectangle(x, y, w, h, COLOR_WHITE) else @@ -207,8 +287,8 @@ local function save_to_cloud (img) img:save (MEME_OUTPUT) img:free() -- Upload to dcav - local img_name = 'otmemes_'..os.time() - copy_remotely('localhost', MEME_OUTPUT, CONFIG.STORAGE_SERVER, CONFIG.STORAGE_SERVER_PATH..img_name..'.png') + local img_name = 'otmemes_'..os.time()..'.png' + copy_remotely('localhost', MEME_OUTPUT, CONFIG.STORAGE_SERVER, CONFIG.STORAGE_SERVER_PATH..img_name) return CONFIG.STORAGE_DIR_URL..img_name end @@ -251,7 +331,7 @@ local function generate_comparison_meme_generator (positions) assert(type(positions.base_img_path) == 'string') return function (topics) - assert(type(topics) == 'table' and #topics == 2) + assert(type(topics) == 'table' and #topics == #positions) local font_name = choose_random_font() @@ -267,7 +347,7 @@ local function generate_comparison_meme_generator (positions) -- Paste topic onto head for index, pos in ipairs(rand_positions) do - paste_topic_onto_image(base_img, topics[index], pos.x, pos.y, pos.w, pos.h, nil, font_name) + paste_topic_onto_image(base_img, topics[index], pos.x, pos.y, pos.w, pos.h, nil, font_name, pos.font_color) end -- Droste @@ -292,6 +372,12 @@ local generate_drake_egon_olsen = generate_comparison_meme_generator { { x = 377, xr = 0, y = 354, yr = 0, w = 383, h = 360 }, } +local generate_skorsten_image = generate_comparison_meme_generator { + base_img_path = './images/bamse_skorsten_1.png', + + { x = 646, xr = 0, y = 366, yr = 0, w = 631, h = 215, font_color = COLOR_WHITE }, +} + local GENERATE_COMPARISON_MEME_OF_2 = { generate_distracted_boyfriend, generate_drake_egon_olsen @@ -548,6 +634,18 @@ local function handle_message(bot, user, channel, message, is_slow_channel) return 'MACHINE' end + -- Vælter min skorsten + do + local problem_text = message:lower():match 'vælter%s+min%s+skorsten%s*(.+)$' + if problem_text then + if problem_text:match '^er' then problem_text = problem_text:match '^er%s*(.+)$' end + if problem_text:match '^:' then problem_text = problem_text:match '^:%s*(.+)$' end + local img_link = generate_skorsten_image {{ type = 'text', text = problem_text }} + bot:sendChat(channel, img_link) + return 'SKRSTEN' + end + end + -- Comparison memes local topics = get_topics_from_comparison_message(message) if not topics then return end