mesa(www.3dmesa.org)

Started by
7 comments, last by handsomeguy 15 years, 6 months ago
I use following code(www.mesa3d.org) to render offscreen(render directly to memory buffer) and save it as a format called "ppm". here goes my question. i'm wondering there is anyway to save it as jpg instead of ppm which is huge. thx in advance (Help!) winthan /////////////////////////////

#include "glu.h"
#include "GL/osmesa.h"


write_ppm(const char *filename, const GLubyte *buffer, int width, int height)
{
   const int binary = 0;
   FILE *f = fopen( filename, "w" );
   if (f) {
      int i, x, y;
      const GLubyte *ptr = buffer;
      if (binary) {
         fprintf(f,"P6\n");
         fprintf(f,"# ppm-file created by osdemo.c\n");
         fprintf(f,"%i %i\n", width,height);
         fprintf(f,"255\n");
         fclose(f);
         f = fopen( filename, "ab" );  /* reopen in binary append mode */
         for (y=height-1; y>=0; y--) {
            for (x=0; x<width; x++) {
               i = (y*width + x) * 4;
               fputc(ptr, f);   /* write red */
               fputc(ptr[i+1], f); /* write green */
               fputc(ptr[i+2], f); /* write blue */
            }
         }
      }
      else {
         /*ASCII*/
         int counter = 0;
         fprintf(f,"P3\n");
         fprintf(f,"# ascii ppm file created by osdemo.c\n");
         fprintf(f,"%i %i\n", width, height);
         fprintf(f,"255\n");
         for (y=height-1; y>=0; y--) {
            for (x=0; x<width; x++) {
               i = (y*width + x) * 4;
               fprintf(f, " %3d %3d %3d", ptr, ptr[i+1], ptr[i+2]);
               counter++;
               if (counter % 5 == 0)
                  fprintf(f, "\n");
            }
         }
      }
      fclose(f);
   }
}


static GLvoid test(GLenum type, GLint bits, const char *filename)
{
   const GLint z = 16, stencil = 0, accum = 0;
   OSMesaContext ctx;
   void *buffer;
   GLint cBits;

   assert(bits == 8 ||
          bits == 16 ||
          bits == 32);

   assert(type == GL_UNSIGNED_BYTE ||
          type == GL_UNSIGNED_SHORT ||
          type == GL_FLOAT);

   ctx = OSMesaCreateContextExt(OSMESA_RGBA, z, stencil, accum, NULL );
   if (!ctx) {
      printf("OSMesaCreateContextExt() failed!\n");
//      return 0;
   }

   /* Allocate the image buffer */
   buffer = malloc(WIDTH * HEIGHT * 4 * bits / 8);
   if (!buffer) {
      printf("Alloc image buffer failed!\n");
    //  return 0;
   }

   /* Bind the buffer to the context and make it current */
   if (!OSMesaMakeCurrent( ctx, buffer, type, WIDTH, HEIGHT )) {
      printf("OSMesaMakeCurrent (%d bits/channel) failed!\n", bits);
      free(buffer);
      OSMesaDestroyContext(ctx);
    //  return 0;
   }

   /* sanity checks */
   glGetIntegerv(GL_RED_BITS, &cBits);
   assert(cBits == bits);
   glGetIntegerv(GL_GREEN_BITS, &cBits);
   assert(cBits == bits);
   glGetIntegerv(GL_BLUE_BITS, &cBits);
   assert(cBits == bits);
   glGetIntegerv(GL_ALPHA_BITS, &cBits);
   assert(cBits == bits);

   if (WriteFiles)
      printf("Rendering %d bit/channel image: %s\n", bits, filename);
   else
      printf("Rendering %d bit/channel image\n", bits);

   //OSMesaColorClamp(GL_TRUE);

  // init_context();
   render_image();
   if (Gradient)
      render_gradient();

   /* Make sure buffered commands are finished! */
   glFinish();


   //if (WriteFiles && filename != NULL) {
   if (filename != NULL) {
      if (type == GL_UNSIGNED_SHORT) {
         GLushort *buffer16 = (GLushort *) buffer;
         GLubyte *buffer8 = (GLubyte *) malloc(WIDTH * HEIGHT * 4);
         int i;
         for (i = 0; i < WIDTH * HEIGHT * 4; i++)
            buffer8 = buffer16 >> 8;
         write_ppm(filename, buffer8, WIDTH, HEIGHT);
         free(buffer8);
      }
      else if (type == GL_FLOAT) {
         GLfloat *buffer32 = (GLfloat *) buffer;
         GLubyte *buffer8 = (GLubyte *) malloc(WIDTH * HEIGHT * 4);
         int i;
         /* colors may be outside [0,1] so we need to clamp */
         for (i = 0; i < WIDTH * HEIGHT * 4; i++)
            buffer8 = (GLubyte) (buffer32 * 255.0);
         write_ppm(filename, buffer8, WIDTH, HEIGHT);
         free(buffer8);
      }
      else {
         write_ppm(filename, (GLubyte*)buffer, WIDTH, HEIGHT);
      }
   }

   OSMesaDestroyContext(ctx);

   free(buffer);

[Edited by - wwinthan on October 10, 2008 12:48:47 PM]
Advertisement
Try using libjpeg

Also, when you post chunks of code to the forum, could you please use the 'source' tag?
one last question. libjpg is for converting from ppm to jpg? or directly write into jpg from buffer? do you by any chance have the sample code for converting ppm format to jpg format?
thx
winthan
You can write a raw image buffer into a JPEG file with libjpeg (and load it back, if you need). Download the source distribution and see 'example.c' - it writes a JPEG from an image buffer.
I use mesa(www.mesa3d.org) to render off-screen. after that i use libjpeg to save it as jpeg. i can save it to ppm by using the example code from "mesa3d.org" and after that i use write_ppm to save it as ppm image file.it's working fine with ppm but when i pass the buffer to isavejpeg(which is part of function in jpeglib. but jpeg alignment mismatched. can't save as jpeg.since i barely have idea with image processing so please help by going through the code below plz!
thanks
winthan

   GLenum type= GL_FLOAT;   GLint bits=8;   const char *filename ="C:\\image81.ppm";   const GLint z = 16;   const GLint stencil = 0;   const GLint accum = 0;   OSMesaContext ctx;   void *buffer;   GLint cBits;   assert(bits == 8 ||          bits == 16 ||          bits == 32);   assert(type == GL_UNSIGNED_BYTE ||          type == GL_UNSIGNED_SHORT ||          type == GL_FLOAT);   ctx = OSMesaCreateContextExt(OSMESA_RGBA, z, stencil, accum, NULL );     if (!ctx) {      printf("OSMesaCreateContextExt() failed!\n");//      return 0;   }   /* Allocate the image buffer */   buffer = malloc(WIDTH * HEIGHT * 4 * bits / 8);  // buffer = malloc(WIDTH * HEIGHT * 4 * bits);   if (!buffer) {      printf("Alloc image buffer failed!\n");    //  return 0;   }   /* Bind the buffer to the context and make it current */   if (!OSMesaMakeCurrent( ctx, buffer, type, WIDTH, HEIGHT )) {      printf("OSMesaMakeCurrent (%d bits/channel) failed!\n", bits);      free(buffer);      OSMesaDestroyContext(ctx);   glGetIntegerv(GL_RED_BITS, &cBits);   assert(cBits == bits);   glGetIntegerv(GL_GREEN_BITS, &cBits);   assert(cBits == bits);   glGetIntegerv(GL_BLUE_BITS, &cBits);   assert(cBits == bits);   glGetIntegerv(GL_ALPHA_BITS, &cBits);   assert(cBits == bits);if (filename != NULL) {      if (type == GL_UNSIGNED_SHORT) {         GLushort *buffer16 = (GLushort *) buffer;         GLubyte *buffer8 = (GLubyte *) malloc(WIDTH * HEIGHT * 4);         int i;         for (i = 0; i < WIDTH * HEIGHT * 4; i++)            buffer8 = buffer16 >> 8;         write_ppm(filename, buffer8, WIDTH, HEIGHT);         free(buffer8);      }      else if (type == GL_FLOAT) {		  bimage image1;		 image1.Create(WIDTH,HEIGHT,24);         GLfloat *buffer32 = (GLfloat *) buffer;         GLubyte *buffer8 = (GLubyte *) malloc(WIDTH * HEIGHT * 4);         int i;         /* colors may be outside [0,1] so we need to clamp */         for (i = 0; i < WIDTH * HEIGHT * 4; i++)            buffer8 = (GLubyte) (buffer32 * 255.0);		 iSaveJpeg(image1,buffer8,"C:\\jpgimage.jpg");         write_ppm(filename, buffer8, WIDTH, HEIGHT);         free(buffer8);      }///////////////////////////////////////////////////////////write_ppm function is herevoid write_ppm(const char *filename, const GLubyte *buffer, int width, int height){   const int binary = 0;   FILE *f = fopen( filename, "w" );   if (f) {      int i, x, y;      const GLubyte *ptr = buffer;      if (binary) {         fprintf(f,"P6\n");         fprintf(f,"# ppm-file created by osdemo.c\n");         fprintf(f,"%i %i\n", width,height);         fprintf(f,"255\n");         fclose(f);         f = fopen( filename, "ab" );  /* reopen in binary append mode */         for (y=height-1; y>=0; y--) {            for (x=0; x<width; x++) {               i = (y*width + x) * 4;               fputc(ptr, f);   /* write red */               fputc(ptr[i+1], f); /* write green */               fputc(ptr[i+2], f); /* write blue */            }         }      }      else {         /*ASCII*/         int counter = 0;         fprintf(f,"P3\n");         fprintf(f,"# ascii ppm file created by osdemo.c\n");         fprintf(f,"%i %i\n", width, height);         fprintf(f,"255\n");         for (y=height-1; y>=0; y--) {            for (x=0; x<width; x++) {               i = (y*width + x) * 4;               fprintf(f, " %3d %3d %3d", ptr, ptr[i+1], ptr[i+2]);               counter++;               if (counter % 5 == 0)                  fprintf(f, "\n");            }         }      }      fclose(f);   }}////////////////////////////////////////////////////iSaveJpeg function comes here#include "jpeglib.h"} //extern JSAMPLE * image_buffer;	/* Points to large array of R,G,B-order data *///extern int image_height;	/* Number of rows in image *///extern int image_width;		/* Number of columns in image */// It returns true, so that it can be used in ASSERT(Save()) for debuggingtemplate <class T> bool iSaveJpeg(cBaseImage<T>& image,unsigned char* buffersimage,char * filename){	JSAMPLE* image_buffer;	/* Points to large array of R,G,B-order data */	int image_height;	/* Number of rows in image */	int image_width;		image_height = 1000;	image_width = 1000;image_buffer = buffersimage;  struct jpeg_compress_struct cinfo;  struct jpeg_error_mgr jerr;  FILE * outfile;		/* target file */  JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row */</span><br>  <span class="cpp-keyword">int</span> row_stride;		<span class="cpp-comment">/* physical row width in image buffer */</span><br>  cinfo.err = jpeg_std_error(&amp;jerr);<br>  jpeg_create_compress(&amp;cinfo);<br><br>  <span class="cpp-keyword">if</span> ((outfile = fopen(filename, <span class="cpp-literal">"wb"</span>)) == NULL) {<br>    fprintf(stderr, <span class="cpp-literal">"can't open %s\n"</span>, filename);<br>    exit(<span class="cpp-number">1</span>);<br>  }<br>  jpeg_stdio_dest(&amp;cinfo, outfile);<br>  cinfo.image_width = image_width; 	<span class="cpp-comment">/* image width and height, in pixels */</span><br>  cinfo.image_height = image_height;<br>  cinfo.input_components = <span class="cpp-number">3</span>;		<span class="cpp-comment">/* # of color components per pixel */</span><br>  cinfo.in_color_space = JCS_RGB; 	<span class="cpp-comment">/* colorspace of input image */</span><br>  jpeg_set_defaults(&amp;cinfo);<br>  <span class="cpp-keyword">int</span> quality=<span class="cpp-number">1000</span>;<br>  jpeg_set_quality(&amp;cinfo, quality, <span class="cpp-keyword">TRUE</span> <span class="cpp-comment">/* limit to baseline-JPEG values */</span>);<br>  jpeg_start_compress(&amp;cinfo, <span class="cpp-keyword">TRUE</span>);<br>  row_stride = image_width * <span class="cpp-number">3</span>;	<span class="cpp-comment">/* JSAMPLEs per row in image_buffer */</span><br>  <span class="cpp-keyword">while</span> (cinfo.next_scanline &lt; cinfo.image_height) {<br>    row_pointer[<span class="cpp-number">0</span>] = &amp; image_buffer[cinfo.next_scanline * row_stride];<br>    (<span class="cpp-keyword">void</span>) jpeg_write_scanlines(&amp;cinfo, row_pointer, <span class="cpp-number">1</span>);<br>  }<br>  jpeg_finish_compress(&amp;cinfo);<br>  fclose(outfile);<br>  jpeg_destroy_compress(&amp;cinfo);<br>  <span class="cpp-keyword">return</span> <span class="cpp-keyword">true</span>;<br>}<br><br><br></pre></div><!–ENDSCRIPT–><br><br><img src="http://hosting07.imagecross.com/image-hosting-th-04/8060jpgimage.jpg"><br><img src="http://hosting07.imagecross.com/image-hosting-th-04/4170orignal.jpg"><br><br><!–EDIT–><span class=editedby><!–/EDIT–>[Edited by - wwinthan on October 10, 2008 2:35:05 PM]<!–EDIT–></span><!–/EDIT–>
I haven't looked that closely, but you probably have the wrong format in your buffer when saving from the float image. You have an RGBA surface, but libjpeg is expecting RGB.
Change this:
int i;/* colors may be outside [0,1] so we need to clamp */for (i = 0; i < WIDTH * HEIGHT * 4; i++)  buffer8 = (GLubyte) (buffer32 * 255.0);iSaveJpeg(image1,buffer8,"C:\\jpgimage.jpg");

to this:
int i, j;/* colors may be outside [0,1] so we need to clamp */for (j = 0; j < HEIGHT; j++) {  for (i = 0; i < WIDTH; i++) {    buffer8[(j * WIDTH * 3) + (i * 3)] = (GLubyte) (buffer32[(j * WIDTH * 4) + (i * 4)] * 255.0);    buffer8[(j * WIDTH * 3) + (i * 3) + 1] = (GLubyte) (buffer32[(j * WIDTH * 4) + (i * 4) + 1] * 255.0);    buffer8[(j * WIDTH * 3) + (i * 3) + 2] = (GLubyte) (buffer32[(j * WIDTH * 4) + (i * 4) + 2] * 255.0);  }}iSaveJpeg(image1,buffer8,"C:\\jpgimage.jpg");

See what happens. You may have further problems.
it's working now but the image is reverse...ppm image works fine. but jpg image displays in the reverse.could you please tell me where is wrong?
Orignal image

Image by using jpg
Try this:
int i, j;/* colors may be outside [0,1] so we need to clamp */for (j = 0; j < HEIGHT; j++) {  for (i = 0; i < WIDTH; i++) {    buffer8[(j * WIDTH * 3) + (i * 3)] = (GLubyte) (buffer32[((HEIGHT - j - 1) * WIDTH * 4) + (i * 4)] * 255.0);    buffer8[(j * WIDTH * 3) + (i * 3) + 1] = (GLubyte) (buffer32[((HEIGHT - j - 1) * WIDTH * 4) + (i * 4) + 1] * 255.0);    buffer8[(j * WIDTH * 3) + (i * 3) + 2] = (GLubyte) (buffer32[((HEIGHT - j - 1) * WIDTH * 4) + (i * 4) + 2] * 255.0);  }}iSaveJpeg(image1,buffer8,"C:\\jpgimage.jpg");
hi graz, thanks a million for your help
one last thing is where i can learn more about it? how you come out with the formula?it would be great if you would like to explain to me or point me the resource where i can dig more about that.
thanks
winthan

This topic is closed to new replies.

Advertisement