00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
00113 png_init_io(png_ptr, fout);
00114
00115
00116
00117
00118
00119 png_set_filter(png_ptr, 0, PNG_FILTER_PAETH);
00120
00121
00122 png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
00123
00124
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
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
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
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
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);
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
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
00286 png_init_io(png_ptr, fout);
00287
00288
00289
00290
00291
00292 png_set_filter(png_ptr, 0, PNG_FILTER_PAETH);
00293
00294
00295 png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
00296
00297
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
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
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
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 }