Sign in to follow this  
wwinthan

mesa(www.3dmesa.org)

Recommended Posts

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[i], 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[i], 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[i] = buffer16[i] >> 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[i] = (GLubyte) (buffer32[i] * 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]

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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[i] = buffer16[i] >> 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[i] = (GLubyte) (buffer32[i] * 255.0);
iSaveJpeg(image1,buffer8,"C:\\jpgimage.jpg");
write_ppm(filename, buffer8, WIDTH, HEIGHT);
free(buffer8);
}
///////////////////////////////////////////////////////////
write_ppm function is here


void 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[i], 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[i], 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 debugging
template <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[s] */
int row_stride; /* physical row width in image buffer */
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);

if ((outfile = fopen(filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
exit(1);
}
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = image_width; /* image width and height, in pixels */
cinfo.image_height = image_height;
cinfo.input_components = 3; /* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
jpeg_set_defaults(&cinfo);
int quality=1000;
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
jpeg_start_compress(&cinfo, TRUE);
row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
return true;
}







[Edited by - wwinthan on October 10, 2008 2:35:05 PM]

Share this post


Link to post
Share on other sites
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[i] = (GLubyte) (buffer32[i] * 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.

Share this post


Link to post
Share on other sites
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");

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this