├── .gitignore ├── house.bmp ├── boat.512.bmp ├── boatcolor.512.bmp ├── assets ├── 30kb_quota.bmp ├── 50kb_quota.bmp ├── 70kb_quota.bmp ├── original.bmp ├── original_color.bmp ├── 100kb_quota_color.bmp ├── 140kb_quota_color.bmp └── 70kb_quota_color.bmp ├── example ├── src │ ├── stb_lib.c │ ├── example_decode.c │ ├── example_encode.c │ ├── example_decode_color.c │ ├── example_encode_color.c │ └── icer_util.c └── inc │ └── color_util.h ├── lib_icer ├── CMakeLists.txt ├── inc │ ├── crc.h │ └── icer.h └── src │ ├── icer_util.c │ ├── icer_config.c │ ├── icer_decoding.c │ ├── crc32.c │ ├── icer_encoding.c │ ├── icer_init.c │ ├── icer_partition.c │ ├── icer_compress.c │ └── icer_context_modeller.c ├── CMakeLists.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | cmake-build-debug 3 | cmake-build-release 4 | *.bmp 5 | ./*.bin -------------------------------------------------------------------------------- /house.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/house.bmp -------------------------------------------------------------------------------- /boat.512.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/boat.512.bmp -------------------------------------------------------------------------------- /boatcolor.512.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/boatcolor.512.bmp -------------------------------------------------------------------------------- /assets/30kb_quota.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/assets/30kb_quota.bmp -------------------------------------------------------------------------------- /assets/50kb_quota.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/assets/50kb_quota.bmp -------------------------------------------------------------------------------- /assets/70kb_quota.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/assets/70kb_quota.bmp -------------------------------------------------------------------------------- /assets/original.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/assets/original.bmp -------------------------------------------------------------------------------- /assets/original_color.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/assets/original_color.bmp -------------------------------------------------------------------------------- /assets/100kb_quota_color.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/assets/100kb_quota_color.bmp -------------------------------------------------------------------------------- /assets/140kb_quota_color.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/assets/140kb_quota_color.bmp -------------------------------------------------------------------------------- /assets/70kb_quota_color.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheRealOrange/icer_compression/HEAD/assets/70kb_quota_color.bmp -------------------------------------------------------------------------------- /example/src/stb_lib.c: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #define STB_IMAGE_RESIZE_IMPLEMENTATION 3 | #define STB_IMAGE_WRITE_IMPLEMENTATION 4 | 5 | #include "stb_image.h" 6 | #include "stb_image_resize.h" 7 | #include "stb_image_write.h" -------------------------------------------------------------------------------- /lib_icer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(icer C) 3 | 4 | set(CMAKE_C_STANDARD 11) 5 | 6 | include_directories(inc) 7 | 8 | add_library(icer inc/icer.h src/icer_wavelet.c inc/crc.h src/crc32.c src/icer_encoding.c src/icer_decoding.c src/icer_partition.c src/icer_util.c src/icer_context_modeller.c src/icer_init.c src/icer_config.c src/icer_compress.c src/icer_color.c) -------------------------------------------------------------------------------- /lib_icer/inc/crc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** CRC.H - header file for SNIPPETS CRC and checksum functions 3 | */ 4 | 5 | #ifndef CRC__H 6 | #define CRC__H 7 | 8 | #include /* For size_t */ 9 | #include /* For uint8_t, uint16_t, uint32_t */ 10 | #include /* For bool, true, false */ 11 | 12 | /* 13 | ** File: ARCCRC16.C 14 | */ 15 | 16 | void init_crc_table(void); 17 | uint16_t crc_calc(uint16_t crc, char *buf, unsigned nbytes); 18 | void do_file(char *fn); 19 | 20 | /* 21 | ** File: CRC-16.C 22 | */ 23 | 24 | uint16_t crc16(char *data_p, uint16_t length); 25 | 26 | /* 27 | ** File: CRC-16F.C 28 | */ 29 | 30 | uint16_t updcrc(uint16_t icrc, uint8_t *icp, size_t icnt); 31 | 32 | /* 33 | ** File: CRC_32.C 34 | */ 35 | 36 | #define UPDC32(octet,crc) (crc_32_tab[((crc)\ 37 | ^ ((uint8_t)octet)) & 0xff] ^ ((crc) >> 8)) 38 | 39 | uint32_t updateCRC32(unsigned char ch, uint32_t crc); 40 | bool crc32file(char *name, uint32_t *crc, long *charcnt); 41 | uint32_t crc32buf(char *buf, size_t len); 42 | 43 | /* 44 | ** File: CHECKSUM.C 45 | */ 46 | 47 | unsigned checksum(void *buffer, size_t len, unsigned int seed); 48 | 49 | /* 50 | ** File: CHECKEXE.C 51 | */ 52 | 53 | void checkexe(char *fname); 54 | 55 | 56 | 57 | #endif /* CRC__H */ 58 | -------------------------------------------------------------------------------- /example/inc/color_util.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by linyi on 28/3/2023. 3 | // 4 | 5 | #ifndef ICER_COMPRESSION_COLOR_UTIL_H 6 | #define ICER_COMPRESSION_COLOR_UTIL_H 7 | 8 | #define CLIP(X) ( (X) > 255 ? 255 : (X) < 0 ? 0 : X) 9 | 10 | // taken from https://stackoverflow.com/questions/1737726/how-to-perform-rgb-yuv-conversion-in-c-c 11 | 12 | // RGB -> YUV 13 | #define RGB2Y(R, G, B) CLIP(( ( 66 * (R) + 129 * (G) + 25 * (B) + 128) >> 8) + 16) 14 | #define RGB2U(R, G, B) CLIP(( ( -38 * (R) - 74 * (G) + 112 * (B) + 128) >> 8) + 128) 15 | #define RGB2V(R, G, B) CLIP(( ( 112 * (R) - 94 * (G) - 18 * (B) + 128) >> 8) + 128) 16 | 17 | // YUV -> RGB 18 | #define C(Y) ( (Y) - 16 ) 19 | #define D(U) ( (U) - 128 ) 20 | #define E(V) ( (V) - 128 ) 21 | 22 | #define YUV2R(Y, U, V) CLIP(( 298 * C(Y) + 409 * E(V) + 128) >> 8) 23 | #define YUV2G(Y, U, V) CLIP(( 298 * C(Y) - 100 * D(U) - 208 * E(V) + 128) >> 8) 24 | #define YUV2B(Y, U, V) CLIP(( 298 * C(Y) + 516 * D(U) + 128) >> 8) 25 | 26 | // RGB -> YCbCr 27 | #define CRGB2Y(R, G, B) CLIP((19595 * R + 38470 * G + 7471 * B ) >> 16) 28 | #define CRGB2Cb(R, G, B) CLIP((36962 * (B - CLIP((19595 * R + 38470 * G + 7471 * B ) >> 16) ) >> 16) + 128) 29 | #define CRGB2Cr(R, G, B) CLIP((46727 * (R - CLIP((19595 * R + 38470 * G + 7471 * B ) >> 16) ) >> 16) + 128) 30 | 31 | // YCbCr -> RGB 32 | #define CYCbCr2R(Y, Cb, Cr) CLIP( Y + ( 91881 * Cr >> 16 ) - 179 ) 33 | #define CYCbCr2G(Y, Cb, Cr) CLIP( Y - (( 22544 * Cb + 46793 * Cr ) >> 16) + 135) 34 | #define CYCbCr2B(Y, Cb, Cr) CLIP( Y + (116129 * Cb >> 16 ) - 226 ) 35 | 36 | #endif //ICER_COMPRESSION_COLOR_UTIL_H 37 | -------------------------------------------------------------------------------- /example/src/example_decode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "stb_image_resize.h" 8 | #include "stb_image_write.h" 9 | 10 | #define USE_DECODE_FUNCTIONS 11 | #define USE_UINT16_FUNCTIONS 12 | 13 | #include "icer.h" 14 | 15 | const char compressed_filename[] = "./compressed.bin"; 16 | const char filename[] = "./decompress.bmp"; 17 | 18 | int main() { 19 | const size_t out_w = 1000; 20 | const size_t out_h = 1000; 21 | const int stages = 4; 22 | const enum icer_filter_types filt = ICER_FILTER_A; 23 | const int segments = 6; 24 | 25 | uint16_t *decompress = malloc(out_w*out_h*2); 26 | uint8_t *display = malloc(out_w*out_h); 27 | 28 | int res = 0; 29 | clock_t begin, end; 30 | 31 | icer_init(); 32 | 33 | printf("test decompression code\n"); 34 | 35 | FILE *ptr2; 36 | uint8_t *buf = malloc(500); 37 | size_t buf_size = 500; 38 | size_t length = 0; 39 | 40 | ptr2 = fopen(compressed_filename,"rb"); 41 | while (fread(buf+length, sizeof *buf, 1, ptr2) == 1) { 42 | if (length >= buf_size-1) { 43 | buf_size += 500; 44 | buf = (uint8_t*)realloc(buf, buf_size); 45 | } 46 | length++; 47 | } 48 | fclose(ptr2); 49 | 50 | printf("decompress start\n"); 51 | 52 | size_t decomp_w, decomp_h; 53 | begin = clock(); 54 | res = icer_decompress_image_uint16(decompress, &decomp_w, &decomp_h, out_w*out_h, buf, length, stages, filt, segments); 55 | if (res != ICER_RESULT_OK) { 56 | printf("error: %d\n", res); 57 | return 0; 58 | } 59 | end = clock(); 60 | printf("decompress time taken: %lf\n", (float)(end-begin)/CLOCKS_PER_SEC); 61 | 62 | for (size_t i = 0;i < out_w*out_h;i++) { 63 | display[i] = icer_min_int(0xff, decompress[i]); 64 | } 65 | 66 | printf("saving decompressed image to: \"%s\"\n", filename); 67 | res = stbi_write_bmp(filename, decomp_w, decomp_h, 1, display); 68 | if (res == 0) { 69 | printf("save failed\nexiting...\n"); 70 | return 0; 71 | } 72 | 73 | free(decompress); 74 | free(display); 75 | free(buf); 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /example/src/example_encode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "stb_image.h" 8 | #include "stb_image_resize.h" 9 | 10 | #define USE_ENCODE_FUNCTIONS 11 | #define USE_UINT16_FUNCTIONS 12 | 13 | #include "icer.h" 14 | 15 | const char compressed_filename[] = "./compressed.bin"; 16 | const char filename[] = "./boat.512.bmp"; 17 | 18 | int main() { 19 | const size_t out_w = 512; 20 | const size_t out_h = 512; 21 | const int stages = 4; 22 | const enum icer_filter_types filt = ICER_FILTER_A; 23 | const int segments = 6; 24 | 25 | const int datastream_size = 30000; 26 | 27 | int src_w, src_h, n; 28 | uint8_t *data; 29 | 30 | uint8_t *resized = malloc(out_w*out_h); 31 | uint16_t *compress = malloc(out_w*out_h*2); 32 | 33 | int res = 0; 34 | clock_t begin, end; 35 | 36 | icer_init(); 37 | 38 | printf("test compression code\n"); 39 | 40 | printf("loading image: \"%s\"\n", filename); 41 | data = stbi_load(filename, &src_w, &src_h, &n, 1); 42 | if (data == NULL) { 43 | printf("invalid image\nexiting...\n"); 44 | return 0; 45 | } 46 | 47 | printf("loaded image\nwidth : %5d\nheight : %5d\nchannels : %5d\n", src_w, src_h, n); 48 | 49 | printf("resizing image to width: %4llu, height: %4llu\n", out_w, out_h); 50 | res = stbir_resize_uint8(data, src_w, src_h, 0, 51 | resized, out_w, out_h, 0, 52 | 1); 53 | if (res == 0) { 54 | printf("resize failed\nexiting...\n"); 55 | return 0; 56 | } 57 | printf("resize complete\n"); 58 | 59 | printf("converting to int16\n"); 60 | for (size_t i = 0;i < out_h*out_w;i++) { 61 | compress[i] = resized[i]; 62 | } 63 | 64 | uint8_t *datastream = malloc(datastream_size*2+500); 65 | icer_output_data_buf_typedef output; 66 | icer_init_output_struct(&output, datastream, datastream_size*2, datastream_size); 67 | 68 | begin = clock(); 69 | icer_compress_image_uint16(compress, out_w, out_h, stages, filt, segments, &output); 70 | end = clock(); 71 | 72 | printf("compressed size %llu, time taken: %lf\n", output.size_used, (float)(end-begin)/CLOCKS_PER_SEC); 73 | 74 | FILE *ptr1; 75 | 76 | ptr1 = fopen(compressed_filename,"wb"); 77 | size_t written = fwrite(output.rearrange_start, sizeof(output.rearrange_start[0]), output.size_used, ptr1); 78 | printf("written: %llu\n", written); 79 | fflush(ptr1); 80 | fclose(ptr1); 81 | 82 | printf("output saved\n"); 83 | 84 | free(resized); 85 | free(compress); 86 | free(datastream); 87 | stbi_image_free(data); 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(icer_compression C) 3 | 4 | set(CMAKE_C_STANDARD 11) 5 | 6 | if(NOT CMAKE_BUILD_TYPE) 7 | set(CMAKE_BUILD_TYPE Release) 8 | endif() 9 | 10 | set(CMAKE_C_FLAGS "-Wall -Wextra") 11 | set(CMAKE_C_FLAGS_DEBUG "-g") 12 | set(CMAKE_C_FLAGS_RELEASE "-O2") 13 | 14 | include_directories(example/inc) 15 | include_directories(lib_icer/inc) 16 | add_subdirectory(lib_icer) 17 | 18 | # Implementation examples 19 | add_executable(compress example/src/example_encode.c example/src/stb_lib.c) 20 | add_executable(decompress example/src/example_decode.c example/src/stb_lib.c) 21 | add_executable(compress_color example/src/example_encode_color.c example/src/stb_lib.c) 22 | add_executable(decompress_color example/src/example_decode_color.c example/src/stb_lib.c) 23 | 24 | # Command-line utility 25 | add_executable(icer_util example/src/icer_util.c example/src/stb_lib.c) 26 | 27 | # Examples 28 | target_link_libraries(compress PRIVATE m) 29 | target_link_libraries(compress PUBLIC icer) 30 | 31 | target_link_libraries(decompress PRIVATE m) 32 | target_link_libraries(decompress PUBLIC icer) 33 | 34 | target_link_libraries(compress_color PRIVATE m) 35 | target_link_libraries(compress_color PUBLIC icer) 36 | 37 | target_link_libraries(decompress_color PRIVATE m) 38 | target_link_libraries(decompress_color PUBLIC icer) 39 | 40 | # Utility 41 | target_link_libraries(icer_util PRIVATE m) 42 | target_link_libraries(icer_util PUBLIC icer) 43 | 44 | # testing with sample images 45 | add_custom_target(test_examples 46 | COMMAND ${CMAKE_COMMAND} -E echo "Testing ICER implementation examples..." 47 | 48 | # Copy test images from source to build directory if they exist 49 | COMMAND test -f ${CMAKE_CURRENT_SOURCE_DIR}/boat.512.bmp && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/boat.512.bmp . || echo "boat.512.bmp not found in source directory" 50 | COMMAND test -f ${CMAKE_CURRENT_SOURCE_DIR}/boatcolor.512.bmp && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/boatcolor.512.bmp . || echo "boatcolor.512.bmp not found in source directory" 51 | 52 | COMMAND ${CMAKE_COMMAND} -E echo "Testing grayscale compression:" 53 | COMMAND test -f boat.512.bmp && ./compress && ./decompress || echo "boat.512.bmp not available, skipping grayscale test" 54 | COMMAND ${CMAKE_COMMAND} -E echo "" 55 | COMMAND ${CMAKE_COMMAND} -E echo "Testing color compression:" 56 | COMMAND test -f boatcolor.512.bmp && ./compress_color && ./decompress_color || echo "boatcolor.512.bmp not available, skipping color test" 57 | COMMAND ${CMAKE_COMMAND} -E echo "" 58 | COMMAND ${CMAKE_COMMAND} -E echo "Testing standalone utility:" 59 | COMMAND test -f boat.512.bmp && ./icer_util compress boat.512.bmp test_compressed.bin --grayscale && ./icer_util decompress test_compressed.bin test_decompressed.bmp --grayscale || echo "boat.512.bmp not available, skipping utility test" 60 | COMMAND test -f boatcolor.512.bmp && ./icer_util compress boatcolor.512.bmp test_compressed_color.bin --color && ./icer_util decompress test_compressed_color.bin test_decompressed_color.bmp --color || echo "boatcolor.512.bmp not available, skipping color utility test" 61 | DEPENDS compress decompress compress_color decompress_color icer_util 62 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 63 | COMMENT "Running ICER compression tests" 64 | ) -------------------------------------------------------------------------------- /example/src/example_decode_color.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "stb_image_resize.h" 8 | #include "stb_image_write.h" 9 | 10 | #define USE_DECODE_FUNCTIONS 11 | #define USE_UINT16_FUNCTIONS 12 | 13 | #include "icer.h" 14 | #include "color_util.h" 15 | 16 | const char compressed_filename[] = "./compressed.bin"; 17 | const char filename[] = "./decompress.bmp"; 18 | 19 | void yuv_to_rgb888_packed(uint16_t *y_channel, uint16_t *u_channel, uint16_t *v_channel, uint8_t *img, size_t image_w, size_t image_h, size_t rowstride) { 20 | int32_t y, u, v; 21 | uint8_t *pixel; 22 | 23 | uint16_t *input_y, *input_u, *input_v; 24 | for (size_t row = 0;row < image_h;row++) { 25 | pixel = img + 3 * rowstride * row; 26 | input_y = y_channel + rowstride * row; 27 | input_u = u_channel + rowstride * row; 28 | input_v = v_channel + rowstride * row; 29 | for (size_t col = 0;col < image_w;col++) { 30 | y = *input_y; 31 | u = *input_u; 32 | v = *input_v; 33 | 34 | pixel[0] = CYCbCr2R(y, u, v); 35 | pixel[1] = CYCbCr2G(y, u, v); 36 | pixel[2] = CYCbCr2B(y, u, v); 37 | 38 | pixel += 3; 39 | input_y++; input_u++; input_v++; 40 | } 41 | } 42 | } 43 | 44 | int main() { 45 | const size_t out_w = 1000; 46 | const size_t out_h = 1000; 47 | const int stages = 4; 48 | const enum icer_filter_types filt = ICER_FILTER_A; 49 | const int segments = 10; 50 | 51 | uint16_t *decompress[3]; 52 | uint8_t *display = malloc(out_w*out_h*3); 53 | 54 | for (int chan = 0;chan <= 2;chan++) { 55 | decompress[chan] = malloc(out_w*out_h*2); 56 | } 57 | 58 | int res = 0; 59 | clock_t begin, end; 60 | 61 | icer_init(); 62 | 63 | printf("test decompression code\n"); 64 | 65 | FILE *ptr2; 66 | uint8_t *buf = malloc(500); 67 | size_t buf_size = 500; 68 | size_t length = 0; 69 | 70 | ptr2 = fopen(compressed_filename,"rb"); 71 | while (fread(buf+length, sizeof *buf, 1, ptr2) == 1) { 72 | if (length >= buf_size-1) { 73 | buf_size += 500; 74 | buf = (uint8_t*)realloc(buf, buf_size); 75 | } 76 | length++; 77 | } 78 | fclose(ptr2); 79 | 80 | printf("decompress start\n"); 81 | 82 | size_t decomp_w, decomp_h; 83 | begin = clock(); 84 | res = icer_decompress_image_yuv_uint16(decompress[0], decompress[1], decompress[2], &decomp_w, &decomp_h, out_w*out_h, buf, length, stages, filt, segments); 85 | if (res != ICER_RESULT_OK) { 86 | printf("error: %d\n", res); 87 | return 0; 88 | } 89 | end = clock(); 90 | printf("decompress time taken: %lf\n", (float)(end-begin)/CLOCKS_PER_SEC); 91 | 92 | printf("converting to rgb\n"); 93 | yuv_to_rgb888_packed(decompress[0], decompress[1], decompress[2], display, decomp_w, decomp_h, decomp_w); 94 | 95 | printf("saving decompressed image to: \"%s\"\n", filename); 96 | res = stbi_write_bmp(filename, decomp_w, decomp_h, 3, display); 97 | if (res == 0) { 98 | printf("save failed\nexiting...\n"); 99 | return 0; 100 | } 101 | 102 | for (int chan = 0;chan <= 2;chan++) free(decompress[chan]); 103 | free(display); 104 | free(buf); 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /lib_icer/src/icer_util.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by linyi on 19/3/2023. 3 | // 4 | 5 | #include "icer.h" 6 | 7 | #ifndef CRC32BUF_FUNCTION 8 | #include "crc.h" 9 | #define CRC32BUF_FUNCTION(x, y) crc32buf(x, y) 10 | #endif 11 | 12 | #ifndef USER_PROVIDED_BUFFERS 13 | 14 | #ifdef USE_UINT8_FUNCTIONS 15 | #ifdef USE_ENCODE_FUNCTIONS 16 | icer_packet_context icer_packets[ICER_MAX_PACKETS]; 17 | icer_image_segment_typedef *icer_rearrange_segments_8[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][7][ICER_MAX_SEGMENTS + 1]; 18 | #endif 19 | 20 | #ifdef USE_DECODE_FUNCTIONS 21 | const icer_image_segment_typedef *icer_reconstruct_data_8[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][ICER_MAX_SEGMENTS + 1][7]; 22 | #endif 23 | #endif 24 | 25 | #ifdef USE_UINT16_FUNCTIONS 26 | #ifdef USE_ENCODE_FUNCTIONS 27 | icer_packet_context icer_packets_16[ICER_MAX_PACKETS_16]; 28 | icer_image_segment_typedef *icer_rearrange_segments_16[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][15][ICER_MAX_SEGMENTS + 1]; 29 | #endif 30 | 31 | #ifdef USE_DECODE_FUNCTIONS 32 | const icer_image_segment_typedef *icer_reconstruct_data_16[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][ICER_MAX_SEGMENTS + 1][15]; 33 | #endif 34 | #endif 35 | 36 | #endif 37 | 38 | int icer_init_output_struct(icer_output_data_buf_typedef *out, uint8_t *data, size_t buf_len, size_t byte_quota) { 39 | if (byte_quota * 2 > buf_len) return ICER_OUTPUT_BUF_TOO_SMALL; 40 | out->size_used = 0; 41 | out->data_start = data; 42 | out->size_allocated = byte_quota; 43 | out->rearrange_start = data + byte_quota; 44 | return ICER_RESULT_OK; 45 | } 46 | 47 | /* compute which bin of the interleaved entropy coder to place a bit to be encoded based of the probability cutoffs of each bin */ 48 | int icer_compute_bin(uint32_t zero_cnt, uint32_t total_cnt) { 49 | uint32_t comp = zero_cnt * ICER_BIN_PROBABILITY_DENOMINATOR; 50 | for (int16_t bin = ICER_ENCODER_BIN_MAX;bin > ICER_ENC_BIN_1;bin--) { 51 | if (comp >= total_cnt * icer_bin_probability_cutoffs[bin-1]) { 52 | return bin; 53 | } 54 | } 55 | return ICER_ENC_BIN_1; 56 | } 57 | 58 | /* calculates the crc32 for the header of each segment of the image */ 59 | uint32_t icer_calculate_packet_crc32(const icer_image_segment_typedef *pkt) { 60 | return crc32buf((char*)pkt, sizeof(icer_image_segment_typedef) - 4); 61 | } 62 | 63 | /* calculates the crc32 for the data portion of each segment of the image */ 64 | uint32_t icer_calculate_segment_crc32(const icer_image_segment_typedef *pkt) { 65 | return crc32buf((char*)pkt + sizeof(icer_image_segment_typedef), icer_ceil_div_uint32(pkt->data_length, 8)); 66 | } 67 | 68 | #ifdef USE_DECODE_FUNCTIONS 69 | #ifdef USE_UINT8_FUNCTIONS 70 | void icer_remove_negative_uint8(uint8_t * const image, size_t image_w, size_t image_h) { 71 | size_t data_length = image_w * image_h; 72 | int8_t *data_end = (int8_t *)(image + data_length); 73 | for (int8_t *pixel = (int8_t *)image;pixel < data_end;pixel++) { 74 | if (*pixel < 0) { 75 | *pixel = 0; 76 | } 77 | } 78 | } 79 | #endif 80 | 81 | #ifdef USE_UINT16_FUNCTIONS 82 | void icer_remove_negative_uint16(uint16_t * const image, size_t image_w, size_t image_h) { 83 | size_t data_length = image_w * image_h; 84 | int16_t *data_end = (int16_t *)(image + data_length); 85 | for (int16_t *pixel = (int16_t *)image;pixel < data_end;pixel++) { 86 | if (*pixel < 0) { 87 | *pixel = 0; 88 | } 89 | } 90 | } 91 | #endif 92 | #endif -------------------------------------------------------------------------------- /example/src/example_encode_color.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "stb_image.h" 8 | #include "stb_image_resize.h" 9 | 10 | #define USE_ENCODE_FUNCTIONS 11 | #define USE_UINT16_FUNCTIONS 12 | 13 | #include "icer.h" 14 | #include "color_util.h" 15 | 16 | const char compressed_filename[] = "./compressed.bin"; 17 | const char filename[] = "./boatcolor.512.bmp"; 18 | 19 | void rgb888_packed_to_yuv(uint16_t *y_channel, uint16_t *u_channel, uint16_t *v_channel, uint8_t *img, size_t image_w, size_t image_h, size_t rowstride) { 20 | int32_t r, g, b; 21 | uint8_t *pixel; 22 | 23 | uint16_t *output_y, *output_u, *output_v; 24 | for (size_t row = 0;row < image_h;row++) { 25 | pixel = img + 3 * rowstride * row; 26 | output_y = y_channel + rowstride * row; 27 | output_u = u_channel + rowstride * row; 28 | output_v = v_channel + rowstride * row; 29 | for (size_t col = 0;col < image_w;col++) { 30 | r = pixel[0]; 31 | g = pixel[1]; 32 | b = pixel[2]; 33 | 34 | *output_y = CRGB2Y(r, g, b); 35 | *output_u = CRGB2Cb(r, g, b); 36 | *output_v = CRGB2Cr(r, g, b); 37 | pixel += 3; 38 | output_y++; output_u++; output_v++; 39 | } 40 | } 41 | } 42 | 43 | int main() { 44 | const size_t out_w = 512; 45 | const size_t out_h = 512; 46 | const int stages = 4; 47 | const enum icer_filter_types filt = ICER_FILTER_A; 48 | const int segments = 10; 49 | 50 | const int datastream_size = 100000; 51 | 52 | int src_w, src_h, n; 53 | uint8_t *data; 54 | 55 | uint8_t *resized = malloc(out_w*out_h*3); 56 | uint16_t *compress[3]; 57 | 58 | for (int chan = 0;chan <= 2;chan++) { 59 | compress[chan] = malloc(out_w*out_h*2); 60 | } 61 | 62 | int res = 0; 63 | clock_t begin, end; 64 | 65 | icer_init(); 66 | 67 | printf("test compression code\n"); 68 | 69 | printf("loading image: \"%s\"\n", filename); 70 | data = stbi_load(filename, &src_w, &src_h, &n, 3); 71 | if (data == NULL) { 72 | printf("invalid image\nexiting...\n"); 73 | return 0; 74 | } 75 | 76 | printf("loaded image\nwidth : %5d\nheight : %5d\nchannels : %5d\n", src_w, src_h, n); 77 | 78 | printf("resizing image to width: %4zu, height: %4zu\n", out_w, out_h); 79 | res = stbir_resize_uint8(data, src_w, src_h, 0, 80 | resized, out_w, out_h, 0, 81 | 3); 82 | if (res == 0) { 83 | printf("resize failed\nexiting...\n"); 84 | return 0; 85 | } 86 | printf("resize complete\n"); 87 | 88 | printf("converting to yuv\n"); 89 | rgb888_packed_to_yuv(compress[0], compress[1], compress[2], resized, out_w, out_h, out_w); 90 | 91 | uint8_t *datastream = malloc(datastream_size*2+500); 92 | icer_output_data_buf_typedef output; 93 | icer_init_output_struct(&output, datastream, datastream_size*2, datastream_size); 94 | 95 | begin = clock(); 96 | icer_compress_image_yuv_uint16(compress[0], compress[1], compress[2], out_w, out_h, stages, filt, segments, &output); 97 | end = clock(); 98 | 99 | printf("compressed size %zu, time taken: %lf\n", output.size_used, (float)(end-begin)/CLOCKS_PER_SEC); 100 | 101 | FILE *ptr1; 102 | 103 | ptr1 = fopen(compressed_filename,"wb"); 104 | size_t written = fwrite(output.rearrange_start, sizeof(output.rearrange_start[0]), output.size_used, ptr1); 105 | printf("written: %zu\n", written); 106 | fflush(ptr1); 107 | fclose(ptr1); 108 | 109 | printf("output saved\n"); 110 | 111 | free(resized); 112 | free(datastream); 113 | for (int chan = 0;chan <= 2;chan++) free(compress[chan]); 114 | stbi_image_free(data); 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /lib_icer/src/icer_config.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by linyi on 19/3/2023. 3 | // 4 | #include "icer.h" 5 | 6 | #ifdef USE_ENCODE_FUNCTIONS 7 | icer_custom_code_typedef icer_custom_coding_scheme[ICER_ENCODER_BIN_MAX + 1][CUSTOM_CODING_MAX_LOOKUP]; 8 | #endif 9 | 10 | #ifdef USE_DECODE_FUNCTIONS 11 | icer_custom_code_typedef icer_custom_decode_scheme[ICER_ENCODER_BIN_MAX + 1][CUSTOM_CODING_MAX_LOOKUP]; 12 | #endif 13 | 14 | icer_custom_flush_typedef icer_custom_code_flush_bits[ICER_ENCODER_BIN_MAX + 1][CUSTOM_CODE_FLUSH_MAX_LOOKUP + 1][MAX_NUM_BITS_BEFORE_FLUSH + 1]; 15 | 16 | icer_golomb_code_typedef icer_golomb_coders[ICER_ENCODER_BIN_MAX + 1]; 17 | 18 | const int16_t icer_wavelet_filter_parameters[][4] = {{0, 4, 4, 0}, 19 | {0, 4, 6, 4}, 20 | {-1, 4, 8, 6}, 21 | {0, 4, 5, 2}, 22 | {0, 3, 8, 6}, 23 | {0, 3, 9, 8}, 24 | {0, 4, 4, 4}}; 25 | 26 | const uint8_t icer_context_table_ll_lh_hl[3][3][5] = { 27 | { 28 | { ICER_CONTEXT_0, ICER_CONTEXT_1, ICER_CONTEXT_2, ICER_CONTEXT_2, ICER_CONTEXT_2}, 29 | { ICER_CONTEXT_3, ICER_CONTEXT_3, ICER_CONTEXT_3, ICER_CONTEXT_3, ICER_CONTEXT_3}, 30 | { ICER_CONTEXT_4, ICER_CONTEXT_4, ICER_CONTEXT_4, ICER_CONTEXT_4, ICER_CONTEXT_4} 31 | }, 32 | { 33 | { ICER_CONTEXT_5, ICER_CONTEXT_6, ICER_CONTEXT_7, ICER_CONTEXT_7, ICER_CONTEXT_7}, 34 | { ICER_CONTEXT_7, ICER_CONTEXT_7, ICER_CONTEXT_7, ICER_CONTEXT_7, ICER_CONTEXT_7}, 35 | { ICER_CONTEXT_7, ICER_CONTEXT_7, ICER_CONTEXT_7, ICER_CONTEXT_7, ICER_CONTEXT_7} 36 | }, 37 | { 38 | { ICER_CONTEXT_8, ICER_CONTEXT_8, ICER_CONTEXT_8, ICER_CONTEXT_8, ICER_CONTEXT_8}, 39 | { ICER_CONTEXT_8, ICER_CONTEXT_8, ICER_CONTEXT_8, ICER_CONTEXT_8, ICER_CONTEXT_8}, 40 | { ICER_CONTEXT_8, ICER_CONTEXT_8, ICER_CONTEXT_8, ICER_CONTEXT_8, ICER_CONTEXT_8}, 41 | } 42 | }; 43 | 44 | const uint8_t icer_context_table_hh[5][5] = { 45 | { ICER_CONTEXT_0, ICER_CONTEXT_3, ICER_CONTEXT_6, ICER_CONTEXT_8, ICER_CONTEXT_8}, 46 | { ICER_CONTEXT_1, ICER_CONTEXT_4, ICER_CONTEXT_7, ICER_CONTEXT_8, ICER_CONTEXT_8}, 47 | { ICER_CONTEXT_2, ICER_CONTEXT_5, ICER_CONTEXT_7, ICER_CONTEXT_8, ICER_CONTEXT_8}, 48 | { ICER_CONTEXT_2, ICER_CONTEXT_5, ICER_CONTEXT_7, ICER_CONTEXT_8, ICER_CONTEXT_8}, 49 | { ICER_CONTEXT_2, ICER_CONTEXT_5, ICER_CONTEXT_7, ICER_CONTEXT_8, ICER_CONTEXT_8}, 50 | }; 51 | 52 | const uint8_t icer_sign_context_table[5][5] = { 53 | {ICER_CONTEXT_14, ICER_CONTEXT_14, ICER_CONTEXT_15, ICER_CONTEXT_16, ICER_CONTEXT_16}, 54 | {ICER_CONTEXT_14, ICER_CONTEXT_14, ICER_CONTEXT_15, ICER_CONTEXT_16, ICER_CONTEXT_16}, 55 | {ICER_CONTEXT_13, ICER_CONTEXT_13, ICER_CONTEXT_12, ICER_CONTEXT_13, ICER_CONTEXT_13}, 56 | {ICER_CONTEXT_16, ICER_CONTEXT_16, ICER_CONTEXT_15, ICER_CONTEXT_14, ICER_CONTEXT_14}, 57 | {ICER_CONTEXT_16, ICER_CONTEXT_16, ICER_CONTEXT_15, ICER_CONTEXT_14, ICER_CONTEXT_14}, 58 | }; 59 | 60 | /* 1 is negative, 0 is positive */ 61 | const uint8_t icer_sign_prediction_table[5][5] = { 62 | {1, 1, 1, 1, 1}, 63 | {1, 1, 1, 1, 1}, 64 | {0, 0, 0, 1, 1}, 65 | {0, 0, 0, 0, 0}, 66 | {0, 0, 0, 0, 0} 67 | }; 68 | 69 | const uint32_t icer_bin_probability_cutoffs[ICER_ENCODER_BIN_MAX+1] = { 70 | 35298, 71 | 37345, 72 | 40503, 73 | 43591, 74 | 47480, 75 | 50133, 76 | 53645, 77 | 55902, 78 | 57755, 79 | 58894, 80 | 60437, 81 | 62267, 82 | 63613, 83 | 64557, 84 | 65134, 85 | 65392, 86 | 65536 87 | }; 88 | 89 | const int32_t icer_bin_coding_scheme[ICER_ENCODER_BIN_MAX+1] = { 90 | 0, 91 | -1, 92 | -1, 93 | -1, 94 | -1, 95 | -1, 96 | -1, 97 | -1, 98 | 5, 99 | 6, 100 | 7, 101 | 11, 102 | 17, 103 | 31, 104 | 70, 105 | 200, 106 | 512 107 | }; 108 | size_t icer_slice_lengths[MAX_K] = {0}; 109 | -------------------------------------------------------------------------------- /lib_icer/src/icer_decoding.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by linyi on 19/3/2023. 3 | // 4 | 5 | #include 6 | #include "icer.h" 7 | 8 | #ifdef USE_DECODE_FUNCTIONS 9 | 10 | #define ICER_BITMASK_MACRO(x) (((unsigned)1 << x) - 1) 11 | 12 | void icer_init_entropy_decoder_context(icer_decoder_context_typedef *decoder_context, uint8_t *encoded_words, size_t encoded_bits) { 13 | decoder_context->encoded_bits_total = encoded_bits; 14 | decoder_context->decoded_bits_total = 0; 15 | decoder_context->decoded_words = 0; 16 | 17 | decoder_context->encoded_words = encoded_words; 18 | decoder_context->encode_bit_offset = 0; 19 | decoder_context->encode_ind = 0; 20 | 21 | for (size_t it = 0;it < ICER_ENCODER_BIN_MAX+1;it++) { 22 | decoder_context->bin_bits[it] = 0; 23 | decoder_context->bin_decode_index[it] = 0; 24 | for (size_t j = 0;j < ICER_DECODER_BIT_BIN_MAX;j++) decoder_context->bin_buf[it][j] = 0; 25 | } 26 | } 27 | 28 | void icer_push_bin_bits(icer_decoder_context_typedef *decoder_context, uint8_t bin, uint16_t bits, uint16_t num_bits) { 29 | int32_t bin_ind, bin_bit_offset; 30 | bin_ind = decoder_context->bin_bits[bin] / 32; 31 | bin_bit_offset = decoder_context->bin_bits[bin] % 32; 32 | decoder_context->bin_bits[bin] += num_bits; 33 | 34 | int bits_to_push; 35 | while (num_bits) { 36 | bits_to_push = icer_min_int(num_bits, 32-bin_bit_offset); 37 | decoder_context->bin_buf[bin][bin_ind] |= ((bits & ICER_BITMASK_MACRO(bits_to_push)) << bin_bit_offset); 38 | num_bits -= bits_to_push; 39 | 40 | bin_bit_offset += bits_to_push; 41 | bin_ind += bin_bit_offset / 32; 42 | bin_bit_offset %= 32; 43 | } 44 | } 45 | 46 | int icer_get_bit_from_codeword(icer_decoder_context_typedef *decoder_context, uint8_t bits) { 47 | uint8_t bitoffset = decoder_context->encode_bit_offset; 48 | size_t ind = decoder_context->encode_ind; 49 | uint16_t d, r; 50 | bitoffset += (bits - 1); 51 | r = bitoffset / 8; 52 | d = bitoffset % 8; 53 | ind += r; 54 | bitoffset = d; 55 | 56 | return (decoder_context->encoded_words[ind] & (1 << bitoffset)) >> bitoffset; 57 | } 58 | 59 | int icer_get_bits_from_codeword(icer_decoder_context_typedef *decoder_context, uint8_t bits) { 60 | int num = 0; 61 | int bits_to_decode, decoded = 0; 62 | uint8_t bitoffset = decoder_context->encode_bit_offset; 63 | size_t ind = decoder_context->encode_ind; 64 | uint16_t d, r; 65 | while (bits) { 66 | bits_to_decode = icer_min_int(8-bitoffset, bits); 67 | if (decoder_context->decoded_bits_total + bits_to_decode > decoder_context->encoded_bits_total) { 68 | return ICER_DECODER_OUT_OF_DATA; 69 | } 70 | num |= (int)((((decoder_context->encoded_words[ind] & (ICER_BITMASK_MACRO(bits_to_decode)) << bitoffset)) >> bitoffset) << decoded); 71 | bits -= bits_to_decode; 72 | decoded += bits_to_decode; 73 | bitoffset += bits_to_decode; 74 | r = bitoffset / 8; 75 | d = bitoffset % 8; 76 | bitoffset = d; 77 | if (r) { 78 | ind++; 79 | } 80 | } 81 | return num; 82 | } 83 | 84 | int icer_pop_bits_from_codeword(icer_decoder_context_typedef *decoder_context, uint8_t bits) { 85 | int num = 0; 86 | int bits_to_decode, decoded = 0; 87 | uint16_t d, r; 88 | while (bits) { 89 | bits_to_decode = icer_min_int(8-decoder_context->encode_bit_offset, bits); 90 | if (decoder_context->decoded_bits_total + bits_to_decode > decoder_context->encoded_bits_total) { 91 | return ICER_DECODER_OUT_OF_DATA; 92 | } 93 | num |= (int)(((decoder_context->encoded_words[decoder_context->encode_ind] & (ICER_BITMASK_MACRO(bits_to_decode) << decoder_context->encode_bit_offset)) >> decoder_context->encode_bit_offset) << decoded); 94 | bits -= bits_to_decode; 95 | decoded += bits_to_decode; 96 | decoder_context->encode_bit_offset += bits_to_decode; 97 | r = decoder_context->encode_bit_offset / 8; 98 | d = decoder_context->encode_bit_offset % 8; 99 | decoder_context->encode_bit_offset = d; 100 | if (r) { 101 | decoder_context->encode_ind++; 102 | } 103 | } 104 | return num; 105 | } 106 | 107 | 108 | int icer_decode_bit(icer_decoder_context_typedef *decoder_context, uint8_t *bit, uint32_t zero_cnt, uint32_t total_cnt) { 109 | bool inv = false, b; 110 | int code_bit; 111 | uint16_t codeword; 112 | uint8_t num_bits; 113 | uint16_t golomb_k; 114 | if (zero_cnt < (total_cnt >> 1)) { 115 | /* 116 | * we may assume that the probability of zero for each bit is contained 117 | * the interval [1/2, 1] 118 | * in the case that the probability of zero < 1/2 119 | * we simple invert the bit, and its associated probability 120 | * this is duplicated in the decoder 121 | */ 122 | zero_cnt = total_cnt - zero_cnt; 123 | inv = true; 124 | } 125 | 126 | int bin = icer_compute_bin(zero_cnt, total_cnt); 127 | 128 | if (decoder_context->bin_bits[bin] <= 0 || decoder_context->decoded_words - decoder_context->bin_decode_index[bin] >= ICER_CIRC_BUF_SIZE) { 129 | /* ran out of bits in the bit, time to process a new codeword */ 130 | decoder_context->bin_bits[bin] = 0; 131 | memset(decoder_context->bin_buf[bin], 0, ICER_DECODER_BIT_BIN_MAX*sizeof(decoder_context->bin_buf[bin][0])); 132 | if (bin > ICER_ENC_BIN_8) { 133 | /* golomb code bins */ 134 | code_bit = icer_get_bit_from_codeword(decoder_context, 1); 135 | if (code_bit == ICER_DECODER_OUT_OF_DATA) return ICER_DECODER_OUT_OF_DATA; //major oops moment 136 | if (code_bit) { 137 | /* if the first bit is one, return m 0s */ 138 | icer_pop_bits_from_codeword(decoder_context, 1); 139 | icer_push_bin_bits(decoder_context, bin, 0b0, icer_golomb_coders[bin].m); 140 | } else { 141 | golomb_k = icer_get_bits_from_codeword(decoder_context, icer_golomb_coders[bin].l); 142 | icer_reverse_bits(&golomb_k, icer_golomb_coders[bin].l); 143 | if (golomb_k < icer_golomb_coders[bin].i) { 144 | icer_pop_bits_from_codeword(decoder_context, icer_golomb_coders[bin].l); 145 | icer_push_bin_bits(decoder_context, bin, 0b1, 1); 146 | icer_push_bin_bits(decoder_context, bin, 0b0, golomb_k); 147 | } else { 148 | golomb_k = icer_pop_bits_from_codeword(decoder_context, icer_golomb_coders[bin].l + 1); 149 | icer_reverse_bits(&golomb_k, icer_golomb_coders[bin].l + 1); 150 | icer_push_bin_bits(decoder_context, bin, 0b1, 1); 151 | icer_push_bin_bits(decoder_context, bin, 0b0, golomb_k - icer_golomb_coders[bin].i); 152 | } 153 | } 154 | } else if (bin != ICER_ENC_BIN_1) { 155 | /* custom non prefix code bins */ 156 | codeword = 0; 157 | num_bits = 0; 158 | do { 159 | if (decoder_context->decoded_bits_total + num_bits + 1 >= decoder_context->encoded_bits_total) return ICER_DECODER_OUT_OF_DATA; 160 | codeword |= icer_get_bit_from_codeword(decoder_context, num_bits+1) << num_bits; 161 | num_bits++; 162 | if (codeword < 32) { 163 | if (icer_custom_decode_scheme[bin][codeword].input_code_bits == num_bits) { 164 | icer_push_bin_bits(decoder_context, bin, icer_custom_decode_scheme[bin][codeword].output_code, icer_custom_decode_scheme[bin][codeword].output_code_bits); 165 | int test = icer_pop_bits_from_codeword(decoder_context, num_bits); 166 | if (codeword != test) { 167 | return ICER_DECODED_INVALID_DATA; 168 | } else { 169 | break; 170 | } 171 | } 172 | } else { 173 | return ICER_DECODED_INVALID_DATA; 174 | } 175 | } while (num_bits < 10); 176 | } else { 177 | /* uncoded bin */ 178 | code_bit = icer_pop_bits_from_codeword(decoder_context, 1); 179 | if (code_bit == ICER_DECODER_OUT_OF_DATA) return ICER_DECODER_OUT_OF_DATA; 180 | icer_push_bin_bits(decoder_context, bin, code_bit != 0, 1); 181 | } 182 | 183 | decoder_context->decoded_words++; 184 | decoder_context->bin_decode_index[bin] = decoder_context->decoded_words; 185 | } 186 | int32_t bin_ind = decoder_context->bin_bits[bin] / 32; 187 | int32_t bit_offset = decoder_context->bin_bits[bin] % 32; 188 | b = (decoder_context->bin_buf[bin][bin_ind] & (1 << (bit_offset-1))) != 0; 189 | decoder_context->bin_buf[bin][bin_ind] &= ~(1 << (bit_offset-1)); 190 | decoder_context->bin_bits[bin]--; 191 | (*bit) = inv == !b; 192 | 193 | return ICER_RESULT_OK; 194 | } 195 | 196 | #endif -------------------------------------------------------------------------------- /lib_icer/src/crc32.c: -------------------------------------------------------------------------------- 1 | /* Crc - 32 BIT ANSI X3.66 CRC checksum files */ 2 | 3 | #include 4 | #include "../inc/crc.h" 5 | 6 | #ifdef __TURBOC__ 7 | #pragma warn -cln 8 | #endif 9 | 10 | /**********************************************************************\ 11 | |* Demonstration program to compute the 32-bit CRC used as the frame *| 12 | |* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| 13 | |* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| 14 | |* protocol). The 32-bit FCS was added via the Federal Register, *| 15 | |* 1 June 1982, p.23798. I presume but don't know for certain that *| 16 | |* this polynomial is or will be included in CCITT V.41, which *| 17 | |* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| 18 | |* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| 19 | |* errors by a factor of 10^-5 over 16-bit FCS. *| 20 | \**********************************************************************/ 21 | 22 | /* Need an unsigned type capable of holding 32 bits; */ 23 | 24 | typedef uint32_t UNS_32_BITS; 25 | 26 | /* Copyright (C) 1986 Gary S. Brown. You may use this program, or 27 | code or tables extracted from it, as desired without restriction.*/ 28 | 29 | /* First, the polynomial itself and its table of feedback terms. The */ 30 | /* polynomial is */ 31 | /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ 32 | /* Note that we take it "backwards" and put the highest-order term in */ 33 | /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ 34 | /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ 35 | /* the MSB being 1. */ 36 | 37 | /* Note that the usual hardware shift register implementation, which */ 38 | /* is what we're using (we're merely optimizing it by doing eight-bit */ 39 | /* chunks at a time) shifts bits into the lowest-order term. In our */ 40 | /* implementation, that means shifting towards the right. Why do we */ 41 | /* do it this way? Because the calculated CRC must be transmitted in */ 42 | /* order from highest-order term to lowest-order term. UARTs transmit */ 43 | /* characters in order from LSB to MSB. By storing the CRC this way, */ 44 | /* we hand it to the UART in the order low-byte to high-byte; the UART */ 45 | /* sends each low-bit to hight-bit; and the result is transmission bit */ 46 | /* by bit from highest- to lowest-order term without requiring any bit */ 47 | /* shuffling on our part. Reception works similarly. */ 48 | 49 | /* The feedback terms table consists of 256, 32-bit entries. Notes: */ 50 | /* */ 51 | /* 1. The table can be generated at runtime if desired; code to do so */ 52 | /* is shown later. It might not be obvious, but the feedback */ 53 | /* terms simply represent the results of eight shift/xor opera- */ 54 | /* tions for all combinations of data and CRC register values. */ 55 | /* */ 56 | /* 2. The CRC accumulation logic is the same for all CRC polynomials, */ 57 | /* be they sixteen or thirty-two bits wide. You simply choose the */ 58 | /* appropriate table. Alternatively, because the table can be */ 59 | /* generated at runtime, you can start by generating the table for */ 60 | /* the polynomial in question and use exactly the same "updcrc", */ 61 | /* if your application needn't simultaneously handle two CRC */ 62 | /* polynomials. (Note, however, that XMODEM is strange.) */ 63 | /* */ 64 | /* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ 65 | /* of course, 32-bit entries work OK if the high 16 bits are zero. */ 66 | /* */ 67 | /* 4. The values must be right-shifted by eight bits by the "updcrc" */ 68 | /* logic; the shift must be unsigned (bring in zeroes). On some */ 69 | /* hardware you could probably optimize the shift in assembler by */ 70 | /* using byte-swap instructions. */ 71 | 72 | static UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ 73 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 74 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 75 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 76 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 77 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 78 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 79 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 80 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 81 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 82 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 83 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 84 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 85 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 86 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 87 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 88 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 89 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 90 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 91 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 92 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 93 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 94 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 95 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 96 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 97 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 98 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 99 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 100 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 101 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 102 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 103 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 104 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 105 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 106 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 107 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 108 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 109 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 110 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 111 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 112 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 113 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 114 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 115 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 116 | }; 117 | 118 | uint32_t updateCRC32(unsigned char ch, uint32_t crc) 119 | { 120 | return UPDC32(ch, crc); 121 | } 122 | 123 | bool crc32file(char *name, uint32_t *crc, long *charcnt) 124 | { 125 | register FILE *fin; 126 | register uint32_t oldcrc32; 127 | register int c; 128 | 129 | oldcrc32 = 0xFFFFFFFF; *charcnt = 0; 130 | #ifdef MSDOS 131 | if ((fin=fopen(name, "rb"))==NULL) 132 | #else 133 | if ((fin=fopen(name, "r"))==NULL) 134 | #endif 135 | { 136 | perror(name); 137 | return false; 138 | } 139 | while ((c=getc(fin))!=EOF) 140 | { 141 | ++*charcnt; 142 | oldcrc32 = UPDC32(c, oldcrc32); 143 | } 144 | 145 | if (ferror(fin)) 146 | { 147 | perror(name); 148 | *charcnt = -1; 149 | } 150 | fclose(fin); 151 | 152 | *crc = oldcrc32 = ~oldcrc32; 153 | 154 | return true; 155 | } 156 | 157 | uint32_t crc32buf(char *buf, size_t len) 158 | { 159 | register uint32_t oldcrc32; 160 | 161 | oldcrc32 = 0xFFFFFFFF; 162 | 163 | for ( ; len; --len, ++buf) 164 | { 165 | oldcrc32 = UPDC32(*buf, oldcrc32); 166 | } 167 | 168 | return ~oldcrc32; 169 | } 170 | 171 | #ifdef TEST 172 | 173 | int main(int argc, char *argv[]) 174 | { 175 | uint32_t crc = 0; 176 | long charcnt = 0; 177 | bool errors = false; 178 | 179 | for (int i = 1; i < argc; ++ i) 180 | { 181 | errors = errors || crc32file(argv[i], &crc, &charcnt); 182 | printf("%08X %7ld %s\n", crc, charcnt, argv[i]); 183 | } 184 | return !errors; 185 | } 186 | 187 | #endif /* TEST */ 188 | -------------------------------------------------------------------------------- /lib_icer/src/icer_encoding.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by linyi on 19/3/2023. 3 | // 4 | 5 | #include "icer.h" 6 | 7 | #ifdef USE_ENCODE_FUNCTIONS 8 | #ifndef USER_PROVIDED_BUFFERS 9 | uint16_t icer_encode_circ_buf[ICER_CIRC_BUF_SIZE]; 10 | #endif 11 | 12 | static inline uint16_t pop_buf(icer_encoder_context_typedef *cntxt); 13 | static inline int16_t alloc_buf(icer_encoder_context_typedef *cntxt); 14 | 15 | void icer_init_entropy_coder_context(icer_encoder_context_typedef *encoder_context, uint16_t *encode_buffer, size_t buffer_length, uint8_t *encoder_out, size_t enc_out_max) { 16 | encoder_context->max_output_length = enc_out_max; 17 | encoder_context->output_buffer = encoder_out; 18 | 19 | encoder_context->buffer_length = buffer_length; 20 | encoder_context->encode_buffer = encode_buffer; 21 | 22 | encoder_context->head = 0; 23 | encoder_context->tail = 0; 24 | encoder_context->used = 0; 25 | 26 | for (size_t it = 0;it < ICER_ENCODER_BIN_MAX+1;it++) { 27 | encoder_context->bin_current_buf[it] = -1; 28 | encoder_context->bin_current_buf_bits[it] = 0; 29 | } 30 | 31 | encoder_context->output_ind = 0; 32 | encoder_context->output_bit_offset = 0; 33 | encoder_context->output_buffer[encoder_context->output_ind] = 0; 34 | } 35 | 36 | 37 | int icer_encode_bit(icer_encoder_context_typedef *encoder_context, uint8_t bit, uint32_t zero_cnt, uint32_t total_cnt) { 38 | 39 | uint16_t *curr_bin; 40 | if (zero_cnt < (total_cnt >> 1)) { 41 | /* 42 | * we may assume that the probability of zero for each bit is contained 43 | * the interval [1/2, 1] 44 | * in the case that the probability of zero < 1/2 45 | * we simple invert the bit, and its associated probability 46 | * this is duplicated in the decoder 47 | */ 48 | zero_cnt = total_cnt - zero_cnt; 49 | bit = bit ^ 0b1; 50 | } 51 | 52 | int bin = icer_compute_bin(zero_cnt, total_cnt); 53 | uint16_t prefix; 54 | uint16_t golomb_k; 55 | uint16_t golomb_out_code; 56 | uint8_t golomb_out_bits; 57 | uint16_t bit16 = (bit != 0); 58 | 59 | if (encoder_context->bin_current_buf[bin] == -1) { 60 | encoder_context->bin_current_buf[bin] = alloc_buf(encoder_context); 61 | if (encoder_context->bin_current_buf[bin] == -1) { 62 | if (icer_flush_encode(encoder_context) == ICER_BYTE_QUOTA_EXCEEDED) return ICER_BYTE_QUOTA_EXCEEDED; 63 | else encoder_context->bin_current_buf[bin] = alloc_buf(encoder_context); 64 | } 65 | curr_bin = encoder_context->encode_buffer + encoder_context->bin_current_buf[bin]; 66 | (*curr_bin) = bin << ICER_ENC_BUF_BITS_OFFSET; 67 | } else curr_bin = encoder_context->encode_buffer + encoder_context->bin_current_buf[bin]; 68 | 69 | if (bin > ICER_ENC_BIN_8) { 70 | /* golomb code bins */ 71 | if (!bit16) (*curr_bin)++; 72 | if (bit16) { 73 | golomb_k = (*curr_bin) & ICER_ENC_BUF_DATA_MASK; 74 | golomb_out_code = golomb_k + ((golomb_k < icer_golomb_coders[bin].i) ? 0 : icer_golomb_coders[bin].i); 75 | golomb_out_bits = icer_golomb_coders[bin].l + (golomb_k >= icer_golomb_coders[bin].i); 76 | icer_reverse_bits(&golomb_out_code, golomb_out_bits); 77 | (*curr_bin) = (golomb_out_bits << ICER_ENC_BUF_BITS_OFFSET); 78 | (*curr_bin) |= (golomb_out_code & ICER_ENC_BUF_DATA_MASK); 79 | (*curr_bin) |= ICER_ENC_BUF_DONE_MASK; 80 | encoder_context->bin_current_buf[bin] = -1; 81 | } else if (((*curr_bin) & ICER_ENC_BUF_DATA_MASK) >= icer_golomb_coders[bin].m) { 82 | (*curr_bin) = 1 << ICER_ENC_BUF_BITS_OFFSET; 83 | (*curr_bin) |= 1; 84 | (*curr_bin) |= ICER_ENC_BUF_DONE_MASK; 85 | encoder_context->bin_current_buf[bin] = -1; 86 | } 87 | } else if (bin != ICER_ENC_BIN_1) { 88 | /* custom non prefix code bins */ 89 | (*curr_bin) |= (bit16 << encoder_context->bin_current_buf_bits[bin]); 90 | encoder_context->bin_current_buf_bits[bin]++; 91 | prefix = (*curr_bin) & ICER_ENC_BUF_DATA_MASK; 92 | if (icer_custom_coding_scheme[bin][prefix].input_code_bits == encoder_context->bin_current_buf_bits[bin]) { 93 | (*curr_bin) = icer_custom_coding_scheme[bin][prefix].output_code_bits << ICER_ENC_BUF_BITS_OFFSET; 94 | (*curr_bin) |= icer_custom_coding_scheme[bin][prefix].output_code & ICER_ENC_BUF_DATA_MASK; 95 | (*curr_bin) |= ICER_ENC_BUF_DONE_MASK; 96 | encoder_context->bin_current_buf[bin] = -1; 97 | encoder_context->bin_current_buf_bits[bin] = 0; 98 | } 99 | 100 | } else { 101 | /* uncoded bin */ 102 | (*curr_bin) = bit16 & 0b1; 103 | (*curr_bin) |= (1 << ICER_ENC_BUF_BITS_OFFSET); 104 | (*curr_bin) |= ICER_ENC_BUF_DONE_MASK; 105 | encoder_context->bin_current_buf[bin] = -1; 106 | } 107 | 108 | if (icer_popbuf_while_avail(encoder_context) == ICER_BYTE_QUOTA_EXCEEDED) { 109 | return ICER_BYTE_QUOTA_EXCEEDED; 110 | } 111 | return ICER_RESULT_OK; 112 | } 113 | 114 | int icer_popbuf_while_avail(icer_encoder_context_typedef *encoder_context) { 115 | uint16_t out, bits; 116 | uint16_t d, r; 117 | int bits_to_encode; 118 | while (encoder_context->used > 0 && (encoder_context->encode_buffer[encoder_context->head] & ICER_ENC_BUF_DONE_MASK)) { 119 | out = pop_buf(encoder_context); 120 | bits = out >> ICER_ENC_BUF_BITS_OFFSET; 121 | while (bits) { 122 | bits_to_encode = icer_min_int(8-encoder_context->output_bit_offset, bits); 123 | encoder_context->output_buffer[encoder_context->output_ind] |= (out & ((1 << bits_to_encode) - 1)) << (encoder_context->output_bit_offset); 124 | out >>= bits_to_encode; 125 | bits -= bits_to_encode; 126 | r = (encoder_context->output_bit_offset + bits_to_encode) / 8; 127 | d = (encoder_context->output_bit_offset + bits_to_encode) % 8; 128 | encoder_context->output_bit_offset = d; 129 | if (r) { 130 | encoder_context->output_ind += r; 131 | encoder_context->output_buffer[encoder_context->output_ind] = 0; 132 | } 133 | if (encoder_context->output_ind == encoder_context->max_output_length) { 134 | return ICER_BYTE_QUOTA_EXCEEDED; 135 | } 136 | } 137 | } 138 | return ICER_RESULT_OK; 139 | } 140 | 141 | int icer_flush_encode(icer_encoder_context_typedef *encoder_context) { 142 | uint16_t *first = encoder_context->encode_buffer + encoder_context->head; 143 | icer_custom_flush_typedef *flush; 144 | uint16_t prefix; 145 | if (((*first) & ICER_ENC_BUF_DONE_MASK) == 0) { 146 | uint8_t bin = (*first) >> ICER_ENC_BUF_BITS_OFFSET; 147 | 148 | uint16_t golomb_k; 149 | uint16_t golomb_out_code; 150 | uint8_t golomb_out_bits; 151 | 152 | if (bin > ICER_ENC_BIN_8) { 153 | /* golomb code bins */ 154 | golomb_k = (*first) & ICER_ENC_BUF_DATA_MASK; 155 | if (golomb_k == icer_golomb_coders[bin].m - 1) { 156 | *first = 1 << ICER_ENC_BUF_BITS_OFFSET; 157 | *first |= 1; 158 | *first |= ICER_ENC_BUF_DONE_MASK; 159 | } else { 160 | golomb_out_code = golomb_k + ((golomb_k < icer_golomb_coders[bin].i) ? 0 : icer_golomb_coders[bin].i); 161 | golomb_out_bits = icer_golomb_coders[bin].l + (golomb_k >= icer_golomb_coders[bin].i); 162 | icer_reverse_bits(&golomb_out_code, golomb_out_bits); 163 | *first = (golomb_out_bits << ICER_ENC_BUF_BITS_OFFSET); 164 | *first |= (golomb_out_code & ICER_ENC_BUF_DATA_MASK); 165 | *first |= ICER_ENC_BUF_DONE_MASK; 166 | } 167 | encoder_context->bin_current_buf[bin] = -1; 168 | } else if (bin != ICER_ENC_BIN_1) { 169 | /* custom non prefix code bins */ 170 | flush = &(icer_custom_code_flush_bits[bin][(*first) & ICER_ENC_BUF_DATA_MASK][encoder_context->bin_current_buf_bits[bin]]); 171 | (*first) |= flush->flush_bit << encoder_context->bin_current_buf_bits[bin]; 172 | encoder_context->bin_current_buf_bits[bin] = (int16_t)(encoder_context->bin_current_buf_bits[bin] + flush->flush_bit_numbers); 173 | 174 | prefix = (*first) & ICER_ENC_BUF_DATA_MASK; 175 | 176 | (*first) = icer_custom_coding_scheme[bin][prefix].output_code_bits << ICER_ENC_BUF_BITS_OFFSET; 177 | (*first) |= icer_custom_coding_scheme[bin][prefix].output_code & ICER_ENC_BUF_DATA_MASK; 178 | (*first) |= ICER_ENC_BUF_DONE_MASK; 179 | encoder_context->bin_current_buf[bin] = -1; 180 | encoder_context->bin_current_buf_bits[bin] = 0; 181 | } else { 182 | /* uncoded bin */ 183 | // this should never happen? 184 | } 185 | } 186 | 187 | if (icer_popbuf_while_avail(encoder_context) == ICER_BYTE_QUOTA_EXCEEDED) return ICER_BYTE_QUOTA_EXCEEDED; 188 | return ICER_RESULT_OK; 189 | } 190 | 191 | /* circular buffer helper functions */ 192 | 193 | static inline uint16_t pop_buf(icer_encoder_context_typedef *cntxt) { 194 | if (cntxt->used > 0) cntxt->used--; 195 | uint16_t res = cntxt->encode_buffer[cntxt->head]; 196 | cntxt->head = (cntxt->head + 1) % cntxt->buffer_length; 197 | return res; 198 | } 199 | 200 | static inline int16_t alloc_buf(icer_encoder_context_typedef *cntxt) { 201 | if (cntxt->used >= cntxt->buffer_length) return -1; 202 | cntxt->used++; 203 | int16_t ind = (int16_t)cntxt->tail; 204 | cntxt->tail = (cntxt->tail+1) % cntxt->buffer_length; 205 | return ind; 206 | } 207 | 208 | /* data packet functions */ 209 | 210 | int icer_allocate_data_packet(icer_image_segment_typedef **pkt, icer_output_data_buf_typedef * const output_data, uint8_t segment_num, const icer_packet_context *context) { 211 | size_t buf_len = output_data->size_allocated - output_data->size_used; 212 | if (buf_len < sizeof(icer_image_segment_typedef)) { 213 | return ICER_BYTE_QUOTA_EXCEEDED; 214 | } 215 | (*pkt) = (icer_image_segment_typedef *) (output_data->data_start + output_data->size_used); 216 | (*pkt)->preamble = ICER_PACKET_PREAMBLE; 217 | (*pkt)->decomp_level = context->decomp_level; 218 | (*pkt)->subband_type = context->subband_type; 219 | (*pkt)->segment_number = segment_num; 220 | (*pkt)->lsb_chan = context->lsb | ICER_SET_CHANNEL_MACRO(context->channel); 221 | (*pkt)->ll_mean_val = context->ll_mean_val; 222 | (*pkt)->image_w = context->image_w; 223 | (*pkt)->image_h = context->image_h; 224 | (*pkt)->data_crc32 = 0; 225 | (*pkt)->crc32 = 0; 226 | 227 | output_data->size_used += sizeof(icer_image_segment_typedef); 228 | buf_len -= sizeof(icer_image_segment_typedef); 229 | 230 | // store max data length first 231 | (*pkt)->data_length = buf_len; 232 | 233 | return ICER_RESULT_OK; 234 | } 235 | 236 | #endif -------------------------------------------------------------------------------- /lib_icer/src/icer_init.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by linyi on 19/3/2023. 3 | // 4 | 5 | #include "icer.h" 6 | 7 | #define INIT_CODING_SCHEME(bin, inp, inp_bits, out, out_bits) { \ 8 | icer_custom_coding_scheme[bin][inp].input_code_bits = inp_bits; \ 9 | icer_custom_coding_scheme[bin][inp].output_code = out; \ 10 | icer_custom_coding_scheme[bin][inp].output_code_bits = out_bits; \ 11 | } 12 | 13 | #define INIT_FLUSH_BITS(bin, inp, inp_bits, out, out_bits) { \ 14 | icer_custom_code_flush_bits[bin][inp][inp_bits].flush_bit = out; \ 15 | icer_custom_code_flush_bits[bin][inp][inp_bits].flush_bit_numbers = out_bits; \ 16 | } 17 | 18 | #define INIT_DECODE_SCHEME(bin, out, out_bits, inp, inp_bits) { \ 19 | icer_custom_decode_scheme[bin][inp].input_code_bits = inp_bits; \ 20 | icer_custom_decode_scheme[bin][inp].output_code = out; \ 21 | icer_custom_decode_scheme[bin][inp].output_code_bits = out_bits; \ 22 | } 23 | 24 | int icer_init() { 25 | icer_init_golombcoder(); 26 | #ifdef USE_ENCODE_FUNCTIONS 27 | icer_init_codingscheme(); 28 | #endif 29 | #ifdef USE_DECODE_FUNCTIONS 30 | icer_init_decodescheme(); 31 | #endif 32 | icer_init_flushbits(); 33 | 34 | return ICER_RESULT_OK; 35 | } 36 | 37 | #ifdef USE_DECODE_FUNCTIONS 38 | void icer_init_decodescheme() { 39 | for (int it = 0; it <= ICER_ENCODER_BIN_MAX; it++) { 40 | for (int j = 0; j < CUSTOM_CODING_MAX_LOOKUP; j++) { 41 | icer_custom_decode_scheme[it][j].input_code_bits = 0; 42 | icer_custom_decode_scheme[it][j].output_code_bits = 0; 43 | } 44 | } 45 | 46 | INIT_DECODE_SCHEME(ICER_ENC_BIN_2, 0b01, 2, 0b10, 2); 47 | INIT_DECODE_SCHEME(ICER_ENC_BIN_2, 0b011, 3, 0b011, 3); 48 | INIT_DECODE_SCHEME(ICER_ENC_BIN_2, 0b0111, 4, 0b1111, 4); 49 | INIT_DECODE_SCHEME(ICER_ENC_BIN_2, 0b1111, 4, 0b10000, 5); 50 | INIT_DECODE_SCHEME(ICER_ENC_BIN_2, 0b10, 2, 0b01, 2); 51 | INIT_DECODE_SCHEME(ICER_ENC_BIN_2, 0b100, 3, 0b100, 3); 52 | INIT_DECODE_SCHEME(ICER_ENC_BIN_2, 0b1000, 4, 0b1000, 4); 53 | INIT_DECODE_SCHEME(ICER_ENC_BIN_2, 0b10000, 5, 0b00000, 5); 54 | INIT_DECODE_SCHEME(ICER_ENC_BIN_2, 0b00000, 5, 0b0111, 4); 55 | 56 | INIT_DECODE_SCHEME(ICER_ENC_BIN_3, 0b10, 2, 0b01, 2); 57 | INIT_DECODE_SCHEME(ICER_ENC_BIN_3, 0b100, 3, 0b00, 2); 58 | INIT_DECODE_SCHEME(ICER_ENC_BIN_3, 0b0000, 4, 0b011, 3); 59 | INIT_DECODE_SCHEME(ICER_ENC_BIN_3, 0b11000, 5, 0b10010, 5); 60 | INIT_DECODE_SCHEME(ICER_ENC_BIN_3, 0b01000, 5, 0b1111, 4); 61 | INIT_DECODE_SCHEME(ICER_ENC_BIN_3, 0b01, 2, 0b110, 3); 62 | INIT_DECODE_SCHEME(ICER_ENC_BIN_3, 0b0011, 4, 0b0111, 4); 63 | INIT_DECODE_SCHEME(ICER_ENC_BIN_3, 0b1011, 4, 0b00010, 5); 64 | INIT_DECODE_SCHEME(ICER_ENC_BIN_3, 0b111, 3, 0b1010, 4); 65 | 66 | INIT_DECODE_SCHEME(ICER_ENC_BIN_4, 0b10, 2, 0b10, 2); 67 | INIT_DECODE_SCHEME(ICER_ENC_BIN_4, 0b100, 3, 0b011, 3); 68 | INIT_DECODE_SCHEME(ICER_ENC_BIN_4, 0b000, 3, 0b00, 2); 69 | INIT_DECODE_SCHEME(ICER_ENC_BIN_4, 0b01, 2, 0b01, 2); 70 | INIT_DECODE_SCHEME(ICER_ENC_BIN_4, 0b11, 2, 0b111, 3); 71 | 72 | INIT_DECODE_SCHEME(ICER_ENC_BIN_5, 0b00, 2, 0b1, 1); 73 | INIT_DECODE_SCHEME(ICER_ENC_BIN_5, 0b010, 3, 0b000, 3); 74 | INIT_DECODE_SCHEME(ICER_ENC_BIN_5, 0b110, 3, 0b1010, 4); 75 | INIT_DECODE_SCHEME(ICER_ENC_BIN_5, 0b101, 3, 0b0010, 4); 76 | INIT_DECODE_SCHEME(ICER_ENC_BIN_5, 0b1001, 4, 0b1110, 4); 77 | INIT_DECODE_SCHEME(ICER_ENC_BIN_5, 0b00001, 5, 0b0100, 4); 78 | INIT_DECODE_SCHEME(ICER_ENC_BIN_5, 0b10001, 5, 0b00110, 5); 79 | INIT_DECODE_SCHEME(ICER_ENC_BIN_5, 0b011, 3, 0b1100, 4); 80 | INIT_DECODE_SCHEME(ICER_ENC_BIN_5, 0b111, 3, 0b10110, 5); 81 | 82 | INIT_DECODE_SCHEME(ICER_ENC_BIN_6, 0b1, 1, 0b10, 2); 83 | INIT_DECODE_SCHEME(ICER_ENC_BIN_6, 0b010, 3, 0b011, 3); 84 | INIT_DECODE_SCHEME(ICER_ENC_BIN_6, 0b110, 3, 0b1111, 4); 85 | INIT_DECODE_SCHEME(ICER_ENC_BIN_6, 0b100, 3, 0b101, 3); 86 | INIT_DECODE_SCHEME(ICER_ENC_BIN_6, 0b1000, 4, 0b001, 3); 87 | INIT_DECODE_SCHEME(ICER_ENC_BIN_6, 0b10000, 5, 0b0111, 4); 88 | INIT_DECODE_SCHEME(ICER_ENC_BIN_6, 0b00000, 5, 0b00, 2); 89 | 90 | INIT_DECODE_SCHEME(ICER_ENC_BIN_7, 0b000, 3, 0b0, 1); 91 | INIT_DECODE_SCHEME(ICER_ENC_BIN_7, 0b100, 3, 0b001, 3); 92 | INIT_DECODE_SCHEME(ICER_ENC_BIN_7, 0b010, 3, 0b101, 3); 93 | INIT_DECODE_SCHEME(ICER_ENC_BIN_7, 0b110, 3, 0b01111, 5); 94 | INIT_DECODE_SCHEME(ICER_ENC_BIN_7, 0b11, 2, 0b0111, 4); 95 | INIT_DECODE_SCHEME(ICER_ENC_BIN_7, 0b001, 3, 0b011, 3); 96 | INIT_DECODE_SCHEME(ICER_ENC_BIN_7, 0b101, 3, 0b11111, 5); 97 | 98 | INIT_DECODE_SCHEME(ICER_ENC_BIN_8, 0b10, 2, 0b101, 3); 99 | INIT_DECODE_SCHEME(ICER_ENC_BIN_8, 0b100, 3, 0b001, 3); 100 | INIT_DECODE_SCHEME(ICER_ENC_BIN_8, 0b0000, 4, 0b0, 1); 101 | INIT_DECODE_SCHEME(ICER_ENC_BIN_8, 0b01000, 5, 0b0111, 4); 102 | INIT_DECODE_SCHEME(ICER_ENC_BIN_8, 0b11000, 5, 0b01111, 5); 103 | INIT_DECODE_SCHEME(ICER_ENC_BIN_8, 0b01, 2, 0b011, 3); 104 | INIT_DECODE_SCHEME(ICER_ENC_BIN_8, 0b11, 2, 0b11111, 5); 105 | 106 | 107 | for (int it = 0; it <= ICER_ENCODER_BIN_MAX; it++) { 108 | for (int j = 0; j < CUSTOM_CODING_MAX_LOOKUP; j++) { 109 | if (icer_custom_decode_scheme[it][j].output_code_bits != 0) { 110 | uint8_t reversed = 0; 111 | for (int b = 0; b < icer_custom_decode_scheme[it][j].output_code_bits; b++) { 112 | reversed <<= 1; 113 | reversed |= icer_custom_decode_scheme[it][j].output_code & 1; 114 | icer_custom_decode_scheme[it][j].output_code >>= 1; 115 | } 116 | icer_custom_decode_scheme[it][j].output_code = reversed; 117 | } 118 | } 119 | } 120 | } 121 | #endif 122 | 123 | #ifdef USE_ENCODE_FUNCTIONS 124 | void icer_init_codingscheme() { 125 | for (int it = 0; it <= ICER_ENCODER_BIN_MAX; it++) { 126 | for (int j = 0; j < CUSTOM_CODING_MAX_LOOKUP; j++) icer_custom_coding_scheme[it][j].input_code_bits = 0; 127 | } 128 | 129 | INIT_CODING_SCHEME(ICER_ENC_BIN_2, 0b01, 2, 0b10, 2); 130 | INIT_CODING_SCHEME(ICER_ENC_BIN_2, 0b011, 3, 0b011, 3); 131 | INIT_CODING_SCHEME(ICER_ENC_BIN_2, 0b0111, 4, 0b1111, 4); 132 | INIT_CODING_SCHEME(ICER_ENC_BIN_2, 0b1111, 4, 0b10000, 5); 133 | INIT_CODING_SCHEME(ICER_ENC_BIN_2, 0b10, 2, 0b01, 2); 134 | INIT_CODING_SCHEME(ICER_ENC_BIN_2, 0b100, 3, 0b100, 3); 135 | INIT_CODING_SCHEME(ICER_ENC_BIN_2, 0b1000, 4, 0b1000, 4); 136 | INIT_CODING_SCHEME(ICER_ENC_BIN_2, 0b10000, 5, 0b00000, 5); 137 | INIT_CODING_SCHEME(ICER_ENC_BIN_2, 0b00000, 5, 0b0111, 4); 138 | 139 | INIT_CODING_SCHEME(ICER_ENC_BIN_3, 0b10, 2, 0b01, 2); 140 | INIT_CODING_SCHEME(ICER_ENC_BIN_3, 0b100, 3, 0b00, 2); 141 | INIT_CODING_SCHEME(ICER_ENC_BIN_3, 0b0000, 4, 0b011, 3); 142 | INIT_CODING_SCHEME(ICER_ENC_BIN_3, 0b11000, 5, 0b10010, 5); 143 | INIT_CODING_SCHEME(ICER_ENC_BIN_3, 0b01000, 5, 0b1111, 4); 144 | INIT_CODING_SCHEME(ICER_ENC_BIN_3, 0b01, 2, 0b110, 3); 145 | INIT_CODING_SCHEME(ICER_ENC_BIN_3, 0b0011, 4, 0b0111, 4); 146 | INIT_CODING_SCHEME(ICER_ENC_BIN_3, 0b1011, 4, 0b00010, 5); 147 | INIT_CODING_SCHEME(ICER_ENC_BIN_3, 0b111, 3, 0b1010, 4); 148 | 149 | INIT_CODING_SCHEME(ICER_ENC_BIN_4, 0b10, 2, 0b10, 2); 150 | INIT_CODING_SCHEME(ICER_ENC_BIN_4, 0b100, 3, 0b011, 3); 151 | INIT_CODING_SCHEME(ICER_ENC_BIN_4, 0b000, 3, 0b00, 2); 152 | INIT_CODING_SCHEME(ICER_ENC_BIN_4, 0b01, 2, 0b01, 2); 153 | INIT_CODING_SCHEME(ICER_ENC_BIN_4, 0b11, 2, 0b111, 3); 154 | 155 | INIT_CODING_SCHEME(ICER_ENC_BIN_5, 0b00, 2, 0b1, 1); 156 | INIT_CODING_SCHEME(ICER_ENC_BIN_5, 0b010, 3, 0b000, 3); 157 | INIT_CODING_SCHEME(ICER_ENC_BIN_5, 0b110, 3, 0b1010, 4); 158 | INIT_CODING_SCHEME(ICER_ENC_BIN_5, 0b101, 3, 0b0010, 4); 159 | INIT_CODING_SCHEME(ICER_ENC_BIN_5, 0b1001, 4, 0b1110, 4); 160 | INIT_CODING_SCHEME(ICER_ENC_BIN_5, 0b00001, 5, 0b0100, 4); 161 | INIT_CODING_SCHEME(ICER_ENC_BIN_5, 0b10001, 5, 0b00110, 5); 162 | INIT_CODING_SCHEME(ICER_ENC_BIN_5, 0b011, 3, 0b1100, 4); 163 | INIT_CODING_SCHEME(ICER_ENC_BIN_5, 0b111, 3, 0b10110, 5); 164 | 165 | INIT_CODING_SCHEME(ICER_ENC_BIN_6, 0b1, 1, 0b10, 2); 166 | INIT_CODING_SCHEME(ICER_ENC_BIN_6, 0b010, 3, 0b011, 3); 167 | INIT_CODING_SCHEME(ICER_ENC_BIN_6, 0b110, 3, 0b1111, 4); 168 | INIT_CODING_SCHEME(ICER_ENC_BIN_6, 0b100, 3, 0b101, 3); 169 | INIT_CODING_SCHEME(ICER_ENC_BIN_6, 0b1000, 4, 0b001, 3); 170 | INIT_CODING_SCHEME(ICER_ENC_BIN_6, 0b10000, 5, 0b0111, 4); 171 | INIT_CODING_SCHEME(ICER_ENC_BIN_6, 0b00000, 5, 0b00, 2); 172 | 173 | INIT_CODING_SCHEME(ICER_ENC_BIN_7, 0b000, 3, 0b0, 1); 174 | INIT_CODING_SCHEME(ICER_ENC_BIN_7, 0b100, 3, 0b001, 3); 175 | INIT_CODING_SCHEME(ICER_ENC_BIN_7, 0b010, 3, 0b101, 3); 176 | INIT_CODING_SCHEME(ICER_ENC_BIN_7, 0b110, 3, 0b01111, 5); 177 | INIT_CODING_SCHEME(ICER_ENC_BIN_7, 0b11, 2, 0b0111, 4); 178 | INIT_CODING_SCHEME(ICER_ENC_BIN_7, 0b001, 3, 0b011, 3); 179 | INIT_CODING_SCHEME(ICER_ENC_BIN_7, 0b101, 3, 0b11111, 5); 180 | 181 | INIT_CODING_SCHEME(ICER_ENC_BIN_8, 0b10, 2, 0b101, 3); 182 | INIT_CODING_SCHEME(ICER_ENC_BIN_8, 0b100, 3, 0b001, 3); 183 | INIT_CODING_SCHEME(ICER_ENC_BIN_8, 0b0000, 4, 0b0, 1); 184 | INIT_CODING_SCHEME(ICER_ENC_BIN_8, 0b01000, 5, 0b0111, 4); 185 | INIT_CODING_SCHEME(ICER_ENC_BIN_8, 0b11000, 5, 0b01111, 5); 186 | INIT_CODING_SCHEME(ICER_ENC_BIN_8, 0b01, 2, 0b011, 3); 187 | INIT_CODING_SCHEME(ICER_ENC_BIN_8, 0b11, 2, 0b11111, 5); 188 | } 189 | #endif 190 | 191 | void icer_init_flushbits() { 192 | INIT_FLUSH_BITS(ICER_ENC_BIN_2, 0b1, 1, 0, 1); 193 | INIT_FLUSH_BITS(ICER_ENC_BIN_2, 0b11, 2, 0, 1); 194 | INIT_FLUSH_BITS(ICER_ENC_BIN_2, 0b111, 3, 0, 1); 195 | INIT_FLUSH_BITS(ICER_ENC_BIN_2, 0b0, 1, 1, 1); 196 | INIT_FLUSH_BITS(ICER_ENC_BIN_2, 0b00, 2, 1, 1); 197 | INIT_FLUSH_BITS(ICER_ENC_BIN_2, 0b000, 3, 1, 1); 198 | INIT_FLUSH_BITS(ICER_ENC_BIN_2, 0b0000, 4, 0, 1); 199 | 200 | INIT_FLUSH_BITS(ICER_ENC_BIN_3, 0b0, 1, 1, 1); 201 | INIT_FLUSH_BITS(ICER_ENC_BIN_3, 0b00, 2, 1, 1); 202 | INIT_FLUSH_BITS(ICER_ENC_BIN_3, 0b000, 3, 0, 1); 203 | INIT_FLUSH_BITS(ICER_ENC_BIN_3, 0b1000, 4, 0, 1); 204 | INIT_FLUSH_BITS(ICER_ENC_BIN_3, 0b1, 1, 0, 1); 205 | INIT_FLUSH_BITS(ICER_ENC_BIN_3, 0b11, 2, 1, 1); 206 | INIT_FLUSH_BITS(ICER_ENC_BIN_3, 0b011, 3, 0, 1); 207 | 208 | INIT_FLUSH_BITS(ICER_ENC_BIN_4, 0b0, 1, 1, 1); 209 | INIT_FLUSH_BITS(ICER_ENC_BIN_4, 0b00, 2, 0, 1); 210 | INIT_FLUSH_BITS(ICER_ENC_BIN_4, 0b1, 1, 0, 1); 211 | 212 | INIT_FLUSH_BITS(ICER_ENC_BIN_5, 0b0, 1, 0, 1); 213 | INIT_FLUSH_BITS(ICER_ENC_BIN_5, 0b10, 2, 0, 1); 214 | INIT_FLUSH_BITS(ICER_ENC_BIN_5, 0b01, 2, 1, 1); 215 | INIT_FLUSH_BITS(ICER_ENC_BIN_5, 0b001, 3, 1, 1); 216 | INIT_FLUSH_BITS(ICER_ENC_BIN_5, 0b0001, 4, 0, 1); 217 | INIT_FLUSH_BITS(ICER_ENC_BIN_5, 0b1, 1, 0b01, 2); 218 | INIT_FLUSH_BITS(ICER_ENC_BIN_5, 0b11, 2, 0, 1); 219 | 220 | INIT_FLUSH_BITS(ICER_ENC_BIN_6, 0b0, 1, 0b01, 2); 221 | INIT_FLUSH_BITS(ICER_ENC_BIN_6, 0b01, 2, 0, 1); 222 | INIT_FLUSH_BITS(ICER_ENC_BIN_6, 0b00, 2, 1, 1); 223 | INIT_FLUSH_BITS(ICER_ENC_BIN_6, 0b000, 3, 1, 1); 224 | INIT_FLUSH_BITS(ICER_ENC_BIN_6, 0b0000, 4, 0, 1); 225 | 226 | INIT_FLUSH_BITS(ICER_ENC_BIN_7, 0b0, 1, 0b00, 2); 227 | INIT_FLUSH_BITS(ICER_ENC_BIN_7, 0b00, 2, 0, 1); 228 | INIT_FLUSH_BITS(ICER_ENC_BIN_7, 0b10, 2, 0, 1); 229 | INIT_FLUSH_BITS(ICER_ENC_BIN_7, 0b1, 1, 1, 1); 230 | INIT_FLUSH_BITS(ICER_ENC_BIN_7, 0b01, 2, 0, 1); 231 | 232 | INIT_FLUSH_BITS(ICER_ENC_BIN_8, 0b0, 1, 1, 1); 233 | INIT_FLUSH_BITS(ICER_ENC_BIN_8, 0b00, 2, 1, 1); 234 | INIT_FLUSH_BITS(ICER_ENC_BIN_8, 0b000, 3, 0, 1); 235 | INIT_FLUSH_BITS(ICER_ENC_BIN_8, 0b1000, 4, 0, 1); 236 | INIT_FLUSH_BITS(ICER_ENC_BIN_8, 0b1, 1, 0, 1); 237 | } 238 | 239 | void icer_init_golombcoder() { 240 | for (int it = 0; it <= ICER_ENCODER_BIN_MAX; it++) { 241 | if (icer_bin_coding_scheme[it] > 0) { 242 | unsigned int m = icer_bin_coding_scheme[it]; 243 | icer_golomb_coders[it].m = m; 244 | 245 | // compute ceil( log2( m ) ) 246 | unsigned int l = 31 - __builtin_clz(m); 247 | l += ((m ^ (1 << l)) != 0); 248 | 249 | // compute 2^l - m 250 | unsigned int i = icer_pow_uint(2, l) - m; 251 | 252 | icer_golomb_coders[it].i = i; 253 | icer_golomb_coders[it].l = l; 254 | } 255 | } 256 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ICER Image Compression Algorithm 2 | 3 | The code in this repository implements the NASA ICER image compression algorithm as a C library. Said compression algorithm is a progressive, wavelet-based image compression algorithm designed to be resistant to data loss, making it suitable for use as the image compression algorithm when encoding images to be transmitted over unreliable delivery channels, such as those in satellite radio communications. 4 | 5 | This library was designed with memory-constrained embedded systems in mind, hence the language choice of C, but it should function just as well on normal machines. 6 | 7 | ## Features 8 | 9 | Note: You may want to check out the alternate branch `include-metadata` for future use, where the compressed output includes the details of the compression parameters used. 10 | 11 | ### Core Capabilities 12 | 13 | - Full color image compression using YUV color space 14 | - Progressive image compression with configurable quality levels 15 | - Wavelet-based compression using various filter types 16 | - Error containment segments to limit data loss effects 17 | - Configurable output size targeting 18 | - Support for both lossless and lossy compression 19 | - Integer-only arithmetic operations for embedded systems 20 | - Memory-conscious implementation with no dynamic allocation 21 | 22 | ## Compression Examples 23 | 24 | Below are sample images of the compression algorithm producing output images of varying quality depending on the space allocated for it. 10 error containment segments are used, and 9 bitplanes were compressed 25 | 26 | ### Color Compression 27 | 28 | | ![original_color](https://github.com/TheRealOrange/icer_compression/blob/master/assets/original_color.bmp?raw=true) | ![140kb_quota_color](https://github.com/TheRealOrange/icer_compression/blob/master/assets/140kb_quota_color.bmp?raw=true) | 29 | | ------------------------------------------------------------ | ------------------------------------------------------------ | 30 | | original color image (512x512, 768 kilobyte) | 140 kilobyte quota | 31 | | ![100kb_quota_color](https://github.com/TheRealOrange/icer_compression/blob/master/assets/100kb_quota_color.bmp?raw=true) | ![70kb_quota_color](https://github.com/TheRealOrange/icer_compression/blob/master/assets/70kb_quota_color.bmp?raw=true) | 32 | | 100 kilobyte quota | 70 kilobyte quota | 33 | 34 | ### Grayscale Compression 35 | 36 | | ![original](https://github.com/TheRealOrange/icer_compression/blob/master/assets/original.bmp?raw=true) | ![70kb_quota](https://github.com/TheRealOrange/icer_compression/blob/master/assets/70kb_quota.bmp?raw=true) | 37 | | ------------------------------------------------------------ | ------------------------------------------------------------ | 38 | | original image (512x512, 262 kilobyte) | 70 kilobyte quota | 39 | | ![50kb_quota](https://github.com/TheRealOrange/icer_compression/blob/master/assets/50kb_quota.bmp?raw=true) | ![30kb_quota](https://github.com/TheRealOrange/icer_compression/blob/master/assets/30kb_quota.bmp?raw=true) | 40 | | 50 kilobyte quota | 30 kilobyte quota | 41 | 42 | The compression effectiveness depends greatly on the number of error containment segments chosen. 43 | 44 | ## What is this? 45 | 46 | This compression algorithm is based on [a document published by NASA](https://ipnpr.jpl.nasa.gov/progress_report/42-155/155J.pdf). This repository implements the algorithm as described by the paper, with additional support for color images. 47 | 48 | This algorithm is best described by the abstract of the document by NASA, which reads as follows: 49 | 50 | > ICER is a progressive, wavelet-based image data compressor designed to meet the specialized needs of deep-space applications while achieving state-of-the-art compression effectiveness. ICER can provide lossless and lossy compression, and incorporates an error-containment scheme to limit the effects of data loss during transmission. The Mars Exploration Rover (MER) mission will rely primarily on a software implementation of ICER for image compression. This article describes ICER and the methods it uses to meet its goals, and explains the rationale behind the choice of methods. Performance results also are presented. 51 | 52 | ## Credits 53 | 54 | This library uses code from: 55 | 56 | - CRC32 checksum library from the [SNIPPETS C Source Code Archive](https://github.com/vonj/snippets.org) 57 | - Image parsing libraries from [STB libraries](https://github.com/nothings/stb) 58 | 59 | ## Key Features 60 | 61 | There are a few key design considerations which were taking into account when writing this library, which are as follows: 62 | 63 | - Designed to only utilise integer arithmetic operations, as designed by NASA 64 | - Avoids dynamic memory allocation in the library, so memory can be better managed in memory-constrained embedded systems 65 | - Optimised for execution on embedded systems 66 | - Error containment features prevent data loss from affecting the quality of the whole image 67 | - Ability to set a output size target and stop compression once the quota is reached 68 | - Able to compress images losslessly (if the output quota permits) 69 | 70 | (again, recommended that you carefully read the NASA document to understand why and how these are significant) 71 | 72 | ## How do I test it? 73 | 74 | The project uses CMake for building. To build all components: 75 | 76 | ```bash 77 | mkdir build 78 | cd build 79 | cmake -DCMAKE_BUILD_TYPE=Release .. 80 | make 81 | ``` 82 | 83 | This will build: 84 | - `compress`, `decompress`, Grayscale compression/decompression **implementation** examples 85 | - `compress_color`, `decompress_color` - Color compression/decompression **implementation** examples 86 | - `icer_util` - Standalone command-line utility to compress/decompress ICER images 87 | 88 | ### Command-line Tool 89 | 90 | The `icer_util` program is a command-line program for compressing and decompressing images with the ICER algorithm. You can use this to test the compression efficacy on input images, and play around with byte quotas. 91 | 92 | #### Basic Usage 93 | 94 | ```bash 95 | # Compress an image (with default parameters) 96 | ./icer_util compress input.jpg output.bin 97 | 98 | # Decompress an image (compulsory to specify color or grayscale) 99 | ./icer_util decompress compressed.bin output.bmp --color 100 | ./icer_util decompress compressed.bin output.bmp --grayscale 101 | 102 | # Show availabe options 103 | ./icer_util --help 104 | ``` 105 | 106 | #### Advanced Options 107 | 108 | ```bash 109 | # Compress with specific parameters 110 | # if compressing with non-default parameters it is 111 | # necessary to supply the parameters used during decompression 112 | ./icer_util compress input.png output.bin \ 113 | --stages 5 \ 114 | --filter B \ 115 | --segments 10 \ 116 | -t 150000 # byte quota 117 | 118 | # Decompress with specific parameters 119 | # if the image was compressed with non-default parameters it is 120 | # necessary to supply the parameters used 121 | ./icer_util decompress output.bin output.bmp \ 122 | --stages 5 \ 123 | --filter B \ 124 | --segments 10 125 | 126 | # Set target compression size in bytes 127 | ./icer_util compress input.jpg output.bin -t 100000 128 | ``` 129 | 130 | #### Supported Image Formats 131 | 132 | - **Input (compression):** JPEG, PNG, BMP, TGA, and other formats supported by the STB Image library 133 | - **Output (decompression):** BMP format 134 | 135 | ### Integration Examples 136 | 137 | The integration examples show an example usage of the library functions within a project. It is for reference only, though you can build and run it to test. 138 | 139 | To run the example code, simply build it and place the `boat.512.bmp` (and `boatcolor.512.bmp` for color encode) image as the same folder as the executable to generate the output. 140 | 141 | The examples demonstrate: 142 | - `compress` / `example_encode.c` - Basic grayscale image compression 143 | - `decompress` / `example_decode.c` - Basic grayscale image decompression 144 | - `compress_color` / `example_encode_color.c` - Color image compression using YUV 145 | - `decompress_color` / `example_decode_color.c` - Color image decompression from YUV 146 | 147 | ## How do I use it in my project? 148 | 149 | The project is designed as a C-library and as such is intended to be used as a part of a larger program, not as a standalone program. 150 | 151 | To include the library, select the appropriate flags for which parts of the library to compile: 152 | 153 | ```c 154 | #define USE_ENCODE_FUNCTIONS // Compile encode functions 155 | #define USE_DECODE_FUNCTIONS // Compile decode functions 156 | 157 | #define USE_UINT16_FUNCTIONS // Compile functions for uint16_t arrays 158 | #define USE_UINT8_FUNCTIONS // Compile functions for uint8_t arrays 159 | 160 | #include "icer.h" 161 | ``` 162 | 163 | Then, somewhere at the start, one must call 164 | 165 | ```c 166 | int icer_init(); 167 | ``` 168 | 169 | in order to initialise the constants and look up tables used in encode and decode functions. 170 | 171 | The main functions which are important for the usage of the library are (here we only show the `uint8_t` functions, but the `uint16_t` versions exists too): 172 | 173 | 1. Compression functions 174 | 175 | ```c 176 | // For grayscale/single channel images 177 | int icer_compress_image_uint8(uint8_t *image, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt, uint8_t segments, icer_output_data_buf_typedef *output_data); 178 | 179 | // For colour images 180 | int icer_compress_image_yuv_uint8(uint8_t *y_channel, uint8_t *u_channel, uint8_t *v_channel, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt, uint8_t segments, icer_output_data_buf_typedef *output_data); 181 | ``` 182 | 183 | which is the function which enables the user to specify an image buffer of a specific width and height, as well as the filter coefficients to use, the number of time to perform wavelet decomposition, and the number of error containment segments to subdivide the image into 184 | 185 | 2. Decompression functions 186 | 187 | ```c 188 | // For grayscale/single channel images 189 | int icer_decompress_image_uint8(uint8_t *image, size_t *image_w, size_t *image_h, size_t image_bufsize, uint8_t *datastream, size_t data_length, uint8_t stages, enum icer_filter_types filt, uint8_t segments); 190 | 191 | // For colour images 192 | int icer_decompress_image_yuv_uint8(uint8_t *y_channel, uint8_t *u_channel, uint8_t *v_channel, size_t *image_w, size_t *image_h, size_t image_bufsize, const uint8_t *datastream, size_t data_length, uint8_t stages, enum icer_filter_types filt, uint8_t segments); 193 | ``` 194 | 195 | which is the function which enables the user to decompress a byte stream stored inside `datastream` and fill the image and the dimensions into the buffer specified. 196 | 197 | 3. Utility Functions 198 | 199 | ```c 200 | int icer_get_image_dimensions(const uint8_t *datastream, size_t data_length, size_t *image_w, size_t *image_h); 201 | ``` 202 | 203 | which can be used to get the dimensions of an encoded image (useful for knowing how much space to allocate for the image to decode it). 204 | 205 | ## Advanced Configuration 206 | 207 | The library provides several compile-time configuration options through preprocessor definitions that allow you to optimize memory usage and customize functionality for your specific needs. 208 | 209 | ### Memory and Buffer Configuration 210 | 211 | ```c 212 | // Maximum number of error containment segments 213 | #ifndef ICER_MAX_SEGMENTS 214 | #define ICER_MAX_SEGMENTS 32 215 | #endif 216 | 217 | // Maximum number of wavelet decomposition stages 218 | #ifndef ICER_MAX_DECOMP_STAGES 219 | #define ICER_MAX_DECOMP_STAGES 6 220 | #endif 221 | 222 | // Maximum number of packets for 8-bit and 16-bit processing 223 | #ifndef ICER_MAX_PACKETS 224 | #define ICER_MAX_PACKETS 300 225 | #endif 226 | 227 | #ifndef ICER_MAX_PACKETS_16 228 | #define ICER_MAX_PACKETS_16 800 229 | #endif 230 | 231 | // Number of bitplanes to compress for 8-bit and 16-bit modes 232 | #ifndef ICER_BITPLANES_TO_COMPRESS_8 233 | #define ICER_BITPLANES_TO_COMPRESS_8 7 234 | #endif 235 | 236 | #ifndef ICER_BITPLANES_TO_COMPRESS_16 237 | #define ICER_BITPLANES_TO_COMPRESS_16 9 238 | #endif 239 | ``` 240 | 241 | ### Feature Selection Flags 242 | 243 | ```c 244 | // Select which bit depth functions to compile 245 | #if !defined(USE_UINT8_FUNCTIONS) && !defined(USE_UINT16_FUNCTIONS) 246 | #define USE_UINT8_FUNCTIONS 247 | #define USE_UINT16_FUNCTIONS 248 | #endif 249 | 250 | // Select whether to compile encode/decode functions 251 | #if !defined(USE_DECODE_FUNCTIONS) && !defined(USE_ENCODE_FUNCTIONS) 252 | #define USE_DECODE_FUNCTIONS 253 | #define USE_ENCODE_FUNCTIONS 254 | #endif 255 | ``` 256 | 257 | ### Advanced Memory Management 258 | 259 | ```c 260 | // Enable user-provided buffers for fine-grained memory control 261 | //#define USER_PROVIDED_BUFFERS 262 | ``` 263 | 264 | When `USER_PROVIDED_BUFFERS` is defined, you must allocate the following buffers: 265 | 266 | For 8-bit encoding: 267 | 268 | ```c 269 | icer_packet_context icer_packets[ICER_MAX_PACKETS]; 270 | icer_image_segment_typedef *icer_rearrange_segments_8[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][7][ICER_MAX_SEGMENTS + 1]; 271 | ``` 272 | 273 | For 8-bit decoding: 274 | 275 | ```c 276 | const icer_image_segment_typedef *icer_reconstruct_data_8[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][ICER_MAX_SEGMENTS + 1][7]; 277 | ``` 278 | 279 | For 16-bit encoding: 280 | 281 | ```c 282 | icer_packet_context icer_packets_16[ICER_MAX_PACKETS_16]; 283 | icer_image_segment_typedef *icer_rearrange_segments_16[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][15][ICER_MAX_SEGMENTS + 1]; 284 | ``` 285 | 286 | For 16-bit decoding: 287 | 288 | ```c 289 | const icer_image_segment_typedef *icer_reconstruct_data_16[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][ICER_MAX_SEGMENTS + 1][15]; 290 | ``` 291 | 292 | Common encoding buffer: 293 | 294 | ```c 295 | uint16_t icer_encode_circ_buf[ICER_CIRC_BUF_SIZE]; // ICER_CIRC_BUF_SIZE = 2048 296 | ``` 297 | 298 | ### Custom CRC32 Implementation 299 | 300 | ```c 301 | // Define custom CRC32 implementation (e.g., hardware acceleration) 302 | //#define CRC32BUF_FUNCTION(x, y) your_custom_crc32_function 303 | ``` 304 | 305 | When defined, you can provide your own CRC32 implementation with the following signature: 306 | 307 | ```c 308 | uint32_t crc32buf(char *buf, size_t len) 309 | ``` 310 | 311 | ## Note: Work in progress! 312 | 313 | The library now supports: 314 | 315 | - 8-bit and 16-bit image processing 316 | - Full color support using YUV color space 317 | - Multiple wavelet filter types 318 | - Configurable error containment segments 319 | - Progressive compression with size targeting 320 | 321 | Future improvements may include: 322 | 323 | - Additional color space support 324 | - Enhanced compression options for different color channels 325 | 326 | -------------------------------------------------------------------------------- /example/src/icer_util.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Lin Yicheng on 4/8/25. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "stb_image.h" 13 | #include "stb_image_write.h" 14 | #include "color_util.h" 15 | 16 | // ICER library configuration 17 | #define USE_ENCODE_FUNCTIONS 18 | #define USE_DECODE_FUNCTIONS 19 | #define USE_UINT16_FUNCTIONS 20 | 21 | #include "icer.h" 22 | 23 | typedef struct { 24 | char *input_file; 25 | char *output_file; 26 | char *operation; // "compress" or "decompress" 27 | int stages; 28 | enum icer_filter_types filter; 29 | int segments; 30 | int target_size; // Target output size in bytes (0 = lossless) 31 | int force_color; 32 | int force_grayscale; 33 | } icer_config_t; 34 | 35 | void print_usage(const char *program_name) { 36 | printf("usage: %s [options]\n\n", program_name); 37 | printf("operations:\n"); 38 | printf(" compress Compress an image file\n"); 39 | printf(" decompress Decompress a compressed file\n\n"); 40 | printf("options:\n"); 41 | printf(" -s, --stages Number of wavelet decomposition stages (default: 4)\n"); 42 | printf(" -f, --filter Filter type: A, B, C, D, E, F, Q (default: A)\n"); 43 | printf(" -g, --segments Number of error containment segments (default: 6)\n"); 44 | printf(" -c, --color Use color mode (YUV)\n"); 45 | printf(" -G, --grayscale Use grayscale mode\n"); 46 | printf("\n"); 47 | printf("compression-only options:\n"); 48 | printf(" -t, --size Target compressed size in bytes (default: lossless)\n"); 49 | printf("\n"); 50 | printf("others:\n"); 51 | printf(" --help Show this help message\n\n"); 52 | printf("You must specify either --color or --grayscale for decompression operations\n"); 53 | printf(" If not using default compression parameters, parameters (stages, filter, segments) must be specified for decompression\n"); 54 | } 55 | 56 | enum icer_filter_types parse_filter_type(const char *filter_str) { 57 | if (strcasecmp(filter_str, "A") == 0) return ICER_FILTER_A; 58 | if (strcasecmp(filter_str, "B") == 0) return ICER_FILTER_B; 59 | if (strcasecmp(filter_str, "C") == 0) return ICER_FILTER_C; 60 | if (strcasecmp(filter_str, "D") == 0) return ICER_FILTER_D; 61 | if (strcasecmp(filter_str, "E") == 0) return ICER_FILTER_E; 62 | if (strcasecmp(filter_str, "F") == 0) return ICER_FILTER_F; 63 | if (strcasecmp(filter_str, "Q") == 0) return ICER_FILTER_Q; 64 | 65 | fprintf(stderr, "Invalid filter type: %s. Using default filter A.\n", filter_str); 66 | return ICER_FILTER_A; 67 | } 68 | 69 | void rgb888_packed_to_yuv(uint16_t *y_channel, uint16_t *u_channel, uint16_t *v_channel, 70 | uint8_t *img, size_t image_w, size_t image_h, size_t rowstride) { 71 | int32_t r, g, b; 72 | uint8_t *pixel; 73 | uint16_t *output_y, *output_u, *output_v; 74 | 75 | for (size_t row = 0; row < image_h; row++) { 76 | pixel = img + 3 * rowstride * row; 77 | output_y = y_channel + rowstride * row; 78 | output_u = u_channel + rowstride * row; 79 | output_v = v_channel + rowstride * row; 80 | 81 | for (size_t col = 0; col < image_w; col++) { 82 | r = pixel[0]; 83 | g = pixel[1]; 84 | b = pixel[2]; 85 | 86 | *output_y = CRGB2Y(r, g, b); 87 | *output_u = CRGB2Cb(r, g, b); 88 | *output_v = CRGB2Cr(r, g, b); 89 | 90 | pixel += 3; 91 | output_y++; output_u++; output_v++; 92 | } 93 | } 94 | } 95 | 96 | void yuv_to_rgb888_packed(uint16_t *y_channel, uint16_t *u_channel, uint16_t *v_channel, 97 | uint8_t *img, size_t image_w, size_t image_h, size_t rowstride) { 98 | int32_t y, u, v; 99 | uint8_t *pixel; 100 | uint16_t *input_y, *input_u, *input_v; 101 | 102 | for (size_t row = 0; row < image_h; row++) { 103 | pixel = img + 3 * rowstride * row; 104 | input_y = y_channel + rowstride * row; 105 | input_u = u_channel + rowstride * row; 106 | input_v = v_channel + rowstride * row; 107 | 108 | for (size_t col = 0; col < image_w; col++) { 109 | y = *input_y; 110 | u = *input_u; 111 | v = *input_v; 112 | 113 | pixel[0] = CYCbCr2R(y, u, v); 114 | pixel[1] = CYCbCr2G(y, u, v); 115 | pixel[2] = CYCbCr2B(y, u, v); 116 | 117 | pixel += 3; 118 | input_y++; input_u++; input_v++; 119 | } 120 | } 121 | } 122 | 123 | int compress_image(icer_config_t *config) { 124 | int src_w, src_h, channels; 125 | uint8_t *data; 126 | clock_t begin, end; 127 | int result = 0; 128 | 129 | int target_channels = 0; 130 | if (config->force_color) { 131 | target_channels = 3; 132 | } else if (config->force_grayscale) { 133 | target_channels = 1; 134 | } 135 | 136 | data = stbi_load(config->input_file, &src_w, &src_h, &channels, target_channels); 137 | if (data == NULL) { 138 | fprintf(stderr, "Error: Could not load image %s\n", config->input_file); 139 | return 1; 140 | } 141 | 142 | printf("Loaded image: %s (%dx%d, %d channels)\n", config->input_file, src_w, src_h, channels); 143 | 144 | int use_color = 0; 145 | if (target_channels == 0 && channels == 3) { 146 | use_color = 1; 147 | } else if (target_channels == 3) { 148 | use_color = 1; 149 | } 150 | 151 | printf("Compression mode: %s\n", use_color ? "Color (YUV)" : "Grayscale"); 152 | 153 | uint16_t *compress[3] = {NULL, NULL, NULL}; 154 | 155 | if (use_color) { 156 | for (int i = 0; i < 3; i++) { 157 | compress[i] = malloc(src_w * src_h * sizeof(uint16_t)); 158 | } 159 | 160 | // Convert RGB to YUV for ICER 161 | rgb888_packed_to_yuv(compress[0], compress[1], compress[2], data, src_w, src_h, src_w); 162 | } else { 163 | compress[0] = malloc(src_w * src_h * sizeof(uint16_t)); 164 | 165 | // convert to uint16 for ICER 166 | for (int i = 0; i < src_w * src_h; i++) { 167 | compress[0][i] = data[i]; 168 | } 169 | } 170 | 171 | // calculate target size 172 | int byte_quote; 173 | if (config->target_size > 0) { 174 | // use specified target size 175 | byte_quote = config->target_size; 176 | } else { 177 | // lossless, set the quota the original image size to be safe 178 | byte_quote = src_w * src_h * (use_color ? 3 : 1); 179 | } 180 | 181 | // alloc output buffer to at least twice the target size 182 | int buffer_size = byte_quote * 2 + 50; 183 | uint8_t *datastream = malloc(buffer_size); 184 | 185 | icer_output_data_buf_typedef output; 186 | icer_init_output_struct(&output, datastream, buffer_size, byte_quote); 187 | 188 | printf("Starting compression...\n"); 189 | printf("Parameters: stages=%d, filter=%d, segments=%d", 190 | config->stages, config->filter, config->segments); 191 | if (config->target_size > 0) { 192 | printf(", target_size=%.2fKB", config->target_size / 1024.0); 193 | } else { 194 | printf(", mode=lossless, quota=%.2fKB", byte_quote / 1024.0); 195 | } 196 | printf("\n"); 197 | 198 | begin = clock(); 199 | int compress_result; 200 | if (use_color) { 201 | compress_result = icer_compress_image_yuv_uint16(compress[0], compress[1], compress[2], 202 | src_w, src_h, config->stages, 203 | config->filter, config->segments, &output); 204 | } else { 205 | compress_result = icer_compress_image_uint16(compress[0], src_w, src_h, config->stages, 206 | config->filter, config->segments, &output); 207 | } 208 | end = clock(); 209 | 210 | if (compress_result != ICER_RESULT_OK && compress_result != ICER_BYTE_QUOTA_EXCEEDED) { 211 | fprintf(stderr, "Error: Compression failed with code %d\n", compress_result); 212 | result = 1; 213 | goto cleanup; 214 | } 215 | 216 | printf("Compression completed in %.3f seconds\n", (double)(end-begin)/CLOCKS_PER_SEC); 217 | printf("Compressed size: %zu bytes (%.1f%% of original)\n", 218 | output.size_used, 100.0 * output.size_used / (src_w * src_h * (use_color ? 3 : 1))); 219 | 220 | FILE *output_file = fopen(config->output_file, "wb"); 221 | if (!output_file) { 222 | fprintf(stderr, "Error: Could not create output file %s\n", config->output_file); 223 | result = 1; 224 | goto cleanup; 225 | } 226 | 227 | size_t written = fwrite(output.rearrange_start, 1, output.size_used, output_file); 228 | fclose(output_file); 229 | 230 | if (written != output.size_used) { 231 | fprintf(stderr, "Error: Failed to write complete output file\n"); 232 | result = 1; 233 | goto cleanup; 234 | } 235 | 236 | printf("Compressed image saved to: %s (%zu bytes)\n", config->output_file, output.size_used); 237 | 238 | cleanup: 239 | if (data) stbi_image_free(data); 240 | if (datastream) free(datastream); 241 | for (int i = 0; i < 3; i++) { 242 | if (compress[i]) free(compress[i]); 243 | } 244 | 245 | return result; 246 | } 247 | 248 | int decompress_image(icer_config_t *config) { 249 | FILE *input_file; 250 | uint8_t *compressed_data = NULL; 251 | size_t compressed_size = 0; 252 | size_t buffer_size = 1024; 253 | clock_t begin, end; 254 | int result = 0; 255 | 256 | if (!config->force_color && !config->force_grayscale) { 257 | fprintf(stderr, "Error: For decompression, you must specify either --color or --grayscale\n"); 258 | return 1; 259 | } 260 | 261 | int use_color = config->force_color; 262 | input_file = fopen(config->input_file, "rb"); 263 | if (!input_file) { 264 | fprintf(stderr, "Error: Could not open input file %s\n", config->input_file); 265 | return 1; 266 | } 267 | 268 | compressed_data = malloc(buffer_size); 269 | while (fread(compressed_data + compressed_size, 1, 1, input_file) == 1) { 270 | compressed_size++; 271 | if (compressed_size >= buffer_size - 1) { 272 | buffer_size += 1024; 273 | compressed_data = realloc(compressed_data, buffer_size); 274 | } 275 | } 276 | fclose(input_file); 277 | 278 | printf("Loaded compressed data: %zu bytes\n", compressed_size); 279 | size_t image_w, image_h; 280 | uint16_t *decompress[3]; 281 | uint8_t *display = NULL; 282 | 283 | int dim_result = icer_get_image_dimensions(compressed_data, compressed_size, &image_w, &image_h); 284 | if (dim_result != ICER_RESULT_OK) { 285 | fprintf(stderr, "Error: Could not determine image dimensions from compressed data\n"); 286 | result = 1; 287 | goto cleanup; 288 | } 289 | 290 | printf("Image dimensions: %zux%zu\n", image_w, image_h); 291 | 292 | // Allocate decompression buffers 293 | for (int i = 0; i < 3; i++) { 294 | decompress[i] = malloc(image_w * image_h * sizeof(uint16_t)); 295 | } 296 | 297 | printf("Starting decompression as %s image...\n", use_color ? "color" : "grayscale"); 298 | printf("Using parameters: stages=%d, filter=%d, segments=%d\n", 299 | config->stages, config->filter, config->segments); 300 | 301 | begin = clock(); 302 | 303 | size_t actual_w, actual_h; 304 | int decompress_result; 305 | 306 | if (use_color) { 307 | // Decompress as color 308 | decompress_result = icer_decompress_image_yuv_uint16(decompress[0], decompress[1], decompress[2], 309 | &actual_w, &actual_h, image_w * image_h, 310 | compressed_data, compressed_size, 311 | config->stages, config->filter, config->segments); 312 | if (decompress_result == ICER_RESULT_OK) { 313 | display = malloc(image_w * image_h * 3); 314 | yuv_to_rgb888_packed(decompress[0], decompress[1], decompress[2], display, actual_w, actual_h, actual_w); 315 | } 316 | } else { 317 | // Decompress as grayscale 318 | decompress_result = icer_decompress_image_uint16(decompress[0], &actual_w, &actual_h, image_w * image_h, 319 | compressed_data, compressed_size, 320 | config->stages, config->filter, config->segments); 321 | if (decompress_result == ICER_RESULT_OK) { 322 | display = malloc(image_w * image_h); 323 | for (size_t i = 0; i < actual_w * actual_h; i++) { 324 | display[i] = (decompress[0][i] > 255) ? 255 : decompress[0][i]; 325 | } 326 | } 327 | } 328 | 329 | end = clock(); 330 | 331 | if (decompress_result != ICER_RESULT_OK) { 332 | fprintf(stderr, "Error: Decompression failed with code %d\n", decompress_result); 333 | fprintf(stderr, "Make sure the compression parameters match those used for compression\n"); 334 | result = 1; 335 | goto cleanup; 336 | } 337 | 338 | printf("Decompression completed in %.3f seconds\n", (double)(end-begin)/CLOCKS_PER_SEC); 339 | printf("Decompressed to %zux%zu %s image\n", actual_w, actual_h, use_color ? "color" : "grayscale"); 340 | 341 | // Save decompressed image 342 | int save_result; 343 | if (use_color) { 344 | save_result = stbi_write_bmp(config->output_file, actual_w, actual_h, 3, display); 345 | } else { 346 | save_result = stbi_write_bmp(config->output_file, actual_w, actual_h, 1, display); 347 | } 348 | 349 | if (!save_result) { 350 | fprintf(stderr, "Error: Failed to save output image %s\n", config->output_file); 351 | result = 1; 352 | goto cleanup; 353 | } 354 | 355 | printf("Decompressed image saved to: %s\n", config->output_file); 356 | 357 | cleanup: 358 | if (compressed_data) free(compressed_data); 359 | if (display) free(display); 360 | for (int i = 0; i < 3; i++) { 361 | if (decompress[i]) free(decompress[i]); 362 | } 363 | 364 | return result; 365 | } 366 | 367 | int main(int argc, char *argv[]) { 368 | icer_config_t config = { 369 | .input_file = NULL, 370 | .output_file = NULL, 371 | .operation = NULL, 372 | .stages = 4, 373 | .filter = ICER_FILTER_A, 374 | .segments = 6, 375 | .target_size = 0, // 0 = lossless (no size limit) 376 | .force_color = 0, 377 | .force_grayscale = 0, 378 | }; 379 | 380 | static struct option long_options[] = { 381 | {"stages", required_argument, 0, 's'}, 382 | {"filter", required_argument, 0, 'f'}, 383 | {"segments", required_argument, 0, 'g'}, 384 | {"size", required_argument, 0, 't'}, 385 | {"color", no_argument, 0, 'c'}, 386 | {"grayscale", no_argument, 0, 'G'}, 387 | {"help", no_argument, 0, 0}, 388 | {0, 0, 0, 0} 389 | }; 390 | 391 | int option_index = 0; 392 | int c; 393 | 394 | while ((c = getopt_long(argc, argv, "s:f:g:t:cG", long_options, &option_index)) != -1) { 395 | switch (c) { 396 | case 's': 397 | config.stages = atoi(optarg); 398 | if (config.stages < 1 || config.stages > 6) { 399 | fprintf(stderr, "Error: Stages must be between 1 and 6\n"); 400 | return 1; 401 | } 402 | break; 403 | case 'f': 404 | config.filter = parse_filter_type(optarg); 405 | break; 406 | case 'g': 407 | config.segments = atoi(optarg); 408 | if (config.segments < 1 || config.segments > 32) { 409 | fprintf(stderr, "Error: Segments must be between 1 and 32\n"); 410 | return 1; 411 | } 412 | break; 413 | case 't': 414 | config.target_size = atoi(optarg); 415 | if (config.target_size < 0) { 416 | fprintf(stderr, "Error: Target size must be non-negative (0 = lossless)\n"); 417 | return 1; 418 | } 419 | break; 420 | case 'c': 421 | config.force_color = 1; 422 | break; 423 | case 'G': 424 | config.force_grayscale = 1; 425 | break; 426 | case 0: 427 | if (strcmp(long_options[option_index].name, "help") == 0) { 428 | print_usage(argv[0]); 429 | return 0; 430 | } 431 | break; 432 | case '?': 433 | return 1; 434 | default: 435 | print_usage(argv[0]); 436 | return 1; 437 | } 438 | } 439 | 440 | if (config.force_color && config.force_grayscale) { 441 | fprintf(stderr, "Error: Cannot specify both --color and --grayscale\n"); 442 | return 1; 443 | } 444 | 445 | if (optind + 2 >= argc) { 446 | fprintf(stderr, "Error: Missing required arguments\n"); 447 | print_usage(argv[0]); 448 | return 1; 449 | } 450 | 451 | config.operation = argv[optind]; 452 | config.input_file = argv[optind + 1]; 453 | config.output_file = argv[optind + 2]; 454 | 455 | if (!config.force_color && !config.force_grayscale && strcmp(config.operation, "decompress") == 0) { 456 | fprintf(stderr, "Error: You must specify either --color or --grayscale for decompression\n"); 457 | return 1; 458 | } 459 | 460 | if (strcmp(config.operation, "compress") != 0 && strcmp(config.operation, "decompress") != 0) { 461 | fprintf(stderr, "Error: Operation must be 'compress' or 'decompress'\n"); 462 | return 1; 463 | } 464 | 465 | // init ICER library 466 | int init_result = icer_init(); 467 | if (init_result != ICER_RESULT_OK) { 468 | fprintf(stderr, "Error: Failed to initialize ICER library\n"); 469 | return 1; 470 | } 471 | 472 | if (strcmp(config.operation, "compress") == 0) { 473 | return compress_image(&config); 474 | } else { 475 | return decompress_image(&config); 476 | } 477 | } -------------------------------------------------------------------------------- /lib_icer/src/icer_partition.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by linyi on 19/3/2023. 3 | // 4 | 5 | #include "icer.h" 6 | 7 | int icer_generate_partition_parameters(partition_param_typdef *params, size_t ll_w, size_t ll_h, uint16_t segments) { 8 | uint16_t r, c, r_t, h_t, x_t, c_t0, y_t, r_t0; 9 | uint16_t x_b = 0, c_b0 = 0, y_b = 0, r_b0 = 0; 10 | 11 | if (segments > (ll_w * ll_h) || segments > ICER_MAX_SEGMENTS) { 12 | return ICER_TOO_MANY_SEGMENTS; 13 | } 14 | 15 | if (ll_h > (segments - 1) * ll_w) { 16 | r = segments; 17 | } else { 18 | for (r = 1; r < segments && (r + 1) * r * ll_w < ll_h * segments; r++); 19 | } 20 | c = segments / r; 21 | r_t = (c + 1) * r - segments; 22 | h_t = icer_max_uint(r_t, ((2 * ll_h * c * r_t + segments) / 2) / segments); 23 | x_t = ll_w / c; 24 | c_t0 = (x_t + 1) * c - ll_w; 25 | y_t = h_t / r_t; 26 | r_t0 = (y_t + 1) * r_t - h_t; 27 | 28 | if (r_t < r) { 29 | x_b = ll_w / (c + 1); 30 | c_b0 = (x_b + 1) * (c + 1) - ll_w; 31 | y_b = (ll_h - h_t) / (r - r_t); 32 | r_b0 = (y_b + 1) * (r - r_t) - (ll_h - h_t); 33 | } 34 | 35 | params->w = ll_w; 36 | params->h = ll_h; 37 | params->s = segments; 38 | 39 | params->r = r; 40 | params->c = c; 41 | params->r_t = r_t; 42 | params->h_t = h_t; 43 | params->x_t = x_t; 44 | params->c_t0 = c_t0; 45 | params->y_t = y_t; 46 | params->r_t0 = r_t0; 47 | 48 | params->x_b = x_b; 49 | params->c_b0 = c_b0; 50 | params->y_b = y_b; 51 | params->r_b0 = r_b0; 52 | 53 | return ICER_RESULT_OK; 54 | } 55 | 56 | #ifdef USE_UINT8_FUNCTIONS 57 | 58 | #ifdef USE_ENCODE_FUNCTIONS 59 | int icer_compress_partition_uint8(const uint8_t *data, partition_param_typdef *params, size_t rowstride, icer_packet_context *pkt_context, 60 | icer_output_data_buf_typedef * const output_data, const icer_image_segment_typedef *segments_encoded[]) { 61 | int res; 62 | size_t segment_w, segment_h; 63 | const uint8_t *segment_start; 64 | uint16_t segment_num = 0; 65 | 66 | size_t partition_col_ind; 67 | size_t partition_row_ind = 0; 68 | 69 | icer_context_model_typedef context_model; 70 | icer_encoder_context_typedef context; 71 | icer_image_segment_typedef *seg; 72 | 73 | uint32_t data_in_bytes; 74 | /* 75 | * process top region which consists of c columns 76 | * height of top region is h_t and it contains r_t rows 77 | */ 78 | for (uint16_t row = 0; row < params->r_t; row++) { 79 | /* 80 | * the first r_t0 rows have height y_t 81 | * the remainder have height y_t + 1 82 | */ 83 | segment_h = params->y_t + ((row >= params->r_t0) ? 1 : 0); 84 | partition_col_ind = 0; 85 | 86 | for (uint16_t col = 0; col < params->c; col++) { 87 | /* the first c_t0 columns have width x_t 88 | * the remainder have width x_t + 1 89 | */ 90 | segment_w = params->x_t + ((col >= params->c_t0) ? 1 : 0); 91 | segment_start = data + partition_row_ind * rowstride + partition_col_ind; 92 | partition_col_ind += segment_w; 93 | 94 | icer_init_context_model_vals(&context_model, pkt_context->subband_type); 95 | res = icer_allocate_data_packet(&seg, output_data, segment_num, pkt_context); 96 | if (res != ICER_RESULT_OK) return res; 97 | 98 | icer_init_entropy_coder_context(&context, icer_encode_circ_buf, ICER_CIRC_BUF_SIZE, 99 | (uint8_t *) seg + sizeof(icer_image_segment_typedef), seg->data_length); 100 | res = icer_compress_bitplane_uint8(segment_start, segment_w, segment_h, rowstride, &context_model, &context, 101 | pkt_context); 102 | if (res != ICER_RESULT_OK) { 103 | output_data->size_used -= sizeof(icer_image_segment_typedef); 104 | return res; 105 | } 106 | 107 | data_in_bytes = context.output_ind + (context.output_bit_offset > 0); 108 | seg->data_length = context.output_ind * 8 + context.output_bit_offset; 109 | seg->data_crc32 = icer_calculate_segment_crc32(seg); 110 | seg->crc32 = icer_calculate_packet_crc32(seg); 111 | output_data->size_used += data_in_bytes; 112 | 113 | segments_encoded[segment_num] = seg; 114 | 115 | segment_num++; 116 | } 117 | partition_row_ind += segment_h; 118 | } 119 | 120 | /* 121 | * if the bottom region exists, process bottom region 122 | * which consists of c+1 columns 123 | */ 124 | for (uint16_t row = 0; row < (params->r - params->r_t); row++) { 125 | /* 126 | * the first r_b0 rows have height y_b 127 | * the remainder have height y_b + 1 128 | */ 129 | segment_h = params->y_b + ((row >= params->r_b0) ? 1 : 0); 130 | partition_col_ind = 0; 131 | 132 | for (uint16_t col = 0; col < (params->c + 1); col++) { 133 | /* the first c_b0 columns have width x_b 134 | * the remainder have width x_b + 1 135 | */ 136 | segment_w = params->x_b + ((col >= params->c_b0) ? 1 : 0); 137 | segment_start = data + partition_row_ind * rowstride + partition_col_ind; 138 | partition_col_ind += segment_w; 139 | 140 | icer_init_context_model_vals(&context_model, pkt_context->subband_type); 141 | res = icer_allocate_data_packet(&seg, output_data, segment_num, pkt_context); 142 | if (res != ICER_RESULT_OK) return res; 143 | 144 | icer_init_entropy_coder_context(&context, icer_encode_circ_buf, ICER_CIRC_BUF_SIZE, 145 | (uint8_t *) seg + sizeof(icer_image_segment_typedef), seg->data_length); 146 | res = icer_compress_bitplane_uint8(segment_start, segment_w, segment_h, rowstride, &context_model, &context, 147 | pkt_context); 148 | if (res != ICER_RESULT_OK) { 149 | output_data->size_used -= sizeof(icer_image_segment_typedef); 150 | return res; 151 | } 152 | 153 | data_in_bytes = context.output_ind + (context.output_bit_offset > 0); 154 | seg->data_length = context.output_ind * 8 + context.output_bit_offset; 155 | seg->data_crc32 = icer_calculate_segment_crc32(seg); 156 | seg->crc32 = icer_calculate_packet_crc32(seg); 157 | output_data->size_used += data_in_bytes; 158 | 159 | segments_encoded[segment_num] = seg; 160 | 161 | segment_num++; 162 | } 163 | partition_row_ind += segment_h; 164 | } 165 | 166 | return ICER_RESULT_OK; 167 | } 168 | #endif 169 | 170 | #ifdef USE_DECODE_FUNCTIONS 171 | int icer_decompress_partition_uint8(uint8_t * const data, const partition_param_typdef *params, size_t rowstride, 172 | const icer_image_segment_typedef *seg[][7]) { 173 | int res; 174 | size_t segment_w, segment_h; 175 | uint8_t *segment_start; 176 | uint16_t segment_num = 0; 177 | 178 | size_t partition_col_ind; 179 | size_t partition_row_ind = 0; 180 | 181 | icer_context_model_typedef context_model; 182 | icer_decoder_context_typedef context; 183 | icer_packet_context pkt_context; 184 | int lsb; 185 | /* 186 | * process top region which consists of c columns 187 | * height of top region is h_t and it contains r_t rows 188 | */ 189 | for (uint16_t row = 0; row < params->r_t; row++) { 190 | /* 191 | * the first r_t0 rows have height y_t 192 | * the remainder have height y_t + 1 193 | */ 194 | segment_h = params->y_t + ((row >= params->r_t0) ? 1 : 0); 195 | partition_col_ind = 0; 196 | 197 | for (uint16_t col = 0; col < params->c; col++) { 198 | /* the first c_t0 columns have width x_t 199 | * the remainder have width x_t + 1 200 | */ 201 | segment_w = params->x_t + ((col >= params->c_t0) ? 1 : 0); 202 | segment_start = data + partition_row_ind * rowstride + partition_col_ind; 203 | partition_col_ind += segment_w; 204 | 205 | lsb = ICER_BITPLANES_TO_COMPRESS_8 - 1; 206 | /* decompress starting from the msb, and stop whenever there is a missing bitplane */ 207 | /* it is impossible to decompress subsequent bit planes if there is a missing bit plane, due to how the context 208 | * modeller works; it relies on the previously decoded bbitplanes to determine a bit's context */ 209 | while (seg[segment_num][lsb] != NULL && lsb >= 0) { 210 | pkt_context.subband_type = seg[segment_num][ICER_BITPLANES_TO_COMPRESS_8 - 1]->subband_type; 211 | pkt_context.lsb = lsb; 212 | pkt_context.decomp_level = seg[segment_num][ICER_BITPLANES_TO_COMPRESS_8 - 1]->decomp_level; 213 | icer_init_context_model_vals(&context_model, pkt_context.subband_type); 214 | icer_init_entropy_decoder_context(&context, (uint8_t *) seg[segment_num][lsb] + 215 | sizeof(icer_image_segment_typedef), 216 | seg[segment_num][lsb]->data_length); 217 | res = icer_decompress_bitplane_uint8(segment_start, segment_w, segment_h, rowstride, &context_model, &context, 218 | &pkt_context); 219 | if (res != ICER_RESULT_OK) break; 220 | lsb--; 221 | } 222 | 223 | segment_num++; 224 | } 225 | partition_row_ind += segment_h; 226 | } 227 | 228 | /* 229 | * if the bottom region exists, process bottom region 230 | * which consists of c+1 columns 231 | */ 232 | for (uint16_t row = 0; row < (params->r - params->r_t); row++) { 233 | /* 234 | * the first r_b0 rows have height y_b 235 | * the remainder have height y_b + 1 236 | */ 237 | segment_h = params->y_b + ((row >= params->r_b0) ? 1 : 0); 238 | partition_col_ind = 0; 239 | 240 | for (uint16_t col = 0; col < (params->c + 1); col++) { 241 | /* the first c_b0 columns have width x_b 242 | * the remainder have width x_b + 1 243 | */ 244 | segment_w = params->x_b + ((col >= params->c_b0) ? 1 : 0); 245 | segment_start = data + partition_row_ind * rowstride + partition_col_ind; 246 | partition_col_ind += segment_w; 247 | 248 | lsb = ICER_BITPLANES_TO_COMPRESS_8 - 1; 249 | /* decompress starting from the msb, and stop whenever there is a missing bitplane */ 250 | /* it is impossible to decompress subsequent bit planes if there is a missing bit plane, due to how the context 251 | * modeller works; it relies on the previously decoded bbitplanes to determine a bit's context */ 252 | while (seg[segment_num][lsb] != NULL && lsb >= 0) { 253 | pkt_context.subband_type = seg[segment_num][ICER_BITPLANES_TO_COMPRESS_8 - 1]->subband_type; 254 | pkt_context.lsb = lsb; 255 | pkt_context.decomp_level = seg[segment_num][ICER_BITPLANES_TO_COMPRESS_8 - 1]->decomp_level; 256 | icer_init_context_model_vals(&context_model, pkt_context.subband_type); 257 | icer_init_entropy_decoder_context(&context, (uint8_t *) seg[segment_num][lsb] + 258 | sizeof(icer_image_segment_typedef), 259 | seg[segment_num][lsb]->data_length); 260 | res = icer_decompress_bitplane_uint8(segment_start, segment_w, segment_h, rowstride, &context_model, &context, 261 | &pkt_context); 262 | if (res != ICER_RESULT_OK) break; 263 | lsb--; 264 | } 265 | 266 | segment_num++; 267 | } 268 | partition_row_ind += segment_h; 269 | } 270 | 271 | return ICER_RESULT_OK; 272 | } 273 | #endif 274 | #endif 275 | 276 | #ifdef USE_UINT16_FUNCTIONS 277 | 278 | #ifdef USE_ENCODE_FUNCTIONS 279 | int icer_compress_partition_uint16(const uint16_t *data, const partition_param_typdef *params, size_t rowstride, 280 | const icer_packet_context *pkt_context, icer_output_data_buf_typedef *output_data, 281 | const icer_image_segment_typedef *segments_encoded[]) { 282 | int res; 283 | size_t segment_w, segment_h; 284 | const uint16_t *segment_start; 285 | uint16_t segment_num = 0; 286 | 287 | size_t partition_col_ind; 288 | size_t partition_row_ind = 0; 289 | 290 | icer_context_model_typedef context_model; 291 | icer_encoder_context_typedef context; 292 | icer_image_segment_typedef *seg; 293 | 294 | uint32_t data_in_bytes; 295 | /* 296 | * process top region which consists of c columns 297 | * height of top region is h_t and it contains r_t rows 298 | */ 299 | for (uint16_t row = 0; row < params->r_t; row++) { 300 | /* 301 | * the first r_t0 rows have height y_t 302 | * the remainder have height y_t + 1 303 | */ 304 | segment_h = params->y_t + ((row >= params->r_t0) ? 1 : 0); 305 | partition_col_ind = 0; 306 | 307 | for (uint16_t col = 0; col < params->c; col++) { 308 | /* the first c_t0 columns have width x_t 309 | * the remainder have width x_t + 1 310 | */ 311 | segment_w = params->x_t + ((col >= params->c_t0) ? 1 : 0); 312 | segment_start = data + partition_row_ind * rowstride + partition_col_ind; 313 | partition_col_ind += segment_w; 314 | 315 | icer_init_context_model_vals(&context_model, pkt_context->subband_type); 316 | res = icer_allocate_data_packet(&seg, output_data, segment_num, pkt_context); 317 | if (res != ICER_RESULT_OK) return res; 318 | 319 | icer_init_entropy_coder_context(&context, icer_encode_circ_buf, ICER_CIRC_BUF_SIZE, 320 | (uint8_t *) seg + sizeof(icer_image_segment_typedef), seg->data_length); 321 | res = icer_compress_bitplane_uint16(segment_start, segment_w, segment_h, rowstride, &context_model, &context, 322 | pkt_context); 323 | if (res != ICER_RESULT_OK) { 324 | output_data->size_used -= sizeof(icer_image_segment_typedef); 325 | return res; 326 | } 327 | 328 | data_in_bytes = context.output_ind + (context.output_bit_offset > 0); 329 | seg->data_length = context.output_ind * 8 + context.output_bit_offset; 330 | seg->data_crc32 = icer_calculate_segment_crc32(seg); 331 | seg->crc32 = icer_calculate_packet_crc32(seg); 332 | output_data->size_used += data_in_bytes; 333 | 334 | segments_encoded[segment_num] = seg; 335 | 336 | segment_num++; 337 | } 338 | partition_row_ind += segment_h; 339 | } 340 | 341 | /* 342 | * if the bottom region exists, process bottom region 343 | * which consists of c+1 columns 344 | */ 345 | for (uint16_t row = 0; row < (params->r - params->r_t); row++) { 346 | /* 347 | * the first r_b0 rows have height y_b 348 | * the remainder have height y_b + 1 349 | */ 350 | segment_h = params->y_b + ((row >= params->r_b0) ? 1 : 0); 351 | partition_col_ind = 0; 352 | 353 | for (uint16_t col = 0; col < (params->c + 1); col++) { 354 | /* the first c_b0 columns have width x_b 355 | * the remainder have width x_b + 1 356 | */ 357 | segment_w = params->x_b + ((col >= params->c_b0) ? 1 : 0); 358 | segment_start = data + partition_row_ind * rowstride + partition_col_ind; 359 | partition_col_ind += segment_w; 360 | 361 | icer_init_context_model_vals(&context_model, pkt_context->subband_type); 362 | res = icer_allocate_data_packet(&seg, output_data, segment_num, pkt_context); 363 | if (res != ICER_RESULT_OK) return res; 364 | 365 | icer_init_entropy_coder_context(&context, icer_encode_circ_buf, ICER_CIRC_BUF_SIZE, 366 | (uint8_t *) seg + sizeof(icer_image_segment_typedef), seg->data_length); 367 | res = icer_compress_bitplane_uint16(segment_start, segment_w, segment_h, rowstride, &context_model, &context, 368 | pkt_context); 369 | if (res != ICER_RESULT_OK) { 370 | output_data->size_used -= sizeof(icer_image_segment_typedef); 371 | return res; 372 | } 373 | 374 | data_in_bytes = context.output_ind + (context.output_bit_offset > 0); 375 | seg->data_length = context.output_ind * 8 + context.output_bit_offset; 376 | seg->data_crc32 = icer_calculate_segment_crc32(seg); 377 | seg->crc32 = icer_calculate_packet_crc32(seg); 378 | output_data->size_used += data_in_bytes; 379 | 380 | segments_encoded[segment_num] = seg; 381 | 382 | segment_num++; 383 | } 384 | partition_row_ind += segment_h; 385 | } 386 | 387 | return ICER_RESULT_OK; 388 | } 389 | #endif 390 | 391 | 392 | #ifdef USE_DECODE_FUNCTIONS 393 | int icer_decompress_partition_uint16(uint16_t * const data, const partition_param_typdef * params, size_t rowstride, 394 | const icer_image_segment_typedef *seg[][15]) { 395 | int res; 396 | size_t segment_w, segment_h; 397 | uint16_t *segment_start; 398 | uint16_t segment_num = 0; 399 | 400 | size_t partition_col_ind; 401 | size_t partition_row_ind = 0; 402 | 403 | icer_context_model_typedef context_model; 404 | icer_decoder_context_typedef context; 405 | icer_packet_context pkt_context; 406 | int lsb; 407 | /* 408 | * process top region which consists of c columns 409 | * height of top region is h_t and it contains r_t rows 410 | */ 411 | for (uint16_t row = 0; row < params->r_t; row++) { 412 | /* 413 | * the first r_t0 rows have height y_t 414 | * the remainder have height y_t + 1 415 | */ 416 | segment_h = params->y_t + ((row >= params->r_t0) ? 1 : 0); 417 | partition_col_ind = 0; 418 | 419 | for (uint16_t col = 0; col < params->c; col++) { 420 | /* the first c_t0 columns have width x_t 421 | * the remainder have width x_t + 1 422 | */ 423 | segment_w = params->x_t + ((col >= params->c_t0) ? 1 : 0); 424 | segment_start = data + partition_row_ind * rowstride + partition_col_ind; 425 | partition_col_ind += segment_w; 426 | 427 | lsb = ICER_BITPLANES_TO_COMPRESS_16 - 1; 428 | /* decompress starting from the msb, and stop whenever there is a missing bitplane */ 429 | /* it is impossible to decompress subsequent bit planes if there is a missing bit plane, due to how the context 430 | * modeller works; it relies on the previously decoded bbitplanes to determine a bit's context */ 431 | while (seg[segment_num][lsb] != NULL && lsb >= 0) { 432 | pkt_context.subband_type = seg[segment_num][ICER_BITPLANES_TO_COMPRESS_16 - 1]->subband_type; 433 | pkt_context.lsb = lsb; 434 | pkt_context.decomp_level = seg[segment_num][ICER_BITPLANES_TO_COMPRESS_16 - 1]->decomp_level; 435 | icer_init_context_model_vals(&context_model, pkt_context.subband_type); 436 | icer_init_entropy_decoder_context(&context, (uint8_t *) seg[segment_num][lsb] + 437 | sizeof(icer_image_segment_typedef), 438 | seg[segment_num][lsb]->data_length); 439 | res = icer_decompress_bitplane_uint16(segment_start, segment_w, segment_h, rowstride, &context_model, &context, 440 | &pkt_context); 441 | if (res != ICER_RESULT_OK) break; 442 | lsb--; 443 | } 444 | 445 | segment_num++; 446 | } 447 | partition_row_ind += segment_h; 448 | } 449 | 450 | /* 451 | * if the bottom region exists, process bottom region 452 | * which consists of c+1 columns 453 | */ 454 | for (uint16_t row = 0; row < (params->r - params->r_t); row++) { 455 | /* 456 | * the first r_b0 rows have height y_b 457 | * the remainder have height y_b + 1 458 | */ 459 | segment_h = params->y_b + ((row >= params->r_b0) ? 1 : 0); 460 | partition_col_ind = 0; 461 | 462 | for (uint16_t col = 0; col < (params->c + 1); col++) { 463 | /* the first c_b0 columns have width x_b 464 | * the remainder have width x_b + 1 465 | */ 466 | segment_w = params->x_b + ((col >= params->c_b0) ? 1 : 0); 467 | segment_start = data + partition_row_ind * rowstride + partition_col_ind; 468 | partition_col_ind += segment_w; 469 | 470 | lsb = ICER_BITPLANES_TO_COMPRESS_16 - 1; 471 | /* decompress starting from the msb, and stop whenever there is a missing bitplane */ 472 | /* it is impossible to decompress subsequent bit planes if there is a missing bit plane, due to how the context 473 | * modeller works; it relies on the previously decoded bbitplanes to determine a bit's context */ 474 | while (seg[segment_num][lsb] != NULL && lsb >= 0) { 475 | pkt_context.subband_type = seg[segment_num][ICER_BITPLANES_TO_COMPRESS_16 - 1]->subband_type; 476 | pkt_context.lsb = lsb; 477 | pkt_context.decomp_level = seg[segment_num][ICER_BITPLANES_TO_COMPRESS_16 - 1]->decomp_level; 478 | icer_init_context_model_vals(&context_model, pkt_context.subband_type); 479 | icer_init_entropy_decoder_context(&context, (uint8_t *) seg[segment_num][lsb] + 480 | sizeof(icer_image_segment_typedef), 481 | seg[segment_num][lsb]->data_length); 482 | res = icer_decompress_bitplane_uint16(segment_start, segment_w, segment_h, rowstride, &context_model, &context, 483 | &pkt_context); 484 | if (res != ICER_RESULT_OK) break; 485 | lsb--; 486 | } 487 | 488 | segment_num++; 489 | } 490 | partition_row_ind += segment_h; 491 | } 492 | 493 | return ICER_RESULT_OK; 494 | } 495 | #endif 496 | #endif 497 | 498 | -------------------------------------------------------------------------------- /lib_icer/inc/icer.h: -------------------------------------------------------------------------------- 1 | #ifndef ICER_COMPRESSION_ICER_H 2 | #define ICER_COMPRESSION_ICER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef _MSC_VER 10 | #include 11 | 12 | #define __builtin_popcount __popcnt 13 | #define __builtin_clz __clz 14 | 15 | uint32_t __inline __clz( uint32_t value ) { 16 | uint32_t leading_zero = 0; 17 | 18 | if ( _BitScanReverse( &leading_zero, value ) ) { 19 | return 31 - leading_zero; 20 | } else { 21 | // Same remarks as above 22 | return 32; 23 | } 24 | } 25 | #endif 26 | 27 | #define ICER_CIRC_BUF_SIZE 2048 28 | #define MAX_K 12 29 | #ifndef ICER_MAX_SEGMENTS 30 | #define ICER_MAX_SEGMENTS 32 31 | #endif 32 | #ifndef ICER_MAX_DECOMP_STAGES 33 | #define ICER_MAX_DECOMP_STAGES 6 34 | #endif 35 | #ifndef ICER_MAX_PACKETS 36 | #define ICER_MAX_PACKETS 300 37 | #endif 38 | #ifndef ICER_MAX_PACKETS_16 39 | #define ICER_MAX_PACKETS_16 800 40 | #endif 41 | #ifndef ICER_BITPLANES_TO_COMPRESS_8 42 | #define ICER_BITPLANES_TO_COMPRESS_8 7 43 | #endif 44 | #ifndef ICER_BITPLANES_TO_COMPRESS_16 45 | #define ICER_BITPLANES_TO_COMPRESS_16 9 46 | #endif 47 | 48 | //#define USER_PROVIDED_BUFFERS 49 | /* 50 | * if the user decides to specify explicitly where to place the buffers used during encoding and 51 | * decoding, the user should define the above line and allocate memory for the buffers listed below 52 | * 53 | * for encoding uint8 54 | * icer_packet_context icer_packets[ICER_MAX_PACKETS]; 55 | * icer_image_segment_typedef *icer_rearrange_segments_8[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][7][ICER_MAX_SEGMENTS + 1]; 56 | * 57 | * for decoding uint8 58 | * icer_image_segment_typedef *icer_reconstruct_data_8[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][ICER_MAX_SEGMENTS + 1][7]; 59 | * 60 | * for encoding uint16 61 | * icer_packet_context icer_packets_16[ICER_MAX_PACKETS_16]; 62 | * icer_image_segment_typedef *icer_rearrange_segments_16[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][15][ICER_MAX_SEGMENTS + 1]; 63 | * 64 | * for decoding uint16 65 | * icer_image_segment_typedef *icer_reconstruct_data_16[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][ICER_MAX_SEGMENTS + 1][15]; 66 | * 67 | * common to all encoding 68 | * uint16_t icer_encode_circ_buf[ICER_CIRC_BUF_SIZE]; 69 | */ 70 | 71 | //#define CRC32BUF_FUNCTION(x, y) xxx 72 | /* 73 | * 74 | * if the user decides to use a custom provided crc32 implementation (perhaps in hardware) the 75 | * user should define the above line with the function as specified below 76 | * 77 | * uint32_t crc32buf(char *buf, size_t len) 78 | * 79 | * override function with a custom defined function 80 | */ 81 | 82 | #if !defined(USE_UINT8_FUNCTIONS) && !defined(USE_UINT16_FUNCTIONS) 83 | #define USE_UINT8_FUNCTIONS 84 | #define USE_UINT16_FUNCTIONS 85 | #endif 86 | 87 | #if !defined(USE_DECODE_FUNCTIONS) && !defined(USE_ENCODE_FUNCTIONS) 88 | #define USE_DECODE_FUNCTIONS 89 | #define USE_ENCODE_FUNCTIONS 90 | #endif 91 | 92 | enum icer_status { 93 | ICER_RESULT_OK = 0, 94 | ICER_INTEGER_OVERFLOW = -1, 95 | ICER_OUTPUT_BUF_TOO_SMALL = -2, 96 | ICER_TOO_MANY_SEGMENTS = -3, 97 | ICER_TOO_MANY_STAGES = -4, 98 | ICER_BYTE_QUOTA_EXCEEDED = -5, 99 | ICER_BITPLANE_OUT_OF_RANGE = -6, 100 | ICER_DECODER_OUT_OF_DATA = -7, 101 | ICER_DECODED_INVALID_DATA = -8, 102 | ICER_PACKET_COUNT_EXCEEDED = -9, 103 | ICER_FATAL_ERROR = -10, 104 | ICER_INVALID_INPUT = -11, 105 | }; 106 | 107 | enum icer_filter_types { 108 | ICER_FILTER_A = 0, 109 | ICER_FILTER_B, 110 | ICER_FILTER_C, 111 | ICER_FILTER_D, 112 | ICER_FILTER_E, 113 | ICER_FILTER_F, 114 | ICER_FILTER_Q 115 | }; 116 | 117 | enum icer_filter_params { 118 | ICER_FILTER_COEF_ALPHA_N1 = 0, 119 | ICER_FILTER_COEF_ALPHA_0, 120 | ICER_FILTER_COEF_ALPHA_1, 121 | ICER_FILTER_COEF_BETA 122 | }; 123 | 124 | #define ICER_FILTER_DENOMINATOR 16 125 | 126 | typedef struct { 127 | uint16_t w; 128 | uint16_t h; 129 | uint16_t r; 130 | uint16_t c; 131 | uint16_t r_t; 132 | uint16_t h_t; 133 | uint16_t x_t; 134 | uint16_t c_t0; 135 | uint16_t y_t; 136 | uint16_t r_t0; 137 | uint16_t x_b; 138 | uint16_t c_b0; 139 | uint16_t y_b; 140 | uint16_t r_b0; 141 | uint16_t s; 142 | } partition_param_typdef; 143 | 144 | extern const int16_t icer_wavelet_filter_parameters[][4]; 145 | 146 | #define ICER_CONTEXT_MAX 16 147 | #define ICER_DEFAULT_CONTEXT_ZERO_COUNT 2 148 | #define ICER_DEFAULT_CONTEXT_TOTAL_COUNT 4 149 | #define ICER_CONTEXT_RESCALING_CAP 500 150 | 151 | enum icer_pixel_contexts { 152 | ICER_CONTEXT_0 = 0, 153 | ICER_CONTEXT_1, 154 | ICER_CONTEXT_2, 155 | ICER_CONTEXT_3, 156 | ICER_CONTEXT_4, 157 | ICER_CONTEXT_5, 158 | ICER_CONTEXT_6, 159 | ICER_CONTEXT_7, 160 | ICER_CONTEXT_8, 161 | ICER_CONTEXT_9, 162 | ICER_CONTEXT_10, 163 | ICER_CONTEXT_11, 164 | ICER_CONTEXT_12, 165 | ICER_CONTEXT_13, 166 | ICER_CONTEXT_14, 167 | ICER_CONTEXT_15, 168 | ICER_CONTEXT_16 = ICER_CONTEXT_MAX, 169 | }; 170 | 171 | extern const uint8_t icer_context_table_ll_lh_hl[3][3][5]; 172 | 173 | extern const uint8_t icer_context_table_hh[5][5]; 174 | 175 | extern const uint8_t icer_sign_context_table[5][5]; 176 | 177 | /* 1 is negative, 0 is positive */ 178 | extern const uint8_t icer_sign_prediction_table[5][5]; 179 | 180 | enum icer_pixel_categories { 181 | ICER_CATEGORY_0 = 0, 182 | ICER_CATEGORY_1, 183 | ICER_CATEGORY_2, 184 | ICER_CATEGORY_3 = 3 185 | }; 186 | 187 | #define ICER_SUBBAND_MAX 3 188 | enum icer_subband_types { 189 | ICER_SUBBAND_LL = 0, 190 | ICER_SUBBAND_HL, 191 | ICER_SUBBAND_LH, 192 | ICER_SUBBAND_HH = ICER_SUBBAND_MAX 193 | }; 194 | 195 | typedef struct { 196 | enum icer_subband_types subband_type; 197 | uint32_t zero_count[ICER_CONTEXT_MAX + 1]; 198 | uint32_t total_count[ICER_CONTEXT_MAX + 1]; 199 | } icer_context_model_typedef; 200 | 201 | #define ICER_ENCODER_BIN_MAX 16 202 | 203 | enum icer_encoder_bins { 204 | ICER_ENC_BIN_1 = 0, 205 | ICER_ENC_BIN_2, 206 | ICER_ENC_BIN_3, 207 | ICER_ENC_BIN_4, 208 | ICER_ENC_BIN_5, 209 | ICER_ENC_BIN_6, 210 | ICER_ENC_BIN_7, 211 | ICER_ENC_BIN_8, 212 | ICER_ENC_BIN_9, 213 | ICER_ENC_BIN_10, 214 | ICER_ENC_BIN_11, 215 | ICER_ENC_BIN_12, 216 | ICER_ENC_BIN_13, 217 | ICER_ENC_BIN_14, 218 | ICER_ENC_BIN_15, 219 | ICER_ENC_BIN_16, 220 | ICER_ENC_BIN_17 = ICER_ENCODER_BIN_MAX 221 | }; 222 | 223 | #define ICER_ENC_BUF_BITS_OFFSET 11 224 | #define ICER_ENC_BUF_SHIFTOUT_OFFSET 6 225 | #define ICER_ENC_BUF_DONE_MASK 0b0000010000000000 226 | #define ICER_ENC_BUF_DATA_MASK 0b0000001111111111 227 | #define ICER_ENC_BUF_INFO_MASK 0b1111100000000000 228 | 229 | extern const uint32_t icer_bin_probability_cutoffs[ICER_ENCODER_BIN_MAX+1]; 230 | 231 | #define ICER_BIN_PROBABILITY_DENOMINATOR 65536 232 | 233 | extern const int32_t icer_bin_coding_scheme[ICER_ENCODER_BIN_MAX+1]; 234 | 235 | typedef struct { 236 | uint8_t input_code_bits; 237 | uint8_t output_code_bits; 238 | uint8_t output_code; 239 | } icer_custom_code_typedef; 240 | 241 | typedef struct { 242 | uint8_t flush_bit; 243 | uint8_t flush_bit_numbers; 244 | } icer_custom_flush_typedef; 245 | 246 | #define CUSTOM_CODING_MAX_LOOKUP 32 247 | #ifdef USE_ENCODE_FUNCTIONS 248 | extern icer_custom_code_typedef icer_custom_coding_scheme[ICER_ENCODER_BIN_MAX + 1][CUSTOM_CODING_MAX_LOOKUP]; 249 | #endif 250 | 251 | #ifdef USE_DECODE_FUNCTIONS 252 | extern icer_custom_code_typedef icer_custom_decode_scheme[ICER_ENCODER_BIN_MAX + 1][CUSTOM_CODING_MAX_LOOKUP]; 253 | #endif 254 | 255 | #define CUSTOM_CODE_FLUSH_MAX_LOOKUP 8 256 | #define MAX_NUM_BITS_BEFORE_FLUSH 5 257 | extern icer_custom_flush_typedef icer_custom_code_flush_bits[ICER_ENCODER_BIN_MAX + 1][CUSTOM_CODE_FLUSH_MAX_LOOKUP + 1][MAX_NUM_BITS_BEFORE_FLUSH + 1]; 258 | 259 | typedef struct { 260 | uint16_t m; 261 | uint16_t l; 262 | uint16_t i; 263 | } icer_golomb_code_typedef; 264 | 265 | extern icer_golomb_code_typedef icer_golomb_coders[ICER_ENCODER_BIN_MAX + 1]; 266 | 267 | typedef struct { 268 | uint8_t decomp_level; 269 | uint8_t subband_type; 270 | uint8_t ll_mean_val; 271 | uint8_t lsb; 272 | uint64_t priority; 273 | size_t image_w; 274 | size_t image_h; 275 | uint8_t channel; 276 | } icer_packet_context; 277 | 278 | #ifdef USE_UINT8_FUNCTIONS 279 | extern icer_packet_context icer_packets[ICER_MAX_PACKETS]; 280 | #endif 281 | 282 | #ifdef USE_UINT16_FUNCTIONS 283 | extern icer_packet_context icer_packets_16[ICER_MAX_PACKETS_16]; 284 | #endif 285 | 286 | #define ICER_PACKET_PREAMBLE 0x605B 287 | #define ICER_SEGMENT_LSB_MASK 0x0f 288 | #define ICER_SEGMENT_CHANNEL_MASK 0xf0 289 | #define ICER_GET_LSB_MACRO(x) ((x) & ICER_SEGMENT_LSB_MASK) 290 | #define ICER_GET_CHANNEL_MACRO(x) (((x) & ICER_SEGMENT_CHANNEL_MASK) >> 4) 291 | #define ICER_SET_CHANNEL_MACRO(x) ((x) << 4) 292 | 293 | typedef struct { 294 | uint16_t preamble; 295 | uint16_t ll_mean_val; 296 | uint8_t decomp_level; 297 | uint8_t subband_type; 298 | uint8_t segment_number; 299 | uint8_t lsb_chan; 300 | uint32_t image_w; 301 | uint32_t image_h; 302 | uint32_t data_length; // store data length in bits for the decoder 303 | uint32_t data_crc32; 304 | uint32_t crc32; 305 | } icer_image_segment_typedef; 306 | 307 | typedef struct { 308 | size_t size_used; 309 | size_t size_allocated; 310 | uint8_t *data_start; 311 | uint8_t *rearrange_start; 312 | } icer_output_data_buf_typedef; 313 | 314 | typedef struct { 315 | size_t buffer_length; 316 | size_t head; 317 | size_t tail; 318 | size_t used; 319 | size_t output_ind; 320 | size_t max_output_length; 321 | uint16_t *encode_buffer; 322 | uint8_t output_bit_offset; 323 | uint8_t *output_buffer; 324 | int16_t bin_current_buf[ICER_ENCODER_BIN_MAX+1]; 325 | int16_t bin_current_buf_bits[ICER_ENCODER_BIN_MAX+1]; 326 | } icer_encoder_context_typedef; 327 | 328 | #define ICER_DECODER_BIT_BIN_MAX 30 329 | 330 | typedef struct { 331 | size_t decoded_words; 332 | size_t encode_ind; 333 | uint8_t encode_bit_offset; 334 | uint32_t encoded_bits_total; 335 | uint32_t decoded_bits_total; 336 | uint8_t *encoded_words; 337 | uint32_t bin_buf[ICER_ENCODER_BIN_MAX+1][ICER_DECODER_BIT_BIN_MAX]; 338 | int32_t bin_bits[ICER_ENCODER_BIN_MAX+1]; 339 | size_t bin_decode_index[ICER_ENCODER_BIN_MAX+1]; 340 | } icer_decoder_context_typedef; 341 | 342 | #define ICER_CHANNEL_MIN 0 343 | #define ICER_CHANNEL_MAX 2 344 | enum icer_color_channels { 345 | ICER_CHANNEL_Y = ICER_CHANNEL_MIN, 346 | ICER_CHANNEL_U = 1, 347 | ICER_CHANNEL_V = ICER_CHANNEL_MAX 348 | }; 349 | 350 | #ifdef USE_UINT8_FUNCTIONS 351 | #ifdef USE_DECODE_FUNCTIONS 352 | extern const icer_image_segment_typedef *icer_reconstruct_data_8[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][ICER_MAX_SEGMENTS + 1][7]; 353 | #endif 354 | 355 | #ifdef USE_ENCODE_FUNCTIONS 356 | extern icer_image_segment_typedef *icer_rearrange_segments_8[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][7][ICER_MAX_SEGMENTS + 1]; 357 | #endif 358 | #endif 359 | 360 | #ifdef USE_UINT16_FUNCTIONS 361 | #ifdef USE_DECODE_FUNCTIONS 362 | extern const icer_image_segment_typedef *icer_reconstruct_data_16[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][ICER_MAX_SEGMENTS + 1][15]; 363 | #endif 364 | 365 | #ifdef USE_ENCODE_FUNCTIONS 366 | extern icer_image_segment_typedef *icer_rearrange_segments_16[ICER_CHANNEL_MAX + 1][ICER_MAX_DECOMP_STAGES + 1][ICER_SUBBAND_MAX + 1][15][ICER_MAX_SEGMENTS + 1]; 367 | #endif 368 | #endif 369 | 370 | int icer_init(void); 371 | 372 | #ifdef USE_DECODE_FUNCTIONS 373 | void icer_init_decodescheme(void); 374 | int icer_get_image_dimensions(const uint8_t *datastream, size_t data_length, size_t *image_w, size_t *image_h); 375 | #endif 376 | 377 | #ifdef USE_ENCODE_FUNCTIONS 378 | void icer_init_codingscheme(void); 379 | #endif 380 | 381 | void icer_init_flushbits(void); 382 | void icer_init_golombcoder(void); 383 | 384 | #ifdef USE_UINT8_FUNCTIONS 385 | #ifdef USE_ENCODE_FUNCTIONS 386 | int icer_compress_image_uint8(uint8_t *image, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt, 387 | uint8_t segments, icer_output_data_buf_typedef *output_data); 388 | int icer_compress_image_yuv_uint8(uint8_t *y_channel, uint8_t *u_channel, uint8_t *v_channel, size_t image_w, 389 | size_t image_h, uint8_t stages, enum icer_filter_types filt, 390 | uint8_t segments, icer_output_data_buf_typedef *const output_data); 391 | 392 | int icer_wavelet_transform_stages_uint8(uint8_t *image, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt); 393 | 394 | int icer_wavelet_transform_2d_uint8(uint8_t *image, size_t image_w, size_t image_h, size_t rowstride, enum icer_filter_types filt); 395 | int icer_wavelet_transform_1d_uint8(uint8_t *data, size_t N, size_t stride, enum icer_filter_types filt); 396 | 397 | int icer_compress_partition_uint8(const uint8_t *data, partition_param_typdef *params, size_t rowstride, 398 | icer_packet_context *pkt_context, icer_output_data_buf_typedef *output_data, 399 | const icer_image_segment_typedef *segments_encoded[]); 400 | int icer_compress_bitplane_uint8(const uint8_t *data, size_t plane_w, size_t plane_h, size_t rowstride, 401 | icer_context_model_typedef *context_model, 402 | icer_encoder_context_typedef *encoder_context, 403 | const icer_packet_context *pkt_context); 404 | #endif 405 | 406 | #ifdef USE_DECODE_FUNCTIONS 407 | int icer_decompress_image_uint8(uint8_t *image, size_t *image_w, size_t *image_h, size_t image_bufsize, const uint8_t *datastream, 408 | size_t data_length, uint8_t stages, enum icer_filter_types filt, uint8_t segments); 409 | int icer_decompress_image_yuv_uint8(uint8_t *y_channel, uint8_t *u_channel, uint8_t *v_channel, size_t *image_w, 410 | size_t *image_h, size_t image_bufsize, const uint8_t *datastream, 411 | size_t data_length, uint8_t stages, enum icer_filter_types filt, 412 | uint8_t segments); 413 | 414 | int icer_inverse_wavelet_transform_stages_uint8(uint8_t *image, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt); 415 | 416 | int icer_inverse_wavelet_transform_2d_uint8(uint8_t *image, size_t image_w, size_t image_h, size_t rowstride, enum icer_filter_types filt); 417 | int icer_inverse_wavelet_transform_1d_uint8(uint8_t *data, size_t N, size_t stride, enum icer_filter_types filt); 418 | 419 | int icer_decompress_partition_uint8(uint8_t *const data, const partition_param_typdef *params, size_t rowstride, 420 | const icer_image_segment_typedef *seg[][7]); 421 | int icer_decompress_bitplane_uint8(uint8_t *const data, size_t plane_w, size_t plane_h, size_t rowstride, 422 | icer_context_model_typedef *context_model, 423 | icer_decoder_context_typedef *decoder_context, 424 | const icer_packet_context *pkt_context); 425 | void icer_remove_negative_uint8(uint8_t * const image, size_t image_w, size_t image_h); 426 | #endif 427 | 428 | void icer_reverse_uint8(uint8_t *data, size_t start, size_t end, size_t stride); 429 | 430 | void icer_interleave_uint8(uint8_t *data, size_t len, size_t stride); 431 | void icer_deinterleave_uint8(uint8_t *data, size_t len, size_t stride); 432 | 433 | 434 | void icer_to_sign_magnitude_int8(uint8_t *data, size_t len); 435 | void icer_from_sign_magnitude_int8(uint8_t *data, size_t len); 436 | #endif 437 | 438 | #ifdef USE_UINT16_FUNCTIONS 439 | #ifdef USE_ENCODE_FUNCTIONS 440 | int icer_compress_image_uint16(uint16_t *image, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt, 441 | uint8_t segments, icer_output_data_buf_typedef *output_data); 442 | int icer_compress_image_yuv_uint16(uint16_t *y_channel, uint16_t *u_channel, uint16_t *v_channel, size_t image_w, 443 | size_t image_h, uint8_t stages, enum icer_filter_types filt, 444 | uint8_t segments, icer_output_data_buf_typedef *output_data); 445 | 446 | int icer_wavelet_transform_stages_uint16(uint16_t *image, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt); 447 | 448 | int icer_wavelet_transform_2d_uint16(uint16_t *image, size_t image_w, size_t image_h, size_t rowstride, enum icer_filter_types filt); 449 | int icer_wavelet_transform_1d_uint16(uint16_t *data, size_t N, size_t stride, enum icer_filter_types filt); 450 | 451 | int icer_compress_partition_uint16(const uint16_t *data, const partition_param_typdef *params, size_t rowstride, 452 | const icer_packet_context *pkt_context, icer_output_data_buf_typedef *output_data, 453 | const icer_image_segment_typedef *segments_encoded[]); 454 | int icer_compress_bitplane_uint16(const uint16_t *data, size_t plane_w, size_t plane_h, size_t rowstride, 455 | icer_context_model_typedef *context_model, 456 | icer_encoder_context_typedef *encoder_context, 457 | const icer_packet_context *pkt_context); 458 | #endif 459 | 460 | #ifdef USE_DECODE_FUNCTIONS 461 | int icer_decompress_image_uint16(uint16_t *image, size_t *image_w, size_t *image_h, size_t image_bufsize, const uint8_t *datastream, 462 | size_t data_length, uint8_t stages, enum icer_filter_types filt, uint8_t segments); 463 | int icer_decompress_image_yuv_uint16(uint16_t * y_channel, uint16_t * u_channel, uint16_t * v_channel, size_t *image_w, 464 | size_t *image_h, size_t image_bufsize, const uint8_t *datastream, 465 | size_t data_length, uint8_t stages, enum icer_filter_types filt, 466 | uint8_t segments); 467 | 468 | int icer_inverse_wavelet_transform_stages_uint16(uint16_t *image, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt); 469 | 470 | int icer_inverse_wavelet_transform_2d_uint16(uint16_t *image, size_t image_w, size_t image_h, size_t rowstride, enum icer_filter_types filt); 471 | int icer_inverse_wavelet_transform_1d_uint16(uint16_t *data, size_t N, size_t stride, enum icer_filter_types filt); 472 | 473 | int icer_decompress_partition_uint16(uint16_t *data, const partition_param_typdef *params, size_t rowstride, 474 | const icer_image_segment_typedef *seg[][15]); 475 | int icer_decompress_bitplane_uint16(uint16_t *data, size_t plane_w, size_t plane_h, size_t rowstride, 476 | icer_context_model_typedef *context_model, 477 | icer_decoder_context_typedef *decoder_context, 478 | const icer_packet_context *pkt_context); 479 | void icer_remove_negative_uint16(uint16_t * image, size_t image_w, size_t image_h); 480 | #endif 481 | 482 | void icer_reverse_uint16(uint16_t *data, size_t start, size_t end, size_t stride); 483 | 484 | void icer_interleave_uint16(uint16_t *data, size_t len, size_t stride); 485 | void icer_deinterleave_uint16(uint16_t *data, size_t len, size_t stride); 486 | 487 | void icer_to_sign_magnitude_int16(uint16_t *data, size_t len); 488 | void icer_from_sign_magnitude_int16(uint16_t *data, size_t len); 489 | #endif 490 | 491 | #ifdef USE_ENCODE_FUNCTIONS 492 | /* inside encoding.c */ 493 | extern uint16_t icer_encode_circ_buf[ICER_CIRC_BUF_SIZE]; 494 | 495 | void icer_init_entropy_coder_context(icer_encoder_context_typedef *encoder_context, uint16_t *encode_buffer, size_t buffer_length, uint8_t *encoder_out, size_t enc_out_max); 496 | int icer_encode_bit(icer_encoder_context_typedef *encoder_context, uint8_t bit, uint32_t zero_cnt, uint32_t total_cnt); 497 | int icer_popbuf_while_avail(icer_encoder_context_typedef *encoder_context); 498 | int icer_flush_encode(icer_encoder_context_typedef *encoder_context); 499 | int icer_allocate_data_packet(icer_image_segment_typedef **pkt, icer_output_data_buf_typedef * const output_data, uint8_t segment_num, const icer_packet_context *context); 500 | #endif 501 | 502 | #ifdef USE_DECODE_FUNCTIONS 503 | /* inside decoding.c */ 504 | void icer_init_entropy_decoder_context(icer_decoder_context_typedef *decoder_context, uint8_t *encoded_words, size_t encoded_bits); 505 | void icer_push_bin_bits(icer_decoder_context_typedef *decoder_context, uint8_t bin, uint16_t bits, uint16_t num_bits); 506 | int icer_get_bit_from_codeword(icer_decoder_context_typedef *decoder_context, uint8_t bits); 507 | int icer_get_bits_from_codeword(icer_decoder_context_typedef *decoder_context, uint8_t bits); 508 | int icer_pop_bits_from_codeword(icer_decoder_context_typedef *decoder_context, uint8_t bits); 509 | int icer_decode_bit(icer_decoder_context_typedef *decoder_context, uint8_t *bit, uint32_t zero_cnt, uint32_t total_cnt); 510 | #endif 511 | 512 | int icer_find_packet_in_bytestream(const icer_image_segment_typedef **seg, const uint8_t *datastream, size_t data_length, size_t * offset); 513 | 514 | uint8_t icer_find_k(size_t len); 515 | size_t icer_get_dim_n_low_stages(size_t dim, uint8_t stages); 516 | size_t icer_get_dim_n_high_stages(size_t dim, uint8_t stages); 517 | 518 | void icer_init_context_model_vals(icer_context_model_typedef* context_model, enum icer_subband_types subband_type); 519 | int icer_generate_partition_parameters(partition_param_typdef *params, size_t ll_w, size_t ll_h, uint16_t segments); 520 | 521 | uint32_t icer_calculate_packet_crc32(const icer_image_segment_typedef *pkt); 522 | uint32_t icer_calculate_segment_crc32(const icer_image_segment_typedef *pkt); 523 | 524 | int icer_init_output_struct(icer_output_data_buf_typedef *out, uint8_t *data, size_t buf_len, size_t byte_quota); 525 | int icer_compute_bin(uint32_t zero_cnt, uint32_t total_cnt); 526 | 527 | static inline unsigned icer_pow_uint(unsigned base, unsigned exp); 528 | 529 | static inline int16_t icer_floor_div_int16(int16_t a, int16_t b); 530 | static inline int32_t icer_floor_div_int32(int32_t a, int32_t b); 531 | static inline size_t icer_floor_div_size_t(size_t a, size_t b); 532 | static inline int16_t icer_ceil_div_int16(int16_t a, int16_t b); 533 | static inline uint32_t icer_ceil_div_uint32(uint32_t a, uint32_t b); 534 | static inline size_t icer_ceil_div_size_t(size_t a, size_t b); 535 | 536 | static inline int icer_max_int(int a, int b); 537 | static inline unsigned icer_max_uint(unsigned a, unsigned b); 538 | 539 | static inline int icer_min_int(int a, int b); 540 | 541 | static inline void icer_reverse_bits(uint16_t *bits, uint8_t num); 542 | 543 | extern size_t icer_slice_lengths[MAX_K]; 544 | 545 | static inline unsigned icer_pow_uint(unsigned base, unsigned exp) { 546 | unsigned res = 1; 547 | while (exp) { 548 | if (exp & 1) res *= base; 549 | exp /= 2; 550 | base *= base; 551 | } 552 | return res; 553 | } 554 | 555 | /* optimizes into single division, as per https://stackoverflow.com/questions/46265403/fast-floor-of-a-signed-integer-division-in-c-c */ 556 | static inline int16_t icer_floor_div_int16(int16_t a, int16_t b) { 557 | int16_t d = a / b; 558 | int16_t r = a % b; 559 | return r ? (d - ((a < 0) ^ (b < 0))) : d; 560 | } 561 | 562 | static inline int32_t icer_floor_div_int32(int32_t a, int32_t b) { 563 | int32_t d = a / b; 564 | int32_t r = a % b; 565 | return r ? (d - ((a < 0) ^ (b < 0))) : d; 566 | } 567 | 568 | static inline size_t icer_floor_div_size_t(size_t a, size_t b) { 569 | return a / b; 570 | } 571 | 572 | static inline int16_t icer_ceil_div_int16(int16_t a, int16_t b) { 573 | int16_t d = a / b; 574 | int16_t r = a % b; 575 | return r ? d + 1 : d; 576 | } 577 | 578 | static inline uint32_t icer_ceil_div_uint32(uint32_t a, uint32_t b) { 579 | uint32_t d = a / b; 580 | uint32_t r = a % b; 581 | return r ? d + 1 : d; 582 | } 583 | 584 | static inline size_t icer_ceil_div_size_t(size_t a, size_t b) { 585 | size_t d = a / b; 586 | size_t r = a % b; 587 | return r ? d + 1 : d; 588 | } 589 | 590 | static inline int icer_max_int(int a, int b) { 591 | return (a > b) ? a : b; 592 | } 593 | 594 | static inline unsigned icer_max_uint(unsigned a, unsigned b) { 595 | return (a > b) ? a : b; 596 | } 597 | 598 | static inline int icer_min_int(int a, int b) { 599 | return (a < b) ? a : b; 600 | } 601 | 602 | static inline void icer_reverse_bits(uint16_t *bits, uint8_t num) { 603 | uint16_t reversed = 0; 604 | for (int b = 0; b < num;b++) { 605 | reversed <<= 1; 606 | reversed |= (*bits) & 1; 607 | (*bits) >>= 1; 608 | } 609 | (*bits) = reversed; 610 | } 611 | 612 | 613 | #endif //ICER_COMPRESSION_ICER_H 614 | -------------------------------------------------------------------------------- /lib_icer/src/icer_compress.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by linyi on 22/3/2023. 3 | // 4 | 5 | #include "icer.h" 6 | #include 7 | 8 | static inline int comp_packet(const void *a, const void *b) { 9 | if (((icer_packet_context *)a)->priority == ((icer_packet_context *)b)->priority) { 10 | // prioritize based on subband type given same priority 11 | return (((icer_packet_context *)a)->subband_type > ((icer_packet_context *)b)->subband_type) ? 1 : 12 | (((icer_packet_context *)a)->subband_type < ((icer_packet_context *)b)->subband_type) ? -1 : 0; 13 | } 14 | return (((icer_packet_context *)a)->priority > ((icer_packet_context *)b)->priority) ? -1 : 1; 15 | } 16 | 17 | #ifdef USE_UINT8_FUNCTIONS 18 | int icer_compress_image_uint8(uint8_t * const image, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt, 19 | uint8_t segments, icer_output_data_buf_typedef * const output_data) { 20 | int res; 21 | int chan = 0; 22 | res = icer_wavelet_transform_stages_uint8(image, image_w, image_h, stages, filt); 23 | if (res != ICER_RESULT_OK) return res; 24 | 25 | size_t ll_w = icer_get_dim_n_low_stages(image_w, stages); 26 | size_t ll_h = icer_get_dim_n_low_stages(image_h, stages); 27 | 28 | uint64_t sum = 0; 29 | uint8_t *pixel; 30 | for (size_t row = 0;row < ll_h;row++) { 31 | pixel = image + image_w * row; 32 | for (size_t col = 0;col < ll_w;col++) { 33 | sum += (*pixel); 34 | pixel++; 35 | } 36 | } 37 | 38 | uint8_t ll_mean = sum / (ll_w * ll_h); 39 | if (ll_mean > INT8_MAX) { 40 | return ICER_INTEGER_OVERFLOW; 41 | } 42 | 43 | int8_t *signed_pixel; 44 | for (size_t row = 0;row < ll_h;row++) { 45 | signed_pixel = (int8_t*)(image + image_w * row); 46 | for (size_t col = 0;col < ll_w;col++) { 47 | *signed_pixel = (int8_t)(*signed_pixel - (int8_t)ll_mean); 48 | signed_pixel++; 49 | } 50 | } 51 | 52 | icer_to_sign_magnitude_int8(image, image_w * image_h); 53 | 54 | uint32_t priority = 0; 55 | uint32_t ind = 0; 56 | for (uint8_t curr_stage = 1;curr_stage <= stages;curr_stage++) { 57 | priority = icer_pow_uint(2, curr_stage); 58 | for (uint8_t lsb = 0;lsb < ICER_BITPLANES_TO_COMPRESS_8;lsb++) { 59 | icer_packets[ind].subband_type = ICER_SUBBAND_HL; 60 | icer_packets[ind].decomp_level = curr_stage; 61 | icer_packets[ind].ll_mean_val = ll_mean; 62 | icer_packets[ind].lsb = lsb; 63 | icer_packets[ind].priority = priority << lsb; 64 | icer_packets[ind].image_w = image_w; 65 | icer_packets[ind].image_h = image_h; 66 | icer_packets[ind].channel = chan; 67 | ind++; if (ind >= ICER_MAX_PACKETS) return ICER_PACKET_COUNT_EXCEEDED; 68 | 69 | icer_packets[ind].subband_type = ICER_SUBBAND_LH; 70 | icer_packets[ind].decomp_level = curr_stage; 71 | icer_packets[ind].ll_mean_val = ll_mean; 72 | icer_packets[ind].lsb = lsb; 73 | icer_packets[ind].priority = priority << lsb; 74 | icer_packets[ind].image_w = image_w; 75 | icer_packets[ind].image_h = image_h; 76 | icer_packets[ind].channel = chan; 77 | ind++; if (ind >= ICER_MAX_PACKETS) return ICER_PACKET_COUNT_EXCEEDED; 78 | 79 | icer_packets[ind].subband_type = ICER_SUBBAND_HH; 80 | icer_packets[ind].decomp_level = curr_stage; 81 | icer_packets[ind].ll_mean_val = ll_mean; 82 | icer_packets[ind].lsb = lsb; 83 | icer_packets[ind].priority = ((priority / 2) << lsb) + 1; 84 | icer_packets[ind].image_w = image_w; 85 | icer_packets[ind].image_h = image_h; 86 | icer_packets[ind].channel = chan; 87 | ind++; if (ind >= ICER_MAX_PACKETS) return ICER_PACKET_COUNT_EXCEEDED; 88 | } 89 | } 90 | 91 | priority = icer_pow_uint(2, stages); 92 | for (uint8_t lsb = 0;lsb < ICER_BITPLANES_TO_COMPRESS_8;lsb++) { 93 | icer_packets[ind].subband_type = ICER_SUBBAND_LL; 94 | icer_packets[ind].decomp_level = stages; 95 | icer_packets[ind].ll_mean_val = ll_mean; 96 | icer_packets[ind].lsb = lsb; 97 | icer_packets[ind].priority = (2 * priority) << lsb; 98 | icer_packets[ind].image_w = image_w; 99 | icer_packets[ind].image_h = image_h; 100 | icer_packets[ind].channel = chan; 101 | ind++; if (ind >= ICER_MAX_PACKETS) return ICER_PACKET_COUNT_EXCEEDED; 102 | 103 | } 104 | 105 | qsort(icer_packets, ind, sizeof(icer_packet_context), comp_packet); 106 | 107 | for (int i = 0;i <= ICER_MAX_DECOMP_STAGES;i++) { 108 | for (int j = 0;j <= ICER_SUBBAND_MAX;j++) { 109 | for (int k = 0;k <= ICER_MAX_SEGMENTS;k++) { 110 | for (int lsb = 0;lsb < ICER_BITPLANES_TO_COMPRESS_8;lsb++) { 111 | icer_rearrange_segments_8[chan][i][j][lsb][k] = NULL; 112 | } 113 | } 114 | } 115 | } 116 | 117 | partition_param_typdef partition_params; 118 | uint8_t *data_start; 119 | for (size_t it = 0;it < ind;it++) { 120 | if (icer_packets[it].subband_type == ICER_SUBBAND_LL) { 121 | ll_w = icer_get_dim_n_low_stages(image_w, icer_packets[it].decomp_level); 122 | ll_h = icer_get_dim_n_low_stages(image_h, icer_packets[it].decomp_level); 123 | data_start = image; 124 | } else if (icer_packets[it].subband_type == ICER_SUBBAND_HL) { 125 | ll_w = icer_get_dim_n_high_stages(image_w, icer_packets[it].decomp_level); 126 | ll_h = icer_get_dim_n_low_stages(image_h, icer_packets[it].decomp_level); 127 | data_start = image + icer_get_dim_n_low_stages(image_w, icer_packets[it].decomp_level); 128 | } else if (icer_packets[it].subband_type == ICER_SUBBAND_LH) { 129 | ll_w = icer_get_dim_n_low_stages(image_w, icer_packets[it].decomp_level); 130 | ll_h = icer_get_dim_n_high_stages(image_h, icer_packets[it].decomp_level); 131 | data_start = image + icer_get_dim_n_low_stages(image_h, icer_packets[it].decomp_level) * image_w; 132 | } else if (icer_packets[it].subband_type == ICER_SUBBAND_HH) { 133 | ll_w = icer_get_dim_n_high_stages(image_w, icer_packets[it].decomp_level); 134 | ll_h = icer_get_dim_n_high_stages(image_h, icer_packets[it].decomp_level); 135 | data_start = image + icer_get_dim_n_low_stages(image_h, icer_packets[it].decomp_level) * image_w + 136 | icer_get_dim_n_low_stages(image_w, icer_packets[it].decomp_level); 137 | } else { 138 | return ICER_FATAL_ERROR; 139 | } 140 | 141 | icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 142 | res = icer_compress_partition_uint8(data_start, &partition_params, image_w, &(icer_packets[it]), output_data, 143 | (const icer_image_segment_typedef **) icer_rearrange_segments_8[chan][icer_packets[it].decomp_level][icer_packets[it].subband_type][icer_packets[it].lsb]); 144 | if (res != ICER_RESULT_OK) { 145 | break; 146 | } 147 | } 148 | 149 | size_t rearrange_offset = 0; 150 | size_t len; 151 | for (int k = 0;k <= ICER_MAX_SEGMENTS;k++) { 152 | for (int j = ICER_SUBBAND_MAX;j >= 0;j--) { 153 | for (int i = ICER_MAX_DECOMP_STAGES;i >= 0;i--) { 154 | for (int lsb = ICER_BITPLANES_TO_COMPRESS_8 - 1;lsb >= 0;lsb--) { 155 | if (icer_rearrange_segments_8[chan][i][j][lsb][k] != NULL) { 156 | len = icer_ceil_div_uint32(icer_rearrange_segments_8[chan][i][j][lsb][k]->data_length, 8) + sizeof(icer_image_segment_typedef); 157 | memcpy(output_data->rearrange_start + rearrange_offset, icer_rearrange_segments_8[chan][i][j][lsb][k], len); 158 | rearrange_offset += len; 159 | } 160 | } 161 | } 162 | } 163 | } 164 | 165 | return res; 166 | } 167 | 168 | int icer_decompress_image_uint8(uint8_t * const image, size_t * const image_w, size_t * const image_h, const size_t image_bufsize, const uint8_t *datastream, 169 | const size_t data_length, const uint8_t stages, const enum icer_filter_types filt, const uint8_t segments) { 170 | int chan = 0; 171 | for (int i = 0;i <= ICER_MAX_DECOMP_STAGES;i++) { 172 | for (int j = 0;j <= ICER_SUBBAND_MAX;j++) { 173 | for (int k = 0;k <= ICER_MAX_SEGMENTS;k++) { 174 | for (int lsb = 0;lsb < ICER_BITPLANES_TO_COMPRESS_8;lsb++) { 175 | icer_reconstruct_data_8[chan][i][j][k][lsb] = NULL; 176 | } 177 | } 178 | } 179 | } 180 | 181 | const icer_image_segment_typedef *seg = NULL; 182 | const uint8_t *seg_start; 183 | size_t offset = 0; 184 | size_t pkt_offset; 185 | int res; 186 | uint16_t ll_mean = 0; 187 | while ((data_length - offset) > 0) { 188 | seg_start = datastream + offset; 189 | res = icer_find_packet_in_bytestream(&seg, seg_start, data_length - offset, &pkt_offset); 190 | if (res == ICER_RESULT_OK) { 191 | icer_reconstruct_data_8[chan][seg->decomp_level][seg->subband_type][seg->segment_number][ICER_GET_LSB_MACRO(seg->lsb_chan)] = seg; 192 | *image_w = seg->image_w; 193 | *image_h = seg->image_h; 194 | ll_mean = seg->ll_mean_val; 195 | } 196 | offset += pkt_offset; 197 | } 198 | 199 | if (image_bufsize < (*image_w) * (*image_h)) { 200 | return ICER_BYTE_QUOTA_EXCEEDED; 201 | } 202 | 203 | uint8_t *data_start; 204 | size_t ll_w; 205 | size_t ll_h; 206 | size_t im_w = *image_w; 207 | size_t im_h = *image_h; 208 | memset(image, 0, im_w * im_h * sizeof(image[0])); 209 | partition_param_typdef partition_params; 210 | for (uint8_t curr_stage = 1;curr_stage <= stages;curr_stage++) { 211 | if (curr_stage == stages) { 212 | /* LL subband */ 213 | ll_w = icer_get_dim_n_low_stages(im_w, curr_stage); 214 | ll_h = icer_get_dim_n_low_stages(im_h, curr_stage); 215 | data_start = image; 216 | 217 | res = icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 218 | if (res != ICER_RESULT_OK) return res; 219 | res = icer_decompress_partition_uint8(data_start, &partition_params, im_w, 220 | icer_reconstruct_data_8[chan][curr_stage][ICER_SUBBAND_LL]); 221 | if (res != ICER_RESULT_OK) return res; 222 | } 223 | 224 | /* HL subband */ 225 | ll_w = icer_get_dim_n_high_stages(im_w, curr_stage); 226 | ll_h = icer_get_dim_n_low_stages(im_h, curr_stage); 227 | data_start = image + icer_get_dim_n_low_stages(im_w, curr_stage); 228 | 229 | res = icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 230 | if (res != ICER_RESULT_OK) return res; 231 | res = icer_decompress_partition_uint8(data_start, &partition_params, im_w, 232 | icer_reconstruct_data_8[chan][curr_stage][ICER_SUBBAND_HL]); 233 | if (res != ICER_RESULT_OK) return res; 234 | 235 | /* LH subband */ 236 | ll_w = icer_get_dim_n_low_stages(im_w, curr_stage); 237 | ll_h = icer_get_dim_n_high_stages(im_h, curr_stage); 238 | data_start = image + icer_get_dim_n_low_stages(im_h, curr_stage) * im_w; 239 | 240 | res = icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 241 | if (res != ICER_RESULT_OK) return res; 242 | res = icer_decompress_partition_uint8(data_start, &partition_params, im_w, 243 | icer_reconstruct_data_8[chan][curr_stage][ICER_SUBBAND_LH]); 244 | if (res != ICER_RESULT_OK) return res; 245 | 246 | /* HH subband */ 247 | ll_w = icer_get_dim_n_high_stages(im_w, curr_stage); 248 | ll_h = icer_get_dim_n_high_stages(im_h, curr_stage); 249 | data_start = image + icer_get_dim_n_low_stages(im_h, curr_stage) * im_w + icer_get_dim_n_low_stages(im_w, curr_stage); 250 | 251 | res = icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 252 | if (res != ICER_RESULT_OK) return res; 253 | res = icer_decompress_partition_uint8(data_start, &partition_params, im_w, 254 | icer_reconstruct_data_8[chan][curr_stage][ICER_SUBBAND_HH]); 255 | if (res != ICER_RESULT_OK) return res; 256 | } 257 | 258 | icer_from_sign_magnitude_int8(image, im_w * im_h); 259 | 260 | ll_w = icer_get_dim_n_low_stages(im_w, stages); 261 | ll_h = icer_get_dim_n_low_stages(im_h, stages); 262 | int8_t *signed_pixel; 263 | for (size_t row = 0;row < ll_h;row++) { 264 | signed_pixel = (int8_t*)(image + im_w * row); 265 | for (size_t col = 0;col < ll_w;col++) { 266 | *signed_pixel = (int8_t)(*signed_pixel + (int8_t)ll_mean); 267 | signed_pixel++; 268 | } 269 | } 270 | 271 | icer_inverse_wavelet_transform_stages_uint8(image, im_w, im_h, stages, filt); 272 | icer_remove_negative_uint8(image, im_w, im_h); 273 | return ICER_RESULT_OK; 274 | } 275 | #endif 276 | 277 | #ifdef USE_UINT16_FUNCTIONS 278 | #ifdef USE_ENCODE_FUNCTIONS 279 | int icer_compress_image_uint16(uint16_t * const image, size_t image_w, size_t image_h, uint8_t stages, enum icer_filter_types filt, 280 | uint8_t segments, icer_output_data_buf_typedef * const output_data) { 281 | int res; 282 | int chan = 0; 283 | res = icer_wavelet_transform_stages_uint16(image, image_w, image_h, stages, filt); 284 | if (res != ICER_RESULT_OK) return res; 285 | 286 | size_t ll_w = icer_get_dim_n_low_stages(image_w, stages); 287 | size_t ll_h = icer_get_dim_n_low_stages(image_h, stages); 288 | 289 | uint64_t sum = 0; 290 | uint16_t *pixel; 291 | for (size_t row = 0;row < ll_h;row++) { 292 | pixel = image + image_w * row; 293 | for (size_t col = 0;col < ll_w;col++) { 294 | sum += (*pixel); 295 | pixel++; 296 | } 297 | } 298 | 299 | uint16_t ll_mean = sum / (ll_w * ll_h); 300 | if (ll_mean > INT16_MAX) { 301 | return ICER_INTEGER_OVERFLOW; 302 | } 303 | 304 | int16_t *signed_pixel; 305 | for (size_t row = 0;row < ll_h;row++) { 306 | signed_pixel = (int16_t*)(image + image_w * row); 307 | for (size_t col = 0;col < ll_w;col++) { 308 | *signed_pixel = (int16_t)(*signed_pixel - (int16_t)ll_mean); 309 | signed_pixel++; 310 | } 311 | } 312 | 313 | icer_to_sign_magnitude_int16(image, image_w * image_h); 314 | 315 | uint64_t priority = 0; 316 | uint32_t ind = 0; 317 | for (uint8_t curr_stage = 1;curr_stage <= stages;curr_stage++) { 318 | priority = icer_pow_uint(2, curr_stage); 319 | for (uint8_t lsb = 0;lsb < ICER_BITPLANES_TO_COMPRESS_16;lsb++) { 320 | icer_packets_16[ind].subband_type = ICER_SUBBAND_HL; 321 | icer_packets_16[ind].decomp_level = curr_stage; 322 | icer_packets_16[ind].ll_mean_val = ll_mean; 323 | icer_packets_16[ind].lsb = lsb; 324 | icer_packets_16[ind].priority = priority << lsb; 325 | icer_packets_16[ind].image_w = image_w; 326 | icer_packets_16[ind].image_h = image_h; 327 | icer_packets_16[ind].channel = chan; 328 | ind++; if (ind >= ICER_MAX_PACKETS_16) return ICER_PACKET_COUNT_EXCEEDED; 329 | 330 | icer_packets_16[ind].subband_type = ICER_SUBBAND_LH; 331 | icer_packets_16[ind].decomp_level = curr_stage; 332 | icer_packets_16[ind].ll_mean_val = ll_mean; 333 | icer_packets_16[ind].lsb = lsb; 334 | icer_packets_16[ind].priority = priority << lsb; 335 | icer_packets_16[ind].image_w = image_w; 336 | icer_packets_16[ind].image_h = image_h; 337 | icer_packets_16[ind].channel = chan; 338 | ind++; if (ind >= ICER_MAX_PACKETS_16) return ICER_PACKET_COUNT_EXCEEDED; 339 | 340 | icer_packets_16[ind].subband_type = ICER_SUBBAND_HH; 341 | icer_packets_16[ind].decomp_level = curr_stage; 342 | icer_packets_16[ind].ll_mean_val = ll_mean; 343 | icer_packets_16[ind].lsb = lsb; 344 | icer_packets_16[ind].priority = ((priority / 2) << lsb) + 1; 345 | icer_packets_16[ind].image_w = image_w; 346 | icer_packets_16[ind].image_h = image_h; 347 | icer_packets_16[ind].channel = chan; 348 | ind++; if (ind >= ICER_MAX_PACKETS_16) return ICER_PACKET_COUNT_EXCEEDED; 349 | } 350 | } 351 | 352 | priority = icer_pow_uint(2, stages); 353 | for (uint8_t lsb = 0;lsb < ICER_BITPLANES_TO_COMPRESS_16;lsb++) { 354 | icer_packets_16[ind].subband_type = ICER_SUBBAND_LL; 355 | icer_packets_16[ind].decomp_level = stages; 356 | icer_packets_16[ind].ll_mean_val = ll_mean; 357 | icer_packets_16[ind].lsb = lsb; 358 | icer_packets_16[ind].priority = (2 * priority) << lsb; 359 | icer_packets_16[ind].image_w = image_w; 360 | icer_packets_16[ind].image_h = image_h; 361 | icer_packets_16[ind].channel = chan; 362 | ind++; if (ind >= ICER_MAX_PACKETS_16) return ICER_PACKET_COUNT_EXCEEDED; 363 | } 364 | 365 | qsort(icer_packets_16, ind, sizeof(icer_packet_context), comp_packet); 366 | 367 | for (int i = 0;i <= ICER_MAX_DECOMP_STAGES;i++) { 368 | for (int j = 0;j <= ICER_SUBBAND_MAX;j++) { 369 | for (int k = 0;k <= ICER_MAX_SEGMENTS;k++) { 370 | for (int lsb = 0;lsb < ICER_BITPLANES_TO_COMPRESS_16;lsb++) { 371 | icer_rearrange_segments_16[chan][i][j][lsb][k] = NULL; 372 | } 373 | } 374 | } 375 | } 376 | 377 | partition_param_typdef partition_params; 378 | uint16_t *data_start; 379 | for (size_t it = 0;it < ind;it++) { 380 | if (icer_packets_16[it].subband_type == ICER_SUBBAND_LL) { 381 | ll_w = icer_get_dim_n_low_stages(image_w, icer_packets_16[it].decomp_level); 382 | ll_h = icer_get_dim_n_low_stages(image_h, icer_packets_16[it].decomp_level); 383 | data_start = image; 384 | } else if (icer_packets_16[it].subband_type == ICER_SUBBAND_HL) { 385 | ll_w = icer_get_dim_n_high_stages(image_w, icer_packets_16[it].decomp_level); 386 | ll_h = icer_get_dim_n_low_stages(image_h, icer_packets_16[it].decomp_level); 387 | data_start = image + icer_get_dim_n_low_stages(image_w, icer_packets_16[it].decomp_level); 388 | } else if (icer_packets_16[it].subband_type == ICER_SUBBAND_LH) { 389 | ll_w = icer_get_dim_n_low_stages(image_w, icer_packets_16[it].decomp_level); 390 | ll_h = icer_get_dim_n_high_stages(image_h, icer_packets_16[it].decomp_level); 391 | data_start = image + icer_get_dim_n_low_stages(image_h, icer_packets_16[it].decomp_level) * image_w; 392 | } else if (icer_packets_16[it].subband_type == ICER_SUBBAND_HH) { 393 | ll_w = icer_get_dim_n_high_stages(image_w, icer_packets_16[it].decomp_level); 394 | ll_h = icer_get_dim_n_high_stages(image_h, icer_packets_16[it].decomp_level); 395 | data_start = image + icer_get_dim_n_low_stages(image_h, icer_packets_16[it].decomp_level) * image_w + 396 | icer_get_dim_n_low_stages(image_w, icer_packets_16[it].decomp_level); 397 | } else { 398 | return ICER_FATAL_ERROR; 399 | } 400 | 401 | icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 402 | res = icer_compress_partition_uint16(data_start, &partition_params, image_w, &(icer_packets_16[it]), 403 | output_data, (const icer_image_segment_typedef **) icer_rearrange_segments_16[chan][icer_packets_16[it].decomp_level][icer_packets_16[it].subband_type][icer_packets_16[it].lsb]); 404 | if (res != ICER_RESULT_OK) { 405 | break; 406 | } 407 | } 408 | 409 | size_t rearrange_offset = 0; 410 | size_t len; 411 | for (int k = 0;k <= ICER_MAX_SEGMENTS;k++) { 412 | for (int j = ICER_SUBBAND_MAX;j >= 0;j--) { 413 | for (int i = ICER_MAX_DECOMP_STAGES;i >= 0;i--) { 414 | for (int lsb = ICER_BITPLANES_TO_COMPRESS_16 - 1;lsb >= 0;lsb--) { 415 | if (icer_rearrange_segments_16[chan][i][j][lsb][k] != NULL) { 416 | len = icer_ceil_div_uint32(icer_rearrange_segments_16[chan][i][j][lsb][k]->data_length, 8) + sizeof(icer_image_segment_typedef); 417 | memcpy(output_data->rearrange_start + rearrange_offset, (uint8_t*)icer_rearrange_segments_16[chan][i][j][lsb][k], len); 418 | rearrange_offset += len; 419 | } 420 | } 421 | } 422 | } 423 | } 424 | 425 | return res; 426 | } 427 | #endif 428 | 429 | #ifdef USE_DECODE_FUNCTIONS 430 | int icer_decompress_image_uint16(uint16_t * const image, size_t * const image_w, size_t * const image_h, size_t image_bufsize, const uint8_t *datastream, 431 | size_t data_length, uint8_t stages, enum icer_filter_types filt, uint8_t segments) { 432 | int chan = 0; 433 | for (int i = 0;i <= ICER_MAX_DECOMP_STAGES;i++) { 434 | for (int j = 0;j <= ICER_SUBBAND_MAX;j++) { 435 | for (int k = 0;k <= ICER_MAX_SEGMENTS;k++) { 436 | for (int lsb = 0;lsb < ICER_BITPLANES_TO_COMPRESS_16;lsb++) { 437 | icer_reconstruct_data_16[chan][i][j][k][lsb] = NULL; 438 | } 439 | } 440 | } 441 | } 442 | 443 | const icer_image_segment_typedef *seg = NULL; 444 | const uint8_t *seg_start; 445 | size_t offset = 0; 446 | size_t pkt_offset = 0; 447 | int res; 448 | uint16_t ll_mean = 0; 449 | while ((data_length - offset) > 0) { 450 | seg_start = datastream + offset; 451 | res = icer_find_packet_in_bytestream(&seg, seg_start, data_length - offset, &pkt_offset); 452 | if (res == ICER_RESULT_OK) { 453 | icer_reconstruct_data_16[chan][seg->decomp_level][seg->subband_type][seg->segment_number][ICER_GET_LSB_MACRO(seg->lsb_chan)] = seg; 454 | *image_w = seg->image_w; 455 | *image_h = seg->image_h; 456 | ll_mean = seg->ll_mean_val; 457 | } 458 | offset += pkt_offset; 459 | } 460 | 461 | if (image_bufsize < (*image_w) * (*image_h)) { 462 | return ICER_BYTE_QUOTA_EXCEEDED; 463 | } 464 | 465 | uint16_t *data_start; 466 | size_t ll_w; 467 | size_t ll_h; 468 | size_t im_w = *image_w; 469 | size_t im_h = *image_h; 470 | memset(image, 0, im_w * im_h * sizeof(image[0])); 471 | partition_param_typdef partition_params; 472 | for (uint8_t curr_stage = 1;curr_stage <= stages;curr_stage++) { 473 | if (curr_stage == stages) { 474 | /* LL subband */ 475 | ll_w = icer_get_dim_n_low_stages(im_w, curr_stage); 476 | ll_h = icer_get_dim_n_low_stages(im_h, curr_stage); 477 | data_start = image; 478 | 479 | res = icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 480 | if (res != ICER_RESULT_OK) return res; 481 | res = icer_decompress_partition_uint16(data_start, &partition_params, im_w, 482 | icer_reconstruct_data_16[chan][curr_stage][ICER_SUBBAND_LL]); 483 | if (res != ICER_RESULT_OK) return res; 484 | } 485 | 486 | /* HL subband */ 487 | ll_w = icer_get_dim_n_high_stages(im_w, curr_stage); 488 | ll_h = icer_get_dim_n_low_stages(im_h, curr_stage); 489 | data_start = image + icer_get_dim_n_low_stages(im_w, curr_stage); 490 | 491 | res = icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 492 | if (res != ICER_RESULT_OK) return res; 493 | res = icer_decompress_partition_uint16(data_start, &partition_params, im_w, 494 | icer_reconstruct_data_16[chan][curr_stage][ICER_SUBBAND_HL]); 495 | if (res != ICER_RESULT_OK) return res; 496 | 497 | /* LH subband */ 498 | ll_w = icer_get_dim_n_low_stages(im_w, curr_stage); 499 | ll_h = icer_get_dim_n_high_stages(im_h, curr_stage); 500 | data_start = image + icer_get_dim_n_low_stages(im_h, curr_stage) * im_w; 501 | 502 | res = icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 503 | if (res != ICER_RESULT_OK) return res; 504 | res = icer_decompress_partition_uint16(data_start, &partition_params, im_w, 505 | icer_reconstruct_data_16[chan][curr_stage][ICER_SUBBAND_LH]); 506 | if (res != ICER_RESULT_OK) return res; 507 | 508 | /* HH subband */ 509 | ll_w = icer_get_dim_n_high_stages(im_w, curr_stage); 510 | ll_h = icer_get_dim_n_high_stages(im_h, curr_stage); 511 | data_start = image + icer_get_dim_n_low_stages(im_h, curr_stage) * im_w + icer_get_dim_n_low_stages(im_w, curr_stage); 512 | 513 | res = icer_generate_partition_parameters(&partition_params, ll_w, ll_h, segments); 514 | if (res != ICER_RESULT_OK) return res; 515 | res = icer_decompress_partition_uint16(data_start, &partition_params, im_w, 516 | icer_reconstruct_data_16[chan][curr_stage][ICER_SUBBAND_HH]); 517 | if (res != ICER_RESULT_OK) return res; 518 | } 519 | 520 | icer_from_sign_magnitude_int16(image, im_w * im_h); 521 | 522 | ll_w = icer_get_dim_n_low_stages(im_w, stages); 523 | ll_h = icer_get_dim_n_low_stages(im_h, stages); 524 | int16_t *signed_pixel; 525 | for (size_t row = 0;row < ll_h;row++) { 526 | signed_pixel = (int16_t*)(image + im_w * row); 527 | for (size_t col = 0;col < ll_w;col++) { 528 | *signed_pixel = (int16_t)(*signed_pixel + (int16_t)ll_mean); 529 | signed_pixel++; 530 | } 531 | } 532 | 533 | icer_inverse_wavelet_transform_stages_uint16(image, im_w, im_h, stages, filt); 534 | icer_remove_negative_uint16(image, im_w, im_h); 535 | return ICER_RESULT_OK; 536 | } 537 | #endif 538 | #endif 539 | 540 | #ifdef USE_DECODE_FUNCTIONS 541 | int icer_get_image_dimensions(const uint8_t *datastream, size_t data_length, size_t *image_w, size_t *image_h) { 542 | if (!datastream || !image_w || !image_h) { 543 | return ICER_INVALID_INPUT; 544 | } 545 | 546 | const icer_image_segment_typedef *seg = NULL; 547 | const uint8_t *seg_start; 548 | size_t offset = 0; 549 | size_t pkt_offset = 0; 550 | int res; 551 | 552 | // Loop through segments to find the first segment containing the image dimensions 553 | while ((data_length - offset) > 0) { 554 | seg_start = datastream + offset; 555 | res = icer_find_packet_in_bytestream(&seg, seg_start, data_length - offset, &pkt_offset); 556 | if (res == ICER_RESULT_OK && seg) { 557 | *image_w = seg->image_w; 558 | *image_h = seg->image_h; 559 | return ICER_RESULT_OK; // Successfully retrieved dimensions 560 | } 561 | offset += pkt_offset; 562 | } 563 | 564 | // If no valid segment found or data length is insufficient 565 | return ICER_DECODER_OUT_OF_DATA; 566 | } 567 | #endif 568 | 569 | int icer_find_packet_in_bytestream(const icer_image_segment_typedef **seg, const uint8_t *datastream, size_t data_length, size_t * const offset) { 570 | (*offset) = 0; 571 | (*seg) = NULL; 572 | while ((*offset) < data_length) { 573 | (*seg) = (icer_image_segment_typedef*)(datastream + (*offset)); 574 | if ((*seg)->preamble == ICER_PACKET_PREAMBLE) { 575 | if ((*seg)->crc32 == icer_calculate_packet_crc32((*seg))) { 576 | if (icer_ceil_div_uint32((*seg)->data_length, 8) <= (data_length-(*offset)-sizeof(icer_image_segment_typedef))) { 577 | if((*seg)->data_crc32 == icer_calculate_segment_crc32((*seg))) { 578 | (*offset) += icer_ceil_div_uint32((*seg)->data_length, 8) + sizeof(icer_image_segment_typedef); 579 | return ICER_RESULT_OK; 580 | } 581 | } 582 | } 583 | } 584 | (*seg) = NULL; 585 | (*offset)++; 586 | } 587 | return ICER_DECODER_OUT_OF_DATA; 588 | } -------------------------------------------------------------------------------- /lib_icer/src/icer_context_modeller.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by linyi on 19/3/2023. 3 | // 4 | 5 | #include "icer.h" 6 | 7 | #ifdef USE_UINT8_FUNCTIONS 8 | static inline uint8_t get_bit_category_uint8(const uint8_t* data, uint8_t lsb); 9 | static inline bool get_bit_significance_uint8(const uint8_t* data, uint8_t lsb); 10 | static inline int8_t get_sign_uint8(const uint8_t* data, uint8_t lsb); 11 | #endif 12 | 13 | #ifdef USE_UINT16_FUNCTIONS 14 | static inline uint8_t get_bit_category_uint16(const uint16_t* data, uint8_t lsb); 15 | static inline bool get_bit_significance_uint16(const uint16_t* data, uint8_t lsb); 16 | static inline int8_t get_sign_uint16(const uint16_t* data, uint8_t lsb); 17 | #endif 18 | 19 | #ifdef USE_UINT8_FUNCTIONS 20 | int icer_compress_bitplane_uint8(const uint8_t *data, size_t plane_w, size_t plane_h, size_t rowstride, 21 | icer_context_model_typedef *context_model, 22 | icer_encoder_context_typedef *encoder_context, 23 | const icer_packet_context *pkt_context) { 24 | int res; 25 | const uint8_t *pos; 26 | const uint8_t *rowstart = data; 27 | int category; 28 | bool bit; 29 | uint8_t lsb = pkt_context->lsb; 30 | uint8_t mask = 0b1 << lsb; 31 | 32 | const uint8_t *h0, *h1, *v0, *v1, *d0, *d1, *d2, *d3; 33 | uint8_t h = 0, v = 0, d = 0, tmp; 34 | int8_t sh0, sh1, sv0, sv1; 35 | uint8_t sh, sv; 36 | uint8_t pred_sign, actual_sign, agreement_bit; 37 | enum icer_pixel_contexts sign_context; 38 | size_t vert_bound = plane_h - 1; 39 | size_t hor_bound = plane_w - 1; 40 | 41 | uint8_t prev_plane = lsb+1; 42 | if (prev_plane >= 8) return ICER_BITPLANE_OUT_OF_RANGE; 43 | 44 | for (size_t row = 0; row < plane_h; row++) { 45 | pos = rowstart; 46 | /* keep track of 8 adjacent pixels */ 47 | h0 = pos - 1; h1 = pos + 1; 48 | v0 = pos - rowstride; v1 = pos + rowstride; 49 | d0 = v0 - 1; d1 = v0 + 1; 50 | d2 = v1 - 1; d3 = v1 + 1; 51 | 52 | enum icer_pixel_contexts cntxt = 0; 53 | 54 | for (size_t col = 0; col < plane_w; col++) { 55 | category = get_bit_category_uint8(pos, lsb); 56 | bit = ((*pos) & mask) != 0; 57 | 58 | if (category == ICER_CATEGORY_3) { 59 | /* pass to uncoded bin */ 60 | res = icer_encode_bit(encoder_context, bit, 1, 2); 61 | if (res != ICER_RESULT_OK) return res; 62 | } else { 63 | if (category == ICER_CATEGORY_0 || category == ICER_CATEGORY_1) { 64 | h = 0; 65 | v = 0; 66 | d = 0; 67 | 68 | /* consider the horizontally adjacent pixels */ 69 | if (col > 0) h += get_bit_significance_uint8(h0, lsb) & 1; 70 | if (col < hor_bound) h += get_bit_significance_uint8(h1, prev_plane) & 1; 71 | 72 | /* consider the vertically adjacent pixels */ 73 | if (row > 0) v += get_bit_significance_uint8(v0, lsb) & 1; 74 | if (row < vert_bound) v += get_bit_significance_uint8(v1, prev_plane) & 1; 75 | 76 | /* consider the diagonally adjacent pixels */ 77 | if (col > 0 && row > 0) d += get_bit_significance_uint8(d0, lsb) & 1; 78 | if (col > 0 && row < vert_bound) d += get_bit_significance_uint8(d2, prev_plane) & 1; 79 | if (col < hor_bound && row > 0) d += get_bit_significance_uint8(d1, lsb) & 1; 80 | if (col < hor_bound && row < vert_bound) d += get_bit_significance_uint8(d3, prev_plane) & 1; 81 | } 82 | 83 | if (category == ICER_CATEGORY_0) { 84 | if (context_model->subband_type == ICER_SUBBAND_HL) { 85 | tmp = h; 86 | h = v; 87 | v = tmp; 88 | } 89 | 90 | if (context_model->subband_type != ICER_SUBBAND_HH) { 91 | cntxt = icer_context_table_ll_lh_hl[h][v][d]; 92 | } else { 93 | cntxt = icer_context_table_hh[h + v][d]; 94 | } 95 | } else if (category == ICER_CATEGORY_1) { 96 | cntxt = (h + v == 0) ? ICER_CONTEXT_9 : ICER_CONTEXT_10; 97 | } else if (category == ICER_CATEGORY_2) { 98 | cntxt = ICER_CONTEXT_11; 99 | } 100 | 101 | res = icer_encode_bit(encoder_context, bit, context_model->zero_count[cntxt], context_model->total_count[cntxt]); 102 | if (res != ICER_RESULT_OK) return res; 103 | 104 | context_model->total_count[cntxt]++; 105 | context_model->zero_count[cntxt] += (uint32_t)(!bit); 106 | if (context_model->total_count[cntxt] >= ICER_CONTEXT_RESCALING_CAP) { 107 | context_model->total_count[cntxt] >>= 1; 108 | if (context_model->zero_count[cntxt] > context_model->total_count[cntxt]) context_model->zero_count[cntxt] >>= 1; 109 | else icer_ceil_div_uint32(context_model->zero_count[cntxt], 2); 110 | } 111 | 112 | if (category == ICER_CATEGORY_0 && bit) { 113 | /* bit is the first magnitude bit to be encoded, thus we will encode the sign bit */ 114 | /* predict sign bit */ 115 | sh0 = 0; sh1 = 0; 116 | sv0 = 0; sv1 = 0; 117 | 118 | /* consider the horizontally adjacent pixels */ 119 | if (col > 0) sh0 = get_sign_uint8(h0, lsb); 120 | if (col < hor_bound) sh1 = get_sign_uint8(h1, prev_plane); 121 | 122 | /* consider the vertically adjacent pixels */ 123 | if (row > 0) sv0 = get_sign_uint8(v0, lsb); 124 | if (row < vert_bound) sv1 = get_sign_uint8(v1, prev_plane); 125 | 126 | sh = sh0 + sh1 + 2; 127 | sv = sv0 + sv1 + 2; 128 | 129 | if (context_model->subband_type == ICER_SUBBAND_HL) { 130 | tmp = sh; 131 | sh = sv; 132 | sv = tmp; 133 | } 134 | 135 | sign_context = icer_sign_context_table[sh][sv]; 136 | pred_sign = icer_sign_prediction_table[sh][sv]; 137 | actual_sign = ((*pos) & 0x80) != 0; 138 | 139 | agreement_bit = (pred_sign ^ actual_sign) & 1; 140 | 141 | res = icer_encode_bit(encoder_context, agreement_bit, context_model->zero_count[sign_context], context_model->total_count[sign_context]); 142 | if (res != ICER_RESULT_OK) return res; 143 | 144 | context_model->total_count[sign_context]++; 145 | context_model->zero_count[sign_context] += (uint32_t)(agreement_bit == 0); 146 | if (context_model->total_count[sign_context] >= ICER_CONTEXT_RESCALING_CAP) { 147 | context_model->total_count[sign_context] >>= 1; 148 | if (context_model->zero_count[sign_context] > context_model->total_count[sign_context]) context_model->zero_count[sign_context] >>= 1; 149 | else icer_ceil_div_uint32(context_model->zero_count[sign_context], 2); 150 | } 151 | } 152 | } 153 | 154 | pos++; 155 | /* increment position pointers of 8 adjacent pixels */ 156 | h0++; h1++; v0++; v1++; d0++; d1++; d2++; d3++; 157 | } 158 | rowstart += rowstride; 159 | } 160 | while (encoder_context->used > 0) { 161 | res = icer_flush_encode(encoder_context); 162 | if (res != ICER_RESULT_OK) return res; 163 | } 164 | return ICER_RESULT_OK; 165 | } 166 | 167 | int icer_decompress_bitplane_uint8(uint8_t * const data, size_t plane_w, size_t plane_h, size_t rowstride, 168 | icer_context_model_typedef *context_model, 169 | icer_decoder_context_typedef *decoder_context, 170 | const icer_packet_context *pkt_context) { 171 | int res; 172 | uint8_t *pos; 173 | uint8_t *rowstart = data; 174 | int category; 175 | uint8_t bit; 176 | uint8_t lsb = pkt_context->lsb; 177 | 178 | uint8_t *h0, *h1, *v0, *v1, *d0, *d1, *d2, *d3; 179 | uint8_t h = 0, v = 0, d = 0, tmp; 180 | int8_t sh0, sh1, sv0, sv1; 181 | uint8_t sh, sv; 182 | uint8_t pred_sign, actual_sign, agreement_bit; 183 | enum icer_pixel_contexts sign_context; 184 | size_t vert_bound = plane_h - 1; 185 | size_t hor_bound = plane_w - 1; 186 | 187 | uint8_t prev_plane = lsb+1; 188 | if (prev_plane >= 8) return ICER_BITPLANE_OUT_OF_RANGE; 189 | 190 | for (size_t row = 0; row < plane_h; row++) { 191 | pos = rowstart; 192 | /* keep track of 8 adjacent pixels */ 193 | h0 = pos - 1; h1 = pos + 1; 194 | v0 = pos - rowstride; v1 = pos + rowstride; 195 | d0 = v0 - 1; d1 = v0 + 1; 196 | d2 = v1 - 1; d3 = v1 + 1; 197 | 198 | enum icer_pixel_contexts cntxt = 0; 199 | 200 | for (size_t col = 0; col < plane_w; col++) { 201 | category = get_bit_category_uint8(pos, lsb); 202 | 203 | if (category == ICER_CATEGORY_3) { 204 | /* pass to uncoded bin */ 205 | res = icer_decode_bit(decoder_context, &bit, 1, 2); 206 | if (res != ICER_RESULT_OK) return res; 207 | (*pos) |= bit << lsb; 208 | } else { 209 | if (category == ICER_CATEGORY_0 || category == ICER_CATEGORY_1) { 210 | h = 0; 211 | v = 0; 212 | d = 0; 213 | 214 | /* consider the horizontally adjacent pixels */ 215 | if (col > 0) h += get_bit_significance_uint8(h0, lsb) & 1; 216 | if (col < hor_bound) h += get_bit_significance_uint8(h1, prev_plane) & 1; 217 | 218 | /* consider the vertically adjacent pixels */ 219 | if (row > 0) v += get_bit_significance_uint8(v0, lsb) & 1; 220 | if (row < vert_bound) v += get_bit_significance_uint8(v1, prev_plane) & 1; 221 | 222 | /* consider the diagonally adjacent pixels */ 223 | if (col > 0 && row > 0) d += get_bit_significance_uint8(d0, lsb) & 1; 224 | if (col > 0 && row < vert_bound) d += get_bit_significance_uint8(d2, prev_plane) & 1; 225 | if (col < hor_bound && row > 0) d += get_bit_significance_uint8(d1, lsb) & 1; 226 | if (col < hor_bound && row < vert_bound) d += get_bit_significance_uint8(d3, prev_plane) & 1; 227 | } 228 | 229 | if (category == ICER_CATEGORY_0) { 230 | if (context_model->subband_type == ICER_SUBBAND_HL) { 231 | tmp = h; 232 | h = v; 233 | v = tmp; 234 | } 235 | 236 | if (context_model->subband_type != ICER_SUBBAND_HH) { 237 | cntxt = icer_context_table_ll_lh_hl[h][v][d]; 238 | } else { 239 | cntxt = icer_context_table_hh[h + v][d]; 240 | } 241 | } else if (category == ICER_CATEGORY_1) { 242 | cntxt = (h + v == 0) ? ICER_CONTEXT_9 : ICER_CONTEXT_10; 243 | } else if (category == ICER_CATEGORY_2) { 244 | cntxt = ICER_CONTEXT_11; 245 | } 246 | 247 | res = icer_decode_bit(decoder_context, &bit, context_model->zero_count[cntxt], context_model->total_count[cntxt]); 248 | if (res != ICER_RESULT_OK) return res; 249 | (*pos) |= bit << lsb; 250 | 251 | context_model->total_count[cntxt]++; 252 | context_model->zero_count[cntxt] += (uint32_t)(!bit); 253 | if (context_model->total_count[cntxt] >= ICER_CONTEXT_RESCALING_CAP) { 254 | context_model->total_count[cntxt] >>= 1; 255 | if (context_model->zero_count[cntxt] > context_model->total_count[cntxt]) context_model->zero_count[cntxt] >>= 1; 256 | else icer_ceil_div_uint32(context_model->zero_count[cntxt], 2); 257 | } 258 | 259 | if (category == ICER_CATEGORY_0 && bit) { 260 | /* bit is the first magnitude bit to be encoded, thus we will encode the sign bit */ 261 | /* predict sign bit */ 262 | sh0 = 0; sh1 = 0; 263 | sv0 = 0; sv1 = 0; 264 | 265 | /* consider the horizontally adjacent pixels */ 266 | if (col > 0) sh0 = get_sign_uint8(h0, lsb); 267 | if (col < hor_bound) sh1 = get_sign_uint8(h1, prev_plane); 268 | 269 | /* consider the vertically adjacent pixels */ 270 | if (row > 0) sv0 = get_sign_uint8(v0, lsb); 271 | if (row < vert_bound) sv1 = get_sign_uint8(v1, prev_plane); 272 | 273 | sh = sh0 + sh1 + 2; 274 | sv = sv0 + sv1 + 2; 275 | 276 | if (context_model->subband_type == ICER_SUBBAND_HL) { 277 | tmp = sh; 278 | sh = sv; 279 | sv = tmp; 280 | } 281 | 282 | sign_context = icer_sign_context_table[sh][sv]; 283 | pred_sign = icer_sign_prediction_table[sh][sv]; 284 | 285 | res = icer_decode_bit(decoder_context, &agreement_bit, context_model->zero_count[sign_context], context_model->total_count[sign_context]); 286 | if (res != ICER_RESULT_OK) return res; 287 | actual_sign = (agreement_bit ^ pred_sign) & 1; 288 | (*pos) |= actual_sign << 7; 289 | 290 | context_model->total_count[sign_context]++; 291 | context_model->zero_count[sign_context] += (uint32_t)(agreement_bit == 0); 292 | if (context_model->total_count[sign_context] >= ICER_CONTEXT_RESCALING_CAP) { 293 | context_model->total_count[sign_context] >>= 1; 294 | if (context_model->zero_count[sign_context] > context_model->total_count[sign_context]) context_model->zero_count[sign_context] >>= 1; 295 | else icer_ceil_div_uint32(context_model->zero_count[sign_context], 2); 296 | } 297 | } 298 | } 299 | 300 | pos++; 301 | /* increment position pointers of 8 adjacent pixels */ 302 | h0++; h1++; v0++; v1++; d0++; d1++; d2++; d3++; 303 | } 304 | rowstart += rowstride; 305 | } 306 | return ICER_RESULT_OK; 307 | } 308 | #endif 309 | 310 | #ifdef USE_UINT16_FUNCTIONS 311 | #ifdef USE_ENCODE_FUNCTIONS 312 | int icer_compress_bitplane_uint16(const uint16_t *data, size_t plane_w, size_t plane_h, size_t rowstride, 313 | icer_context_model_typedef *context_model, 314 | icer_encoder_context_typedef *encoder_context, 315 | const icer_packet_context *pkt_context) { 316 | int res; 317 | const uint16_t *pos; 318 | const uint16_t *rowstart = data; 319 | int category; 320 | bool bit; 321 | uint8_t lsb = pkt_context->lsb; 322 | uint16_t mask = 0b1 << lsb; 323 | 324 | const uint16_t *h0, *h1, *v0, *v1, *d0, *d1, *d2, *d3; 325 | uint8_t h = 0, v = 0, d = 0, tmp; 326 | int8_t sh0, sh1, sv0, sv1; 327 | uint8_t sh, sv; 328 | uint8_t pred_sign, actual_sign, agreement_bit; 329 | enum icer_pixel_contexts sign_context; 330 | size_t vert_bound = plane_h - 1; 331 | size_t hor_bound = plane_w - 1; 332 | 333 | uint8_t prev_plane = lsb+1; 334 | if (prev_plane >= 16) return ICER_BITPLANE_OUT_OF_RANGE; 335 | 336 | for (size_t row = 0; row < plane_h; row++) { 337 | pos = rowstart; 338 | /* keep track of 8 adjacent pixels */ 339 | h0 = pos - 1; h1 = pos + 1; 340 | v0 = pos - rowstride; v1 = pos + rowstride; 341 | d0 = v0 - 1; d1 = v0 + 1; 342 | d2 = v1 - 1; d3 = v1 + 1; 343 | 344 | enum icer_pixel_contexts cntxt = 0; 345 | 346 | for (size_t col = 0; col < plane_w; col++) { 347 | category = get_bit_category_uint16(pos, lsb); 348 | bit = ((*pos) & mask) != 0; 349 | 350 | if (category == ICER_CATEGORY_3) { 351 | /* pass to uncoded bin */ 352 | res = icer_encode_bit(encoder_context, bit, 1, 2); 353 | if (res != ICER_RESULT_OK) return res; 354 | } else { 355 | if (category == ICER_CATEGORY_0 || category == ICER_CATEGORY_1) { 356 | h = 0; 357 | v = 0; 358 | d = 0; 359 | 360 | /* consider the horizontally adjacent pixels */ 361 | if (col > 0) h += get_bit_significance_uint16(h0, lsb) & 1; 362 | if (col < hor_bound) h += get_bit_significance_uint16(h1, prev_plane) & 1; 363 | 364 | /* consider the vertically adjacent pixels */ 365 | if (row > 0) v += get_bit_significance_uint16(v0, lsb) & 1; 366 | if (row < vert_bound) v += get_bit_significance_uint16(v1, prev_plane) & 1; 367 | 368 | /* consider the diagonally adjacent pixels */ 369 | if (col > 0 && row > 0) d += get_bit_significance_uint16(d0, lsb) & 1; 370 | if (col > 0 && row < vert_bound) d += get_bit_significance_uint16(d2, prev_plane) & 1; 371 | if (col < hor_bound && row > 0) d += get_bit_significance_uint16(d1, lsb) & 1; 372 | if (col < hor_bound && row < vert_bound) d += get_bit_significance_uint16(d3, prev_plane) & 1; 373 | } 374 | 375 | if (category == ICER_CATEGORY_0) { 376 | if (context_model->subband_type == ICER_SUBBAND_HL) { 377 | tmp = h; 378 | h = v; 379 | v = tmp; 380 | } 381 | 382 | if (context_model->subband_type != ICER_SUBBAND_HH) { 383 | cntxt = icer_context_table_ll_lh_hl[h][v][d]; 384 | } else { 385 | cntxt = icer_context_table_hh[h + v][d]; 386 | } 387 | } else if (category == ICER_CATEGORY_1) { 388 | cntxt = (h + v == 0) ? ICER_CONTEXT_9 : ICER_CONTEXT_10; 389 | } else if (category == ICER_CATEGORY_2) { 390 | cntxt = ICER_CONTEXT_11; 391 | } 392 | 393 | res = icer_encode_bit(encoder_context, bit, context_model->zero_count[cntxt], context_model->total_count[cntxt]); 394 | if (res != ICER_RESULT_OK) return res; 395 | 396 | context_model->total_count[cntxt]++; 397 | context_model->zero_count[cntxt] += (uint32_t)(!bit); 398 | if (context_model->total_count[cntxt] >= ICER_CONTEXT_RESCALING_CAP) { 399 | context_model->total_count[cntxt] >>= 1; 400 | if (context_model->zero_count[cntxt] > context_model->total_count[cntxt]) context_model->zero_count[cntxt] >>= 1; 401 | else icer_ceil_div_uint32(context_model->zero_count[cntxt], 2); 402 | } 403 | 404 | if (category == ICER_CATEGORY_0 && bit) { 405 | /* bit is the first magnitude bit to be encoded, thus we will encode the sign bit */ 406 | /* predict sign bit */ 407 | sh0 = 0; sh1 = 0; 408 | sv0 = 0; sv1 = 0; 409 | 410 | /* consider the horizontally adjacent pixels */ 411 | if (col > 0) sh0 = get_sign_uint16(h0, lsb); 412 | if (col < hor_bound) sh1 = get_sign_uint16(h1, prev_plane); 413 | 414 | /* consider the vertically adjacent pixels */ 415 | if (row > 0) sv0 = get_sign_uint16(v0, lsb); 416 | if (row < vert_bound) sv1 = get_sign_uint16(v1, prev_plane); 417 | 418 | sh = sh0 + sh1 + 2; 419 | sv = sv0 + sv1 + 2; 420 | 421 | if (context_model->subband_type == ICER_SUBBAND_HL) { 422 | tmp = sh; 423 | sh = sv; 424 | sv = tmp; 425 | } 426 | 427 | sign_context = icer_sign_context_table[sh][sv]; 428 | pred_sign = icer_sign_prediction_table[sh][sv]; 429 | actual_sign = ((*pos) & 0x8000) != 0; 430 | 431 | agreement_bit = (pred_sign ^ actual_sign) & 1; 432 | 433 | res = icer_encode_bit(encoder_context, agreement_bit, context_model->zero_count[sign_context], context_model->total_count[sign_context]); 434 | if (res != ICER_RESULT_OK) return res; 435 | 436 | context_model->total_count[sign_context]++; 437 | context_model->zero_count[sign_context] += (uint32_t)(agreement_bit == 0); 438 | if (context_model->total_count[sign_context] >= ICER_CONTEXT_RESCALING_CAP) { 439 | context_model->total_count[sign_context] >>= 1; 440 | if (context_model->zero_count[sign_context] > context_model->total_count[sign_context]) context_model->zero_count[sign_context] >>= 1; 441 | else icer_ceil_div_uint32(context_model->zero_count[sign_context], 2); 442 | } 443 | } 444 | } 445 | 446 | pos++; 447 | /* increment position pointers of 8 adjacent pixels */ 448 | h0++; h1++; v0++; v1++; d0++; d1++; d2++; d3++; 449 | } 450 | rowstart += rowstride; 451 | } 452 | while (encoder_context->used > 0) { 453 | res = icer_flush_encode(encoder_context); 454 | if (res != ICER_RESULT_OK) return res; 455 | } 456 | return ICER_RESULT_OK; 457 | } 458 | #endif 459 | 460 | #ifdef USE_DECODE_FUNCTIONS 461 | int icer_decompress_bitplane_uint16(uint16_t * const data, size_t plane_w, size_t plane_h, size_t rowstride, 462 | icer_context_model_typedef *context_model, 463 | icer_decoder_context_typedef *decoder_context, 464 | const icer_packet_context *pkt_context) { 465 | int res; 466 | uint16_t *pos; 467 | uint16_t *rowstart = data; 468 | int category; 469 | uint8_t bit; 470 | uint8_t lsb = pkt_context->lsb; 471 | 472 | uint16_t *h0, *h1, *v0, *v1, *d0, *d1, *d2, *d3; 473 | uint8_t h = 0, v = 0, d = 0, tmp; 474 | int8_t sh0, sh1, sv0, sv1; 475 | uint8_t sh, sv; 476 | uint8_t pred_sign, agreement_bit; 477 | uint16_t actual_sign; 478 | enum icer_pixel_contexts sign_context; 479 | size_t vert_bound = plane_h - 1; 480 | size_t hor_bound = plane_w - 1; 481 | 482 | uint8_t prev_plane = lsb+1; 483 | if (prev_plane >= 16) return ICER_BITPLANE_OUT_OF_RANGE; 484 | 485 | for (size_t row = 0; row < plane_h; row++) { 486 | pos = rowstart; 487 | /* keep track of 8 adjacent pixels */ 488 | h0 = pos - 1; h1 = pos + 1; 489 | v0 = pos - rowstride; v1 = pos + rowstride; 490 | d0 = v0 - 1; d1 = v0 + 1; 491 | d2 = v1 - 1; d3 = v1 + 1; 492 | 493 | enum icer_pixel_contexts cntxt = 0; 494 | 495 | for (size_t col = 0; col < plane_w; col++) { 496 | category = get_bit_category_uint16(pos, lsb); 497 | 498 | if (category == ICER_CATEGORY_3) { 499 | /* pass to uncoded bin */ 500 | res = icer_decode_bit(decoder_context, &bit, 1, 2); 501 | if (res != ICER_RESULT_OK) return res; 502 | (*pos) |= (uint16_t)bit << lsb; 503 | } else { 504 | if (category == ICER_CATEGORY_0 || category == ICER_CATEGORY_1) { 505 | h = 0; 506 | v = 0; 507 | d = 0; 508 | 509 | /* consider the horizontally adjacent pixels */ 510 | if (col > 0) h += get_bit_significance_uint16(h0, lsb) & 1; 511 | if (col < hor_bound) h += get_bit_significance_uint16(h1, prev_plane) & 1; 512 | 513 | /* consider the vertically adjacent pixels */ 514 | if (row > 0) v += get_bit_significance_uint16(v0, lsb) & 1; 515 | if (row < vert_bound) v += get_bit_significance_uint16(v1, prev_plane) & 1; 516 | 517 | /* consider the diagonally adjacent pixels */ 518 | if (col > 0 && row > 0) d += get_bit_significance_uint16(d0, lsb) & 1; 519 | if (col > 0 && row < vert_bound) d += get_bit_significance_uint16(d2, prev_plane) & 1; 520 | if (col < hor_bound && row > 0) d += get_bit_significance_uint16(d1, lsb) & 1; 521 | if (col < hor_bound && row < vert_bound) d += get_bit_significance_uint16(d3, prev_plane) & 1; 522 | } 523 | 524 | if (category == ICER_CATEGORY_0) { 525 | if (context_model->subband_type == ICER_SUBBAND_HL) { 526 | tmp = h; 527 | h = v; 528 | v = tmp; 529 | } 530 | 531 | if (context_model->subband_type != ICER_SUBBAND_HH) { 532 | cntxt = icer_context_table_ll_lh_hl[h][v][d]; 533 | } else { 534 | cntxt = icer_context_table_hh[h + v][d]; 535 | } 536 | } else if (category == ICER_CATEGORY_1) { 537 | cntxt = (h + v == 0) ? ICER_CONTEXT_9 : ICER_CONTEXT_10; 538 | } else if (category == ICER_CATEGORY_2) { 539 | cntxt = ICER_CONTEXT_11; 540 | } 541 | 542 | res = icer_decode_bit(decoder_context, &bit, context_model->zero_count[cntxt], context_model->total_count[cntxt]); 543 | if (res != ICER_RESULT_OK) return res; 544 | (*pos) |= (uint16_t)bit << lsb; 545 | 546 | context_model->total_count[cntxt]++; 547 | context_model->zero_count[cntxt] += (uint32_t)(!bit); 548 | if (context_model->total_count[cntxt] >= ICER_CONTEXT_RESCALING_CAP) { 549 | context_model->total_count[cntxt] >>= 1; 550 | if (context_model->zero_count[cntxt] > context_model->total_count[cntxt]) context_model->zero_count[cntxt] >>= 1; 551 | else icer_ceil_div_uint32(context_model->zero_count[cntxt], 2); 552 | } 553 | 554 | if (category == ICER_CATEGORY_0 && bit) { 555 | /* bit is the first magnitude bit to be encoded, thus we will encode the sign bit */ 556 | /* predict sign bit */ 557 | sh0 = 0; sh1 = 0; 558 | sv0 = 0; sv1 = 0; 559 | 560 | /* consider the horizontally adjacent pixels */ 561 | if (col > 0) sh0 = get_sign_uint16(h0, lsb); 562 | if (col < hor_bound) sh1 = get_sign_uint16(h1, prev_plane); 563 | 564 | /* consider the vertically adjacent pixels */ 565 | if (row > 0) sv0 = get_sign_uint16(v0, lsb); 566 | if (row < vert_bound) sv1 = get_sign_uint16(v1, prev_plane); 567 | 568 | sh = sh0 + sh1 + 2; 569 | sv = sv0 + sv1 + 2; 570 | 571 | if (context_model->subband_type == ICER_SUBBAND_HL) { 572 | tmp = sh; 573 | sh = sv; 574 | sv = tmp; 575 | } 576 | 577 | sign_context = icer_sign_context_table[sh][sv]; 578 | pred_sign = icer_sign_prediction_table[sh][sv]; 579 | 580 | res = icer_decode_bit(decoder_context, &agreement_bit, context_model->zero_count[sign_context], context_model->total_count[sign_context]); 581 | if (res != ICER_RESULT_OK) return res; 582 | actual_sign = (agreement_bit ^ pred_sign) & 1; 583 | (*pos) |= actual_sign << 15; 584 | 585 | context_model->total_count[sign_context]++; 586 | context_model->zero_count[sign_context] += (uint32_t)(agreement_bit == 0); 587 | if (context_model->total_count[sign_context] >= ICER_CONTEXT_RESCALING_CAP) { 588 | context_model->total_count[sign_context] >>= 1; 589 | if (context_model->zero_count[sign_context] > context_model->total_count[sign_context]) context_model->zero_count[sign_context] >>= 1; 590 | else icer_ceil_div_uint32(context_model->zero_count[sign_context], 2); 591 | } 592 | } 593 | } 594 | 595 | pos++; 596 | /* increment position pointers of 8 adjacent pixels */ 597 | h0++; h1++; v0++; v1++; d0++; d1++; d2++; d3++; 598 | } 599 | rowstart += rowstride; 600 | } 601 | return ICER_RESULT_OK; 602 | } 603 | #endif 604 | #endif 605 | 606 | 607 | void icer_init_context_model_vals(icer_context_model_typedef* context_model, enum icer_subband_types subband_type) { 608 | context_model->subband_type = subband_type; 609 | for (size_t i = 0;i <= ICER_CONTEXT_MAX;i++) { 610 | context_model->zero_count[i] = ICER_DEFAULT_CONTEXT_ZERO_COUNT; 611 | context_model->total_count[i] = ICER_DEFAULT_CONTEXT_TOTAL_COUNT; 612 | } 613 | } 614 | 615 | #ifdef USE_UINT8_FUNCTIONS 616 | static inline uint8_t get_bit_category_uint8(const uint8_t* data, uint8_t lsb) { 617 | int msb = 32 - (__builtin_clz(((*data) & 0x7f) | 0b1)) - 1; 618 | return icer_min_int((msb < lsb) ? 0 : msb - lsb, 3); 619 | } 620 | 621 | static inline bool get_bit_significance_uint8(const uint8_t* data, uint8_t lsb) { 622 | return __builtin_popcount(((*data) & 0x7f) >> lsb) != 0; 623 | } 624 | 625 | static inline int8_t get_sign_uint8(const uint8_t* data, uint8_t lsb) { 626 | return (int8_t)(((int8_t)(*data) >> 7) * (int8_t)get_bit_significance_uint8(data, lsb)); 627 | } 628 | #endif 629 | 630 | #ifdef USE_UINT16_FUNCTIONS 631 | static inline uint8_t get_bit_category_uint16(const uint16_t* data, uint8_t lsb) { 632 | int msb = 32 - (__builtin_clz(((*data) & 0x7fff) | 0b1)) - 1; 633 | return icer_min_int((msb < lsb) ? 0 : msb - lsb, 3); 634 | } 635 | 636 | static inline bool get_bit_significance_uint16(const uint16_t* data, uint8_t lsb) { 637 | return __builtin_popcount(((*data) & 0x7fff) >> lsb) != 0; 638 | } 639 | 640 | static inline int8_t get_sign_uint16(const uint16_t* data, uint8_t lsb) { 641 | return (int8_t)(((int16_t)(*data) >> 15) * (int8_t)get_bit_significance_uint16(data, lsb)); 642 | } 643 | #endif 644 | --------------------------------------------------------------------------------