File: jpeg.c

package info (click to toggle)
grafix 1.6-5
  • links: PTS
  • area: main
  • in suites: woody
  • size: 1,156 kB
  • ctags: 1,962
  • sloc: ansic: 20,183; makefile: 186; sh: 3
file content (156 lines) | stat: -rw-r--r-- 5,328 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// jpeg.c : define member function for saving windows in JPEG files
//          'void window::save_jpeg(char* fina, int q)' // q = quality
//          it is not defined in window.c !!
//          wolfk 5/2000

/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/

#include "window.h"
#include <X11/Xutil.h>

struct ppm { // struct for 3byte ppm rgb pixels rgb=888 needed for jpeg
  unsigned char r,g,b;
  inline void boost(unsigned short c565) { // blow up rgb565 -> rgb888 
    r = (c565 >> 11) << 3;
    g = (c565 >> 5) << 2;
    b = c565 << 3;
  }
  inline unsigned short c565() { // return standard 565 color
    unsigned short val = b >> 3;
    val |= (g >> 2) << 5; 
    val |= (r >> 3) << 11;
    return val;
  }
};

extern "C" {
#include "jpeglib.h" 
}

// to be called after initialization of the cinfo struct 
// write one frame compressed to file stream associated with cinfo
// may be called succesively for more frames
void JPEG_compress(struct jpeg_compress_struct *cinfo, int image_width, unsigned short *image_buffer) {
  jpeg_start_compress(cinfo, TRUE);
  struct ppm ppm_buffer[image_width]; // buffer for one scanline

  /* pointer to JSAMPLE row[s] */
  JSAMPROW pptr = (unsigned char*) ppm_buffer;

  while (cinfo->next_scanline < cinfo->image_height) {
    unsigned short *im_line = image_buffer + image_width*cinfo->next_scanline;
    for (int i=0; i < image_width; i++) ppm_buffer[i].boost(im_line[i]);
    jpeg_write_scanlines(cinfo, &pptr, 1);
  }
  jpeg_finish_compress(cinfo);
}

void compress_jpeg(FILE *fsave, int quality, int ww, int hh, unsigned short* image_buf) {
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;

  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_compress(&cinfo);
  jpeg_stdio_dest(&cinfo, fsave);

  cinfo.image_width = ww; 	/* image width and height, in pixels */
  cinfo.image_height = hh;
  cinfo.input_components = 3;		/* # of color components per pixel */
  cinfo.in_color_space = JCS_RGB; 	/* colorspace of input image */
  jpeg_set_defaults(&cinfo);
  jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
  JPEG_compress(&cinfo,ww,image_buf);

  jpeg_destroy_compress(&cinfo);
}

void compress_jpeg(FILE *fsave, int quality, XImage *xi) {
  int ww = xi->bytes_per_line/2; // = (width/2)*2 :  
  compress_jpeg(fsave, quality, ww, xi->height, (unsigned short*) xi->data);
} 
    

// to be called after initialization of the cinfo struct 
// read one frame from file stream associated with cinfo and decompress 
// may be called succesively for more frames of a video
void JPEG_decompress(struct jpeg_decompress_struct *cinfo, unsigned short *image_buffer) {
  int ww = cinfo->output_width; 
  int row_stride = ww * cinfo->output_components;
  
  /* Make a one-row-high sample array that will go away when done with image */
   JSAMPARRAY buffer = (*cinfo->mem->alloc_sarray)
                       ((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, 1);

  while (cinfo->output_scanline < cinfo->output_height) {
    jpeg_read_scanlines(cinfo, buffer, 1);
    unsigned short *capline= image_buffer + ww*cinfo->output_scanline;
    ppm* ppline = (ppm*) buffer[0];
    for (int i=0; i < ww; i++) capline[i] = ppline[i].c565();
  }
}

// the following functions are only for demonstrations
void load_jpeg_file(FILE *fload) {  
  if (fload == NULL) return;
  static struct jpeg_decompress_struct cinfo; // static for retry
  static struct jpeg_error_mgr jerr;
  cinfo.err = jpeg_std_error(&jerr); 
  jpeg_create_decompress(&cinfo);  
  jpeg_stdio_src(&cinfo, fload);
  
  jpeg_read_header(&cinfo, TRUE);
  jpeg_start_decompress(&cinfo); 
  /*
  if ((int) cinfo.output_width != biWidth || 
      (int) cinfo.output_height != biHeight) {
    printf("adapting size to %dx%d\n",cinfo.output_width,cinfo.output_height);
    adjust_size(cinfo.output_width,cinfo.output_height);
  } 
  */
 
  // JPEG_decompress(&cinfo, cap_buf);
  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);
  //  map_and_redraw();
}

void load_jpeg(char* fina) {
  if (! True_Color_Visual) error("jpegs only supported for TrueColor Mode");

  FILE *fload = fopen(fina,"r");
  if (fload == NULL) return;

  load_jpeg_file(fload);

  printf("loaded jpeg image from '%s'\n",fina);
  
  fclose(fload);
}

// interface function
void window::save_jpeg(char* fina, int q) { // q = quality
  if (! True_Color_Visual) error("jpegs only supported for TrueColor Mode");
  FILE *fsave = fopen(fina,"w");
  if (fsave == NULL) return;
  XImage *xi = GetImage();
  compress_jpeg(fsave,q,xi);
  int fsize = ftell(fsave);
  printf("saved jpeg q = %d to '%s' (%d x %d) %d byte compfct = %.1f\n",
	 q,fina,width,height,fsize,2.0*width*height/fsize);
  fclose(fsave);
  XDestroyImage(xi);
}

void save_jpeg(window *w, char* fina, int q = 50) { // q = quality
  int ww = w->width, hh = w->height;
  if (! True_Color_Visual) error("jpegs only supported for TrueColor Mode");
  FILE *fsave = fopen(fina,"w");
  if (fsave == NULL) return;
  XImage *xi = XGetImage(display,w->Win,0,0,ww,hh,AllPlanes,ZPixmap);
  compress_jpeg(fsave,q,ww,hh, (unsigned short*) xi->data);
  int fsize = ftell(fsave);
  printf("saved jpeg q = %d to '%s' (%d x %d) %d byte compfct = %.1f\n",
	 q,fina,ww,hh,fsize,2.0*ww*hh/fsize);
  fclose(fsave);
  XDestroyImage(xi);
}