SFML logo
  • Main Page
  • Namespaces
  • Classes
  • Files
  • File List

ImageLoader.cpp

00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
00028 #include <SFML/Graphics/ImageLoader.hpp>
00029 extern "C"
00030 {
00031     #include <SFML/Graphics/libjpeg/jpeglib.h>
00032     #include <SFML/Graphics/libjpeg/jerror.h>
00033 }
00034 #include <SFML/Graphics/libpng/png.h>
00035 #include <SFML/Graphics/SOIL/SOIL.h>
00036 #include <SFML/System/Err.hpp>
00037 
00038 
00039 namespace
00040 {
00044     void PngErrorHandler(png_structp png, png_const_charp message)
00045     {
00046         sf::Err() << "Failed to write PNG image. Reason : " << message << std::endl;
00047         longjmp(png->jmpbuf, 1);
00048     }
00049 }
00050 
00051 
00052 namespace sf
00053 {
00054 namespace priv
00055 {
00059 ImageLoader& ImageLoader::GetInstance()
00060 {
00061     static ImageLoader Instance;
00062 
00063     return Instance;
00064 }
00065 
00066 
00070 ImageLoader::ImageLoader()
00071 {
00072     // Nothing to do
00073 }
00074 
00075 
00079 ImageLoader::~ImageLoader()
00080 {
00081     // Nothing to do
00082 }
00083 
00084 
00088 bool ImageLoader::LoadImageFromFile(const std::string& filename, std::vector<Color>& pixels, unsigned int& width, unsigned int& height)
00089 {
00090     // Clear the array (just in case)
00091     pixels.clear();
00092 
00093     // Load the image and get a pointer to the pixels in memory
00094     int imgWidth, imgHeight, imgChannels;
00095     unsigned char* ptr = SOIL_load_image(filename.c_str(), &imgWidth, &imgHeight, &imgChannels, SOIL_LOAD_RGBA);
00096 
00097     if (ptr)
00098     {
00099         // Assign the image properties
00100         width  = imgWidth;
00101         height = imgHeight;
00102 
00103         // Copy the loaded pixels to the pixel buffer
00104         pixels.resize(width * height);
00105         memcpy(&pixels[0], ptr, width * height * 4);
00106 
00107         // Free the loaded pixels (they are now in our own pixel buffer)
00108         SOIL_free_image_data(ptr);
00109 
00110         return true;
00111     }
00112     else
00113     {
00114         // Error, failed to load the image
00115         Err() << "Failed to load image \"" << filename << "\". Reason : " << SOIL_last_result() << std::endl;
00116 
00117         return false;
00118     }
00119 }
00120 
00121 
00125 bool ImageLoader::LoadImageFromMemory(const void* data, std::size_t sizeInBytes, std::vector<Color>& pixels, unsigned int& width, unsigned int& height)
00126 {
00127     // Clear the array (just in case)
00128     pixels.clear();
00129 
00130     // Load the image and get a pointer to the pixels in memory
00131     const unsigned char* buffer = reinterpret_cast<const unsigned char*>(data);
00132     int size = static_cast<int>(sizeInBytes);
00133     int imgWidth, imgHeight, imgChannels;
00134     unsigned char* ptr = SOIL_load_image_from_memory(buffer, size, &imgWidth, &imgHeight, &imgChannels, SOIL_LOAD_RGBA);
00135 
00136     if (ptr)
00137     {
00138         // Assign the image properties
00139         width  = imgWidth;
00140         height = imgHeight;
00141 
00142         // Copy the loaded pixels to the pixel buffer
00143         pixels.resize(width * height);
00144         memcpy(&pixels[0], ptr, width * height * 4);
00145 
00146         // Free the loaded pixels (they are now in our own pixel buffer)
00147         SOIL_free_image_data(ptr);
00148 
00149         return true;
00150     }
00151     else
00152     {
00153         // Error, failed to load the image
00154         Err() << "Failed to load image from memory. Reason : " << SOIL_last_result() << std::endl;
00155 
00156         return false;
00157     }
00158 }
00159 
00160 
00164 bool ImageLoader::SaveImageToFile(const std::string& filename, const std::vector<Color>& pixels, unsigned int width, unsigned int height)
00165 {
00166     // Deduce the image type from its extension
00167     int type = -1;
00168     if (filename.size() > 3)
00169     {
00170         std::string extension = filename.substr(filename.size() - 3);
00171         if      (extension == "bmp" || extension == "BMP") type = SOIL_SAVE_TYPE_BMP;
00172         else if (extension == "tga" || extension == "TGA") type = SOIL_SAVE_TYPE_TGA;
00173         else if (extension == "dds" || extension == "DDS") type = SOIL_SAVE_TYPE_DDS;
00174 
00175         // Special handling for PNG and JPG -- not handled by SOIL
00176         else if (extension == "png" || extension == "PNG") return WritePng(filename, pixels, width, height);
00177         else if (extension == "jpg" || extension == "JPG") return WriteJpg(filename, pixels, width, height);
00178     }
00179 
00180     if (type == -1)
00181     {
00182         // Error, incompatible type
00183         Err() << "Failed to save image \"" << filename << "\". Reason: this image format is not supported" << std::endl;
00184         return false;
00185     }
00186 
00187     // Finally save the image
00188     const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&pixels[0]);
00189     if (!SOIL_save_image(filename.c_str(), type, static_cast<int>(width), static_cast<int>(height), 4, ptr))
00190     {
00191         // Error, failed to save the image
00192         Err() << "Failed to save image \"" << filename << "\". Reason: " << SOIL_last_result() << std::endl;
00193         return false;
00194     }
00195 
00196     return true;
00197 }
00198 
00199 
00203 bool ImageLoader::WriteJpg(const std::string& filename, const std::vector<Color>& pixels, unsigned int width, unsigned int height)
00204 {
00205     // Open the file to write in
00206     FILE* file = fopen(filename.c_str(), "wb");
00207     if (!file)
00208     {
00209         Err() << "Failed to save image file \"" << filename << "\". Reason : cannot open file" << std::endl;
00210         return false;
00211     }
00212 
00213     // Initialize the error handler
00214     jpeg_compress_struct compressInfos;
00215     jpeg_error_mgr errorManager;
00216     compressInfos.err = jpeg_std_error(&errorManager);
00217 
00218     // Initialize all the writing and compression infos
00219     jpeg_create_compress(&compressInfos);
00220     compressInfos.image_width      = width;
00221     compressInfos.image_height     = height;
00222     compressInfos.input_components = 3;
00223     compressInfos.in_color_space   = JCS_RGB;
00224     jpeg_stdio_dest(&compressInfos, file);
00225     jpeg_set_defaults(&compressInfos);
00226     jpeg_set_quality(&compressInfos, 90, TRUE);
00227 
00228     // Get rid of the aplha channel
00229     std::vector<Uint8> buffer(width * height * 3);
00230     for (std::size_t i = 0; i < pixels.size(); ++i)
00231     {
00232         buffer[i * 3 + 0] = pixels[i].r;
00233         buffer[i * 3 + 1] = pixels[i].g;
00234         buffer[i * 3 + 2] = pixels[i].b;
00235     }
00236     Uint8* ptr = &buffer[0];
00237 
00238     // Start compression
00239     jpeg_start_compress(&compressInfos, TRUE);
00240 
00241     // Write each row of the image
00242     while (compressInfos.next_scanline < compressInfos.image_height)
00243     {
00244         JSAMPROW rawPointer = ptr + (compressInfos.next_scanline * width * 3);
00245         jpeg_write_scanlines(&compressInfos, &rawPointer, 1);
00246     }
00247 
00248     // Finish compression
00249     jpeg_finish_compress(&compressInfos);
00250     jpeg_destroy_compress(&compressInfos);
00251 
00252     // Close the file
00253     fclose(file);
00254 
00255     return true;
00256 }
00257 
00258 
00262 bool ImageLoader::WritePng(const std::string& filename, const std::vector<Color>& pixels, unsigned int width, unsigned int height)
00263 {
00264     // Open the file to write in
00265     FILE* file = fopen(filename.c_str(), "wb");
00266     if (!file)
00267     {
00268         Err() << "Failed to save image file \"" << filename << "\". Reason : cannot open file" << std::endl;
00269         return false;
00270     }
00271 
00272     // Create the main PNG structure
00273     png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &PngErrorHandler, NULL);
00274     if (!png)
00275     {
00276         fclose(file);
00277         Err() << "Failed to save image file \"" << filename << "\". Reason : cannot allocate PNG write structure" << std::endl;
00278         return false;
00279     }
00280 
00281     // Initialize the image informations
00282     png_infop pngInfos = png_create_info_struct(png);
00283     if (!pngInfos)
00284     {
00285         fclose(file);
00286         png_destroy_write_struct(&png, NULL);
00287         Err() << "Failed to save image file \"" << filename << "\". Reason : cannot allocate PNG info structure" << std::endl;
00288         return false;
00289     }
00290 
00291     // For proper error handling...
00292     if (setjmp(png->jmpbuf))
00293     {
00294         png_destroy_write_struct(&png, &pngInfos);
00295         return false;
00296     }
00297 
00298     // Link the file to the PNG structure
00299     png_init_io(png, file);
00300 
00301     // Set the image informations
00302     png_set_IHDR(png, pngInfos, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
00303 
00304     // Write the header
00305     png_write_info(png, pngInfos);
00306 
00307     // Get the pointers to the pixels rows into an array
00308     png_byte* ptr = (png_byte*)&pixels[0];
00309     std::vector<png_byte*> rawPointers(height);
00310     for (unsigned int i = 0; i < height; ++i)
00311     {
00312         rawPointers[i] = ptr;
00313         ptr += width * 4;
00314     }
00315 
00316     // Write pixels row by row
00317     png_set_rows(png, pngInfos, &rawPointers[0]);
00318     png_write_png(png, pngInfos, PNG_TRANSFORM_IDENTITY, NULL);
00319 
00320     // Finish writing the file
00321     png_write_end(png, pngInfos);
00322 
00323     // Cleanup resources
00324     png_destroy_write_struct(&png, &pngInfos);
00325     fclose(file);
00326 
00327     return true;
00328 }
00329 
00330 } // namespace priv
00331 
00332 } // namespace sf

 ::  Copyright © 2007-2008 Laurent Gomila, all rights reserved  ::  Documentation generated by doxygen 1.5.2  ::