Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

ShImage.cpp

00001 // Sh: A GPU metaprogramming language. 00002 // 00003 // Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory 00004 // Project administrator: Michael D. McCool 00005 // Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa, 00006 // Michael D. McCool 00007 // 00008 // This software is provided 'as-is', without any express or implied 00009 // warranty. In no event will the authors be held liable for any damages 00010 // arising from the use of this software. 00011 // 00012 // Permission is granted to anyone to use this software for any purpose, 00013 // including commercial applications, and to alter it and redistribute it 00014 // freely, subject to the following restrictions: 00015 // 00016 // 1. The origin of this software must not be misrepresented; you must 00017 // not claim that you wrote the original software. If you use this 00018 // software in a product, an acknowledgment in the product documentation 00019 // would be appreciated but is not required. 00020 // 00021 // 2. Altered source versions must be plainly marked as such, and must 00022 // not be misrepresented as being the original software. 00023 // 00024 // 3. This notice may not be removed or altered from any source 00025 // distribution. 00027 #include "ShImage.hpp" 00028 #include <string> 00029 #include <cstring> 00030 #include <cstdio> 00031 #include <cmath> 00032 #include <png.h> 00033 #include <sstream> 00034 #include "ShException.hpp" 00035 #include "ShError.hpp" 00036 #include "ShDebug.hpp" 00037 00038 namespace SH { 00039 00040 ShImage::ShImage() 00041 : m_width(0), m_height(0), m_elements(0), m_memory(0) 00042 { 00043 } 00044 00045 ShImage::ShImage(int width, int height, int elements) 00046 : m_width(width), m_height(height), m_elements(elements), 00047 m_memory(new ShHostMemory(sizeof(float) * m_width * m_height * m_elements)) 00048 { 00049 } 00050 00051 ShImage::ShImage(const ShImage& other) 00052 : m_width(other.m_width), m_height(other.m_height), m_elements(other.m_elements), 00053 m_memory(other.m_memory ? new ShHostMemory(sizeof(float) * m_width * m_height * m_elements) : 0) 00054 { 00055 if (m_memory) { 00056 std::memcpy(m_memory->hostStorage()->data(), 00057 other.m_memory->hostStorage()->data(), 00058 m_width * m_height * m_elements * sizeof(float)); 00059 } 00060 } 00061 00062 ShImage::~ShImage() 00063 { 00064 } 00065 00066 ShImage& ShImage::operator=(const ShImage& other) 00067 { 00068 m_width = other.m_width; 00069 m_height = other.m_height; 00070 m_elements = other.m_elements; 00071 m_memory = (other.m_memory ? new ShHostMemory(sizeof(float) * m_width * m_height * m_elements) : 0); 00072 std::memcpy(m_memory->hostStorage()->data(), 00073 other.m_memory->hostStorage()->data(), 00074 m_width * m_height * m_elements * sizeof(float)); 00075 00076 return *this; 00077 } 00078 00079 int ShImage::width() const 00080 { 00081 return m_width; 00082 } 00083 00084 int ShImage::height() const 00085 { 00086 return m_height; 00087 } 00088 00089 int ShImage::elements() const 00090 { 00091 return m_elements; 00092 } 00093 00094 float ShImage::operator()(int x, int y, int i) const 00095 { 00096 SH_DEBUG_ASSERT(m_memory); 00097 return data()[m_elements * (m_width * y + x) + i]; 00098 } 00099 00100 float& ShImage::operator()(int x, int y, int i) 00101 { 00102 return data()[m_elements * (m_width * y + x) + i]; 00103 } 00104 00105 void ShImage::savePng(const std::string& filename, int inverse_alpha) 00106 { 00107 FILE* fout = std::fopen(filename.c_str(), "w"); 00108 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 00109 png_infop info_ptr = png_create_info_struct(png_ptr); 00110 setjmp(png_ptr->jmpbuf); 00111 00112 /* Setup PNG I/O */ 00113 png_init_io(png_ptr, fout); 00114 00115 /* Optionally setup a callback to indicate when a row has been 00116 * written. */ 00117 00118 /* Setup filtering. Use Paeth filtering */ 00119 png_set_filter(png_ptr, 0, PNG_FILTER_PAETH); 00120 00121 /* Setup compression level. */ 00122 png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); 00123 00124 /* Setup PNG header information and write it to the file */ 00125 00126 int color_type; 00127 switch (m_elements) { 00128 case 1: 00129 color_type = PNG_COLOR_TYPE_GRAY; 00130 break; 00131 case 2: 00132 color_type = PNG_COLOR_TYPE_GRAY_ALPHA; 00133 break; 00134 case 3: 00135 color_type = PNG_COLOR_TYPE_RGB; 00136 break; 00137 case 4: 00138 color_type = PNG_COLOR_TYPE_RGBA; 00139 break; 00140 default: 00141 throw ShImageException("Invalid element size"); 00142 } 00143 00144 png_set_IHDR(png_ptr, info_ptr, 00145 m_width, m_height, 00146 8, 00147 color_type, 00148 PNG_INTERLACE_NONE, 00149 PNG_COMPRESSION_TYPE_DEFAULT, 00150 PNG_FILTER_TYPE_DEFAULT); 00151 png_write_info(png_ptr, info_ptr); 00152 00153 // Actual writing 00154 png_byte* tempLine = (png_byte*)malloc(m_width * sizeof(png_byte) * m_elements); 00155 00156 for(int i=0;i<m_height;i+=1){ 00157 for(int j=0;j<m_width;j+=1){ 00158 for(int k = 0;k<m_elements;k+=1) 00159 tempLine[m_elements*j+k] = static_cast<png_byte>((*this)(j, i, k)*255.0); 00160 00161 // inverse alpha 00162 if(inverse_alpha && m_elements == 4) 00163 tempLine[m_elements*j+3] = 255 - tempLine[m_elements*j+3]; 00164 } 00165 png_write_row(png_ptr, tempLine); 00166 } 00167 00168 // closing and freeing the structs 00169 png_write_end(png_ptr, info_ptr); 00170 png_destroy_write_struct(&png_ptr, &info_ptr); 00171 free(tempLine); 00172 fclose(fout); 00173 } 00174 00175 void ShImage::loadPng(const std::string& filename) 00176 { 00177 // check that the file is a png file 00178 png_byte buf[8]; 00179 00180 FILE* in = std::fopen(filename.c_str(), "rb"); 00181 00182 if (!in) shError( ShImageException("Unable to open " + filename) ); 00183 00184 for (int i = 0; i < 8; i++) { 00185 if (!(buf[i] = fgetc(in))) shError( ShImageException("Not a PNG file") ); 00186 } 00187 if (png_sig_cmp(buf, 0, 8)) shError( ShImageException("Not a PNG file") ); 00188 00189 png_structp png_ptr = 00190 png_create_read_struct(PNG_LIBPNG_VER_STRING, 00191 0, 0, 0); // FIXME: use error handlers 00192 if (!png_ptr) shError( ShImageException("Error initialising libpng (png_ptr)") ); 00193 00194 png_infop info_ptr = png_create_info_struct(png_ptr); 00195 if (!info_ptr) { 00196 png_destroy_read_struct(&png_ptr, 0, 0); 00197 shError( ShImageException("Error initialising libpng (info_ptr)") ); 00198 } 00199 00200 if (setjmp(png_jmpbuf(png_ptr))) { 00201 png_destroy_read_struct(&png_ptr, 0, 0); 00202 shError( ShImageException("Error initialising libpng (setjmp/lngjmp)") ); 00203 } 00204 00205 // png_set_read_fn(png_ptr, reinterpret_cast<void*>(&in), my_istream_read_data); 00206 png_init_io(png_ptr, in); 00207 00208 png_set_sig_bytes(png_ptr, 8); 00209 00210 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0); 00211 00212 int bit_depth = png_get_bit_depth(png_ptr, info_ptr); 00213 if (bit_depth % 8) { 00214 png_destroy_read_struct(&png_ptr, 0, 0); 00215 std::ostringstream os; 00216 os << "Invalid bit elements " << bit_depth; 00217 shError( ShImageException(os.str()) ); 00218 } 00219 00220 int colour_type = png_get_color_type(png_ptr, info_ptr); 00221 00222 if (colour_type == PNG_COLOR_TYPE_PALETTE) { 00223 png_set_palette_to_rgb(png_ptr); 00224 colour_type = PNG_COLOR_TYPE_RGB; 00225 } 00226 00227 if (colour_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { 00228 png_set_gray_1_2_4_to_8(png_ptr); 00229 } 00230 00231 if (colour_type != PNG_COLOR_TYPE_RGB 00232 && colour_type != PNG_COLOR_TYPE_GRAY 00233 && colour_type != PNG_COLOR_TYPE_RGBA) { 00234 png_destroy_read_struct(&png_ptr, 0, 0); 00235 shError( ShImageException("Invalid colour type") ); 00236 } 00237 00238 m_memory = 0; 00239 00240 m_width = png_get_image_width(png_ptr, info_ptr); 00241 m_height = png_get_image_height(png_ptr, info_ptr); 00242 switch (colour_type) { 00243 case PNG_COLOR_TYPE_RGB: 00244 m_elements = 3; 00245 break; 00246 case PNG_COLOR_TYPE_RGBA: 00247 m_elements = 4; 00248 break; 00249 default: 00250 m_elements = 1; 00251 break; 00252 } 00253 00254 png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr); 00255 00256 m_memory = new ShHostMemory(sizeof(float) * m_width * m_height * m_elements); 00257 00258 for (int y = 0; y < m_height; y++) { 00259 for (int x = 0; x < m_width; x++) { 00260 for (int i = 0; i < m_elements; i++) { 00261 png_byte *row = row_pointers[y]; 00262 int index = m_elements * (y * m_width + x) + i; 00263 00264 long element = 0; 00265 for (int j = bit_depth/8 - 1; j >= 0; j--) { 00266 element <<= 8; 00267 element += row[(x * m_elements + i) * bit_depth/8 + j]; 00268 } 00269 00270 data()[index] = element / static_cast<float>((1 << bit_depth) - 1); 00271 } 00272 } 00273 } 00274 00275 png_destroy_read_struct(&png_ptr, &info_ptr, 0); 00276 } 00277 00278 void ShImage::savePng16(const std::string& filename, int inverse_alpha) 00279 { 00280 FILE* fout = std::fopen(filename.c_str(), "w"); 00281 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 00282 png_infop info_ptr = png_create_info_struct(png_ptr); 00283 setjmp(png_ptr->jmpbuf); 00284 00285 /* Setup PNG I/O */ 00286 png_init_io(png_ptr, fout); 00287 00288 /* Optionally setup a callback to indicate when a row has been 00289 * written. */ 00290 00291 /* Setup filtering. Use Paeth filtering */ 00292 png_set_filter(png_ptr, 0, PNG_FILTER_PAETH); 00293 00294 /* Setup compression level. */ 00295 png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); 00296 00297 /* Setup PNG header information and write it to the file */ 00298 00299 int color_type; 00300 switch (m_elements) { 00301 case 1: 00302 color_type = PNG_COLOR_TYPE_GRAY; 00303 break; 00304 case 2: 00305 color_type = PNG_COLOR_TYPE_GRAY_ALPHA; 00306 break; 00307 case 3: 00308 color_type = PNG_COLOR_TYPE_RGB; 00309 break; 00310 case 4: 00311 color_type = PNG_COLOR_TYPE_RGBA; 00312 break; 00313 default: 00314 throw ShImageException("Invalid element size"); 00315 } 00316 00317 png_set_IHDR(png_ptr, info_ptr, 00318 m_width, m_height, 00319 16, 00320 color_type, 00321 PNG_INTERLACE_NONE, 00322 PNG_COMPRESSION_TYPE_DEFAULT, 00323 PNG_FILTER_TYPE_DEFAULT); 00324 png_write_info(png_ptr, info_ptr); 00325 00326 // Actual writing 00327 png_uint_16* tempLine = (png_uint_16*)malloc(m_width * sizeof(png_uint_16) * m_elements); 00328 00329 for(int i=0;i<m_height;i+=1){ 00330 for(int j=0;j<m_width;j+=1){ 00331 for(int k = 0;k<m_elements;k+=1) 00332 tempLine[m_elements*j+k] = static_cast<png_uint_16>((*this)(j, i, k)*65535.0); 00333 00334 // inverse alpha 00335 if(inverse_alpha && m_elements == 4) 00336 tempLine[m_elements*j+3] = 65535 - tempLine[m_elements*j+3]; 00337 } 00338 png_write_row(png_ptr, (png_byte*)tempLine); 00339 } 00340 00341 // closing and freeing the structs 00342 png_write_end(png_ptr, info_ptr); 00343 png_destroy_write_struct(&png_ptr, &info_ptr); 00344 free(tempLine); 00345 fclose(fout); 00346 } 00347 00348 ShImage ShImage::getNormalImage() 00349 { 00350 int w = width(); 00351 int h = height(); 00352 ShImage output_image(w,h,3); 00353 for (int j = 0; j < h; j++) { 00354 int jp1 = j + 1; 00355 if (jp1 >= h) jp1 = 0; 00356 int jm1 = (j - 1); 00357 if (jm1 < 0) jm1 = h - 1; 00358 for (int i = 0; i < w; i++) { 00359 int ip1 = i + 1; 00360 if (ip1 >= w) ip1 = 0; 00361 int im1 = (i - 1); 00362 if (im1 < 0) im1 = w - 1; 00363 float x, y, z; 00364 x = ((*this)(ip1,j,0) - (*this)(im1,j,0))/2.0f; 00365 output_image(i,j,0) = x/2.0f + 0.5f; 00366 y = ((*this)(i,jp1,0) - (*this)(i,jm1,0))/2.0f; 00367 output_image(i,j,1) = y/2.0f + 0.5f; 00368 z = x*x + y*y; 00369 z = (z > 1.0f) ? z = 0.0f : sqrt(1 - z); 00370 output_image(i,j,2) = z; 00371 } 00372 } 00373 return output_image; 00374 } 00375 00376 const float* ShImage::data() const 00377 { 00378 if (!m_memory) return 0; 00379 return reinterpret_cast<const float*>(m_memory->hostStorage()->data()); 00380 } 00381 00382 float* ShImage::data() 00383 { 00384 if (!m_memory) return 0; 00385 return reinterpret_cast<float*>(m_memory->hostStorage()->data()); 00386 } 00387 00388 void ShImage::dirty() 00389 { 00390 if (!m_memory) return; 00391 m_memory->hostStorage()->dirty(); 00392 } 00393 00394 ShMemoryPtr ShImage::memory() 00395 { 00396 return m_memory; 00397 } 00398 00399 ShPointer<const ShMemory> ShImage::memory() const 00400 { 00401 return m_memory; 00402 } 00403 00404 }

Generated on Mon Oct 18 14:17:39 2004 for Sh by doxygen 1.3.7