├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── captcha.c ├── captcha.ttf ├── example.png ├── libcaptcha.c └── libcaptcha.h /.gitignore: -------------------------------------------------------------------------------- 1 | /*.a 2 | /*.o 3 | /captcha 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Artem Sheremet, Ilya Averkov 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 18 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | $(CC) -I/usr/local/include -c captcha.c -o captcha.o 3 | $(CC) -I/usr/local/include -c libcaptcha.c -o libcaptcha.o 4 | $(AR) rc libcaptcha.a libcaptcha.o 5 | ranlib libcaptcha.a 6 | $(CC) -I/usr/local/include -o captcha captcha.o -L/usr/local/lib -lgd -L. -lcaptcha -Wl,--format=binary -Wl,captcha.ttf -Wl,--format=default 7 | 8 | clean: 9 | rm -f captcha *.a *.o 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gd-captcha 2 | ========== 3 | 4 | Very simple CAPTCHA generator in C using GD, compatible with ejabberd. 5 | 6 | Single argument: captcha text. You may adjust other options right in the source code. 7 | 8 | Output format: [PNG](http://en.wikipedia.org/wiki/Portable_Network_Graphics). 9 | 10 | Requirements: [libgd](http://libgd.bitbucket.org/). 11 | 12 | License: 3-clause BSD (see [LICENSE](LICENSE)). 13 | 14 | Example: 15 | ![beAtLes](example.png) 16 | -------------------------------------------------------------------------------- /captcha.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "libcaptcha.h" 6 | 7 | extern uint8_t data[] asm("_binary_captcha_ttf_start"); 8 | extern uint8_t data_end[] asm("_binary_captcha_ttf_end"); 9 | 10 | int main(int argc, char **argv) { 11 | FILE *font = NULL; 12 | char *font_name = NULL; 13 | const char *captcha_text = argc > 1 ? argv[1] : "beAtLes"; 14 | 15 | srand(time(NULL)); 16 | 17 | font_name = tmpnam(NULL); 18 | font = fopen(font_name, "w"); 19 | if (font) { 20 | if (!fwrite(data, data_end - data, 1, font)) { 21 | perror("fwrite"); 22 | } 23 | 24 | fclose(font); 25 | 26 | render(captcha_text, stdout, font_name); 27 | unlink(font_name); 28 | 29 | return 0; 30 | } else { 31 | perror("fopen"); 32 | } 33 | 34 | return 1; 35 | } 36 | -------------------------------------------------------------------------------- /captcha.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotdoom/gd-captcha/e704b9b62c263506852c4c876010414691d95873/captcha.ttf -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotdoom/gd-captcha/e704b9b62c263506852c4c876010414691d95873/example.png -------------------------------------------------------------------------------- /libcaptcha.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "libcaptcha.h" 7 | 8 | /* 9 | * Generate a random number in range [0..range]. 10 | */ 11 | static int _range_random(int range) { 12 | if (range) { 13 | return rand() / (RAND_MAX / range); 14 | } else { 15 | return 0; 16 | } 17 | } 18 | 19 | /* 20 | * Generate a random number in range [-1..1]. 21 | */ 22 | static double _norm_random() { 23 | return rand() / (double)RAND_MAX * 2 - 1; 24 | } 25 | 26 | void render(const char *captcha_text, FILE *handle, char *fontname) { 27 | gdImagePtr captcha_image = NULL; 28 | int background_color, font_color, font_size, char_step, i; 29 | int brect[8]; // Bounds rect (set by gdImageStringFT). 30 | 31 | char current_char[2] = { 0 }; 32 | char *font_error = NULL; 33 | 34 | char_step = (CAPTCHA_WIDTH - (CAPTCHA_MARGIN_X * 2)) / strlen(captcha_text); 35 | font_size = CAPTCHA_HEIGHT - 2 * CAPTCHA_MARGIN_Y; 36 | 37 | captcha_image = gdImageCreate(CAPTCHA_WIDTH, CAPTCHA_HEIGHT); 38 | 39 | // First allocated color (white) is set as a background. 40 | background_color = gdImageColorAllocate(captcha_image, 255, 255, 255); 41 | 42 | // R, G, B font color (black). 43 | font_color = gdImageColorAllocate(captcha_image, 0, 0, 0); 44 | for (i = 0; *captcha_text; ++captcha_text, ++i) { 45 | current_char[0] = *captcha_text; 46 | font_error = gdImageStringFT(captcha_image, brect, font_color, fontname, 47 | font_size, CAPTCHA_CHAR_ANGLE * _norm_random(), 48 | CAPTCHA_MARGIN_X + (i * char_step), CAPTCHA_HEIGHT - CAPTCHA_MARGIN_Y, 49 | current_char); 50 | if (font_error) { 51 | fprintf(stderr, "Failed to render char '%c': %s\n", *captcha_text, font_error); 52 | } 53 | } 54 | 55 | gdImageSetThickness(captcha_image, CAPTCHA_STRIKE_WIDTH); 56 | for (i = 0; i < CAPTCHA_STRIKE_LINES; ++i) { 57 | gdImageLine(captcha_image, 58 | _range_random(CAPTCHA_MARGIN_X), 59 | _range_random(CAPTCHA_HEIGHT), 60 | _range_random(CAPTCHA_MARGIN_X) + CAPTCHA_WIDTH - CAPTCHA_MARGIN_X, 61 | _range_random(CAPTCHA_HEIGHT), 62 | i % 2 ? background_color : font_color); 63 | } 64 | gdImagePng(captcha_image, handle); 65 | gdImageDestroy(captcha_image); 66 | } 67 | -------------------------------------------------------------------------------- /libcaptcha.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBCAPTCHA_H 2 | #define LIBCAPTCHA_H 3 | 4 | #include 5 | 6 | // WxH, pixels. 7 | #define CAPTCHA_WIDTH 180 8 | #define CAPTCHA_HEIGHT 60 9 | 10 | // Margins to make captcha more readable. 11 | #define CAPTCHA_MARGIN_X (CAPTCHA_WIDTH * 0.05) 12 | #define CAPTCHA_MARGIN_Y (CAPTCHA_HEIGHT * 0.25) 13 | 14 | // Will be striked through with X random lines, each X pixels thick. 15 | #define CAPTCHA_STRIKE_WIDTH 2 16 | #define CAPTCHA_STRIKE_LINES 3 17 | 18 | // Maximum angle to turn a single char (randomly). 19 | #define CAPTCHA_CHAR_ANGLE (M_PI/8) 20 | 21 | void render(const char *captcha_text, FILE *handle, char *fontname); 22 | 23 | #endif 24 | --------------------------------------------------------------------------------