zw963
June 12, 2025, 10:55am
1
There are some generate PNG shards. but i don’t know how to make image with text in it.
Hi everyone, I wanted to share my PNG implementation in crystal: GitHub - SleepingInsomniac/png: PNG implementation in Crystal . I started working on it to support another project since I didn’t see an existing project with support for all the bit depths, color types, paletted images etc… It was a pretty fun learning experience, and I’m wondering what others think.
I found some example code in pixie shards works for what i need, but the example code not work on my Arch Linux, check this issue.
Right now, I just want to make a small, simple picture with some numbers on it. It will be used as a simple check when people sign up on my website.
Thanks.
This file has code doing it. If you want I can do a more minimal example.
require "../formatter"
require "compress/gzip"
require "digest/sha1"
require "stumpy_png"
require "stumpy_utils"
module Tartrazine
def self.to_png(text : String, language : String,
theme : String = "default-dark",
line_numbers : Bool = false) : String
buf = IO::Memory.new
Tartrazine::Png.new(
theme: Tartrazine.theme(theme),
line_numbers: line_numbers
).format(text, Tartrazine.lexer(name: language), buf)
buf.to_s
end
class FontFiles
This file has been truncated. show original
zw963
June 12, 2025, 1:11pm
3
Thanks a lot, will be check later.
I found another working solution, which use crystal-vips.
require "../src/vips"
# Captcha generator
# Reference: https://github.com/libvips/libvips/issues/898
def wobble(image)
# a warp image is a 2D grid containing the new coordinates of each pixel with
# the new x in band 0 and the new y in band 1
#
# you can also use a complex image
#
# start from a low-res XY image and distort it
xy = Vips::Image.xyz(image.width // 20, image.height // 20)
x_distort = Vips::Image.gaussnoise(xy.width, xy.height)
y_distort = Vips::Image.gaussnoise(xy.width, xy.height)
xy += (x_distort.bandjoin(y_distort) / 150)
xy = xy.resize(20)
xy *= 20
This file has been truncated. show original
1 Like
zw963
June 12, 2025, 5:20pm
4
Create a captcha
shard use naqvis/crystal-vips
Crystal library that generates image CAPTCHAs.
All credits goes to the example code in crystal-vips by @naqvis
1 Like
I don’t think this will be viable for a text-based captcha implementation but for the general case where the images looks relatively the same you could get away with just creating SVGs and then converting to a PNG.
The clock captchas that Invidious uses during registrations are generated this way by manipulating SVG attributes on each picture:
clock_svg = <<-END_SVG
<svg viewBox="0 0 100 100" width="200px" height="200px">
<circle cx="50" cy="50" r="45" fill="#eee" stroke="black" stroke-width="2"></circle>
<text x="69" y="20.091" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 1</text>
<text x="82.909" y="34" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 2</text>
<text x="88" y="53" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 3</text>
<text x="82.909" y="72" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 4</text>
<text x="69" y="85.909" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 5</text>
<text x="50" y="91" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 6</text>
<text x="31" y="85.909" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 7</text>
<text x="17.091" y="72" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 8</text>
<text x="12" y="53" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 9</text>
<text x="17.091" y="34" text-anchor="middle" fill="black" font-family="Arial" font-size="10px">10</text>
<text x="31" y="20.091" text-anchor="middle" fill="black" font-family="Arial" font-size="10px">11</text>
<text x="50" y="15" text-anchor="middle" fill="black" font-family="Arial" font-size="10px">12</text>
<circle cx="50" cy="50" r="3" fill="black"></circle>
<line id="second" transform="rotate(#{second_angle}, 50, 50)" x1="50" y1="50" x2="50" y2="12" fill="black" stroke="black" stroke-width="1"></line>
<line id="minute" transform="rotate(#{minute_angle}, 50, 50)" x1="50" y1="50" x2="50" y2="16" fill="black" stroke="black" stroke-width="2"></line>
This file has been truncated. show original
3 Likes
zw963
June 15, 2025, 6:26am
6
There is a sister shard, name simple_captcha
All credits goes to @Sunrise
The different is:
SimpleCaptcha has no external dependencies other than Crystal,so, you can
built static binary (if this is your’s need)
this shard captcha code only support number.
These two libraries should be interchangeable without the need to change you code.
1 Like