Back to index

libsfml  1.6+dfsg2
ImageLoader.cpp
Go to the documentation of this file.
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 <iostream>
00037 
00038 
00039 namespace
00040 {
00044     void PngErrorHandler(png_structp Png, png_const_charp Message)
00045     {
00046         std::cerr << "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* PixelsPtr = SOIL_load_image(Filename.c_str(), &ImgWidth, &ImgHeight, &ImgChannels, SOIL_LOAD_RGBA);
00096 
00097     if (PixelsPtr)
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], PixelsPtr, Width * Height * 4);
00106 
00107         // Free the loaded pixels (they are now in our own pixel buffer)
00108         SOIL_free_image_data(PixelsPtr);
00109 
00110         return true;
00111     }
00112     else
00113     {
00114         // Error, failed to load the image
00115         std::cerr << "Failed to load image \"" << Filename << "\". Reason : " << SOIL_last_result() << std::endl;
00116 
00117         return false;
00118     }
00119 }
00120 
00121 
00125 bool ImageLoader::LoadImageFromMemory(const char* 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* PixelsPtr = SOIL_load_image_from_memory(Buffer, Size, &ImgWidth, &ImgHeight, &ImgChannels, SOIL_LOAD_RGBA);
00135 
00136     if (PixelsPtr)
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], PixelsPtr, Width * Height * 4);
00145 
00146         // Free the loaded pixels (they are now in our own pixel buffer)
00147         SOIL_free_image_data(PixelsPtr);
00148 
00149         return true;
00150     }
00151     else
00152     {
00153         // Error, failed to load the image
00154         std::cerr << "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         std::cerr << "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* PixelsPtr = 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, PixelsPtr))
00190     {
00191         // Error, failed to save the image
00192         std::cerr << "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         std::cerr << "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 CompressInfo;
00215     jpeg_error_mgr ErrorManager;
00216     CompressInfo.err = jpeg_std_error(&ErrorManager);
00217 
00218     // Initialize all the writing and compression infos
00219     jpeg_create_compress(&CompressInfo);
00220     CompressInfo.image_width      = Width;
00221     CompressInfo.image_height     = Height;
00222     CompressInfo.input_components = 3;
00223     CompressInfo.in_color_space   = JCS_RGB;
00224     jpeg_stdio_dest(&CompressInfo, File);
00225     jpeg_set_defaults(&CompressInfo);
00226     jpeg_set_quality(&CompressInfo, 90, TRUE);
00227 
00228     // Get rid of the aplha channel
00229     std::vector<Uint8> PixelsBuffer(Width * Height * 3);
00230     for (std::size_t i = 0; i < Pixels.size(); ++i)
00231     {
00232         PixelsBuffer[i * 3 + 0] = Pixels[i].r;
00233         PixelsBuffer[i * 3 + 1] = Pixels[i].g;
00234         PixelsBuffer[i * 3 + 2] = Pixels[i].b;
00235     }
00236     Uint8* PixelsPtr = &PixelsBuffer[0];
00237 
00238     // Start compression
00239     jpeg_start_compress(&CompressInfo, TRUE);
00240 
00241     // Write each row of the image
00242     while (CompressInfo.next_scanline < CompressInfo.image_height)
00243     {
00244         JSAMPROW RowPointer = PixelsPtr + (CompressInfo.next_scanline * Width * 3);
00245         jpeg_write_scanlines(&CompressInfo, &RowPointer, 1);
00246     }
00247 
00248     // Finish compression
00249     jpeg_finish_compress(&CompressInfo);
00250     jpeg_destroy_compress(&CompressInfo);
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         std::cerr << "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         std::cerr << "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 PngInfo = png_create_info_struct(Png);
00283     if (!PngInfo)
00284     {
00285         fclose(File);
00286         png_destroy_write_struct(&Png, NULL);
00287         std::cerr << "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, &PngInfo);
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, PngInfo, 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, PngInfo);
00306 
00307     // Get the pointers to the pixels rows into an array
00308     png_byte* PixelsPtr = (png_byte*)&Pixels[0];
00309     std::vector<png_byte*> RowPointers(Height);
00310     for (unsigned int i = 0; i < Height; ++i)
00311     {
00312         RowPointers[i] = PixelsPtr;
00313         PixelsPtr += Width * 4;
00314     }
00315 
00316     // Write pixels row by row
00317     png_set_rows(Png, PngInfo, &RowPointers[0]);
00318     png_write_png(Png, PngInfo, PNG_TRANSFORM_IDENTITY, NULL);
00319 
00320     // Finish writing the file
00321     png_write_end(Png, PngInfo);
00322 
00323     // Cleanup resources
00324     png_destroy_write_struct(&Png, &PngInfo);
00325     fclose(File);
00326 
00327     return true;
00328 }
00329 
00330 } // namespace priv
00331 
00332 } // namespace sf