1 /* 2 Copyright (C) 2010-2014 Kristian Duske 3 4 This file is part of TrenchBroom. 5 6 TrenchBroom is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 TrenchBroom is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "ImageLoaderImpl.h" 21 22 #include "Exceptions.h" 23 #include "Macros.h" 24 #include "IO/Path.h" 25 26 namespace TrenchBroom { 27 namespace IO { InitFreeImage()28 ImageLoaderImpl::InitFreeImage::InitFreeImage() { 29 FreeImage_Initialise(true); 30 } 31 ~InitFreeImage()32 ImageLoaderImpl::InitFreeImage::~InitFreeImage() { 33 FreeImage_DeInitialise(); 34 } 35 ImageLoaderImpl(const ImageLoader::Format format,const Path & path)36 ImageLoaderImpl::ImageLoaderImpl(const ImageLoader::Format format, const Path& path) : 37 m_stream(NULL), 38 m_bitmap(NULL), 39 m_paletteInitialized(false), 40 m_indicesInitialized(false), 41 m_pixelsInitialized(false) { 42 initialize(); 43 const FREE_IMAGE_FORMAT fifFormat = translateFormat(format); 44 if (fifFormat == FIF_UNKNOWN) 45 throw FileFormatException("Unknown image format"); 46 47 m_bitmap = FreeImage_Load(fifFormat, path.asString().c_str()); 48 } 49 ImageLoaderImpl(const ImageLoader::Format format,const char * begin,const char * end)50 ImageLoaderImpl::ImageLoaderImpl(const ImageLoader::Format format, const char* begin, const char* end) : 51 m_stream(NULL), 52 m_bitmap(NULL), 53 m_paletteInitialized(false), 54 m_indicesInitialized(false), 55 m_pixelsInitialized(false) { 56 initialize(); 57 const FREE_IMAGE_FORMAT fifFormat = translateFormat(format); 58 if (fifFormat == FIF_UNKNOWN) 59 throw FileFormatException("Unknown image format"); 60 61 // this is supremely evil, but FreeImage guarantees that it will not modify wrapped memory 62 BYTE* address = reinterpret_cast<BYTE*>(const_cast<char*>(begin)); 63 DWORD length = static_cast<DWORD>(end - begin); 64 m_stream = FreeImage_OpenMemory(address, length); 65 m_bitmap = FreeImage_LoadFromMemory(fifFormat, m_stream); 66 } 67 ~ImageLoaderImpl()68 ImageLoaderImpl::~ImageLoaderImpl() { 69 if (m_bitmap != NULL) { 70 FreeImage_Unload(m_bitmap); 71 m_bitmap = NULL; 72 } 73 if (m_stream != NULL) { 74 FreeImage_CloseMemory(m_stream); 75 m_stream = NULL; 76 } 77 } 78 paletteSize() const79 size_t ImageLoaderImpl::paletteSize() const { 80 return static_cast<size_t>(FreeImage_GetColorsUsed(m_bitmap)); 81 } 82 bitsPerPixel() const83 size_t ImageLoaderImpl::bitsPerPixel() const { 84 return static_cast<size_t>(FreeImage_GetBPP(m_bitmap)); 85 } 86 width() const87 size_t ImageLoaderImpl::width() const { 88 return static_cast<size_t>(FreeImage_GetWidth(m_bitmap)); 89 } 90 height() const91 size_t ImageLoaderImpl::height() const { 92 return static_cast<size_t>(FreeImage_GetHeight(m_bitmap)); 93 } 94 byteWidth() const95 size_t ImageLoaderImpl::byteWidth() const { 96 return static_cast<size_t>(FreeImage_GetLine(m_bitmap)); 97 } 98 scanWidth() const99 size_t ImageLoaderImpl::scanWidth() const { 100 return static_cast<size_t>(FreeImage_GetPitch(m_bitmap)); 101 } 102 hasPalette() const103 bool ImageLoaderImpl::hasPalette() const { 104 return FreeImage_GetPalette(m_bitmap) != NULL; 105 } 106 hasIndices() const107 bool ImageLoaderImpl::hasIndices() const { 108 return FreeImage_GetColorType(m_bitmap) == FIC_PALETTE; 109 } 110 hasPixels() const111 bool ImageLoaderImpl::hasPixels() const { 112 return static_cast<bool>(FreeImage_HasPixels(m_bitmap) == TRUE); 113 } 114 palette() const115 const Buffer<unsigned char>& ImageLoaderImpl::palette() const { 116 assert(hasPalette()); 117 if (!m_paletteInitialized) { 118 const RGBQUAD* pal = FreeImage_GetPalette(m_bitmap); 119 if (pal != NULL) { 120 m_palette = Buffer<unsigned char>(paletteSize() * 3); 121 for (size_t i = 0; i < paletteSize(); ++i) { 122 m_palette[i * 3 + 0] = static_cast<unsigned char>(pal[i].rgbRed); 123 m_palette[i * 3 + 1] = static_cast<unsigned char>(pal[i].rgbGreen); 124 m_palette[i * 3 + 2] = static_cast<unsigned char>(pal[i].rgbBlue); 125 } 126 127 m_paletteInitialized = true; 128 } 129 } 130 131 return m_palette; 132 } 133 indices() const134 const Buffer<unsigned char>& ImageLoaderImpl::indices() const { 135 assert(hasIndices()); 136 if (!m_indicesInitialized) { 137 m_indices = Buffer<unsigned char>(width() * height()); 138 for (unsigned y = 0; y < height(); ++y) { 139 for (unsigned x = 0; x < width(); ++x) { 140 BYTE index = 0; 141 const bool success = (FreeImage_GetPixelIndex(m_bitmap, x, y, &index) == TRUE); 142 assert(success); 143 unused(success); 144 m_indices[(height() - y - 1) * width() + x] = static_cast<unsigned char>(index); 145 } 146 } 147 148 m_indicesInitialized = true; 149 } 150 151 return m_indices; 152 } 153 pixels(const ImageLoader::PixelFormat format) const154 const Buffer<unsigned char>& ImageLoaderImpl::pixels(const ImageLoader::PixelFormat format) const { 155 assert(hasPixels()); 156 if (!m_pixelsInitialized) { 157 const size_t pSize = pixelSize(format); 158 m_pixels = Buffer<unsigned char>(width() * height() * pSize); 159 if (hasIndices()) 160 initializeIndexedPixels(pSize); 161 else 162 initializePixels(pSize); 163 m_pixelsInitialized = true; 164 } 165 166 return m_pixels; 167 } 168 initialize()169 void ImageLoaderImpl::initialize() { 170 static InitFreeImage initFreeImage; 171 } 172 initializeIndexedPixels(const size_t pSize) const173 void ImageLoaderImpl::initializeIndexedPixels(const size_t pSize) const { 174 assert(pSize == 3); 175 const RGBQUAD* pal = FreeImage_GetPalette(m_bitmap); 176 assert(pal != NULL); 177 178 for (unsigned y = 0; y < height(); ++y) { 179 for (unsigned x = 0; x < width(); ++x) { 180 BYTE paletteIndex = 0; 181 const bool success = (FreeImage_GetPixelIndex(m_bitmap, x, y, &paletteIndex) == TRUE); 182 assert(success); 183 unused(success); 184 185 assert(paletteIndex < paletteSize()); 186 187 const size_t pixelIndex = ((height() - y - 1) * width() + x) * pSize; 188 m_pixels[pixelIndex + 0] = static_cast<unsigned char>(pal[paletteIndex].rgbRed); 189 m_pixels[pixelIndex + 1] = static_cast<unsigned char>(pal[paletteIndex].rgbGreen); 190 m_pixels[pixelIndex + 2] = static_cast<unsigned char>(pal[paletteIndex].rgbBlue); 191 } 192 } 193 } 194 initializePixels(const size_t pSize) const195 void ImageLoaderImpl::initializePixels(const size_t pSize) const { 196 for (unsigned y = 0; y < height(); ++y) { 197 for (unsigned x = 0; x < width(); ++x) { 198 RGBQUAD pixel; 199 const bool success = (FreeImage_GetPixelColor(m_bitmap, x, y, &pixel) == TRUE); 200 assert(success); 201 unused(success); 202 203 const size_t pixelIndex = ((height() - y - 1) * width() + x) * pSize; 204 m_pixels[pixelIndex + 0] = static_cast<unsigned char>(pixel.rgbRed); 205 m_pixels[pixelIndex + 1] = static_cast<unsigned char>(pixel.rgbGreen); 206 m_pixels[pixelIndex + 2] = static_cast<unsigned char>(pixel.rgbBlue); 207 if (pSize > 3) 208 m_pixels[pixelIndex + 3] = static_cast<unsigned char>(pixel.rgbReserved); 209 } 210 } 211 } 212 translateFormat(const ImageLoader::Format format)213 FREE_IMAGE_FORMAT ImageLoaderImpl::translateFormat(const ImageLoader::Format format) { 214 switch (format) { 215 case ImageLoader::PCX: 216 return FIF_PCX; 217 switchDefault() 218 } 219 } 220 pixelSize(const ImageLoader::PixelFormat format)221 size_t ImageLoaderImpl::pixelSize(const ImageLoader::PixelFormat format) { 222 switch (format) { 223 case ImageLoader::RGB: 224 return 3; 225 case ImageLoader::RGBA: 226 return 4; 227 switchDefault() 228 } 229 } 230 } 231 } 232