非自己写的,而是前辈写的,希望借此可以提示到别人
jpegenc.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "jpeglib.h"
#include "jerror.h"
#include "stddef.h"
#include "setjmp.h"
struct JPEG_Enc
{
struct jpeg_destination_mgr dst; // A data destination manager provides three methods: https://raw.githubusercontent.com/libjpeg-turbo/libjpeg-turbo/master/libjpeg.txt
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr; // Use standard error mgr
int quality; // 1-100
int jpeg_w;
int jpeg_h;
int jpeg_ch;
// Raw buffer
unsigned char *buffer; // G, RGB, or RGBA format
// Output
FILE *fp;
unsigned char *jpegOutput;
unsigned long jpegOutputSize;
};
#define kBufferSize (4096)
#define kMaxLines (8)
void jpegenc_init_destination(j_compress_ptr cinfo);
unsigned char *jpegenc_get_enc_buf(struct JPEG_Enc *jpeg_enc )
{
return (unsigned char *)jpeg_enc->jpegOutput;
}
unsigned long jpegenc_get_enc_size(struct JPEG_Enc *jpeg_enc )
{
return (unsigned long)jpeg_enc->jpegOutputSize;
}
int jpegenc_compress( struct JPEG_Enc *jpeg_enc, unsigned char *bytes, int quality, int ch )
{
struct jpeg_compress_struct *cinfo = &jpeg_enc->cinfo;
JSAMPROW row_pointer[kMaxLines];
int rowBytes;
unsigned char *srcScan = NULL;
if (bytes == NULL)
goto bail;
if((ch > jpeg_enc->jpeg_ch) || ( ch != 1 && ch != 3 ) )
goto bail;
cinfo->input_components = ch;
rowBytes = cinfo->image_width * cinfo->input_components;
jpeg_enc->cinfo.in_color_space = (ch == 1)? JCS_GRAYSCALE : JCS_RGB;
// Reset output buffer
jpeg_enc->jpegOutputSize = 0;
cinfo->dct_method = JDCT_IFAST;
jpeg_set_defaults(cinfo);
if(quality < 0)
quality = 0;
else if (quality > 100 )
quality = 100;
jpeg_enc->quality = quality;
jpeg_set_quality(cinfo, jpeg_enc->quality, (boolean)1);
// Set scan lines, which used by jpeglib
jpeg_start_compress(cinfo, 1);
while (cinfo->next_scanline < cinfo->image_height) {
JDIMENSION lines = kMaxLines, i;
if (lines > (cinfo->image_height - cinfo->next_scanline))
lines = cinfo->image_height - cinfo->next_scanline;
srcScan = bytes + rowBytes * cinfo->next_scanline;
for (i = 0; i < lines; i++) {
row_pointer[i] = srcScan;
srcScan += rowBytes;
}
jpeg_write_scanlines(cinfo, row_pointer, lines);
}
jpeg_finish_compress(cinfo);
return 0;
bail:
return 1;
}
void jpegenc_init_destination(j_compress_ptr cinfo)
{
struct JPEG_Enc *jpeg_enc = (struct JPEG_Enc *)cinfo->dest;
jpeg_enc->dst.next_output_byte = jpeg_enc->buffer;
jpeg_enc->dst.free_in_buffer = kBufferSize;
}
boolean jpegenc_empty_output_buffer(j_compress_ptr cinfo)
{
struct JPEG_Enc *jpeg_enc = (struct JPEG_Enc *)cinfo->dest;
if (NULL != jpeg_enc->fp)
fwrite(jpeg_enc->buffer, 1, kBufferSize, jpeg_enc->fp);
else {
memmove(jpeg_enc->jpegOutput + jpeg_enc->jpegOutputSize, jpeg_enc->buffer, kBufferSize);
jpeg_enc->jpegOutputSize += kBufferSize;
}
jpeg_enc->dst.next_output_byte = jpeg_enc->buffer;
jpeg_enc->dst.free_in_buffer = kBufferSize;
return 1;
}
void jpegenc_term_destination(j_compress_ptr cinfo)
{
struct JPEG_Enc * jpeg_enc = (struct JPEG_Enc *)cinfo->dest;
int size = (int)(kBufferSize - jpeg_enc->dst.free_in_buffer);
if (NULL != jpeg_enc->fp)
fwrite(jpeg_enc->buffer, 1, size, jpeg_enc->fp);
else {
memmove(jpeg_enc->jpegOutput + jpeg_enc->jpegOutputSize, jpeg_enc->buffer, size);
jpeg_enc->jpegOutputSize += size;
}
}
struct JPEG_Enc *new_jpegenc( int w, int h, int ch )
{
struct JPEG_Enc * jpeg_enc = (struct JPEG_Enc *) malloc(sizeof(struct JPEG_Enc));
if( jpeg_enc == NULL )
goto fail;
memset(jpeg_enc, 0, sizeof(struct JPEG_Enc));
if(ch != 1 && ch != 3)
goto fail;
jpeg_enc->jpeg_w = w;
jpeg_enc->jpeg_h = h;
jpeg_enc->jpeg_ch = ch;
// TODO: Just to elimnate reallocate buffer
// Buffer for encoded bytes for one image/frame
jpeg_enc->jpegOutput = (unsigned char*)malloc(jpeg_enc->jpeg_w * jpeg_enc->jpeg_h * ch);
if (jpeg_enc->jpegOutput == NULL)
{
goto fail;
}
// Used by scan lines - temp buffer for encoded bytes
jpeg_enc->buffer = (unsigned char*)malloc(kBufferSize);
if (jpeg_enc->buffer == NULL)
{
goto fail;
}
// Allocate and initialize JPEG compression object
// Error manager
jpeg_enc->cinfo.err = jpeg_std_error(&jpeg_enc->jerr);
//jpeg_enc->cinfo.err->error_exit = ???;
jpeg_create_compress(&jpeg_enc->cinfo);
// destination manager
jpeg_enc->cinfo.dest = &jpeg_enc->dst;
jpeg_enc->dst.init_destination = jpegenc_init_destination;
jpeg_enc->dst.empty_output_buffer = jpegenc_empty_output_buffer;
jpeg_enc->dst.term_destination = jpegenc_term_destination;
jpeg_enc->quality = 60;
jpeg_enc->cinfo.image_width = w;
jpeg_enc->cinfo.image_height = h;
jpeg_enc->cinfo.input_components = ch;
jpeg_enc->cinfo.in_color_space = (ch == 1)? JCS_GRAYSCALE : JCS_RGB;
jpeg_enc->cinfo.dct_method = JDCT_IFAST;
return jpeg_enc;
fail:
if(jpeg_enc)
{
if(jpeg_enc->buffer)
free(jpeg_enc->buffer);
if(jpeg_enc->jpegOutput)
free(jpeg_enc->jpegOutput);
free(jpeg_enc);
}
return NULL;
}
void dispose_jpegenc( struct JPEG_Enc *jpeg_enc )
{
if(jpeg_enc)
{
if(jpeg_enc->buffer)
free(jpeg_enc->buffer);
if(jpeg_enc->jpegOutput)
free(jpeg_enc->jpegOutput);
if(jpeg_enc->fp)
fclose(jpeg_enc->fp);
jpeg_destroy_compress(&jpeg_enc->cinfo);
free(jpeg_enc);
}
}
jepgenc.h
#ifndef __JPEGENCODERH__
#define __JPEGENCODERH__
struct JPEG_Enc;
/*
Notes:
1. New a jpegenc with image features: width, height, and channel (1,3 are valid)
2. Prepare image raw bytes buffer (for example rawbuf), which should have format Gray or RGB
3. execute jpegenc_compress
4. Then get result from jpegenc_get_enc_size(...) and jpegenc_get_enc_buf(...)
*/
int jpegenc_compress( struct JPEG_Enc *jpeg_enc, unsigned char *bytes, int quality, int ch );
unsigned long jpegenc_get_enc_size(struct JPEG_Enc *jpeg_enc );
unsigned char *jpegenc_get_enc_buf(struct JPEG_Enc *jpeg_enc );
//unsigned char *jpegenc_get_raw_buf(struct JPEG_Enc *jpeg_enc );
struct JPEG_Enc *new_jpegenc( int w, int h, int ch );
void dispose_jpegenc( struct JPEG_Enc *jpeg_enc );
#endif //__JPEGENCODERH__
test_jpeg.c
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "jpeglib.h"
#include "jpegenc.h"
void get_now_ms( unsigned long *ms)
{
struct timeval now;
gettimeofday(&now, NULL);
*ms = now.tv_sec * 1000 + now.tv_usec/1000;
}
// Creates a test image for saving. Creates a Mandelbrot Set fractal of size width x height
float *createMandelbrotImage(int width, int height, float xS, float yS, float rad, int maxIteration);
// This takes the float value 'val', converts it to red, green & blue values, then
// sets those values into the image memory buffer location pointed to by 'ptr'
void setRGB(unsigned char *ptr, float val);
void convertBuffer(unsigned char *buf_b, float *buf_f, int w, int h, int has_alpha);
void makeGrayImg(unsigned char *buf, int w, int h, int sz) {
unsigned char val = 0;
// Do not check sz can be dived by w
unsigned char *p = buf;
for(int i=0; i< h; i+=sz) {
memset(p, val, w*sz);
p += w*sz;
val = ~val;
}
}
void test_jpeg_file()
{
struct JPEG_Enc *jpeg_enc;
FILE *fp = NULL;
int ch = 3;
int has_alpha = 0;
// Specify an output image size
int width = 640;
int height = 480;
// Create a test image
printf("Creating Image\n");
float *buffer_f = createMandelbrotImage(width, height, -0.802, -0.177, 0.011, 110);
if (buffer_f == NULL) {
return;
}
// Then convert to bytes
unsigned char *buffer_b = (unsigned char *) malloc((3 + (has_alpha?1:0)) * width * height * sizeof(unsigned char));
if (buffer_b == NULL) {
return;
}
convertBuffer(buffer_b, buffer_f, width, height, (3 + has_alpha));
unsigned char *buffer_g = (unsigned char *) malloc( width * height * sizeof(unsigned char));
if (buffer_g == NULL) {
return;
}
convertBuffer(buffer_g, buffer_f, width, height, 1);
// JPEG encoding for RGB image
jpeg_enc = new_jpegenc(width, height, ch);
if(jpeg_enc == NULL) {
return;
}
// Encoding
unsigned long t0, t1;
get_now_ms(&t0);
jpegenc_compress(jpeg_enc, buffer_b, 60, ch);
get_now_ms(&t1);
printf("Compress RGB image to JPEG using %ldms\n", t1-t0);
printf("Saving JPEG\n");
fp = fopen("test_rgb.jpg", "wb");
if (fp == NULL) {
fprintf(stderr, "Could not open file for writing\n");
return;
}
fwrite(jpegenc_get_enc_buf(jpeg_enc), 1, jpegenc_get_enc_size(jpeg_enc), fp);
//dispose_jpegenc(jpeg_enc);
if (fp != NULL)
fclose(fp);
// JPEG encoding for Gray image
// Encoding
get_now_ms(&t0);
jpegenc_compress(jpeg_enc, buffer_g, 60, 1);
get_now_ms(&t1);
printf("Compress Gray image to JPEG using %ldms\n", t1-t0);
printf("Saving JPEG\n");
fp = fopen("test_gray.jpg", "wb");
if (fp == NULL) {
fprintf(stderr, "Could not open file for writing\n");
return;
}
fwrite(jpegenc_get_enc_buf(jpeg_enc), 1, jpegenc_get_enc_size(jpeg_enc), fp);
//dispose_jpegenc(jpeg_enc);
if (fp != NULL)
fclose(fp);
// Free up the memorty used to store the image
free(buffer_f);
free(buffer_b);
free(buffer_g);
// Added another example: 20190603
unsigned char *grayBuf = malloc(640*480 * sizeof(char));
makeGrayImg(grayBuf, 640, 480, 16);
get_now_ms(&t0);
jpegenc_compress(jpeg_enc, grayBuf, 60, 1);
get_now_ms(&t1);
printf("Compress Gray image to JPEG using %ldms\n", t1-t0);
printf("Saving JPEG\n");
fp = fopen("test_gray1.jpg", "wb");
if (fp == NULL) {
fprintf(stderr, "Could not open file for writing\n");
return;
}
fwrite(jpegenc_get_enc_buf(jpeg_enc), 1, jpegenc_get_enc_size(jpeg_enc), fp);
dispose_jpegenc(jpeg_enc);
if (fp != NULL)
fclose(fp);
}
void setGray(unsigned char *ptr, float val)
{
int v = (int)(val * 767);
if (v < 0) v = 0;
if (v > 767) v = 767;
int offset = v % 256;
if (v<256) {
ptr[0] = offset;
}
else if (v<512) {
ptr[0] = 255-offset;
}
else {
ptr[0] = 0;
}
}
// ch can be '1', '3', '4'
void convertBuffer(unsigned char *buf_b, float *buf_f, int w, int h, int ch)
{
int x, y;
int line_sz = w*(ch);
int pixel_sz = (ch);
int has_alpha = (ch == 4);
if(ch == 1) {
for (y=0 ; y<h ; y++) {
//printf("%d\n", y);
for (x=0 ; x<w ; x++)
{
setGray(&(buf_b[y*line_sz + x*pixel_sz ]), buf_f[y*w + x]);
}
}
}
else {
for (y=0 ; y<h ; y++) {
//printf("%d\n", y);
for (x=0 ; x<w ; x++)
{
setRGB(&(buf_b[y*line_sz + x*pixel_sz ]), buf_f[y*w + x]);
if(has_alpha)
buf_b[y*line_sz + x*pixel_sz +3] = 255;
}
}
}
}
void setRGB(unsigned char *ptr, float val)
{
int v = (int)(val * 767);
if (v < 0) v = 0;
if (v > 767) v = 767;
int offset = v % 256;
if (v<256) {
ptr[0] = 0; ptr[1] = 0; ptr[2] = offset;
}
else if (v<512) {
ptr[0] = 0; ptr[1] = offset; ptr[2] = 255-offset;
}
else {
ptr[0] = offset; ptr[1] = 255-offset; ptr[2] = 0;
}
}
float *createMandelbrotImage(int width, int height, float xS, float yS, float rad, int maxIteration)
{
float *buffer = (float *) malloc(width * height * sizeof(float));
if (buffer == NULL) {
fprintf(stderr, "Could not create image buffer\n");
return NULL;
}
// Create Mandelbrot set image
int xPos, yPos;
float minMu = maxIteration;
float maxMu = 0;
for (yPos=0 ; yPos<height ; yPos++)
{
float yP = (yS-rad) + (2.0f*rad/height)*yPos;
for (xPos=0 ; xPos<width ; xPos++)
{
float xP = (xS-rad) + (2.0f*rad/width)*xPos;
int iteration = 0;
float x = 0;
float y = 0;
while (x*x + y*y <= 4 && iteration < maxIteration)
{
float tmp = x*x - y*y + xP;
y = 2*x*y + yP;
x = tmp;
iteration++;
}
if (iteration < maxIteration) {
float modZ = sqrt(x*x + y*y);
float mu = iteration - (log(log(modZ))) / log(2);
if (mu > maxMu) maxMu = mu;
if (mu < minMu) minMu = mu;
buffer[yPos * width + xPos] = mu;
}
else {
buffer[yPos * width + xPos] = 0;
}
}
}
// Scale buffer values between 0 and 1
int count = width * height;
while (count) {
count --;
buffer[count] = (buffer[count] - minMu) / (maxMu - minMu);
}
return buffer;
}
int main(void)
{
test_jpeg_file();
}
编译需链接 -ljpeg