1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-22 20:13:04 +01:00

Add possibility to save QR code in PNG file format

This commit is contained in:
Ansa89 2016-10-05 11:55:45 +02:00
parent e17fa89d8f
commit 958df9f2e8
No known key found for this signature in database
GPG Key ID: 19B3DFBF159E800E
12 changed files with 234 additions and 67 deletions

View File

@ -60,7 +60,7 @@ all: $(BUILD_DIR)/toxic
$(BUILD_DIR)/toxic: $(OBJ) $(BUILD_DIR)/toxic: $(OBJ)
@echo " LD $(@:$(BUILD_DIR)/%=%)" @echo " LD $(@:$(BUILD_DIR)/%=%)"
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/toxic $(OBJ) $(LDFLAGS) $(CC) $(CFLAGS) -o $(BUILD_DIR)/toxic $(OBJ) $(LDFLAGS)
$(BUILD_DIR)/osx_video.o: $(SRC_DIR)/$(OSX_VIDEO) $(BUILD_DIR)/osx_video.o: $(SRC_DIR)/$(OSX_VIDEO)
@echo " CC $(@:$(BUILD_DIR)/)osx_video.o" @echo " CC $(@:$(BUILD_DIR)/)osx_video.o"

View File

@ -34,6 +34,12 @@ ifneq ($(DESK_NOTIFY), disabled)
-include $(CHECKS_DIR)/desktop_notifications.mk -include $(CHECKS_DIR)/desktop_notifications.mk
endif endif
# Check if we want build QR exported as PNG support
QR_PNG = $(shell if [ -z "$(DISABLE_QRPNG)" ] || [ "$(DISABLE_QRPNG)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(QR_PNG), disabled)
-include $(CHECKS_DIR)/qr_png.mk
endif
# Check if we can build Toxic # Check if we can build Toxic
CHECK_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error") CHECK_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
ifneq ($(CHECK_LIBS), error) ifneq ($(CHECK_LIBS), error)

15
cfg/checks/qr_png.mk Normal file
View File

@ -0,0 +1,15 @@
# Variables for QR exported as PNG support
PNG_LIBS = libpng
PNG_CFLAGS = -DQRPNG
# Check if we can build QR exported as PNG support
CHECK_PNG_LIBS = $(shell pkg-config --exists $(PNG_LIBS) || echo -n "error")
ifneq ($(CHECK_PNG_LIBS), error)
LIBS += $(PNG_LIBS)
CFLAGS += $(PNG_CFLAGS)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_PNG_LIBS = $(shell for lib in $(PNG_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without QR exported as PNG support)
$(warning WARNING -- You need these libraries for QR exported as PNG support)
$(warning WARNING -- $(MISSING_PNG_LIBS))
endif

View File

@ -14,6 +14,7 @@ help:
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support" @echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support" @echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
@echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support" @echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
@echo " DISABLE_QRPNG: Set to \"1\" to force building without QR exported as PNG support"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS" @echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS" @echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")" @echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"

View File

@ -452,25 +452,42 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
char dir[data_file_len + 1]; char dir[data_file_len + 1];
size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir); size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir);
#ifdef QRPNG
if (argc == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
return;
} else if (!strcmp(argv[1], "txt")) {
#endif /* QRPNG */
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1]; char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1];
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT); snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
FILE *output = fopen(qr_path, "wb"); if (ID_to_QRcode_txt(id_string, qr_path) == -1) {
if (output == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
return;
}
if (ID_to_QRcode(id_string, output) == -1) {
fclose(output);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
fclose(output); #ifdef QRPNG
} else if (!strcmp(argv[1], "png")) {
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT_PNG) + 1];
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
if (ID_to_QRcode_png(id_string, qr_path) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
return;
}
#endif /* QRPNG */
} }
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])

View File

@ -158,7 +158,11 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, " /log <on> or <off> : Enable/disable logging\n"); wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n"); wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
wprintw(win, " /myid : Print your Tox ID\n"); wprintw(win, " /myid : Print your Tox ID\n");
#ifdef QRPNG
wprintw(win, " /myqr <txt> or <png> : Print your Tox ID's QR code to a file.\n");
#else
wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n"); wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n");
#endif /* QRPNG */
wprintw(win, " /clear : Clear window history\n"); wprintw(win, " /clear : Clear window history\n");
wprintw(win, " /close : Close the current chat window\n"); wprintw(win, " /close : Close the current chat window\n");
wprintw(win, " /quit or /exit : Exit Toxic\n"); wprintw(win, " /quit or /exit : Exit Toxic\n");

View File

@ -37,10 +37,10 @@ void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *
#ifdef __OBJC__ #ifdef __OBJC__
@interface OSXVideo : @interface OSXVideo :
NSObject <AVCaptureVideoDataOutputSampleBufferDelegate> NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
- (instancetype)initWithDeviceNames: - (instancetype)initWithDeviceNames:
(char **)device_names AmtDevices: (char **)device_names AmtDevices:
(int *)size; (int *)size;
@end @end
#endif /* __OBJC__ */ #endif /* __OBJC__ */

View File

@ -127,19 +127,20 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
} }
- (instancetype)initWithDeviceNames: - (instancetype)initWithDeviceNames:
(char **)device_names AmtDevices: (char **)device_names AmtDevices:
(int *)size { (int *)size
{
_session = [[AVCaptureSession alloc] init]; _session = [[AVCaptureSession alloc] init];
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo]; NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
int i; int i;
for (i = 0; i < [devices count]; ++i) { for (i = 0; i < [devices count]; ++i) {
AVCaptureDevice *device = [devices objectAtIndex: i]; AVCaptureDevice *device = [devices objectAtIndex: i];
char *video_input_name; char *video_input_name;
NSString *localizedName = [device localizedName]; NSString *localizedName = [device localizedName];
video_input_name = (char *)malloc(strlen([localizedName cStringUsingEncoding: NSUTF8StringEncoding]) + 1); video_input_name = (char *)malloc(strlen([localizedName cStringUsingEncoding: NSUTF8StringEncoding]) + 1);
strcpy(video_input_name, (char *)[localizedName cStringUsingEncoding: NSUTF8StringEncoding]); strcpy(video_input_name, (char *)[localizedName cStringUsingEncoding: NSUTF8StringEncoding]);
device_names[i] = video_input_name; device_names[i] = video_input_name;
} }
@ -151,7 +152,8 @@ strcpy(video_input_name, (char *)[localizedName cStringUsingEncoding: NSUTF8Stri
return self; return self;
} }
- (void)dealloc { - (void)dealloc
{
pthread_mutex_destroy(&_frameLock); pthread_mutex_destroy(&_frameLock);
[_session release]; [_session release];
[_linkerVideo release]; [_linkerVideo release];
@ -160,16 +162,17 @@ strcpy(video_input_name, (char *)[localizedName cStringUsingEncoding: NSUTF8Stri
} }
- (int)openVideoDeviceIndex: - (int)openVideoDeviceIndex:
(uint32_t)device_idx Width: (uint32_t)device_idx Width:
(uint16_t *)width Height: (uint16_t *)width Height:
(uint16_t *)height { (uint16_t *)height
{
pthread_mutex_init(&_frameLock, NULL); pthread_mutex_init(&_frameLock, NULL);
pthread_mutex_lock(&_frameLock); pthread_mutex_lock(&_frameLock);
_processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL); _processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL);
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo]; NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
AVCaptureDevice *device = [devices objectAtIndex: device_idx]; AVCaptureDevice *device = [devices objectAtIndex: device_idx];
NSError *error = NULL; NSError *error = NULL;
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error]; AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
if ( error != NULL ) { if ( error != NULL ) {
[input release]; [input release];
@ -177,7 +180,7 @@ AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device err
} }
[_session beginConfiguration]; [_session beginConfiguration];
[_session addInput: input]; [_session addInput: input];
//_session.sessionPreset = AVCaptureSessionPreset640x480; //_session.sessionPreset = AVCaptureSessionPreset640x480;
//*width = 640; //*width = 640;
//*height = 480; //*height = 480;
@ -200,19 +203,20 @@ AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device err
} }
_linkerVideo = [[AVCaptureVideoDataOutput alloc] init]; _linkerVideo = [[AVCaptureVideoDataOutput alloc] init];
[_linkerVideo setSampleBufferDelegate: self queue: _processingQueue]; [_linkerVideo setSampleBufferDelegate: self queue: _processingQueue];
// TODO possibly get a better pixel format // TODO possibly get a better pixel format
if (_shouldMangleDimensions) { if (_shouldMangleDimensions) {
[_linkerVideo setVideoSettings: @ { [_linkerVideo setVideoSettings: @ {
(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA), (id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
(id)kCVPixelBufferWidthKey: @640, (id)kCVPixelBufferWidthKey: @640,
(id)kCVPixelBufferHeightKey: @480 (id)kCVPixelBufferHeightKey: @480
}]; }];
} else { } else {
[_linkerVideo setVideoSettings: @{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}]; [_linkerVideo setVideoSettings: @ {(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
} }
[_session addOutput: _linkerVideo];
[_session addOutput: _linkerVideo];
[_session startRunning]; [_session startRunning];
pthread_mutex_unlock(&_frameLock); pthread_mutex_unlock(&_frameLock);
@ -220,21 +224,23 @@ AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device err
} }
- (void)closeVideoDeviceIndex: - (void)closeVideoDeviceIndex:
(uint32_t)device_idx { (uint32_t)device_idx
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo]; {
AVCaptureDevice *device = [devices objectAtIndex: device_idx]; NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
AVCaptureDevice *device = [devices objectAtIndex: device_idx];
NSError *error = NULL; NSError *error = NULL;
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error]; AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
[_session stopRunning]; [_session stopRunning];
[_session removeOutput: _linkerVideo]; [_session removeOutput: _linkerVideo];
[_session removeInput: input]; [_session removeInput: input];
[_linkerVideo release]; [_linkerVideo release];
} }
- (void)captureOutput: - (void)captureOutput:
(AVCaptureOutput *)captureOutput didOutputSampleBuffer: (AVCaptureOutput *)captureOutput didOutputSampleBuffer:
(CMSampleBufferRef)sampleBuffer fromConnection: (CMSampleBufferRef)sampleBuffer fromConnection:
(AVCaptureConnection *)connection { (AVCaptureConnection *)connection
{
pthread_mutex_lock(&_frameLock); pthread_mutex_lock(&_frameLock);
CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer); CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer);
@ -248,15 +254,17 @@ AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device err
// we're not going to do anything to it, so it's safe to lock it always // we're not going to do anything to it, so it's safe to lock it always
CVPixelBufferLockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly); CVPixelBufferLockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly);
} }
pthread_mutex_unlock(&_frameLock); pthread_mutex_unlock(&_frameLock);
} }
- (int)getVideoFrameY: - (int)getVideoFrameY:
(uint8_t *)y U: (uint8_t *)y U:
(uint8_t *)u V: (uint8_t *)u V:
(uint8_t *)v Width: (uint8_t *)v Width:
(uint16_t *)width Height: (uint16_t *)width Height:
(uint16_t *)height { (uint16_t *)height
{
if (!_currentFrame) { if (!_currentFrame) {
return -1; return -1;
} }
@ -293,7 +301,7 @@ static OSXVideo *_OSXVideo = nil;
int osx_video_init(char **device_names, int *size) int osx_video_init(char **device_names, int *size)
{ {
_OSXVideo = [[OSXVideo alloc] initWithDeviceNames: device_names AmtDevices: size]; _OSXVideo = [[OSXVideo alloc] initWithDeviceNames: device_names AmtDevices: size];
if ( _OSXVideo == nil ) if ( _OSXVideo == nil )
return -1; return -1;
@ -312,12 +320,12 @@ int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height)
if ( _OSXVideo == nil ) if ( _OSXVideo == nil )
return -1; return -1;
return [_OSXVideo openVideoDeviceIndex: selection Width: width Height: height]; return [_OSXVideo openVideoDeviceIndex: selection Width: width Height: height];
} }
void osx_video_close_device(uint32_t device_idx) void osx_video_close_device(uint32_t device_idx)
{ {
[_OSXVideo closeVideoDeviceIndex: device_idx]; [_OSXVideo closeVideoDeviceIndex: device_idx];
} }
int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height) int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height)
@ -325,7 +333,7 @@ int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, u
if ( _OSXVideo == nil ) if ( _OSXVideo == nil )
return -1; return -1;
return [_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height]; return [_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height];
} }
/* /*
* End of C-interface for OSXVideo * End of C-interface for OSXVideo

View File

@ -28,18 +28,25 @@
#include "windows.h" #include "windows.h"
#include "qr_code.h" #include "qr_code.h"
#ifdef QRPNG
#include <png.h>
#define INCHES_PER_METER (100.0/2.54)
#endif /* QRPNG */
#define BORDER_LEN 1 #define BORDER_LEN 1
#define CHAR_1 "\342\226\210" #define CHAR_1 "\342\226\210"
#define CHAR_2 "\342\226\204" #define CHAR_2 "\342\226\204"
#define CHAR_3 "\342\226\200" #define CHAR_3 "\342\226\200"
/* Converts a tox ID string into a QRcode and prints it to the given file stream. /* Converts a tox ID string into a QRcode and prints it into the given filename.
* *
* Returns 0 on success. * Returns 0 on success.
* Returns -1 on failure. * Returns -1 on failure.
*/ */
int ID_to_QRcode(const char *tox_id, FILE *fp) int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
{ {
FILE *fp = fopen(outfile, "wb");
if (fp == NULL) if (fp == NULL)
return -1; return -1;
@ -83,7 +90,106 @@ int ID_to_QRcode(const char *tox_id, FILE *fp)
fprintf(fp, "\n"); fprintf(fp, "\n");
} }
fclose(fp);
QRcode_free(qr_obj); QRcode_free(qr_obj);
return 0; return 0;
} }
#ifdef QRPNG
/* Converts a tox ID string into a QRcode and prints it into the given filename as png.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int ID_to_QRcode_png(const char *tox_id, const char *outfile)
{
static FILE *fp;
unsigned char *row, *p;
unsigned char black[4] = {0, 0, 0, 255};
size_t x, y, xx, yy, real_width;
size_t margin = BORDER_LEN;
size_t size = 5;
size_t dpi = 72;
png_structp png_ptr;
png_infop info_ptr;
fp = fopen(outfile, "wb");
if (fp == NULL)
return -1;
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
if (qr_obj == NULL)
return -1;
real_width = (qr_obj->width + margin * 2) * size;
row = malloc(real_width * 4);
if (row == NULL)
return -1;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL)
return -1;
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
return -1;
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_write_struct(&png_ptr, &info_ptr);
return -1;
}
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, real_width, real_width, 8,
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_pHYs(png_ptr, info_ptr, dpi * INCHES_PER_METER,
dpi * INCHES_PER_METER, PNG_RESOLUTION_METER);
png_write_info(png_ptr, info_ptr);
/* top margin */
memset(row, 0xff, real_width * 4);
for (y = 0; y < margin * size; y++)
png_write_row(png_ptr, row);
/* data */
p = qr_obj->data;
for (y = 0; y < qr_obj->width; y++) {
memset(row, 0xff, real_width * 4);
for (x = 0; x < qr_obj->width; x++) {
for (xx = 0; xx < size; xx++)
if (*p & 1)
memcpy(&row[((margin + x) * size + xx) * 4], black, 4);
p++;
}
for (yy = 0; yy < size; yy++)
png_write_row(png_ptr, row);
}
/* bottom margin */
memset(row, 0xff, real_width * 4);
for (y = 0; y < margin * size; y++)
png_write_row(png_ptr, row);
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
free(row);
QRcode_free(qr_obj);
return 0;
}
#endif /* QRPNG */

View File

@ -25,11 +25,21 @@
#define QRCODE_FILENAME_EXT ".QRcode" #define QRCODE_FILENAME_EXT ".QRcode"
/* Converts a tox ID string into a QRcode and prints it to the given file stream. /* Converts a tox ID string into a QRcode and prints it into the given filename.
* *
* Returns 0 on success. * Returns 0 on success.
* Returns -1 on failure. * Returns -1 on failure.
*/ */
int ID_to_QRcode(const char *tox_id, FILE *fp); int ID_to_QRcode_txt(const char *tox_id, const char *outfile);
#ifdef QRPNG
#define QRCODE_FILENAME_EXT_PNG ".QRcode.png"
/* Converts a tox ID string into a QRcode and prints it into the given filename as png.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int ID_to_QRcode_png(const char *tox_id, const char *outfile);
#endif /* QRPNG */
#endif /* QR_CODE */ #endif /* QR_CODE */