Parcourir la source

add RAWLS file v2

Jérôme BUISINE il y a 3 ans
Parent
commit
a7e3e8137c
4 fichiers modifiés avec 474 ajouts et 8 suppressions
  1. 4 0
      rawls/CMakeLists.txt
  2. 3 8
      rawls/rawls.cpp
  3. 391 0
      rawls/rawls_v1.cpp
  4. 76 0
      rawls/rawls_v1.h

+ 4 - 0
rawls/CMakeLists.txt

@@ -1,6 +1,10 @@
 add_library(rawls rawls.h rawls.cpp)
+add_library(rawls_v1 rawls_v1.h rawls_v1.cpp)
 
 target_link_libraries(rawls LINK_PUBLIC lodepng)
 target_link_libraries(rawls LINK_PUBLIC stdc++fs)
 
+target_link_libraries(rawls_v1 LINK_PUBLIC lodepng)
+target_link_libraries(rawls_v1 LINK_PUBLIC stdc++fs)
+
 target_include_directories (rawls PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

+ 3 - 8
rawls/rawls.cpp

@@ -127,9 +127,7 @@ bool rawls::saveAsRAWLS(unsigned width, unsigned height, unsigned nbChanels, std
     outfile << "IHDR" << std::endl;
     outfile << ((sizeof(width) + sizeof(height) + sizeof(nbChanels)))  << std::endl;
     outfile.write((char *) &width, sizeof(width));
-    outfile << " ";
     outfile.write((char *) &height, sizeof(height));
-    outfile << " ";
     outfile.write((char *) &nbChanels, sizeof(nbChanels));
     outfile << std::endl;
 
@@ -154,8 +152,8 @@ bool rawls::saveAsRAWLS(unsigned width, unsigned height, unsigned nbChanels, std
             outfile.write((char *) &pixel[0], sizeof(pixel[0]));
             outfile.write((char *) &pixel[1], sizeof(pixel[1]));
             outfile.write((char *) &pixel[2], sizeof(pixel[2]));
-            outfile << std::endl;
         }
+        outfile << std::endl;
     }
 
     outfile.close();
@@ -218,10 +216,9 @@ float* rawls::getPixelsRAWLS(std::string filename){
                 
                 buffer[nbChanels * width * y + nbChanels * x + j] = chanelValue; 
             } 
-
-            // go to next line
-            rf.get(c);
         }
+        // go to next line
+        rf.get(c);
     }
 
     rf.close();
@@ -256,9 +253,7 @@ std::tuple<unsigned, unsigned, unsigned> rawls::getDimensionsRAWLS(std::string f
             std::getline(rf, line); // avoid data size line
 
             rf.read((char *) &width, sizeof(unsigned));
-            rf.get(c);
             rf.read((char *) &height, sizeof(unsigned));
-            rf.get(c);
             rf.read((char *) &nbChanels, sizeof(unsigned));
             rf.get(c);
         }

+ 391 - 0
rawls/rawls_v1.cpp

@@ -0,0 +1,391 @@
+#include "rawls_v1.h"
+
+#include <fstream>
+#include <memory>
+#include "lodepng.h"
+
+/*
+ * Read all pixels values from .rawls image file and save as PPM image
+ */
+bool rawls_v1::convertToPPM(std::string imageName, std::string outfileName){
+
+    // get dimensions and data information from image
+    unsigned width, height, nbChanels;
+    float* buffer;
+
+    std::tuple<unsigned, unsigned, unsigned, float*> data = getDataRAWLS(imageName);
+
+    width = std::get<0>(data);
+    height = std::get<1>(data);
+    nbChanels = std::get<2>(data);
+    buffer = std::get<3>(data);
+
+    return saveAsPPM(width, height, nbChanels, buffer, outfileName);
+}
+
+/*
+ * Read all pixels values from .rawls image file and save as PNG image
+ */
+bool rawls_v1::convertToPNG(std::string imageName, std::string outfileName){
+
+    // get dimensions and data information from image
+    unsigned width, height, nbChanels;
+    float* buffer;
+
+    std::tuple<unsigned, unsigned, unsigned, float*> data = getDataRAWLS(imageName);
+
+    width = std::get<0>(data);
+    height = std::get<1>(data);
+    nbChanels = std::get<2>(data);
+    buffer = std::get<3>(data);
+
+    return saveAsPNG(width, height, nbChanels, buffer, outfileName);
+}
+
+
+/*
+ * Convert buffer using dimensions to PPM image format
+ */
+bool rawls_v1::saveAsPPM(unsigned width, unsigned height, unsigned nbChanels, float* buffer, std::string outfileName){
+
+    // open buffer
+    std::ofstream outfile(outfileName);
+
+    outfile << "P" << nbChanels << std::endl;
+    outfile << width << " " << height << std::endl;
+    outfile << "255" << std::endl;
+
+    for(unsigned y = 0; y < height; y++){
+
+        for(unsigned x = 0; x < width; x++) {
+
+            // for each chanel read and keep save float value i nto new file
+            for(int j = 0; j < nbChanels; j++){
+                outfile << int(GammaConvert(buffer[nbChanels * width * y + nbChanels * x + j])) << " "; 
+            } 
+        }
+
+        outfile << std::endl;
+    }
+
+    std::cout << "Image is now saved as .ppm into " << outfileName << std::endl;
+
+    outfile.close();
+
+    if(!outfile.good()) {
+        std::cout << "Error occurred at writing time!" << std::endl;
+        return false;
+    }
+
+    return true;
+}
+
+
+/*
+ * Convert buffer using dimensions to PNG image format
+ */
+bool rawls_v1::saveAsPNG(unsigned width, unsigned height, unsigned nbChanels, float* buffer, std::string outfileName){
+
+    // image buffer
+    unsigned nbChanelsAlpha = nbChanels + 1;
+    std::unique_ptr<uint8_t[]> outBuf(new uint8_t[width * height * nbChanelsAlpha]);
+    uint8_t *image = outBuf.get();
+
+    for(unsigned y = 0; y < height; y++){
+
+        for(unsigned x = 0; x < width; x++) {
+
+            for(int j = 0; j < nbChanels; j++){
+
+                float value = buffer[nbChanels * width * y + nbChanels * x + j];
+                image[nbChanelsAlpha * width * y + nbChanelsAlpha * x + j] = int(GammaConvert(value)); 
+            } 
+
+            // alpha channel
+            image[nbChanelsAlpha * width * y + nbChanelsAlpha * x + 3] = 255; 
+        }
+    }
+    
+    unsigned error = lodepng::encode(outfileName, image, width, height);
+   
+    //if there's an error, display it
+    if(error) {
+        std::cout << "encoder error " << error << ": "<< lodepng_error_text(error) << std::endl;
+        return false;
+    }
+
+    std::cout << "Image is now saved as .png into " << outfileName << std::endl;
+    
+    return true;
+}
+
+
+bool rawls_v1::saveAsRAWLS(unsigned width, unsigned height, unsigned nbChanels, std::string comments, float* buffer, std::string outfileName){
+    
+    std::ofstream outfile(outfileName, std::ios::out | std::ios::binary);
+
+    outfile << "IHDR" << std::endl;
+    outfile << ((sizeof(width) + sizeof(height) + sizeof(nbChanels)))  << std::endl;
+    outfile.write((char *) &width, sizeof(width));
+    outfile << " ";
+    outfile.write((char *) &height, sizeof(height));
+    outfile << " ";
+    outfile.write((char *) &nbChanels, sizeof(nbChanels));
+    outfile << std::endl;
+
+    // Part 2
+    // Comments (usefull information about scene and generation data used)
+    outfile << "COMMENTS" << std::endl;
+    outfile << comments;
+    
+    // Part 3
+    // using data information write specific chunck
+    outfile << "DATA" << std::endl;
+    outfile << (sizeof(float) * nbChanels * width * height) << std::endl;
+
+    for (int y = 0; y < height; ++y) {
+        for (int x = 0; x < width; ++x) {
+            float pixel[3];
+
+            pixel[0] = buffer[3 * (y * width + x) + 0];
+            pixel[1] = buffer[3 * (y * width + x) + 1];
+            pixel[2] = buffer[3 * (y * width + x) + 2];
+            
+            outfile.write((char *) &pixel[0], sizeof(pixel[0]));
+            outfile.write((char *) &pixel[1], sizeof(pixel[1]));
+            outfile.write((char *) &pixel[2], sizeof(pixel[2]));
+            outfile << std::endl;
+        }
+    }
+
+    outfile.close();
+    
+    if(!outfile.good()) {
+        std::cout << "Error occurred at writing time!" << std::endl;
+        return false;
+    }
+
+    std::cout << "Image is now saved as .rawls into " << outfileName << std::endl;
+
+    return true;
+}
+
+
+float* rawls_v1::getPixelsRAWLS(std::string filename){
+
+    // get dimensions information from image
+    unsigned width, height, nbChanels;
+
+    std::tuple<unsigned, unsigned, unsigned> dimensions = getDimensionsRAWLS(filename);
+
+    width = std::get<0>(dimensions);
+    height = std::get<1>(dimensions);
+    nbChanels = std::get<2>(dimensions);
+
+    std::ifstream rf(filename, std::ios::out | std::ios::binary);
+
+    if(!rf) {
+      std::cout << "Cannot open file!" << std::endl;
+    }
+
+    std::string line; 
+    char c; // to get space of new line char
+  
+    bool dataBegin = false;
+
+    // READ DATA info
+    // case of data chunck begin
+    while (!dataBegin && std::getline(rf, line)) { 
+
+        if (line.find(std::string("DATA")) != std::string::npos){
+            dataBegin = true;
+        }
+    }
+
+    // resize buffer if necessary
+    float* buffer = new float[height * width * nbChanels];
+
+    std::getline(rf, line);
+    unsigned size = std::stoi(line);
+    float chanelValue;
+
+    for(unsigned y = 0; y < height; y++){
+
+        for(unsigned x = 0; x < width; x++) {
+
+            for(int j = 0; j < nbChanels; j++){
+                rf.read((char *) &chanelValue, sizeof(float));  
+                
+                buffer[nbChanels * width * y + nbChanels * x + j] = chanelValue; 
+            } 
+
+            // go to next line
+            rf.get(c);
+        }
+    }
+
+    rf.close();
+
+    if(!rf.good()) {
+        std::cout << "Error occurred at writing time!" << std::endl;
+    }
+
+    return buffer;
+}
+
+
+std::tuple<unsigned, unsigned, unsigned> rawls_v1::getDimensionsRAWLS(std::string filename){
+
+    std::ifstream rf(filename, std::ios::out | std::ios::binary);
+
+    if(!rf) {
+      std::cout << "Cannot open file!" << std::endl;
+    }
+
+    std::string line; 
+    unsigned nbChanels, width, height;
+    char c; // to get space of new line char
+
+    // READ IHDR info
+    bool ihdrBegin = false;
+
+    while (!ihdrBegin && std::getline(rf, line)) { 
+
+        if (line.find(std::string("IHDR")) != std::string::npos){
+            ihdrBegin = true;
+            std::getline(rf, line); // avoid data size line
+
+            rf.read((char *) &width, sizeof(unsigned));
+            rf.get(c);
+            rf.read((char *) &height, sizeof(unsigned));
+            rf.get(c);
+            rf.read((char *) &nbChanels, sizeof(unsigned));
+            rf.get(c);
+        }
+    }
+
+    rf.close();
+
+    if(!rf.good()) {
+        std::cout << "Error occurred at writing time!" << std::endl;
+    }
+
+    return std::make_tuple(width, height, nbChanels);
+}
+
+
+std::tuple<unsigned, unsigned, unsigned, float*> rawls_v1::getDataRAWLS(std::string filename){
+
+    // only one read buffer used for the whole function
+    std::ifstream rf(filename, std::ios::out | std::ios::binary);
+
+    if(!rf) {
+      std::cout << "Cannot open file!" << std::endl;
+    }
+
+    std::string line; 
+    unsigned nbChanels, width, height;
+    char c; // to get space of new line char
+
+    // READ IHDR info
+    bool ihdrBegin = false;
+
+    while (!ihdrBegin && std::getline(rf, line)) { 
+
+        if (line.find(std::string("IHDR")) != std::string::npos){
+            ihdrBegin = true;
+            std::getline(rf, line); // avoid data size line
+
+            rf.read((char *) &width, sizeof(unsigned));
+            rf.get(c);
+            rf.read((char *) &height, sizeof(unsigned));
+            rf.get(c);
+            rf.read((char *) &nbChanels, sizeof(unsigned));
+            rf.get(c);
+        }
+    }
+
+    bool dataBegin = false;
+
+    // READ DATA info
+    // case of data chunck begin
+    while (!dataBegin && std::getline(rf, line)) { 
+
+        if (line.find(std::string("DATA")) != std::string::npos){
+            dataBegin = true;
+        }
+    }
+
+    // resize buffer if necessary
+    float* buffer = new float[height * width * nbChanels];
+
+    std::getline(rf, line);
+    unsigned size = std::stoi(line);
+    float chanelValue;
+
+    for(unsigned y = 0; y < height; y++){
+
+        for(unsigned x = 0; x < width; x++) {
+
+            for(int j = 0; j < nbChanels; j++){
+                rf.read((char *) &chanelValue, sizeof(float));  
+                
+                buffer[nbChanels * width * y + nbChanels * x + j] = chanelValue; 
+            } 
+
+            // go to next line
+            rf.get(c);
+        }
+    }
+
+    rf.close();
+
+    if(!rf.good()) {
+        std::cout << "Error occurred at writing time!" << std::endl;
+    }
+
+    return std::make_tuple(width, height, nbChanels, buffer);
+}
+
+std::string rawls_v1::getCommentsRAWLS(std::string filename){
+
+    std::string comments;
+
+    // only one read buffer used for the whole function
+    std::ifstream rf(filename, std::ios::out | std::ios::binary);
+
+    if(!rf) {
+      std::cout << "Cannot open file!" << std::endl;
+    }
+
+    std::string line; 
+    unsigned nbChanels, width, height;
+    char c; // to get space of new line char
+
+    // READ IHDR info
+    bool commentsBegin = false;
+
+    while (!commentsBegin && std::getline(rf, line)) { 
+
+        if (line.find(std::string("COMMENTS")) != std::string::npos){
+            commentsBegin = true;
+        }
+    }
+
+    bool dataBegin = false;
+
+    // READ DATA info
+    // case of data chunck begin
+    while (!dataBegin && std::getline(rf, line)) { 
+
+        if (line.find(std::string("DATA")) != std::string::npos){
+            dataBegin = true;
+        }
+        else
+        {
+            comments = comments + line + '\n';
+        }
+    }
+
+    return comments;
+}

+ 76 - 0
rawls/rawls_v1.h

@@ -0,0 +1,76 @@
+#include <string.h>
+#include <iostream>
+#include <math.h>
+#include <tuple>
+
+namespace rawls_v1{
+
+/*
+ * Gamma conversion functions
+ */
+inline float GammaCorrect(float value) {
+    if (value <= 0.0031308f) return 12.92f * value;
+    return 1.055f * std::pow(value, (float)(1.f / 2.4f)) - 0.055f;
+}
+
+template <typename T, typename U, typename V>
+inline T Clamp(T val, U low, V high) {
+    if (val < low)
+        return low;
+    else if (val > high)
+        return high;
+    else
+        return val;
+}
+
+inline bool HasExtension(const std::string &value, const std::string &ending) {
+    if (ending.size() > value.size()) return false;
+    return std::equal(
+        ending.rbegin(), ending.rend(), value.rbegin(),
+        [](char a, char b) { return std::tolower(a) == std::tolower(b); });
+}
+
+//#define GAMMA_CONVERT(v) (float) rawls::Clamp(255.f * rawls::GammaCorrect(v) + 0.5f, 0.f, 255.f)
+inline float GammaConvert(float value){
+    return rawls_v1::Clamp(255.f * rawls_v1::GammaCorrect(value) + 0.5f, 0.f, 255.f);
+}
+
+
+/*
+ * Save and write functions
+ */
+bool convertToPPM(std::string imageName, std::string outfileName);
+
+bool convertToPNG(std::string imageName, std::string outfileName);
+
+bool saveAsPPM(unsigned width, unsigned height, unsigned nbChanels, float* buffer, std::string outfileName);
+
+bool saveAsPNG(unsigned width, unsigned height, unsigned nbChanels, float* buffer, std::string outfileName);
+
+bool saveAsRAWLS(unsigned width, unsigned height, unsigned nbChanels, std::string comments, float* buffer, std::string outfileName);
+
+/*
+ * Read `.rawls` image and fill buffer pass as parameter
+ *
+ * `float*` is pointer to data buffer and needed to be deleted
+ */
+float* getPixelsRAWLS(std::string filename);
+
+/*
+ * Returns comments from `.rawls` format
+ */
+std::string getCommentsRAWLS(std::string filename);
+
+/*
+ * Returns tuple with <width, height, channels> information of image
+ */
+std::tuple<unsigned, unsigned, unsigned> getDimensionsRAWLS(std::string filename);
+
+/*
+ * Returns tuple with <width, height, channels, buffer*> information of image
+ *
+ * `float*` is pointer to data buffer and needed to be deleted
+ */
+std::tuple<unsigned, unsigned, unsigned, float*> getDataRAWLS(std::string filename);
+
+};