├── .gitignore ├── CMakeLists.txt ├── README.md ├── demo.jpg ├── jpeg_read.c ├── jpeg_read.h ├── python ├── CMakeLists.txt ├── jpegtools.cpp └── jpegtools │ └── __init__.py ├── setup.py ├── test_jpeg_read.c └── test_jpeg_read_python.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | build 3 | *.pyc 4 | *.so 5 | *egg-info 6 | dist 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | 4 | find_package(JPEG) 5 | include_directories(BEFORE ${JPEG_INCLUDE_DIR}) 6 | link_directories(${JPEG_LIBRARIES}) 7 | message(${JPEG_INCLUDE_DIR}, ${JPEG_LIBRARIES}) 8 | 9 | add_library(extract_dct SHARED jpeg_read.c ) 10 | target_link_libraries(extract_dct ${JPEG_LIBRARIES}) 11 | add_executable(test_jpeg_read test_jpeg_read.c) 12 | target_link_libraries(test_jpeg_read extract_dct) 13 | add_custom_command(TARGET extract_dct POST_BUILD 14 | COMMAND cp $ "${PROJECT_SOURCE_DIR}/python/jpegtools" 15 | ) 16 | 17 | add_subdirectory(python) 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##jpeg toolbox 2 | 3 | this toolbox was written to extract the dct coefficient of jpeg images. 4 | The python interface is wrapped via boost-python. 5 | 6 | 7 | ### 1. dependencies 8 | 9 | cmake 10 | boost-python 11 | python-devel 12 | libjpeg 13 | 14 | ### 2. compilation 15 | 16 | 17 | ``` 18 | mkdir build 19 | cd build 20 | cmake .. 21 | make 22 | ``` 23 | 24 | ### 3. usage 25 | 26 | #### 3.1 c/c++ interface 27 | 28 | the struct `jpegobj` 29 | ```c 30 | typedef struct jpegobj{ 31 | int image_width; 32 | int image_height; 33 | int image_components; 34 | int image_color_space; 35 | int quant_nums; 36 | int coef_array_shape[4][2]; 37 | double *quant_tables; // n*dctsize*dctsize 38 | double **coef_arrays; // num_component * each dimension size 39 | } jpegobj; 40 | ``` 41 | 42 | in `test_jpeg_read.c`: 43 | 44 | ```c 45 | const char *image = "../demo.jpg"; 46 | printf("%s\n",image); 47 | jpegobj obj = read_jpeg(image); 48 | ``` 49 | 50 | #### 3.2 python interface 51 | it returns a dict, which has the same properties as struct `jpegobj` 52 | 53 | usage example: 54 | 55 | ```python 56 | import sys 57 | sys.path.append('./python') 58 | import jpegtools 59 | 60 | jpeginfo = jpegtools.read_jpeg('./demo.jpg') 61 | print jpeginfo 62 | ``` 63 | -------------------------------------------------------------------------------- /demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klauscc/jpeg_toolbox_python/1f0b3673131ef0f00654f0408fa22c241b69719f/demo.jpg -------------------------------------------------------------------------------- /jpeg_read.c: -------------------------------------------------------------------------------- 1 | #include "jpeg_read.h" 2 | #include 3 | 4 | jpegobj read_jpeg(const char *image) 5 | { 6 | 7 | jpegobj obj; 8 | struct jpeg_decompress_struct cinfo; 9 | struct jpeg_error_mgr jerr; 10 | jpeg_component_info *compptr; 11 | jvirt_barray_ptr *coef_arrays; 12 | jpeg_saved_marker_ptr marker_ptr; 13 | FILE *infile; 14 | JDIMENSION blk_x,blk_y; 15 | JBLOCKARRAY buffer; 16 | JCOEFPTR bufptr; 17 | JQUANT_TBL *quant_ptr; 18 | JHUFF_TBL *huff_ptr; 19 | int strlen, c_width, c_height, ci, i, j, n, dims[2]; 20 | 21 | infile = fopen(image, "rb"); 22 | cinfo.err = jpeg_std_error(&jerr); 23 | 24 | /* initialize JPEG decompression object */ 25 | jpeg_create_decompress(&cinfo); 26 | jpeg_stdio_src(&cinfo, infile); 27 | 28 | /* save contents of markers */ 29 | jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF); 30 | 31 | /* read header and coefficients */ 32 | (void) jpeg_read_header(&cinfo, TRUE); 33 | 34 | /* for some reason out_color_components isn't being set by 35 | jpeg_read_header, so we will infer it from out_color_space: */ 36 | switch (cinfo.out_color_space) { 37 | case JCS_GRAYSCALE: 38 | cinfo.out_color_components = 1; 39 | break; 40 | case JCS_RGB: 41 | cinfo.out_color_components = 3; 42 | break; 43 | case JCS_YCbCr: 44 | cinfo.out_color_components = 3; 45 | break; 46 | case JCS_CMYK: 47 | cinfo.out_color_components = 4; 48 | break; 49 | case JCS_YCCK: 50 | cinfo.out_color_components = 4; 51 | break; 52 | } 53 | 54 | obj.image_width = cinfo.image_width; 55 | obj.image_height = cinfo.image_height; 56 | obj.image_components = cinfo.out_color_components; 57 | obj.image_color_space = cinfo.out_color_space; 58 | 59 | /* copy the quantization tables*/ 60 | for (n = 0; n < NUM_QUANT_TBLS && cinfo.quant_tbl_ptrs[n] != NULL; n++) {} 61 | int num_quantable = n; 62 | obj.quant_nums = num_quantable; 63 | obj.quant_tables = malloc(sizeof(double)*num_quantable*DCTSIZE*DCTSIZE); 64 | for (n = 0; n < num_quantable; n++) { 65 | quant_ptr = cinfo.quant_tbl_ptrs[n]; 66 | for (i = 0; i < DCTSIZE; i++) 67 | for (j = 0; j < DCTSIZE; j++) 68 | obj.quant_tables[n*DCTSIZE*DCTSIZE+i*DCTSIZE+j] = (double) quant_ptr->quantval[i*DCTSIZE+j]; 69 | } 70 | 71 | /* creation and population of the DCT coefficient arrays */ 72 | obj.coef_arrays = malloc(sizeof(double *)*cinfo.num_components); 73 | 74 | /* copy coefficients from virtual block arrays */ 75 | double *coef_ci; 76 | coef_arrays = jpeg_read_coefficients(&cinfo); 77 | for (ci = 0; ci < cinfo.num_components; ci++) { 78 | compptr = cinfo.comp_info + ci; 79 | c_height = compptr->height_in_blocks * DCTSIZE; 80 | c_width = compptr->width_in_blocks * DCTSIZE; 81 | /*malloc array of ci component*/ 82 | obj.coef_array_shape[ci][0] = c_height; 83 | obj.coef_array_shape[ci][1] = c_width; 84 | obj.coef_arrays[ci]= malloc((size_t)sizeof(double)*c_height * c_width); 85 | coef_ci = obj.coef_arrays[ci]; 86 | 87 | 88 | /* copy coefficients from virtual block arrays */ 89 | for (blk_y = 0; blk_y < compptr->height_in_blocks; blk_y++) { 90 | buffer = (cinfo.mem->access_virt_barray)((j_common_ptr) &cinfo, coef_arrays[ci], blk_y, 1, FALSE); 91 | for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { 92 | bufptr = buffer[0][blk_x]; 93 | for (i = 0; i < DCTSIZE; i++) /* for each row in block */ 94 | for (j = 0; j < DCTSIZE; j++) /* for each column in block */ 95 | coef_ci[(blk_y*DCTSIZE+i)*c_width+blk_x*DCTSIZE+j] = (double) bufptr[i*DCTSIZE+j]; 96 | } 97 | } 98 | } 99 | 100 | /* done with cinfo */ 101 | jpeg_finish_decompress(&cinfo); 102 | jpeg_destroy_decompress(&cinfo); 103 | 104 | /* close input file */ 105 | fclose(infile); 106 | return obj; 107 | } 108 | 109 | void freeJpegObj(jpegobj obj) 110 | { 111 | free(obj.quant_tables); 112 | double *coef; 113 | int ci; 114 | int num_components = obj.image_components; 115 | for (ci = 0; ci < num_components; ci++) { 116 | coef = obj.coef_arrays[ci]; 117 | free(coef); 118 | } 119 | free(obj.coef_arrays); 120 | } 121 | -------------------------------------------------------------------------------- /jpeg_read.h: -------------------------------------------------------------------------------- 1 | #ifndef JPEG_READ_H 2 | #define JPEG_READ_H 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | 12 | typedef struct jpegobj{ 13 | int image_width; 14 | int image_height; 15 | int image_components; 16 | int image_color_space; 17 | int quant_nums; 18 | int coef_array_shape[4][2]; 19 | double *quant_tables; // n*dctsize*dctsize 20 | double **coef_arrays; // num_component * each dimension size 21 | } jpegobj; 22 | 23 | jpegobj read_jpeg(const char *); 24 | 25 | void freeJpegObj(jpegobj obj); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Boost REQUIRED python) 2 | #FIND_PACKAGE(PythonLibs 2.7 REQUIRED) 3 | FIND_PACKAGE(PythonLibs REQUIRED) 4 | include_directories(${PROJECT_SOURCE_DIR} ${PYTHON_INCLUDE_DIR} ${NUMPY_INCLUDE_DIR} ${Boost_INCLUDE_DIRS}) 5 | add_library(jpegtools SHARED jpegtools.cpp) 6 | target_link_libraries(jpegtools extract_dct ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) 7 | set_target_properties(jpegtools PROPERTIES PREFIX "" OUTPUT_NAME "_jpegtools") 8 | 9 | set(__linkname "${PROJECT_SOURCE_DIR}/python/jpegtools/_jpegtools.so") 10 | add_custom_command(TARGET jpegtools POST_BUILD 11 | COMMAND cp $ "${__linkname}" 12 | ) 13 | -------------------------------------------------------------------------------- /python/jpegtools.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "jpeg_read.h" 4 | 5 | namespace bp = boost::python; 6 | 7 | static bp::list cArray2List(double *data, int length){ 8 | bp::list l; 9 | for (int i=0;i!= length;++i) 10 | l.append(data[i]); 11 | return l; 12 | } 13 | 14 | bp::dict _read_jpeg(const char * image){ 15 | jpegobj obj = read_jpeg(image); 16 | bp::dict jpegDict; 17 | int i; 18 | 19 | jpegDict["image_width"] = obj.image_width; 20 | jpegDict["image_height"] = obj.image_height; 21 | jpegDict["image_components"] = obj.image_components; 22 | jpegDict["image_color_space"] = obj.image_color_space; 23 | bp::list quantable = cArray2List(obj.quant_tables, 64*obj.quant_nums); 24 | jpegDict["quant_nums"] = obj.quant_nums; 25 | jpegDict["quant_tables"] = quantable; 26 | bp::list coef_arrays; 27 | bp::list coef_shape; 28 | int (*coef_array_shape)[2]; 29 | coef_array_shape = obj.coef_array_shape; 30 | for(i=0;i!= obj.image_components;++i){ 31 | coef_arrays.append(cArray2List(obj.coef_arrays[i], coef_array_shape[i][0]*coef_array_shape[i][1])); 32 | coef_shape.append(bp::make_tuple(coef_array_shape[i][0], coef_array_shape[i][1])); 33 | } 34 | jpegDict["coef_array_shape"] = coef_shape; 35 | jpegDict["coef_arrays"] = coef_arrays; 36 | 37 | freeJpegObj(obj); 38 | return jpegDict; 39 | } 40 | 41 | 42 | 43 | BOOST_PYTHON_MODULE(_jpegtools) { 44 | bp::def("read_jpeg", &_read_jpeg); 45 | } 46 | -------------------------------------------------------------------------------- /python/jpegtools/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import ctypes 3 | import numpy as np 4 | 5 | CURRENT_FILE_DIRECTORY = os.path.abspath(os.path.dirname(__file__)) 6 | ctypes.cdll.LoadLibrary(os.path.join(CURRENT_FILE_DIRECTORY, 'libextract_dct.so')) 7 | from . import _jpegtools 8 | 9 | def read_jpeg(image): 10 | jpegobj = _jpegtools.read_jpeg(image) 11 | quantable = np.array(jpegobj['quant_tables']) 12 | quantable = quantable.reshape([jpegobj['quant_nums'], 8, 8]) 13 | jpegobj['quant_tables'] = quantable 14 | 15 | coef_arrays = [] 16 | shape = jpegobj['coef_array_shape'] 17 | for i in range(len(shape)): 18 | coef_array = jpegobj['coef_arrays'][i] 19 | coef_array = np.array(coef_array) 20 | coef_arrays = coef_arrays + [coef_array.reshape(shape[i])] 21 | jpegobj['coef_arrays'] = coef_arrays 22 | return jpegobj 23 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #================================================================ 3 | # God Bless You. 4 | # 5 | # author: klaus 6 | # email: chengfeng2333@gmail.com 7 | # created date: 2020/05/08 8 | # description: 9 | # 10 | #================================================================ 11 | 12 | from setuptools import setup, Extension 13 | 14 | setup( 15 | name='jpegtools', 16 | version='0.0.1', 17 | packages=['jpegtools'], 18 | package_dir={'jpegtools': './python/jpegtools'}, 19 | package_data={'jpegtools': ['_jpegtools.so', 'libextract_dct.so']}, 20 | include_package_data=True, 21 | ) 22 | -------------------------------------------------------------------------------- /test_jpeg_read.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "jpeg_read.h" 3 | 4 | void main(int argc, const char* argv[]) 5 | { 6 | const char *image = "../demo.jpg"; 7 | printf("%s\n",image); 8 | jpegobj obj = read_jpeg(image); 9 | printf("image_width: %d\n image_height: %d\n", obj.image_width, obj.image_height ); 10 | 11 | int i,j,k; 12 | 13 | //print coef_array 14 | for (i = 0; i != obj.quant_nums; ++i){ 15 | printf("quantable %d:\n",i); 16 | for (j=0;j !=8; ++j){ 17 | for (k=0;k!=8;++k){ 18 | printf("%f ",obj.quant_tables[i*64 + j*8 + k]); 19 | } 20 | printf("\n"); 21 | } 22 | } 23 | 24 | double *coef_ci; 25 | for (i = 0; i != obj.image_components; ++i){ 26 | printf("coef %d:\n",i); 27 | coef_ci = obj.coef_arrays[i]; 28 | for (j=64;j != 80; ++j){ 29 | for (k=64;k!=80;++k){ 30 | printf("%-5.0f ",coef_ci[j*obj.coef_array_shape[i][1]+k]); 31 | } 32 | printf("\n"); 33 | } 34 | } 35 | 36 | freeJpegObj(obj); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /test_jpeg_read_python.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('./python') 3 | import jpegtools 4 | 5 | jpeginfo = jpegtools.read_jpeg('./demo.jpg') 6 | print (jpeginfo) 7 | --------------------------------------------------------------------------------