Skip to content

Instantly share code, notes, and snippets.

@neilxp
Created May 15, 2012 12:34
Show Gist options
  • Save neilxp/2701413 to your computer and use it in GitHub Desktop.
Save neilxp/2701413 to your computer and use it in GitHub Desktop.
CPP CAPTCHA generator
#include <memory>
#include <time.h>
#include <vector>
#include <string>
#include <iterator>
#include <fstream>
#include <boost/shared_ptr.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include "gd.h"
using namespace std;
using namespace boost::interprocess;
#define IMAGE_WIDTH 120
#define IMAGE_HEIGHT 55
#define ANGLE_MAX_DEGREE 25
struct CFileCloser{
void operator ()(FILE* file){
if (file) fclose(file);
}
};
static gdImagePtr paintBackground(gdImagePtr im, const char* fileName)
{
boost::shared_ptr<FILE> backgroundFile(fopen(fileName, "rb"), CFileCloser());
if (backgroundFile == NULL){
return NULL;
}
gdImagePtr backgroundImg = gdImageCreateFromPng(backgroundFile.get());
int w = gdImageSX(backgroundImg);
int h = gdImageSY(backgroundImg);
gdImageCopy(im, backgroundImg, 0, 0,
rand() % (w - IMAGE_WIDTH), rand() % (h - IMAGE_HEIGHT), w, h);
gdImageDestroy(backgroundImg);
return im;
}
static bool writeImageToFile(gdImagePtr im, const char* fileName)
{
boost::shared_ptr<FILE> file(fopen(fileName, "wb"), CFileCloser());
if (!file){
return false;
}
gdImagePng(im, file.get());
return true;
}
static void addNoise(gdImagePtr im, int nrStrokes)
{
for (int i = 0; i < nrStrokes; ++i){
int color =
gdImageColorAllocate(im, rand() % 0xff, rand() % 0xff, rand() % 0xff);
int startx = rand() % im->sx;
int starty = rand() % im->sy;
gdImageSetThickness(im, rand() % 2 + 1);
if (rand() % 2) {
gdImageArc(im, startx, starty,
rand() % im->sx, rand() % im->sy, rand() % 180, rand() % 180 + 180,
color);
}else{
gdImageLine(im, startx, starty, rand() % im->sx, rand() % im->sy, color);
}
}
}
static bool paintCode(gdImagePtr im, const string& code, const char *fontPath, int size)
{
char* chars = "ABCEFGHJKLMNPQRTUWXY346789";
int brect[8];
int ingrident, color;
unsigned int nrChars = code.length();
for (int i = 0; i < nrChars; ++i ) {
ingrident = rand() % 0x80 + 0x80;
color = gdImageColorAllocate(im, ingrident, ingrident, ingrident);
if ( 0 != gdImageStringFT(im, &brect[0], color,
const_cast<char*>(fontPath), size,
(double)(rand() % (ANGLE_MAX_DEGREE * 2) - ANGLE_MAX_DEGREE) / 180 * 3.1415,
i * im->sx / (nrChars + 1) + 16 + rand() % 8 - 4,
im->sy / 2 + size / 2 + rand() % 8 - 4,
const_cast<char*>(string(1, code.at(i)).c_str())))
{
return false;
}
}
return true;
}
typedef vector<string> StrVec;
template <class Iterator_>
static void readFontPathes(Iterator_ itr)
{
ifstream configFile("font.list");
string line;
while (getline(configFile, line)){
itr = line;
}
}
struct VerifCodeFactory
{
enum {nrCodeChars = 4};
static string makeCode()
{
static char* chars = "ABCEFGHJKLMNPQRTUWXY346789";
std::vector<char> vecChars;
for (int i = 0; i < nrCodeChars ; ++i ) {
char c = chars[rand() % strlen(chars)];
vecChars.push_back(c);
}
return string(vecChars.begin(), vecChars.end());
}
static string makeFileName( int i )
{
char fileName[50];
snprintf(fileName, sizeof(fileName), "vc%04d.png", i);
return string(fileName);
}
static bool makeImg(const string& code, const string& fileName, const StrVec& fontsPaths)
{
char *backgroundFileName = "hintergrund.png";
gdImagePtr im = gdImageCreateTrueColor(IMAGE_WIDTH, IMAGE_HEIGHT);
paintBackground(im, backgroundFileName);
if(im == NULL ){
fprintf(stderr, "Error open background file %s\n", backgroundFileName);
gdImageDestroy(im);
return false;
}
int strokes = im->sx / 20;
addNoise(im, strokes);
paintCode(im, code, fontsPaths.at(rand() % fontsPaths.size()).c_str(), 25);
addNoise(im, strokes);
writeImageToFile(im, fileName.c_str());
gdImageDestroy(im);
return true;
}
};
#define MUTEX_FILE_NAME "fogsvc.lock"
int main(int argc, char** argv)
{
if (argc < 2) {
printf("Usage: verifCodeGen AMOUNT\n");
return 1;
}
srand ( time(NULL) );
int numPics = atoi(argv[1]);
if (numPics <= 0 || numPics > 1000) numPics = 10;
char outputFileName[50];
StrVec fontsPaths;
readFontPathes(back_inserter(fontsPaths));
if (fontsPaths.size() == 0){
fprintf(stderr, "Read font configuration file error\n");
return 1;
}
named_mutex mutex(open_or_create, MUTEX_FILE_NAME);
scoped_lock<named_mutex> locker(mutex);
ofstream mapFile;
mapFile.open("codemap.csv", ofstream::out | ofstream::trunc);
if (!mapFile.is_open()){
fprintf(stderr, "Error opening map file.\n");
return 1;
}
for (int i = 0; i < numPics; ++i){
string code = VerifCodeFactory::makeCode();
string imgFileName = VerifCodeFactory::makeFileName(i);
if (!VerifCodeFactory::makeImg(code, imgFileName, fontsPaths)){
fprintf(stderr, "Error generate verification code image\n");
continue;
}
mapFile << imgFileName << "," << code << "\n";
}
mapFile << endl;
sleep(10);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment