Added JPEG support

This commit is contained in:
Manuel Reimer 2014-11-02 13:41:21 +01:00
parent 052bc50408
commit e07e56a3fa
3 changed files with 187 additions and 5 deletions

View File

@ -44,8 +44,8 @@ DEFINES += $(shell xml2-config --cflags)
INCLUDES += $(shell pkg-config --cflags freetype2 fontconfig)
INCLUDES += $(shell pkg-config --cflags librsvg-2.0 cairo-png)
LIBS += $(shell pkg-config --libs librsvg-2.0 cairo-png)
INCLUDES += $(shell pkg-config --cflags librsvg-2.0 cairo-png) -ljpeg
LIBS += $(shell pkg-config --libs librsvg-2.0 cairo-png) -ljpeg
LIBS += $(shell xml2-config --libs)

View File

@ -1,7 +1,6 @@
#include "../config.h"
#include "helpers.h"
#include "imageloader.h"
//#include <math.h>
#include <string>
#include <dirent.h>
#include <iostream>
@ -69,6 +68,8 @@ bool cImageLoader::LoadImage(const char *fullpath) {
importer = new cImageImporterPNG;
else if (endswith(fullpath, ".svg"))
importer = new cImageImporterSVG;
else if (endswith(fullpath, ".jpg"))
importer = new cImageImporterJPG;
else
return false;
@ -209,3 +210,137 @@ void cImageImporterSVG::GetImageSize(int &width, int &height) {
height = dim.height;
}
}
//
// Image importer for JPG
//
cImageImporterJPG::cImageImporterJPG() {
cinfo = NULL;
}
cImageImporterJPG::~cImageImporterJPG() {
if (cinfo) {
jpeg_destroy_decompress(cinfo);
free(cinfo);
fclose(infile);
}
}
bool cImageImporterJPG::LoadImage(const char *path) {
if (cinfo) {
jpeg_destroy_decompress(cinfo);
free(cinfo);
fclose(infile);
cinfo = NULL;
}
// Open input file
if ((infile = fopen(path, "rb")) == NULL) {
if (config.debugImageLoading)
dsyslog("skindesigner: Can't open %s", path);
return false;
}
// We set up the normal JPEG error routines, then override error_exit.
struct my_error_mgr jerr;
cinfo = (j_decompress_ptr)malloc(sizeof(struct jpeg_decompress_struct));
cinfo->err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
jerr.pub.output_message = my_output_message;
// Establish the setjmp return context for my_error_exit to use.
if (setjmp(jerr.setjmp_buffer)) {
// If we get here, the JPEG code has signaled an error.
jpeg_destroy_decompress(cinfo);
free(cinfo);
fclose(infile);
cinfo = NULL;
return false;
}
// Now we can initialize the JPEG decompression object.
jpeg_create_decompress(cinfo);
// Step 2: specify data source (eg, a file)
jpeg_stdio_src(cinfo, infile);
// Step 3: read file parameters with jpeg_read_header()
(void) jpeg_read_header(cinfo, TRUE);
return true;
}
void cImageImporterJPG::DrawToCairo(cairo_t *cr) {
if (!cinfo)
return;
unsigned char *bmp_buffer = NULL;
// Re-establish error handling
struct my_error_mgr jerr;
cinfo->err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
jerr.pub.output_message = my_output_message;
if (setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(cinfo);
free(cinfo);
fclose(infile);
free(bmp_buffer);
cinfo = NULL;
return;
}
// Step 4: set parameters for decompression
cinfo->out_color_space = JCS_EXT_ARGB;
// Step 5: Start decompressor
(void) jpeg_start_decompress(cinfo);
// Bytes per row in output buffer
int row_stride = cinfo->output_width * cinfo->output_components;
// Allocate buffer
unsigned long bmp_size = row_stride * cinfo->output_height;
bmp_buffer = (unsigned char*)malloc(bmp_size);
// Step 6: while (scan lines remain to be read)
while (cinfo->output_scanline < cinfo->output_height) {
unsigned char *buffer_array[1];
buffer_array[0] = bmp_buffer + (cinfo->output_scanline) * row_stride;
jpeg_read_scanlines(cinfo, buffer_array, 1);
}
// Step 7: Finish decompression
(void)jpeg_finish_decompress(cinfo);
fclose(infile);
// --> At this point we have raw RGB data in bmp_buffer
// Create new Cairo surface from our raw image data
cairo_surface_t *surface;
surface = cairo_image_surface_create_for_data(bmp_buffer,
CAIRO_FORMAT_ARGB32,
cinfo->output_width,
cinfo->output_height,
row_stride);
// Draw surface to Cairo
if (surface) {
cairo_set_source_surface(cr, surface, 0, 0);
cairo_paint(cr);
cairo_surface_destroy(surface);
}
// Cleanup. In this "ImageImporter" we clean up everything in "DrawToCairo"
// as I'm not really sure whether we are able to draw a second time.
free(bmp_buffer);
jpeg_destroy_decompress(cinfo);
free(cinfo);
cinfo = NULL;
}
void cImageImporterJPG::GetImageSize(int &width, int &height) {
if (cinfo) {
width = cinfo->image_width;
height = cinfo->image_height;
}
}

View File

@ -1,10 +1,10 @@
#ifndef __NOPACITY_IMAGELOADER_H
#define __NOPACITY_IMAGELOADER_H
#define X_DISPLAY_MISSING
#include <cairo.h>
#include <librsvg/rsvg.h>
#include <jpeglib.h>
#include <setjmp.h>
#include <vdr/osd.h>
#include <vdr/tools.h>
@ -44,6 +44,53 @@ private:
RsvgHandle *handle;
};
// Image importer for JPG
#if BITS_IN_JSAMPLE != 8
#error libjpeg-turbo has to be compiled with 8-bit samples!
#endif
#ifndef JCS_EXTENSIONS
#error libjpeg-turbo with JCS_EXTENSIONS required!
#endif
struct my_error_mgr {
struct jpeg_error_mgr pub; // "public" fields
jmp_buf setjmp_buffer; // for return to caller
};
METHODDEF(void)
my_error_exit(j_common_ptr cinfo) {
// cinfo->err really points to a my_error_mgr struct, so coerce pointer
my_error_mgr *myerr = (my_error_mgr*) cinfo->err;
// Always display the message.
// We could postpone this until after returning, if we chose.
(*cinfo->err->output_message) (cinfo);
// Return control to the setjmp point
longjmp(myerr->setjmp_buffer, 1);
}
METHODDEF(void)
my_output_message(j_common_ptr cinfo) {
char buf[JMSG_LENGTH_MAX];
cinfo->err->format_message(cinfo, buf);
dsyslog("skindesigner: libjpeg error: %s", buf);
}
class cImageImporterJPG : public cImageImporter {
public:
cImageImporterJPG();
~cImageImporterJPG();
bool LoadImage(const char *path);
void DrawToCairo(cairo_t *cr);
void GetImageSize(int &width, int &height);
private:
j_decompress_ptr cinfo;
FILE *infile;
};
class cImageLoader {
private: