mirror of https://github.com/grisu48/Infragram.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
4.7 KiB
188 lines
4.7 KiB
/* 2018, Felix Niederwanger |
|
* This is my own libjpeg wrapper |
|
* Do not mind the crappy quality |
|
*/ |
|
|
|
#ifndef _INFRAGRAM_JPEG_HPP |
|
#define _INFRAGRAM_JPEG_HPP |
|
|
|
#include <stdio.h> |
|
#include <unistd.h> |
|
#include <jpeglib.h> |
|
#include <string.h> |
|
#include <errno.h> |
|
|
|
#include <iostream> |
|
|
|
using namespace std; |
|
|
|
struct { |
|
unsigned char r; |
|
unsigned char g; |
|
unsigned char b; |
|
} typedef rgb_t; |
|
|
|
class Jpeg { |
|
public: |
|
int width = 0; |
|
int height = 0; |
|
int depth = 0; |
|
private: |
|
unsigned char *bmap = NULL; |
|
|
|
public: |
|
Jpeg(const Jpeg &src) { |
|
this->width = src.width; |
|
this->height = src.height; |
|
this->depth = src.depth; |
|
|
|
const size_t size = 3*width*height; |
|
this->bmap = new unsigned char[size]; |
|
memcpy(this->bmap, src.bmap, sizeof(unsigned char)*size); |
|
} |
|
Jpeg(Jpeg &&src) { |
|
this->width = src.width; |
|
this->height = src.height; |
|
this->depth = src.depth; |
|
this->bmap = src.bmap; |
|
|
|
src.width = src.height = src.depth = 0; |
|
src.bmap = NULL; |
|
} |
|
Jpeg(const int width, const int height) { |
|
this->width = width; |
|
this->height = height; |
|
this->depth = 32; |
|
|
|
const size_t size = 3*width*height; |
|
this->bmap = new unsigned char[size]; |
|
bzero(this->bmap, sizeof(unsigned char)*size); |
|
|
|
} |
|
|
|
Jpeg(const char *filename) { |
|
unsigned char r, g, b; |
|
struct jpeg_decompress_struct cinfo; |
|
struct jpeg_error_mgr jerr; |
|
|
|
FILE * infile; /* source file */ |
|
JSAMPARRAY pJpegBuffer; /* Output row buffer */ |
|
int row_stride; /* physical row width in output buffer */ |
|
if ((infile = fopen(filename, "rb")) == NULL) { |
|
throw "Error opening jpeg file"; |
|
} |
|
cinfo.err = jpeg_std_error(&jerr); |
|
jpeg_create_decompress(&cinfo); |
|
jpeg_stdio_src(&cinfo, infile); |
|
(void) jpeg_read_header(&cinfo, TRUE); |
|
(void) jpeg_start_decompress(&cinfo); |
|
width = cinfo.output_width; |
|
height = cinfo.output_height; |
|
|
|
unsigned char * pDummy = new unsigned char [width*height*3]; |
|
if (!pDummy) |
|
throw "Out of memory"; |
|
unsigned char * pTest = pDummy; |
|
|
|
row_stride = width * cinfo.output_components; |
|
pJpegBuffer = (*cinfo.mem->alloc_sarray) |
|
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); |
|
|
|
while (cinfo.output_scanline < cinfo.output_height) { |
|
(void) jpeg_read_scanlines(&cinfo, pJpegBuffer, 1); |
|
for (int x = 0; x < width; x++) { |
|
r = pJpegBuffer[0][cinfo.output_components * x]; |
|
if (cinfo.output_components > 2) { |
|
g = pJpegBuffer[0][cinfo.output_components * x + 1]; |
|
b = pJpegBuffer[0][cinfo.output_components * x + 2]; |
|
} else { |
|
g = r; |
|
b = r; |
|
} |
|
*(pDummy++) = r; |
|
*(pDummy++) = g; |
|
*(pDummy++) = b; |
|
} |
|
} |
|
fclose(infile); |
|
(void) jpeg_finish_decompress(&cinfo); |
|
jpeg_destroy_decompress(&cinfo); |
|
|
|
bmap = (unsigned char*)pTest; |
|
depth = 32; |
|
} |
|
|
|
void write(const char* filename, int quality=100) const { |
|
FILE *ofp; |
|
struct jpeg_compress_struct cinfo; /* JPEG compression struct */ |
|
struct jpeg_error_mgr jerr; /* JPEG error handler */ |
|
JSAMPROW row_pointer[1]; /* output row buffer */ |
|
int row_stride; /* physical row width in output buf */ |
|
|
|
if ((ofp = fopen(filename, "wb")) == NULL) |
|
throw "Error opening file"; |
|
cinfo.err = jpeg_std_error(&jerr); |
|
|
|
jpeg_create_compress(&cinfo); |
|
jpeg_stdio_dest(&cinfo, ofp); |
|
|
|
cinfo.image_width = this->width; |
|
cinfo.image_height = this->height; |
|
cinfo.input_components = 3; |
|
cinfo.in_color_space = JCS_RGB; |
|
|
|
jpeg_set_defaults(&cinfo); |
|
jpeg_set_quality(&cinfo, quality, 0); |
|
jpeg_start_compress(&cinfo, TRUE); |
|
|
|
/* Calculate the size of a row in the image */ |
|
row_stride = cinfo.image_width * cinfo.input_components; |
|
|
|
/* compress the JPEG, one scanline at a time into the buffer */ |
|
while (cinfo.next_scanline < cinfo.image_height) { |
|
//cout << "Write cinfo.next_scanline = " << cinfo.next_scanline << endl; |
|
//row_pointer[0] = &(bmap[(cinfo.image_height - cinfo.next_scanline - 1)*row_stride]); |
|
row_pointer[0] = &(bmap[(cinfo.next_scanline)*row_stride]); |
|
jpeg_write_scanlines(&cinfo, row_pointer, 1); |
|
} |
|
|
|
jpeg_finish_compress(&cinfo); |
|
jpeg_destroy_compress(&cinfo); |
|
|
|
fclose(ofp); |
|
|
|
// Everything good so far :-) |
|
} |
|
|
|
virtual ~Jpeg() { |
|
if(this->bmap != NULL) { |
|
delete[] this->bmap; |
|
this->bmap = NULL; |
|
} |
|
} |
|
|
|
rgb_t operator()(int x, int y) const { |
|
return this->rgb(x,y); |
|
} |
|
rgb_t rgb(int x, int y) const { |
|
//if(bmap == NULL) throw "No data"; |
|
rgb_t ret; |
|
|
|
const size_t index = 3*(width*y + x); |
|
ret.r = this->bmap[index]; |
|
ret.g = this->bmap[index+1]; |
|
ret.b = this->bmap[index+2]; |
|
|
|
return ret; |
|
} |
|
/** Set pixel */ |
|
void set(int x, int y, rgb_t rgb) { |
|
const size_t index = 3*(width*y + x); |
|
this->bmap[index ] = rgb.r; |
|
this->bmap[index+1] = rgb.g; |
|
this->bmap[index+2] = rgb.b; |
|
} |
|
}; |
|
|
|
|
|
#endif
|
|
|