├── Makefile ├── README.md └── jpeg_encoder.c /Makefile: -------------------------------------------------------------------------------- 1 | all: release 2 | 3 | clean: 4 | rm -f jpeg_encoder 5 | 6 | release: clean jpeg_encoder.c 7 | gcc -ggdb -O0 -lm -Wall jpeg_encoder.c -o jpeg_encoder 8 | 9 | info: clean jpeg_encoder.c 10 | gcc -ggdb -DINFO -O0 -lm -Wall jpeg_encoder.c -o jpeg_encoder 11 | 12 | debug: clean jpeg_encoder.c 13 | gcc -ggdb -DDEBUG -O0 -lm -Wall jpeg_encoder.c -o jpeg_encoder 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Jpeg Encoder 2 | ============ 3 | 4 | This is a minimalistic implementation of a JPEG encoder for demonstration purposes. It has the following features/limitations: 5 | 6 | * baseline-DCT profile 7 | * fixed 4:2:0 chroma subsampling 8 | * dynamic luma/chroma quantization 9 | * only dimensions which are multiples of 16 are supported 10 | * dynamic huffman table creation 11 | 12 | Only ``PPM`` image files are accepted as input. -------------------------------------------------------------------------------- /jpeg_encoder.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Minimalistic JPEG Encoder 3 | * baseline-DCT profile 4 | * fixed 4:2:0 chroma subsampling 5 | * dynamic luma/chroma quantization 6 | * only dimensions which are multiples of 16 are supported 7 | * dynamic huffman table creation 8 | * 9 | * Schier Michael, April 2011 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | // ==================================================================================================================== 19 | 20 | #define MAX(a,b) (((a)>(b))?(a):(b)) 21 | #define MIN(a,b) (((a)<(b))?(a):(b)) 22 | #define CLIP(n, min, max) MIN((MAX((n),(min))), (max)) 23 | 24 | // ==================================================================================================================== 25 | 26 | /* 27 | * ISO/IEC 10918-1/ K.2 28 | */ 29 | typedef struct __huff_code 30 | { 31 | int sym_freq[257]; // frequency of occurrence of symbol i 32 | int code_len[257]; // code length of symbol i 33 | int next[257]; // index to next symbol in chain of all symbols in current branch of code tree 34 | int code_len_freq[32]; // the frequencies of huff-symbols of length i 35 | int sym_sorted[256]; // the symbols to be encoded 36 | int sym_code_len[256]; // the huffman code length of symbol i 37 | int sym_code[256]; // the huffman code of the symbol i 38 | } huff_code; 39 | 40 | typedef struct __jpeg_data 41 | { 42 | // image dimensions 43 | int width; 44 | int height; 45 | int num_pixel; // = width*height 46 | 47 | // RGB data of the input image 48 | int* red; 49 | int* green; 50 | int* blue; 51 | 52 | // YCbCr for the colorspace-conversion 53 | int* y; 54 | int* cb; 55 | int* cr; 56 | 57 | // sub-sampled chroma 58 | int* cb_sub; 59 | int* cr_sub; 60 | 61 | // dct coefficients: 64 coefficients of the first block, then the second block... 62 | double* dct_y; 63 | double* dct_cb; 64 | double* dct_cr; 65 | 66 | // quantized dct coefficients 67 | int* dct_y_quant; 68 | int* dct_cb_quant; 69 | int* dct_cr_quant; 70 | 71 | // huffman entropy coding parameters 72 | huff_code luma_dc; 73 | huff_code luma_ac; 74 | huff_code chroma_dc; 75 | huff_code chroma_ac; 76 | 77 | } jpeg_data; 78 | 79 | // ==================================================================================================================== 80 | 81 | /* 82 | * stop-watch used for time measurements 83 | */ 84 | double timer() 85 | { 86 | static double last_call = 0; 87 | static struct timeval arg; 88 | gettimeofday(&arg, NULL); 89 | double ret = arg.tv_sec*1000.0 + arg.tv_usec/1000.0 - last_call; 90 | last_call = arg.tv_sec*1000.0 + arg.tv_usec/1000.0; 91 | return ret; 92 | } 93 | 94 | // ==================================================================================================================== 95 | 96 | /* 97 | * print the DCT coefficients of a color channel 98 | */ 99 | void print_dct_coeffs(int num_pixel, int dct[]) 100 | { 101 | int i; 102 | for (i=0; i0) 158 | { 159 | *(--c) = (x%2) ? '1' : '0'; 160 | x/=2; 161 | } 162 | return c; 163 | } 164 | 165 | // ==================================================================================================================== 166 | 167 | /* 168 | * allocates the space needed for the globally used struct jpeg_data 169 | */ 170 | int alloc_jpeg_data(jpeg_data* data) 171 | { 172 | data->red = malloc(data->num_pixel*sizeof(int)); 173 | data->green = malloc(data->num_pixel*sizeof(int)); 174 | data->blue = malloc(data->num_pixel*sizeof(int)); 175 | 176 | data->y = malloc(data->num_pixel*sizeof(int)); 177 | data->cb = malloc(data->num_pixel*sizeof(int)); 178 | data->cr = malloc(data->num_pixel*sizeof(int)); 179 | 180 | data->cb_sub = malloc(data->num_pixel/4*sizeof(int)); 181 | data->cr_sub = malloc(data->num_pixel/4*sizeof(int)); 182 | 183 | data->dct_y = malloc(data->num_pixel*sizeof(double)); 184 | data->dct_cb = malloc(data->num_pixel/4*sizeof(double)); 185 | data->dct_cr = malloc(data->num_pixel/4*sizeof(double)); 186 | 187 | data->dct_y_quant = malloc(data->num_pixel*sizeof(int)); 188 | data->dct_cb_quant = malloc(data->num_pixel/4*sizeof(int)); 189 | data->dct_cr_quant = malloc(data->num_pixel/4*sizeof(int)); 190 | 191 | if (data->red == NULL || data->green == NULL || data->blue == NULL || data->y == NULL || data->cb == NULL || data->cr == NULL || data->cb_sub == NULL || data->cr_sub == NULL 192 | || data->dct_y == NULL || data->dct_cb == NULL || data->dct_cr == NULL || data->dct_y_quant == NULL || data->dct_cb_quant == NULL || data->dct_cr_quant == NULL) 193 | { 194 | fprintf(stderr, "Could not allocate enough memory for image processing\n"); 195 | return -1; 196 | } 197 | return 0; 198 | } 199 | 200 | // ==================================================================================================================== 201 | 202 | /* 203 | * for illustration purposes, saves all color channels in a separate ppm file 204 | */ 205 | void save_channels(jpeg_data* data) 206 | { 207 | FILE* f = fopen("channels.ppm", "w"); 208 | fprintf(f, "P6\n%d %d\n255\n", data->width*3, data->height*3); 209 | 210 | int r,c; 211 | for (r=0; rheight*3; r++) 212 | for (c=0; cwidth*3; c++) 213 | { 214 | int i = (r%data->height)*data->width + (c%data->width); 215 | int j = (r%data->height)/2*data->width/2 + (c%data->width)/2; 216 | if (rheight) 217 | { 218 | if (cwidth) 219 | { 220 | fputc(data->red[i], f); 221 | fputc(0, f); 222 | fputc(0, f); 223 | } 224 | else if (c<2*data->width) 225 | { 226 | fputc(0, f); 227 | fputc(data->green[i], f); 228 | fputc(0, f); 229 | } 230 | else 231 | { 232 | fputc(0, f); 233 | fputc(0, f); 234 | fputc(data->blue[i], f); 235 | } 236 | } 237 | else if (rheight*2) 238 | { 239 | if (cwidth) 240 | { 241 | fputc(data->y[i], f); 242 | fputc(data->y[i], f); 243 | fputc(data->y[i], f); 244 | } 245 | else if (c<2*data->width) 246 | { 247 | fputc(data->cb[i], f); 248 | fputc(data->cb[i], f); 249 | fputc(data->cb[i], f); 250 | } 251 | else 252 | { 253 | fputc(data->cr[i], f); 254 | fputc(data->cr[i], f); 255 | fputc(data->cr[i], f); 256 | } 257 | } 258 | else 259 | { 260 | if (cwidth) 261 | { 262 | fputc(data->red[i], f); 263 | fputc(data->green[i], f); 264 | fputc(data->blue[i], f); 265 | } 266 | else if (c<2*data->width) 267 | { 268 | fputc(data->cb_sub[j], f); 269 | fputc(data->cb_sub[j], f); 270 | fputc(data->cb_sub[j], f); 271 | } 272 | else 273 | { 274 | fputc(data->cr_sub[j], f); 275 | fputc(data->cr_sub[j], f); 276 | fputc(data->cr_sub[j], f); 277 | } 278 | } 279 | } 280 | 281 | fclose(f); 282 | } 283 | 284 | // ==================================================================================================================== 285 | 286 | /* 287 | * Typical PPM File: 288 | * P6\n 289 | * # comment (optional)\n 290 | * width height\n 291 | * bit_depth_per_channel\n 292 | * binary_data 293 | */ 294 | int read_ppm(FILE* f, jpeg_data* data) 295 | { 296 | if( fgetc(f) != 'P' || fgetc(f) != '6' ) 297 | { 298 | fprintf(stderr, "Could not find magic number for this PPM!\n"); 299 | return -1; 300 | } 301 | 302 | if (fgetc(f) != '\n' ) 303 | goto X; 304 | 305 | char buf[1024]; 306 | while(1) 307 | { 308 | char* p = buf; 309 | while ((*p = fgetc(f)) != '\n') 310 | p++; 311 | *p = '\0'; 312 | 313 | if (buf[0] != '#') 314 | break; 315 | #ifdef DEBUG 316 | else 317 | printf("PPM Comment: %s\n", buf+1); 318 | #endif 319 | } 320 | 321 | if (sscanf(buf, "%d %d\n", &data->width, &data->height) != 2) 322 | goto X; 323 | #ifdef DEBUG 324 | printf("Dimension: %dx%d\n", data->width, data->height); 325 | #endif 326 | data->num_pixel = data->width * data->height; 327 | if (data->width%16 != 0 || data->height%16 != 0) 328 | { 329 | fprintf(stderr, "Only pictures with dimensions which are multiples of 16 are supported!\n"); 330 | return -1; 331 | } 332 | 333 | int depth; 334 | if (fscanf(f, "%d\n", &depth) != 1) 335 | goto X; 336 | 337 | if (depth != 255) 338 | { 339 | printf("For simplicity, only a bit-depth of 256 is supported!\n"); 340 | return -1; 341 | } 342 | 343 | long len = ftell(f); 344 | fseek(f, 0L, SEEK_END); 345 | len = ftell(f) - len; 346 | fseek(f, -len, SEEK_END); 347 | if (len != 3*data->num_pixel) // 3 color channels 348 | goto X; 349 | 350 | if (alloc_jpeg_data(data)) 351 | return -1; 352 | 353 | int i; 354 | for (i=0; inum_pixel; i++) 355 | { 356 | data->red[i] = fgetc(f); 357 | data->green[i] = fgetc(f); 358 | data->blue[i] = fgetc(f); 359 | } 360 | 361 | return 0; 362 | 363 | X: fprintf(stderr, "Could not parse the PPM file properly\n"); 364 | return -1; 365 | } 366 | 367 | // ==================================================================================================================== 368 | 369 | /* 370 | * converts the rgb data to ycbcr data 371 | */ 372 | int rgb_to_ycbcr(jpeg_data* data) 373 | { 374 | int i; 375 | for (i=0; inum_pixel; i++) 376 | { 377 | data->y[i] = 0.299 * data->red[i] + 0.587 * data->green[i] + 0.114 * data->blue[i]; 378 | data->cb[i] = 128 - 0.168736 * data->red[i] - 0.331264 * data->green[i] + 0.5 * data->blue[i]; 379 | data->cr[i] = 128 + 0.5 * data->red[i] - 0.418688 * data->green[i] - 0.081312 * data->blue[i]; 380 | assert( 0<=data->y[i] && data->y[i]<=255); 381 | assert( 0<=data->cb[i] && data->cb[i]<=255 ); 382 | assert( 0<=data->cr[i] && data->cr[i]<=255 ); 383 | } 384 | 385 | return 0; 386 | } 387 | 388 | // ==================================================================================================================== 389 | 390 | /* 391 | * subsamples the cb and cr channels (to c?_sub) 392 | */ 393 | void subsample_chroma(jpeg_data* data) 394 | { 395 | int h,w; 396 | for (h=0; hheight/2; h++) 397 | for (w=0; wwidth/2; w++) 398 | { 399 | int i = 2*h*data->width + 2*w; 400 | data->cb_sub[h*data->width/2+w] = ( data->cb[i] + data->cb[i+1] + data->cb[i+data->width] + data->cb[i+data->width+1] ) / 4; 401 | data->cr_sub[h*data->width/2+w] = ( data->cr[i] + data->cr[i+1] + data->cr[i+data->width] + data->cr[i+data->width+1] ) / 4; 402 | assert( 0<=data->cb_sub[h*data->width/2+w] && data->cb_sub[h*data->width/2+w]<=255 ); 403 | assert( 0<=data->cr_sub[h*data->width/2+w] && data->cr_sub[h*data->width/2+w]<=255 ); 404 | } 405 | } 406 | 407 | // ==================================================================================================================== 408 | 409 | /* 410 | * builds a lookup table to speed up the discrete cosine transform 411 | */ 412 | double cos_lookup[8][8]; 413 | void init_dct_lookup() 414 | { 415 | int i, j; 416 | for (i=0; i<8; i++) 417 | for (j=0; j<8; j++) 418 | { 419 | cos_lookup[i][j] = cos( (2*i+1)*j*M_PI/16 ); 420 | assert( -1<=cos_lookup[i][j] && cos_lookup[i][j]<=1 ); 421 | } 422 | } 423 | 424 | /* 425 | * the discrete cosine transform per 8x8 block - outputs floating point values 426 | * optimized by using lookup tables and splitting the terms 427 | */ 428 | inline void dct_block(int gap, int in[], double out[]) 429 | { 430 | int x_f, y_f; // frequency domain coordinates 431 | int x_t, y_t; // time domain coordinates 432 | 433 | double inner_lookup[8][8]; 434 | for (x_t=0; x_t<8; x_t++) 435 | for (y_f=0; y_f<8; y_f++) 436 | { 437 | inner_lookup[x_t][y_f] = 0; 438 | for (y_t=0; y_t<8; y_t++) 439 | inner_lookup[x_t][y_f] += ( in[y_t*gap+x_t] - 128 ) * cos_lookup[y_t][y_f]; 440 | 441 | } 442 | 443 | // freq(x_f,y_f) = ... 444 | double freq; 445 | for (y_f=0; y_f<8; y_f++) 446 | for (x_f=0; x_f<8; x_f++) 447 | { 448 | freq = 0; 449 | for(x_t=0; x_t<8; x_t++) 450 | freq += inner_lookup[x_t][y_f] * cos_lookup[x_t][x_f]; 451 | 452 | if (x_f == 0) 453 | freq *= M_SQRT1_2; 454 | if (y_f == 0) 455 | freq *= M_SQRT1_2; 456 | freq /= 4; 457 | 458 | out[y_f*8+x_f] = freq; 459 | } 460 | } 461 | 462 | /* 463 | * perform the discrete cosine transform 464 | */ 465 | void dct(int blocks_horiz, int blocks_vert, int in[], double out[]) 466 | { 467 | int h,v; 468 | for (v=0; vcode_len[i] = 0; 585 | hc->next[i] = -1; 586 | } 587 | 588 | // derive the code length for each symbol 589 | while (1) 590 | { 591 | int v1 = -1; 592 | int v2 = -1; 593 | int i; 594 | // find least value of freq(v1) and next least value of freq(v2) 595 | for (i=0; i<257; i++) 596 | { 597 | if (hc->sym_freq[i] == 0) 598 | continue; 599 | if ( v1 == -1 || hc->sym_freq[i] <= hc->sym_freq[v1] ) 600 | { 601 | v2 = v1; 602 | v1 = i; 603 | } 604 | else if (v2 == -1 || hc->sym_freq[i] <= hc->sym_freq[v2]) 605 | v2 = i; 606 | } 607 | if (v2 == -1) 608 | break; 609 | 610 | hc->sym_freq[v1] += hc->sym_freq[v2]; 611 | hc->sym_freq[v2] = 0; 612 | while (1) 613 | { 614 | hc->code_len[v1]++; 615 | if (hc->next[v1] == -1) 616 | break; 617 | v1 = hc->next[v1]; 618 | } 619 | hc->next[v1] = v2; 620 | while (1) 621 | { 622 | hc->code_len[v2]++; 623 | if (hc->next[v2] == -1) 624 | break; 625 | v2 = hc->next[v2]; 626 | } 627 | } 628 | 629 | for (i=0; i<32; i++) 630 | hc->code_len_freq[i] = 0; 631 | 632 | // derive code length frequencies 633 | for (i=0; i<257; i++) 634 | if (hc->code_len[i] != 0) 635 | hc->code_len_freq[hc->code_len[i]]++; 636 | 637 | // limit the huffman code length to 16 bits 638 | i=31; 639 | while (1) 640 | { 641 | if (hc->code_len_freq[i] > 0) // if the code is too long ... 642 | { 643 | int j = i-1; 644 | while (hc->code_len_freq[--j] <= 0); // ... we search for an upper layer containing leaves 645 | hc->code_len_freq[i] -= 2; // we remove the two leaves from the lowest layer 646 | hc->code_len_freq[i-1]++; // and put one of them one position higher 647 | hc->code_len_freq[j+1] += 2; // the other one goes at a new branch ... 648 | hc->code_len_freq[j]--; // ... together with the leave node which was there before 649 | continue; 650 | } 651 | i--; 652 | if (i!=16) 653 | continue; 654 | while (hc->code_len_freq[i] == 0) 655 | i--; 656 | hc->code_len_freq[i]--; // remove one leave from the lowest layer (the bottom symbol '111...111') 657 | break; 658 | } 659 | 660 | // sort the input symbols according to their code size 661 | for (i=0; i<256; i++) 662 | hc->sym_sorted[i] = -1; 663 | int j; 664 | int k = 0; 665 | for (i=1; i<32; i++) 666 | for (j=0; j<256; j++) 667 | if (hc->code_len[j] == i) 668 | hc->sym_sorted[k++] = j; 669 | 670 | // determine the size of the huffman code symbols - this may differ from code_len because 671 | // of the 16 bit limit 672 | for (i=0; i<256; i++) 673 | hc->sym_code_len[i] = 0; 674 | k=0; 675 | for (i=1; i<=16; i++) 676 | for (j=1; j<=hc->code_len_freq[i]; j++) 677 | hc->sym_code_len[hc->sym_sorted[k++]] = i; 678 | hc->sym_code_len[hc->sym_sorted[k]] = 0; 679 | 680 | // generate the codes for the symbols 681 | for (i=0; i<256; i++) 682 | hc->sym_code[i] = -1; 683 | k = 0; 684 | int code = 0; 685 | int si = hc->sym_code_len[hc->sym_sorted[0]]; 686 | while (1) 687 | { 688 | do 689 | { 690 | hc->sym_code[hc->sym_sorted[k]] = code; 691 | k++; 692 | code++; 693 | } while (hc->sym_code_len[hc->sym_sorted[k]] == si); 694 | if (hc->sym_code_len[hc->sym_sorted[k]] == 0) 695 | break; 696 | do 697 | { 698 | code <<= 1; 699 | si++; 700 | } while (hc->sym_code_len[hc->sym_sorted[k]] != si); 701 | } 702 | } 703 | 704 | /* 705 | * map the value to its class 706 | * Class-id DC/AC-coeff delta 707 | * ----------------------------------------- 708 | * 0 0 709 | * 1 -1,1 710 | * 2 -3,-2,2,3 711 | * 3 -7,-6,-5,-4,4,5,6,7 712 | * 4 -15,...,-8,8,...,15 713 | * 5 -31,...,-16,16,...31 714 | * 6 -63,...,-32,32,...63 715 | * 7 -127,...,-64,64,...,127 716 | * 8 -255,...,-128,128,...,255 717 | * 9 -511,...,-256,256,...,511 718 | * 10 -1023,...,-512,512,...,1023 719 | * 11 -2047,...,-1024,1024,...,2047 720 | */ 721 | int huff_class(int value) 722 | { 723 | value = value<0 ? -value : value; 724 | int class = 0; 725 | while (value>0) 726 | { 727 | value = value>>1; 728 | class++; 729 | } 730 | return class; 731 | } 732 | 733 | /* 734 | * determine frequencies (DC) - mapped to classes 735 | */ 736 | void calc_dc_freq(int num_pixel, int dct_quant[], int freq[]) 737 | { 738 | int i; 739 | for (i=0; ii; last_nonzero--) 756 | if (dct_quant[last_nonzero] != 0) 757 | break; 758 | continue; 759 | } 760 | 761 | if (i == last_nonzero + 1) 762 | { 763 | freq[0x00]++; // EOB byte 764 | // jump to the next block 765 | i = (i/64+1)*64-1; 766 | continue; 767 | } 768 | 769 | if (dct_quant[i] == 0) 770 | { 771 | num_zeros++; 772 | if (num_zeros == 16) 773 | { 774 | freq[0xF0]++; // ZRL byte 775 | num_zeros = 0; 776 | } 777 | continue; 778 | } 779 | 780 | freq[ ((num_zeros<<4)&0xF0) | (huff_class(dct_quant[i])&0x0F) ]++; 781 | num_zeros = 0; 782 | } 783 | } 784 | 785 | /* 786 | * construct 4 huffman tables for DC/(num_zeros+AC) luma/chroma coefficients 787 | */ 788 | void init_huffman(jpeg_data* data) 789 | { 790 | int i; 791 | 792 | huff_code* luma_dc = &data->luma_dc; 793 | huff_code* luma_ac = &data->luma_ac; 794 | huff_code* chroma_dc = &data->chroma_dc; 795 | huff_code* chroma_ac = &data->chroma_ac; 796 | 797 | // initialize 798 | for (i=0; i<257; i++) 799 | luma_dc->sym_freq[i] = luma_ac->sym_freq[i] = chroma_dc->sym_freq[i] = chroma_ac->sym_freq[i] = 0; 800 | // reserve one code point 801 | luma_dc->sym_freq[256] = luma_ac->sym_freq[256] = chroma_dc->sym_freq[256] = chroma_ac->sym_freq[256] = 1; 802 | 803 | // calculate frequencies as basis for the huffman table construction 804 | calc_dc_freq(data->num_pixel, data->dct_y_quant, luma_dc->sym_freq); 805 | calc_ac_freq(data->num_pixel, data->dct_y_quant, luma_ac->sym_freq); 806 | calc_dc_freq(data->num_pixel/4, data->dct_cb_quant, chroma_dc->sym_freq); 807 | calc_dc_freq(data->num_pixel/4, data->dct_cr_quant, chroma_dc->sym_freq); 808 | calc_ac_freq(data->num_pixel/4, data->dct_cb_quant, chroma_ac->sym_freq); 809 | calc_ac_freq(data->num_pixel/4, data->dct_cr_quant, chroma_ac->sym_freq); 810 | 811 | #ifdef DEBUG 812 | printf("********** Symbol frequencies ( i, sym_freq[i] )\n"); 813 | printf(" Code Luma-DC Luma-AC Chroma-DC Chroma-AC\n"); 814 | for (i=0; i<256; i++) 815 | if (luma_dc->sym_freq[i] || luma_ac->sym_freq[i] || chroma_dc->sym_freq[i] || chroma_ac->sym_freq[i]) 816 | printf(" %2x %10.d %10.d %10.d %10.d\n", i, luma_dc->sym_freq[i], luma_ac->sym_freq[i], chroma_dc->sym_freq[i], chroma_ac->sym_freq[i]); 817 | #endif 818 | 819 | timer(); 820 | printf("Initializing the luma DC Huffman tables "); 821 | init_huff_table(luma_dc); 822 | printf("%10.3f ms\n", timer()); 823 | 824 | printf("Initializing the luma AC Huffman tables "); 825 | init_huff_table(luma_ac); 826 | printf("%10.3f ms\n", timer()); 827 | 828 | printf("Initializing the chroma DC Huffman tables"); 829 | init_huff_table(chroma_dc); 830 | printf("%10.3f ms\n", timer()); 831 | 832 | printf("Initializing the chroma AC Huffman tables"); 833 | init_huff_table(chroma_ac); 834 | printf("%10.3f ms\n", timer()); 835 | 836 | #ifdef INFO 837 | printf("\n********** Encoded symbol lengths ( i, code_len[i] )\n"); 838 | printf(" Code Luma-DC Luma-AC Chroma-DC Chroma-AC\n"); 839 | for (i=0; i<256; i++) 840 | if (luma_dc->code_len[i] || luma_ac->code_len[i] || chroma_dc->code_len[i] || chroma_ac->code_len[i]) 841 | printf(" %2x %10.d %10.d %10.d %10.d\n", i, luma_dc->code_len[i], luma_ac->code_len[i], chroma_dc->code_len[i], chroma_ac->code_len[i]); 842 | 843 | printf("\n********** Encoded symbol length frequencies ( i, code_len_freq[i] )\n"); 844 | printf("Length Luma-DC Luma-AC Chroma-DC Chroma-AC\n"); 845 | for (i=0; i<32; i++) 846 | if (luma_dc->code_len_freq[i] || luma_ac->code_len_freq[i] || chroma_dc->code_len_freq[i] || chroma_ac->code_len_freq[i]) 847 | printf("%6d %10.d %10.d %10.d %10.d\n", i, luma_dc->code_len_freq[i], luma_ac->code_len_freq[i], chroma_dc->code_len_freq[i], chroma_ac->code_len_freq[i]); 848 | 849 | printf("\n********** Symbols ordered by code length ( i, sym_sorted[i], code_len[sym_sorted[i]] )\n"); 850 | printf(" Rank Luma-DC Luma-AC Chroma-DC Chroma-AC\n"); 851 | for (i=0; i<256; i++) 852 | if (luma_dc->sym_sorted[i]>=0 || luma_ac->sym_sorted[i]>=0 || chroma_dc->sym_sorted[i]>=0 || chroma_ac->sym_sorted[i]>=0) 853 | printf("%6d %8x %2.d %8x %2.d %8x %2.d %8x %2.d\n", i, 854 | luma_dc->sym_sorted[i], luma_dc->sym_sorted[i] ==-1 ? 0 : luma_dc->code_len[luma_dc->sym_sorted[i]], 855 | luma_ac->sym_sorted[i], luma_ac->sym_sorted[i] ==-1 ? 0 : luma_ac->code_len[luma_ac->sym_sorted[i]], 856 | chroma_dc->sym_sorted[i], chroma_dc->sym_sorted[i]==-1 ? 0 : chroma_dc->code_len[chroma_dc->sym_sorted[i]], 857 | chroma_ac->sym_sorted[i], chroma_ac->sym_sorted[i]==-1 ? 0 : chroma_ac->code_len[chroma_ac->sym_sorted[i]]); 858 | 859 | printf("\n********** Huffman code words sorted (i, sym_code[i], sym_code_len[i])\n"); 860 | printf(" Code Luma-DC Luma-AC Chroma-DC Chroma-AC\n"); 861 | for (i=0; i<256; i++) 862 | if (luma_dc->sym_code_len[i] || luma_ac->sym_code_len[i] || chroma_dc->sym_code_len[i] || chroma_ac->sym_code_len[i]) 863 | printf(" %2x %16s %2.d %16s %2.d %16s %2.d %16s %2.d\n", i, 864 | binary_string(luma_dc->sym_code[i], luma_dc->sym_code_len[i]), luma_dc->sym_code_len[i], 865 | binary_string(luma_ac->sym_code[i], luma_ac->sym_code_len[i]), luma_ac->sym_code_len[i], 866 | binary_string(chroma_dc->sym_code[i], chroma_dc->sym_code_len[i]), chroma_dc->sym_code_len[i], 867 | binary_string(chroma_ac->sym_code[i], chroma_ac->sym_code_len[i]), chroma_ac->sym_code_len[i]); 868 | #endif 869 | } 870 | 871 | // ==================================================================================================================== 872 | 873 | unsigned char byte_buffer; 874 | int bits_written; 875 | void write_byte(FILE* f, int code_word, int start, int end) 876 | { 877 | if (start == end) 878 | return; 879 | 880 | if (end>0) // we just write into the buffer 881 | { 882 | code_word <<= end; 883 | code_word &= (1<>= (-end); 891 | code_word &= (1<sym_code[class]; 938 | int class_size = huff->sym_code_len[class]; 939 | write_bits(f, class_code, class_size); 940 | 941 | unsigned int id = abs(dc_val); 942 | if (dc_val < 0) 943 | id = ~id; 944 | write_bits(f, id, class); 945 | } 946 | 947 | /* 948 | * write the bit representation of this AC coefficient, which has num_zeros preceeding zeros 949 | */ 950 | void encode_ac_value(FILE* f, int ac_val, int num_zeros, huff_code* huff) 951 | { 952 | #ifdef DEBUG 953 | printf("writing ac_val=%d, num_zeros=%d\n", ac_val, num_zeros); 954 | #endif 955 | 956 | int class = huff_class(ac_val); 957 | int v = ((num_zeros<<4)&0xF0) | (class&0x0F); 958 | int code = huff->sym_code[v]; 959 | int size = huff->sym_code_len[v]; 960 | write_bits(f, code, size); 961 | 962 | unsigned int id = abs(ac_val); 963 | if (ac_val < 0) 964 | id = ~id; 965 | write_bits(f, id, class); 966 | } 967 | 968 | /* 969 | * write the DC and AC coefficients of one color channel 970 | */ 971 | void write_coefficients(FILE* f, int num_pixel, int dct_quant[], huff_code* huff_dc, huff_code* huff_ac) 972 | { 973 | int num_zeros = 0; 974 | int last_nonzero; 975 | int i; 976 | for (i=0; ii; last_nonzero--) 982 | if (dct_quant[last_nonzero] != 0) 983 | break; 984 | continue; 985 | } 986 | 987 | if (i == last_nonzero + 1) 988 | { 989 | write_bits(f, huff_ac->sym_code[0x00], huff_ac->sym_code_len[0x00]); // EOB symbol 990 | // jump to the next block 991 | i = (i/64+1)*64-1; 992 | continue; 993 | } 994 | 995 | if (dct_quant[i] == 0) 996 | { 997 | num_zeros++; 998 | if (num_zeros == 16) 999 | { 1000 | write_bits(f, huff_ac->sym_code[0xF0], huff_ac->sym_code_len[0xF0]); // ZRL symbol 1001 | num_zeros = 0; 1002 | } 1003 | continue; 1004 | } 1005 | 1006 | encode_ac_value(f, dct_quant[i], num_zeros, huff_ac); 1007 | num_zeros = 0; 1008 | } 1009 | } 1010 | 1011 | // ==================================================================================================================== 1012 | 1013 | /* 1014 | * write the information from which decoders can reconstruct the huffman table used 1015 | */ 1016 | void write_dht_header(FILE* f, int code_len_freq[], int sym_sorted[], int tc_th) 1017 | { 1018 | int length = 19; 1019 | int i; 1020 | for (i=1; i<=16; i++) 1021 | length += code_len_freq[i]; 1022 | 1023 | fputc(0xFF, f); fputc(0xC4, f); // DHT Symbol 1024 | 1025 | fputc( (length>>8)&0xFF , f); fputc( length&0xFF, f); // len 1026 | 1027 | fputc(tc_th, f); // table class (0=DC, 1=AC) and table id (0=luma, 1=chroma) 1028 | 1029 | for (i=1; i<=16; i++) 1030 | fputc(code_len_freq[i], f); // number of codes of length i 1031 | 1032 | for (i=0; length>19; i++, length--) 1033 | fputc(sym_sorted[i], f); // huffval, needed to reconstruct the huffman code at the receiver 1034 | } 1035 | 1036 | /* 1037 | * write mandatory header stuff 1038 | * - image dimensions 1039 | * - quantization tables 1040 | * - huffman tables 1041 | */ 1042 | void write_file(char* file_name, jpeg_data* data) 1043 | { 1044 | FILE* f = fopen(file_name, "w"); 1045 | 1046 | fputc(0xFF, f); fputc(0xD8, f); // SOI Symbol 1047 | 1048 | fputc(0xFF, f); fputc(0xE0, f); // APP0 Tag 1049 | fputc(0, f); fputc(16, f); // len 1050 | fputc(0x4A, f); fputc(0x46, f); fputc(0x49, f); fputc(0x46, f); fputc(0x00, f); // JFIF ID 1051 | fputc(0x01, f); fputc(0x01, f); // JFIF Version 1052 | fputc(0x00, f); // units 1053 | fputc(0x00, f); fputc(0x48, f); // X density 1054 | fputc(0x00, f); fputc(0x48, f); // Y density 1055 | fputc(0x00, f); // x thumbnail 1056 | fputc(0x00, f); // y thumbnail 1057 | 1058 | fputc(0xFF, f); fputc(0xDB, f); // DQT Symbol 1059 | fputc(0, f); fputc(67, f); // len 1060 | fputc(0, f); // quant-table id 1061 | int i; 1062 | for (i=0; i<64; i++) 1063 | fputc(luma_quantizer[scan_order[i]], f); 1064 | 1065 | fputc(0xFF, f); fputc(0xDB, f); // DQT Symbol 1066 | fputc(0, f); fputc(67, f); // len 1067 | fputc(1, f); // quant-table id 1068 | for (i=0; i<64; i++) 1069 | fputc(chroma_quantizer[scan_order[i]], f); 1070 | 1071 | write_dht_header(f, data->luma_dc.code_len_freq, data->luma_dc.sym_sorted, 0x00); 1072 | write_dht_header(f, data->luma_ac.code_len_freq, data->luma_ac.sym_sorted, 0x10); 1073 | write_dht_header(f, data->chroma_dc.code_len_freq, data->chroma_dc.sym_sorted, 0x01); 1074 | write_dht_header(f, data->chroma_ac.code_len_freq, data->chroma_ac.sym_sorted, 0x11); 1075 | 1076 | fputc(0xFF, f); fputc(0xC0, f); // SOF0 Symbol (Baseline DCT) 1077 | fputc(0, f); fputc(17, f); // len 1078 | fputc(0x08, f); // data precision - 8bit 1079 | fputc(((data->height)>>8)&0xFF, f); fputc((data->height)&0xFF, f); // picture height 1080 | fputc(((data->width)>>8)&0xFF, f); fputc((data->width)&0xFF, f); // picture width 1081 | fputc(0x03, f); // num components - 3 for y, cb and cr 1082 | // fputc(0x01, f); // num components - 3 for y, cb and cr 1083 | fputc(1, f); // #1 id 1084 | fputc(0x22, f); // sampling factor (bit0-3=vertical, bit4-7=horiz) 1085 | fputc(0, f); // quantization table index 1086 | fputc(2, f); // #2 id 1087 | fputc(0x11, f); // sampling factor (bit0-3=vertical, bit4-7=horiz) 1088 | fputc(1, f); // quantization table index 1089 | fputc(3, f); // #3 id 1090 | fputc(0x11, f); // sampling factor (bit0-3=vertical, bit4-7=horiz) 1091 | fputc(1, f); // quantization table index 1092 | 1093 | fputc(0xFF, f); fputc(0xDA, f); // SOS Symbol 1094 | fputc(0, f); fputc(8, f); // len 1095 | fputc(1, f); // number of components 1096 | fputc(1, f); // id of component 1097 | fputc(0x00, f); // table index, bit0-3=AC-table, bit4-7=DC-table 1098 | fputc(0x00, f); // start of spectral or predictor selection - not used 1099 | fputc(0x3F, f); // end of spectral selection - default value 1100 | fputc(0x00, f); // successive approximation bits - default value 1101 | write_coefficients(f, data->num_pixel, data->dct_y_quant, &data->luma_dc, &data->luma_ac); 1102 | fill_last_byte(f); 1103 | 1104 | fputc(0xFF, f); fputc(0xDA, f); // SOS Symbol 1105 | fputc(0, f); fputc(8, f); // len 1106 | fputc(1, f); // number of components 1107 | fputc(2, f); // id of component 1108 | fputc(0x11, f); // table index, bit0-3=AC-table, bit4-7=DC-table 1109 | fputc(0x00, f); // start of spectral or predictor selection - not used 1110 | fputc(0x3F, f); // end of spectral selection - default value 1111 | fputc(0x00, f); // successive approximation bits - default value 1112 | write_coefficients(f, data->num_pixel/4, data->dct_cb_quant, &data->chroma_dc, &data->chroma_ac); 1113 | fill_last_byte(f); 1114 | 1115 | fputc(0xFF, f); fputc(0xDA, f); // SOS Symbol 1116 | fputc(0, f); fputc(8, f); // len 1117 | fputc(1, f); // number of components 1118 | fputc(3, f); // id of component 1119 | fputc(0x11, f); // table index, bit0-3=AC-table, bit4-7=DC-table 1120 | fputc(0x00, f); // start of spectral or predictor selection - not used 1121 | fputc(0x3F, f); // end of spectral selection - default value 1122 | fputc(0x00, f); // successive approximation bits - default value 1123 | write_coefficients(f, data->num_pixel/4, data->dct_cr_quant, &data->chroma_dc, &data->chroma_ac); 1124 | fill_last_byte(f); 1125 | 1126 | fputc(0xFF, f); fputc(0xD9, f); // EOI Symbol 1127 | 1128 | fclose(f); 1129 | } 1130 | 1131 | // ==================================================================================================================== 1132 | 1133 | /* 1134 | * main routine - one cmd line parameter required: a portable pixmap file (binary format) 1135 | */ 1136 | int main(int argc, char** args) 1137 | { 1138 | if (argc != 3) 1139 | { 1140 | printf("Usage: %s \n", args[0]); 1141 | return -1; 1142 | } 1143 | 1144 | FILE* f_in = fopen(args[1], "r"); 1145 | if (f_in == NULL) 1146 | { 1147 | fprintf(stderr, "Cannot open file '%s'!\n", args[1]); 1148 | return -1; 1149 | } 1150 | 1151 | jpeg_data data; 1152 | int quality; 1153 | if (sscanf(args[2], "%d", &quality) != 1 || quality < 0 || quality > 100) 1154 | { 1155 | fprintf(stderr, "The quality parameter must be in the range [0;100].\n"); 1156 | return -1; 1157 | } 1158 | set_quality(luma_quantizer, quality); 1159 | set_quality(chroma_quantizer, quality); 1160 | 1161 | timer(); 1162 | printf("Reading portable pixmap file "); 1163 | fflush(stdout); 1164 | if (read_ppm(f_in, &data)) 1165 | { 1166 | fclose(f_in); 1167 | return -1; 1168 | } 1169 | fclose(f_in); 1170 | printf("%10.3f ms\n", timer()); 1171 | 1172 | timer(); 1173 | printf("Converting RGB to YCbCr "); 1174 | fflush(stdout); 1175 | if (rgb_to_ycbcr(&data)) 1176 | return -1; 1177 | printf("%10.3f ms\n", timer()); 1178 | 1179 | timer(); 1180 | printf("Subsampling chroma values "); 1181 | fflush(stdout); 1182 | subsample_chroma(&data); 1183 | printf("%10.3f ms\n", timer()); 1184 | 1185 | #ifdef INFO 1186 | save_channels(&data); 1187 | #endif 1188 | 1189 | timer(); 1190 | printf("Performing the discrete cosine transform "); 1191 | fflush(stdout); 1192 | init_dct_lookup(); 1193 | dct(data.width/8, data.height/8, data.y, data.dct_y); 1194 | dct(data.width/16, data.height/16, data.cb_sub, data.dct_cb); 1195 | dct(data.width/16, data.height/16, data.cr_sub, data.dct_cr); 1196 | printf("%10.3f ms\n", timer()); 1197 | 1198 | #ifdef DEBUG 1199 | printf("***** Y-DCT *****"); 1200 | print_dct_coeffs_double(data.num_pixel, data.dct_y); 1201 | printf("***** Cb-DCT *****"); 1202 | print_dct_coeffs_double(data.num_pixel/4, data.dct_cb); 1203 | printf("***** Cr-DCT *****"); 1204 | print_dct_coeffs_double(data.num_pixel/4, data.dct_cr); 1205 | #endif 1206 | 1207 | timer(); 1208 | printf("Quantizing coefficients "); 1209 | fflush(stdout); 1210 | quantize(data.num_pixel, data.dct_y, data.dct_y_quant, luma_quantizer); 1211 | quantize(data.num_pixel/4, data.dct_cb, data.dct_cb_quant, chroma_quantizer); 1212 | quantize(data.num_pixel/4, data.dct_cr, data.dct_cr_quant, chroma_quantizer); 1213 | printf("%10.3f ms\n", timer()); 1214 | 1215 | #ifdef DEBUG 1216 | printf("***** Y-DCT quantized *****"); 1217 | print_dct_coeffs(data.num_pixel, data.dct_y_quant); 1218 | printf("***** Cb-DCT quantized *****"); 1219 | print_dct_coeffs(data.num_pixel/4, data.dct_cb_quant); 1220 | printf("***** Cr-DCT quantized *****"); 1221 | print_dct_coeffs(data.num_pixel/4, data.dct_cr_quant); 1222 | #endif 1223 | 1224 | timer(); 1225 | printf("Reordering coefficients (zig-zag) "); 1226 | fflush(stdout); 1227 | zigzag(data.num_pixel, data.dct_y_quant); 1228 | zigzag(data.num_pixel/4,data.dct_cb_quant); 1229 | zigzag(data.num_pixel/4, data.dct_cr_quant); 1230 | printf("%10.3f ms\n", timer()); 1231 | 1232 | #ifdef DEBUG 1233 | printf("***** Y-DCT quantized, zig-zag *****"); 1234 | print_dct_coeffs(data.num_pixel, data.dct_y_quant); 1235 | printf("***** Cb-DCT quantized, zig-zag *****"); 1236 | print_dct_coeffs(data.num_pixel/4, data.dct_cb_quant); 1237 | printf("***** Cr-DCT quantized, zig-zag *****"); 1238 | print_dct_coeffs(data.num_pixel/4, data.dct_cr_quant); 1239 | #endif 1240 | 1241 | timer(); 1242 | printf("Calculating the DC differences "); 1243 | fflush(stdout); 1244 | diff_dc(data.num_pixel, data.dct_y_quant); 1245 | diff_dc(data.num_pixel/4, data.dct_cb_quant); 1246 | diff_dc(data.num_pixel/4, data.dct_cr_quant); 1247 | printf("%10.3f ms\n", timer()); 1248 | 1249 | #ifdef DEBUG 1250 | printf("***** Y-DCT quantized, zig-zag, DC-diff *****"); 1251 | print_dct_coeffs(data.num_pixel, data.dct_y_quant); 1252 | printf("***** Cb-DCT quantized, zig-zag, DC-diff *****"); 1253 | print_dct_coeffs(data.num_pixel/4, data.dct_cb_quant); 1254 | printf("***** Cr-DCT quantized, zig-zag, DC-diff *****"); 1255 | print_dct_coeffs(data.num_pixel/4, data.dct_cr_quant); 1256 | #endif 1257 | 1258 | init_huffman(&data); 1259 | 1260 | timer(); 1261 | printf("Writing the bitstream "); 1262 | fflush(stdout); 1263 | write_file("out.jpg", &data); 1264 | printf("%10.3f ms\n", timer()); 1265 | 1266 | return 0; 1267 | } 1268 | --------------------------------------------------------------------------------