1 /* 2 RGBAImage.cpp 3 Copyright (C) 2006-2011 Yangli Hector Yee 4 Copyright (C) 2011-2016 Steven Myint, Jeff Terrace 5 6 (This entire file was rewritten by Jim Tilander) 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 2 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT ANY 14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 PARTICULAR PURPOSE. See the GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License along with 18 this program; if not, write to the Free Software Foundation, Inc., 59 Temple 19 Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 #include "rgba_image.h" 23 24 #include <FreeImage.h> 25 26 #include <cassert> 27 #include <ciso646> 28 #include <cstring> 29 #include <string> 30 31 32 namespace pdiff 33 { 34 struct FreeImageDeleter 35 { operator ()pdiff::FreeImageDeleter36 inline void operator()(FIBITMAP *image) 37 { 38 if (image) 39 { 40 FreeImage_Unload(image); 41 } 42 } 43 }; 44 45 to_free_image(const RGBAImage & image)46 static std::shared_ptr<FIBITMAP> to_free_image(const RGBAImage &image) 47 { 48 const auto *data = image.get_data(); 49 50 std::shared_ptr<FIBITMAP> bitmap( 51 FreeImage_Allocate(image.get_width(), image.get_height(), 32, 52 0x000000ff, 0x0000ff00, 0x00ff0000), 53 FreeImageDeleter()); 54 assert(bitmap.get()); 55 56 for (auto y = 0u; y < image.get_height(); 57 y++, data += image.get_width()) 58 { 59 auto scanline = reinterpret_cast<unsigned int *>( 60 FreeImage_GetScanLine(bitmap.get(), image.get_height() - y - 1)); 61 memcpy(scanline, data, sizeof(data[0]) * image.get_width()); 62 } 63 64 return bitmap; 65 } 66 67 to_rgba_image(FIBITMAP * image,const std::string & filename="")68 static std::shared_ptr<RGBAImage> to_rgba_image(FIBITMAP *image, 69 const std::string &filename="") 70 { 71 const auto w = FreeImage_GetWidth(image); 72 const auto h = FreeImage_GetHeight(image); 73 74 auto result = std::make_shared<RGBAImage>(w, h, filename); 75 // Copy the image over to our internal format, FreeImage has the scanlines 76 // bottom to top though. 77 auto dest = result->get_data(); 78 for (unsigned int y = 0; y < h; y++, dest += w) 79 { 80 const auto scanline = reinterpret_cast<const unsigned int *>( 81 FreeImage_GetScanLine(image, h - y - 1)); 82 memcpy(dest, scanline, sizeof(dest[0]) * w); 83 } 84 85 return result; 86 87 } 88 down_sample(unsigned int w,unsigned int h) const89 std::shared_ptr<RGBAImage> RGBAImage::down_sample(unsigned int w, 90 unsigned int h) const 91 { 92 if (w == 0) 93 { 94 w = width_ / 2; 95 } 96 97 if (h == 0) 98 { 99 h = weight_ / 2; 100 } 101 102 if (width_ <= 1 or weight_ <= 1) 103 { 104 return nullptr; 105 } 106 if (width_ == w and weight_ == h) 107 { 108 return nullptr; 109 } 110 assert(w <= width_); 111 assert(h <= weight_); 112 113 auto bitmap = to_free_image(*this); 114 std::unique_ptr<FIBITMAP, FreeImageDeleter> converted( 115 FreeImage_Rescale(bitmap.get(), w, h, FILTER_BICUBIC)); 116 117 auto img = to_rgba_image(converted.get(), name_); 118 119 return img; 120 } 121 write_to_file(const std::string & filename) const122 void RGBAImage::write_to_file(const std::string &filename) const 123 { 124 const auto file_type = FreeImage_GetFIFFromFilename(filename.c_str()); 125 if (FIF_UNKNOWN == file_type) 126 { 127 throw RGBImageException("Can't save to unknown filetype '" + 128 filename + "'"); 129 } 130 131 auto bitmap = to_free_image(*this); 132 133 const bool result = 134 !!FreeImage_Save(file_type, bitmap.get(), filename.c_str()); 135 if (not result) 136 { 137 throw RGBImageException("Failed to save to '" + filename + "'"); 138 } 139 } 140 read_from_file(const std::string & filename)141 std::shared_ptr<RGBAImage> read_from_file(const std::string &filename) 142 { 143 const auto file_type = FreeImage_GetFileType(filename.c_str()); 144 if (FIF_UNKNOWN == file_type) 145 { 146 throw RGBImageException("Unknown filetype '" + filename + "'"); 147 } 148 149 FIBITMAP *free_image = nullptr; 150 if (auto temporary = FreeImage_Load(file_type, filename.c_str(), 0)) 151 { 152 free_image = FreeImage_ConvertTo32Bits(temporary); 153 FreeImage_Unload(temporary); 154 } 155 if (not free_image) 156 { 157 throw RGBImageException("Failed to load the image " + filename); 158 } 159 160 auto result = to_rgba_image(free_image); 161 162 FreeImage_Unload(free_image); 163 164 return result; 165 } 166 } 167