First classes for the qjpeg project. last-libjpeg7
authorviric@llimona
Mon, 22 Jan 2007 00:45:57 +0100
changeset 76 9cbf4c7e7986
parent 75 327eef3fe747
child 78 a55bf2fa3f74
First classes for the qjpeg project.
qjpeg/FloatPlane.cpp
qjpeg/FloatPlane.h
qjpeg/Image.cpp
qjpeg/Image.h
qjpeg/JPEGFile.cpp
qjpeg/JPEGFile.h
qjpeg/Makefile
qjpeg/data.txt
qjpeg/testFP.cpp
qjpeg/testJPEGFile.cpp
--- /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;
+}