Created
May 15, 2012 12:34
-
-
Save neilxp/2701413 to your computer and use it in GitHub Desktop.
CPP CAPTCHA generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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