Audio and video entry articles directory

RGB – to – JPEG review

In the previous article, we created a JPEG image by manually generating a JPEG image from RGB data.

It can be felt that it is quite complex to realize the basic system encoding of JPEG by oneself. The JPEG compression encoding algorithm is divided into 11 steps:

  1. Color mode conversion
  2. The sampling
  3. block
  4. Discrete cosine transform (DCT)
  5. quantitative
  6. Zigzag scan sort
  7. Differential pulse modulation coding of DC coefficients
  8. Intermediate format calculation of DC coefficients
  9. Run-length encoding of AC coefficients
  10. Intermediate format calculation of AC coefficients
  11. Entropy coding

Next, we use libjpeg-turbo to process JPEG images.

Use libjpeg – turbo

Building libjpeg-turbo

Official Build Documentation

mkdir libjpeg-turbo/build
cd libjpeg-turbo/build

cmake -G"Unix Makefiles" -DCMAKE_INSTALL_PREFIX:PATH=./ -DCMAKE_INSTALL_BINDIR:PATH=./ -DCMAKE_INSTALL_DATAROOTDIR:PATH=./ -DCMAKE_INSTALL_DOCDIR:PATH=./ -DCMAKE_INSTALL_LIBDIR:PATH=./  -DCMAKE_INSTALL_INCLUDEDIR:PATH=./  -DCMAKE_INSTALL_MANDIR:PATH=./ ..

make
make install

CMakeLists.txt

Cmake_minimum_required (VERSION 3.14) set(CMAKE_C_STANDARD 99) #aux_source_directory(.. /3rd/libjpeg-turbo LIBJPEG_TURBO_SRC) link_directories(.. /3rd/libjpeg-turbo/build) include_directories(.. /3rd/libjpeg-turbo/build) add_executable(16-RGB-TO-JPEG-Library RGB-TO-JPEG-with-libjpeg-turbo.c util.c target_link_libraries(16-rgb-to-jpeg-library libturbojpeg.dylib)

Libjpeg – Turbo handles JPEG images

JPEG to RGB24

Use libjpeg-turbo to decode JPEG images into RGB format data.

The code used in the JPEG picture

struct ImageData { unsigned char *pixels; long width; long height; }; int decode_JPEG_file(char *inJpegName, char *outRgbName) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; FILE * infile; FILE * outfile; if ((infile = fopen(inJpegName, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", inJpegName); return -1; } if ((outfile = fopen(outRgbName, "wb")) == NULL) { fprintf(stderr, "can't open %s\n", outRgbName); return -1; } cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile); jpeg_read_header(&cinfo, TRUE); printf("image_width = %d\n", cinfo.image_width); printf("image_height = %d\n", cinfo.image_height); printf("num_components = %d\n", cinfo.num_components); printf("enter scale M/N:\n"); jpeg_start_decompress(&cinfo); Printf ("output_width = %d\n", info.output_width); printf("output_height = %d\n", cinfo.output_height); printf("output_components = %d\n", cinfo.output_components); int row_stride = cinfo.output_width * cinfo.output_components; /* Make a one-row-high sample array that will go away when done with image */ JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW)); buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride); struct ImageData imageData = { .width = cinfo.image_width, .height = cinfo.image_height, .pixels = malloc(row_stride*cinfo.image_height) }; long counter = 0; while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, buffer, 1); memcpy(imageData.pixels + counter, buffer[0], row_stride); counter += row_stride; } printf("total size: %ld\n", counter); fwrite(imageData.pixels, counter, 1, outfile); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(infile); fclose(outfile); free(imageData.pixels); return 0; } int main (int arg c, char * argv []) {printf (" left left left left left left left left left left down down down down down down down down down Decode JPEG to RGB24 left left left left left left left left left left down down down down down down down down down \ n "); char *inJpegName1 = "/Users/staff/Desktop/libjpeg-turbo-test-image.jpg"; char *outRgbName1 = "/Users/staff/Desktop/libjpeg-turbo-test-image.rgb24"; int flag1 = decode_JPEG_file(inJpegName1, outRgbName1); if (flag1 == 0) { printf("decode ok! \n"); } else { printf("decode error! \n"); } printf (" write write write write write write write write write write Decode JPEG to RGB24 write write write write write write write write write write \ n \ n "); }

Run the above code and you will get the decoded RGB file libjpeg-turbo-test-image.rgb24:

Use FFPlay to view the RGB24 file:

ffplay -f rawvideo -pixel_format rgb24  -s 800x800 /Users/staff/Desktop/libjpeg-turbo-test-image.rgb24

RGB24 to JPEG

Uint32_t rainbowColors[] = {0XFF0000, // Red 0XFFA500, // Orange 0XFFFF00, // Yellow 0X00FF00, // Green 0X007FFF, // blue 0X0000FF, // blue 0X8B00FF // purple}; void genRGB24Data(uint8_t *rgbData, int width, int height) { for (int i = 0; i < width; ++ I) {// Uint32_t currentColor = rainbowColors[0]; if(i < 100) { currentColor = rainbowColors[0]; } else if(i < 200) { currentColor = rainbowColors[1]; } else if(i < 300) { currentColor = rainbowColors[2]; } else if(i < 400) { currentColor = rainbowColors[3]; } else if(i < 500) { currentColor = rainbowColors[4]; } else if(i < 600) { currentColor = rainbowColors[5]; } else if(i < 700) { currentColor = rainbowColors[6]; } // UINT8_T R = (CurrentColor & 0xFF0000) >> 16; // UINT8_T G = (CurrentColor & 0x00FF00) >> 8; Uint8_t B = currentColor & 0x0000FF; for (int j = 0; j < height; ++j) { int currentIndex = 3*(i*height+j); rgbData[currentIndex] = R; rgbData[currentIndex+1] = G; rgbData[currentIndex+2] = B; } } } int encode_JPEG_file(char *strImageName,uint8_t *image_buffer, int image_height, int image_width, int quality) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; /* More stuff */ FILE * outfile; /* target file */ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); if ((outfile = fopen(strImageName, "wb")) == NULL) { fprintf(stderr, "can't open %s\n", strImageName); //exit(1); return -1; } jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = image_width; /* image width and height, in pixels */ cinfo.image_height = image_height; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, TRUE); row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ int line = 0; while (line < cinfo.image_height) { //row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride]; row_pointer[0] = &image_buffer[line * row_stride]; jpeg_write_scanlines(&cinfo, row_pointer, 1); line++; } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* After finish_compress, we can close the output file. */ fclose(outfile); /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); return 0; } int main (int arg c, char * argv []) {printf (" left left left left left left left left left left down down down down down down down down down Encode RGB24 to JPEG left left left left left left left left left left down down down down down down down down down \ n "); int width = 700, height = 700; char *outJpegName2 = "/Users/staff/Desktop/rainbow-rgb24.jpeg"; //uint8_t rgbBuffer[width*height*3]; uint8_t *rgbBuffer = malloc(width*height*3); genRGB24Data(rgbBuffer, width, height); int flag2 = encode_JPEG_file(outJpegName2, rgbBuffer, width, height, 80); if (flag2 == 0) { printf("encode ok! \n"); } else { printf("encode error! \n"); } free(rgbBuffer); Printf (" write write write write write write write write write write Encode RGB24 to JPEG write write write write write write write write write write \ n \ n "); }

Again generate the rainbow graph, run the above code and you will get the encoded JPEG file rainbow-rgb24.jpeg:

JPEG to YUV

Use libjpeg-turbo to decode JPEG images into YUV format data.

int tjpeg2yuv(unsigned char* jpeg_buffer, int jpeg_size, unsigned char** yuv_buffer, int* yuv_size, int* yuv_type) { tjhandle handle = NULL; int width, height, subsample, colorspace; int flags = 0; int padding = 1; Int ret = 0; int ret = 0; handle = tjInitDecompress(); tjDecompressHeader3(handle, jpeg_buffer, jpeg_size, &width, &height, &subsample, &colorspace); printf("w: %d h: %d subsample: %d color: %d\n", width, height, subsample, colorspace); flags |= 0; *yuv_type = subsample; *yuv_size = tjBufSizeYUV2(width, padding, height, subsample); *yuv_size = tjBufSizeYUV2(width, padding, height, subsample); *yuv_buffer =(unsigned char *)malloc(*yuv_size); if (*yuv_buffer == NULL) { printf("malloc buffer for rgb failed.\n"); return -1; } ret = tjDecompressToYUV2(handle, jpeg_buffer, jpeg_size, *yuv_buffer, width, padding, height, flags); if (ret < 0) { printf("compress to jpeg failed: %s\n", tjGetErrorStr()); } tjDestroy(handle); return ret; } int main (int arg c, char * argv []) {printf (" left left left left left left left left left left down down down down down down down down down Decode JPEG to YUV left left left left left left left left left left down down down down down down down down down \ n "); char *inJpegName3 = "/Users/staff/Desktop/libjpeg-turbo-test-image.jpg"; FILE *jpegFile = fopen(inJpegName3, "rb"); struct stat statbuf; stat(inJpegName3, &statbuf); int fileLen=statbuf.st_size; printf("fileLength2: %d\n", fileLen); uint8_t *jpegData = malloc(fileLen); fread(jpegData, fileLen, 1, jpegFile); fclose(jpegFile); uint8_t *yuvData; int yuvSize; int yuvType; tjpeg2yuv(jpegData, fileLen, &yuvData, &yuvSize, &yuvType); printf("size: %d; type: %d\n", yuvSize, yuvType); char *yuvSuffix; if(yuvType == TJSAMP_444) { yuvSuffix = ".yuv444"; } else if(yuvType == TJSAMP_422) { yuvSuffix = ".yuv422"; } else if(yuvType == TJSAMP_420) { yuvSuffix = ".yuv420"; } else if(yuvType == TJSAMP_GRAY) { yuvSuffix = ".yuv-gray"; } else if(yuvType == TJSAMP_440) { yuvSuffix = ".yuv440"; } else if(yuvType == TJSAMP_411) { yuvSuffix = ".yuv411"; } else { printf("Unsupported type!" ); return -1; } printf("yuv samp: %s\n", yuvSuffix); char yuvFileName[100]; sprintf(yuvFileName, "/Users/staff/Desktop/libjpeg-turbo-test-image%s", yuvSuffix); FILE *yuvFile = fopen(yuvFileName, "wb"); fwrite(yuvData, yuvSize, 1, yuvFile); free(jpegData); free(yuvData); fflush(yuvFile); fclose(yuvFile); Printf (" write write write write write write write write write write Decode JPEG to YUV write write write write write write write write write write \ n \ n "); }

Run the above code and you will get the decoded YUV file libjpeg-turbo-test-image.yuv420:

Use FFPlay to view YUV files:

ffplay -f rawvideo -pixel_format yuv420p  -s 800x800 /Users/staff/Desktop/libjpeg-turbo-test-image.yuv420

YUV to JPEG

The YUV file obtained in the previous step is then encoded into a JPEG file again.

int tyuv2jpeg(unsigned char* yuv_buffer, int yuv_size, int width, int height, int subsample, unsigned char** jpeg_buffer, unsigned long* jpeg_size, int quality) { tjhandle handle = NULL; int flags = 0; int padding = 1; Int need_size = 0; int need_size = 0; int ret = 0; handle = tjInitCompress(); flags |= 0; need_size = tjBufSizeYUV2(width, padding, height, subsample); if (need_size ! = yuv_size) { printf("we detect yuv size: %d, but you give: %d, check again.\n", need_size, yuv_size); return 0; } ret = tjCompressFromYUV(handle, yuv_buffer, width, padding, height, subsample, jpeg_buffer, jpeg_size, quality, flags); if (ret < 0) { printf("compress to jpeg failed: %s\n", tjGetErrorStr()); } tjDestroy(handle); return ret; } int main (int arg c, char * argv []) {printf (" left left left left left left left left left left down down down down down down down down down Encode YUV to JPEG left left left left left left left left left left down down down down down down down down down \ n "); char *yuv420FileName = "/Users/staff/Desktop/libjpeg-turbo-test-image.yuv420"; FILE *yuv420File = fopen(yuv420FileName, "rb"); int yuv420Width = 800, yuv420Height = 800; int yuvSubsample = TJSAMP_420; uint8_t *yuv2jpegBuffer; unsigned long yuv2JpegSize; struct stat yuv420FileStat; stat(yuv420FileName, &yuv420FileStat); int yuv420FileLen = yuv420FileStat.st_size; printf("yuv420 file length: %d\n", yuv420FileLen); uint8_t * yuv420Data = malloc(yuv420FileLen); fread(yuv420Data, yuv420FileLen, 1, yuv420File); printf("yuv420 read finish! \n"); tyuv2jpeg(yuv420Data, yuv420FileLen, yuv420Width, yuv420Height, yuvSubsample, &yuv2jpegBuffer, &yuv2JpegSize, 80); printf("jpeg data size: %ld\n", yuv2JpegSize); FILE *yuv2JpegOutFile = fopen("/Users/staff/Desktop/libjpeg-turbo-yuv-to-jpeg.jpeg", "wb"); fwrite(yuv2jpegBuffer, yuv2JpegSize, 1, yuv2JpegOutFile); fclose(yuv420File); fflush(yuv2JpegOutFile); fclose(yuv2JpegOutFile); free(yuv420Data); Printf (" write write write write write write write write write write Encode YUV to JPEG write write write write write write write write write write \ n \ n "); return 0; }

Run the above code and you will get the encoded JPEG file libjpeg-turbo-yuv-to-jpeg. JPEG:

Congratulations!

So far, we have learned to use libjpeg-turbo to process JPEG images.


Code: 16 – RGB – to – jpeg – library

References:

Main libjpeg-turbo repository

JPEG image compression algorithm process detail

Libjpeg learning 4: libjpeg-turbo YUV

About using the Turbojpeg library under Linux

FFmpeg & FFplay command basic usage

Wrong content? Contact author: