First classes for the qjpeg project.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/FloatPlane.cpp Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,113 @@
+#include "FloatPlane.h"
+#include <cstring>
+
+extern "C" {
+#include <stdio.h>
+#include <pam.h>
+}
+
+FloatPlane::FloatPlane()
+{
+ setMaxMinValue();
+ ready = false;
+}
+
+void FloatPlane::setMaxMinValue(unsigned int max, unsigned int min)
+{
+ MAXVALUE=max;
+ MINVALUE=min;
+}
+
+FloatPlane::FloatPlane(float *_ptr)
+{
+ ptr = _ptr;
+ setMaxMinValue();
+ ready = true;
+}
+
+FloatPlane::FloatPlane(const unsigned int _width, const unsigned int _height)
+{
+ allocate(_width, _height);
+
+ setMaxMinValue();
+ ready = true;
+}
+
+void FloatPlane::allocate(const unsigned int _width, const unsigned int _height)
+{
+ width = _width;
+ height = _height;
+ ptr = new float[width*height];
+ ready = true;
+}
+
+void FloatPlane::writePGM(const char * filename)
+{
+ struct pam outpam;
+ unsigned int row;
+ tuple *tuplerow;
+
+ FILE* file;
+
+ if (!ready)
+ return;
+
+ file = fopen(filename, "wb");
+ if (file == NULL)
+ return;
+
+ outpam.size = sizeof(outpam);
+ outpam.len = outpam.size;
+ outpam.file = file;
+ outpam.format = PGM_FORMAT;
+ outpam.plainformat = 0; /* false */
+ outpam.width = width;
+ outpam.height = height;
+ outpam.depth = 1; /* Grayscale - 1 sample per tuple */
+ outpam.allocation_depth = 0; /* Same as depth. */
+ outpam.maxval = MAXVALUE;
+ std::strcpy(outpam.tuple_type, "GRAYSCALE"); /* PGM non transparent */
+
+ /* needs size,len,file,format,height,width,depth,maxval, tuple_type */
+ pnm_writepaminit(&outpam);
+
+ tuplerow = pnm_allocpamrow(&outpam);
+
+ for (row = 0; row < height; row++) {
+ unsigned int column;
+ for (column = 0; column < width; ++column) {
+ /* Only one plane */
+ /* float to int! */
+ tuplerow[column][0] = ptr[column+width*row];
+ }
+ pnm_writepamrow(&outpam, tuplerow);
+ }
+
+ pnm_freepamrow(tuplerow);
+ fclose(file);
+}
+
+unsigned int FloatPlane::getMaxValue()
+{
+ return MAXVALUE;
+}
+
+unsigned int FloatPlane::getWidth()
+{
+ return width;
+}
+
+unsigned int FloatPlane::getHeight()
+{
+ return height;
+}
+
+float * FloatPlane::getPtr()
+{
+ return ptr;
+}
+
+void FloatPlane::free()
+{
+ delete[] ptr;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/FloatPlane.h Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,27 @@
+class FloatPlane
+{
+ unsigned int width;
+ unsigned int height;
+
+ int MAXVALUE;
+ int MINVALUE;
+
+ bool ready;
+
+ void setMaxMinValue(unsigned int max = 255, unsigned int min = 0);
+
+public:
+ float *ptr;
+
+ FloatPlane();
+ FloatPlane(float *_ptr);
+ FloatPlane(const unsigned int _width, const unsigned int _height);
+
+ void allocate(const unsigned int _width, const unsigned int _height);
+ unsigned int getWidth();
+ float * getPtr();
+ unsigned int getHeight();
+ unsigned int getMaxValue();
+ void writePGM(const char * filename);
+ void free();
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/Image.cpp Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,126 @@
+#include "Image.h"
+#include "FloatPlane.h"
+#include <cstring>
+extern "C" {
+#include <stdio.h>
+#include <pam.h>
+}
+
+Image::Image()
+{
+ ready = false;
+}
+
+
+Image::Image(FloatPlane _plane[], const unsigned int _components)
+{
+ components = _components;
+ plane = new FloatPlane[3];
+ /* Copy FloatPlanes */
+ for(unsigned int i=0; i<components; i++)
+ plane[i] = _plane[i];
+ ready = true;
+}
+
+void Image::setComponents(unsigned int n)
+{
+ if (ready == true)
+ delete[] plane;
+
+ components = n;
+
+ plane = new FloatPlane[n];
+ ready = true;
+}
+
+void Image::free()
+{
+ if (!ready)
+ return;
+
+ for(unsigned int i=0; i<components; i++)
+ plane[i].free();
+
+ delete[] plane;
+
+ ready = false;
+}
+
+bool Image::sameDimensions()
+{
+ bool res = true;
+
+ unsigned int width = plane[0].getWidth();
+ unsigned int height = plane[0].getHeight();
+ for(unsigned int i=1; i<components; i++)
+ {
+ if(plane[i].getWidth() != width || plane[i].getHeight() != height)
+ {
+ res = false;
+ break;
+ }
+ }
+ return res;
+}
+
+void Image::writePPM(const char *filename)
+{
+ if (components != 3)
+ return;
+ if (!sameDimensions())
+ return;
+
+ unsigned int width = plane[0].getWidth();
+ unsigned int height = plane[0].getHeight();
+ unsigned int MAXVALUE = plane[0].getMaxValue();
+
+ struct pam outpam;
+ unsigned int row;
+ tuple *tuplerow;
+
+ FILE* file;
+
+ if (!ready)
+ return;
+
+ file = fopen(filename, "wb");
+ if (file == NULL)
+ return;
+
+
+ outpam.size = sizeof(outpam);
+ outpam.len = outpam.size;
+ outpam.file = file;
+ outpam.format = PPM_FORMAT;
+ outpam.plainformat = 0; /* false */
+ outpam.width = width;
+ outpam.height = height;
+ outpam.depth = 3; /* RGB - 3 sample per tuple */
+ outpam.allocation_depth = 0; /* Same as depth. */
+ outpam.maxval = MAXVALUE;
+ std::strcpy(outpam.tuple_type, "RGB"); /* PNM non transparent */
+
+ float *ptr[3];
+ ptr[0] = plane[0].ptr;
+ ptr[1] = plane[1].ptr;
+ ptr[2] = plane[2].ptr;
+
+ /* needs size,len,file,format,height,width,depth,maxval, tuple_type */
+ pnm_writepaminit(&outpam);
+
+ tuplerow = pnm_allocpamrow(&outpam);
+
+ for (row = 0; row < height; row++) {
+ unsigned int column;
+ for (column = 0; column < width; ++column) {
+ /* Only one plane */
+ /* float to int! */
+ for(unsigned int sample = 0; sample < components; ++sample)
+ tuplerow[column][sample] = ptr[sample][column+width*row];
+ }
+ pnm_writepamrow(&outpam, tuplerow);
+ }
+
+ pnm_freepamrow(tuplerow);
+ fclose(file);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/Image.h Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,20 @@
+class FloatPlane;
+
+class Image
+{
+ unsigned int components;
+ bool ready;
+
+ bool sameDimensions();
+
+public:
+ FloatPlane *plane;
+
+ Image();
+ Image(FloatPlane _plane[], const unsigned int _components);
+
+ void free();
+ void setComponents(unsigned int n);
+ void writePPM(const char *filename);
+ unsigned int getComponents();
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/JPEGFile.cpp Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,214 @@
+#include <cstring>
+#include <cstdio>
+
+extern "C"
+{
+#include <stdio.h>
+#include <jpeglib.h>
+}
+
+#include "FloatPlane.h"
+#include "Image.h"
+#include "JPEGFile.h"
+
+JPEGFile::JPEGFile(const char *_filename)
+{
+ using namespace std;
+ filename = new char[std::strlen(_filename) + 1];
+ std::strcpy(filename, _filename);
+ srcinfo = new jpeg_decompress_struct;
+ jsrcerr = new jpeg_error_mgr;
+}
+
+void JPEGFile::readHeader()
+{
+ srcinfo->err = jpeg_std_error(jsrcerr);
+
+ jpeg_create_decompress(srcinfo);
+
+ inputh = fopen(filename, "rb");
+
+ jpeg_stdio_src(srcinfo, inputh);
+ jpeg_read_header(srcinfo, TRUE);
+}
+
+Image *JPEGFile::getiDCTImage()
+{
+ readHeader();
+
+ /* Set our JPEG decompression parameters */
+ srcinfo->dct_method = JDCT_FLOAT;
+
+ /* jpeglib don't do any postprocessing (scaling/colorq). */
+ srcinfo->raw_data_out = TRUE;
+
+ /* Start decompression of pixels */
+ jpeg_start_decompress(srcinfo);
+
+ unsigned int nplanes = srcinfo->num_components;
+
+ /* Create the planes */
+ FloatPlane *planes = new FloatPlane[nplanes];
+ unsigned int width[nplanes];
+ unsigned int height[nplanes];
+ unsigned int max_width_in_blocks = 0;
+
+ /* Get the pointers to the planes */
+ float *bmp[srcinfo->out_color_components];
+ for (unsigned int i=0; i < nplanes; i++)
+ {
+ /* get the dimensions for every plane*/
+ width[i] = srcinfo->comp_info[i].downsampled_width;
+ height[i] = srcinfo->comp_info[i].downsampled_height;
+
+ if (srcinfo->comp_info[i].width_in_blocks > max_width_in_blocks)
+ max_width_in_blocks = srcinfo->comp_info[i].width_in_blocks;
+ /* Allocate and prepare bmp[] */
+ planes[i].allocate(width[i], height[i]);
+ bmp[i] = planes[i].ptr;
+ }
+
+ /* The function jpeg_read_raw_data will return an MCU per call */
+ int nscanlines = srcinfo->max_v_samp_factor*DCTSIZE;
+
+ /* Get memory for the buffer scanline pointers */
+ JSAMPARRAY *scanplanes = new JSAMPARRAY[nplanes];
+
+ /* Get memory for each scanline in the buffer */
+ for (unsigned int plane = 0; plane < nplanes; ++plane)
+ {
+ scanplanes[plane] = new JSAMPROW[nscanlines];
+ for (int isl = 0; isl < nscanlines; ++isl)
+ scanplanes[plane][isl] = new JSAMPLE[max_width_in_blocks * DCTSIZE];
+ }
+
+ unsigned int row[nplanes];
+ unsigned int div_v_factor[nplanes];
+ for (unsigned int plane = 0; plane < nplanes; ++plane)
+ {
+ row[plane] = 0;
+ div_v_factor[plane] = srcinfo->max_v_samp_factor /
+ srcinfo->comp_info[plane].v_samp_factor;
+ }
+
+ while (srcinfo->output_scanline < srcinfo->output_height) {
+ int read_scanlines =
+ jpeg_read_raw_data(srcinfo, scanplanes, nscanlines);
+ for (unsigned int plane = 0; plane < nplanes; ++plane)
+ {
+ if (row[plane] >= height[plane])
+ continue;
+ for (int isl = 0; isl < (read_scanlines / (int) div_v_factor[plane]); ++isl)
+ {
+ for (unsigned int column = 0; column < width[plane];
+ ++column) {
+ bmp[plane][row[plane] * width[plane] + column] =
+ scanplanes[plane][isl][column];
+ }
+ ++row[plane];
+ }
+ }
+ }
+
+ jpeg_destroy_decompress(srcinfo);
+
+ fclose(inputh);
+
+ Image *i = new Image(planes, nplanes);
+
+ delete[] planes;
+ for (unsigned int plane = 0; plane < nplanes; ++plane)
+ {
+ for (int isl = 0; isl < nscanlines; ++isl)
+ delete[] scanplanes[plane][isl];
+ delete[] scanplanes[plane];
+ }
+ delete[] scanplanes;
+
+ return i;
+}
+
+Image *JPEGFile::getUnpackedImage()
+{
+ readHeader();
+
+ /* Set our JPEG decompression parameters */
+ srcinfo->do_fancy_upsampling = 1;
+ srcinfo->dct_method = JDCT_FLOAT;
+
+ /* Get the number of planes */
+ if (srcinfo->num_components == 1 &&
+ srcinfo->jpeg_color_space == JCS_GRAYSCALE) {
+ srcinfo->out_color_components = 1;
+ srcinfo->out_color_space = JCS_GRAYSCALE;
+ }
+ else {
+ srcinfo->out_color_components = 3;
+ srcinfo->out_color_space = JCS_RGB;
+ }
+
+ /* Start decompression of pixels */
+ jpeg_start_decompress(srcinfo);
+
+ unsigned int nplanes = srcinfo->out_color_components;
+
+ /* Create the planes */
+ FloatPlane *planes = new FloatPlane[nplanes];
+
+ /* Get the pointers to the planes */
+ float *bmp[srcinfo->out_color_components];
+ for (unsigned int i=0; i < nplanes; i++)
+ {
+ planes[i].allocate(srcinfo->output_width, srcinfo->output_height);
+ bmp[i] = planes[i].ptr;
+ }
+
+ /* Get the recommended number of buffer scanlines */
+ int nscanlines = srcinfo->rec_outbuf_height;
+
+ /* Get memory for the buffer scanline pointers */
+ JSAMPROW *scanlines = new JSAMPROW[nscanlines];
+
+ /* Get memory for each scanline in the buffer */
+ for (int isl = 0; isl < nscanlines; ++isl)
+ {
+ scanlines[isl] = new JSAMPLE[srcinfo->output_width * nplanes];
+ }
+
+ int row = 0;
+ while (srcinfo->output_scanline < srcinfo->output_height) {
+ int read_scanlines =
+ jpeg_read_scanlines(srcinfo, scanlines, nscanlines);
+ for (int isl = 0; isl < read_scanlines; ++isl)
+ {
+ for (unsigned int column = 0; column < srcinfo->output_width;
+ ++column) {
+ for (unsigned int plane = 0; plane < nplanes; plane++)
+ bmp[plane][row * srcinfo->output_width + column] =
+ scanlines[isl][column * srcinfo->out_color_components
+ + plane];
+ }
+ ++row;
+ }
+ }
+
+ jpeg_destroy_decompress(srcinfo);
+
+ fclose(inputh);
+
+ Image *i = new Image(planes, nplanes);
+
+ delete[] planes;
+ for (int isl = 0; isl < nscanlines; ++isl)
+ delete[] scanlines[isl];
+ delete[] scanlines;
+
+ return i;
+}
+
+JPEGFile::~JPEGFile()
+{
+ delete[] filename;
+ delete srcinfo;
+ delete jsrcerr;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/JPEGFile.h Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,29 @@
+#include <cstdio>
+
+class Image;
+
+extern "C" {
+struct jpeg_decompress_struct;
+struct jpeg_error_mgr;
+}
+
+class JPEGFile
+{
+ char * filename;
+ Image *iDCTImage;
+ Image *unpackedImage;
+
+ FILE *inputh;
+
+ struct jpeg_decompress_struct *srcinfo;
+ struct jpeg_error_mgr *jsrcerr;
+
+ void readHeader();
+
+public:
+ JPEGFile (const char *_filename);
+ ~JPEGFile();
+
+ Image * getiDCTImage();
+ Image * getUnpackedImage();
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/Makefile Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,23 @@
+CXXFLAGS?=-Wall -g
+
+.o:
+ $(CXX) $(LDFLAGS) $(LIBS) -o $@ $^
+
+# Tests
+tests: testFP testJPEGFile
+
+testFP: testFP.o FloatPlane.o
+ $(CXX) $(LDFLAGS) -lnetpbm -o $@ $^
+testJPEGFile: testJPEGFile.o FloatPlane.o Image.o JPEGFile.o
+ $(CXX) $(LDFLAGS) -lnetpbm -ljpeg -o $@ $^
+testFP.o: testFP.cpp FloatPlane.h
+testJPEGFile.o: testFP.cpp FloatPlane.h
+testJPEGFile.o: testJPEGFile.cpp Image.h JPEGFile.h
+
+# API
+FloatPlane.o: FloatPlane.cpp FloatPlane.h
+Image.o: Image.cpp FloatPlane.h Image.h
+JPEGFile.o: JPEGFile.cpp JPEGFile.h FloatPlane.h Image.h
+
+clean:
+ rm -f *.o testFP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/data.txt Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,7 @@
+output from jpeg_read_scanlines()
+--------------------------------
+JSAMPLE scanlines[0..nscanlines][column * nplanes + plane]
+
+output from decompress() or jpeg_read_raw_data()
+--------------------------------
+JSAMPLE scanlines[0..planes][scanline][column]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/testFP.cpp Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,19 @@
+#include "FloatPlane.h"
+
+int main()
+{
+ FloatPlane a;
+
+ a.allocate(100,100);
+
+ float *p = a.getPtr();
+ unsigned int w = a.getWidth();
+
+ for(int j=0; j < 100; j++)
+ for(int i=0; i < 100; i++)
+ p[j*w + i] = (float) ((i+j) % 255);
+
+ a.writePGM("prova.pgm");
+
+ a.free();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qjpeg/testJPEGFile.cpp Mon Jan 22 00:45:57 2007 +0100
@@ -0,0 +1,31 @@
+#include "JPEGFile.h"
+#include "Image.h"
+#include "FloatPlane.h"
+
+int main()
+{
+ JPEGFile a("a.jpg");
+
+ Image *i;
+
+ i = a.getUnpackedImage();
+
+ /* Write the planes */
+ i->plane[0].writePGM("hola1.pgm");
+ i->plane[1].writePGM("hola2.pgm");
+ i->plane[2].writePGM("hola3.pgm");
+
+ i->writePPM("hola.ppm");
+ /* Remove the image and its planes */
+ i->free();
+
+ i = a.getiDCTImage();
+
+ /* Write the planes */
+ i->plane[0].writePGM("ihola1.pgm");
+ i->plane[1].writePGM("ihola2.pgm");
+ i->plane[2].writePGM("ihola3.pgm");
+
+ i->free();
+ delete i;
+}