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 ::