NGL  6.5
The NCCA Graphics Library
Image.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2015 Jon Macey
3 
4  This program is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17 //----------------------------------------------------------------------------------------------------------------------
20 //----------------------------------------------------------------------------------------------------------------------
21 #include "Image.h"
22 #include "NGLassert.h"
23 #if defined(USEQIMAGE)
24  #include <QtGui/QImage>
25 #endif
26 #if defined(USEIMAGEMAGIC)
27  #include <ImageMagick-6/Magick++.h>
28 #endif
29 #if defined(USEOIIO)
30  #include <OpenImageIO/imageio.h>
31 #endif
32 
33 #include <iostream>
34 
35 namespace ngl
36 {
37 
38 #define IMAGE_DEBUG_ON 1
39 
40 
41 Image::Image(const std::string &_fname)
42 {
43  load(_fname);
44 }
45 
49 {
51  m_data.reset(new unsigned char[ size]);
52  memcpy(m_data.get(),_i.m_data.get(),size);
53 
54 }
55 
56 Colour Image::getColour(const GLuint _x,const GLuint _y ) const noexcept
57 {
58 // make sure were in the image range
59  NGL_ASSERT(_x<=m_width && _y<=m_height);
60  if (m_data !=0)
61  {
62  auto offset=_x*m_channels+((_y)*m_width*m_channels);
63  if(m_channels == 3)
64  {
65  return Colour(m_data[offset],m_data[offset+1],m_data[offset+2]);
66  }
67  else
68  {
69  return Colour(m_data[offset],m_data[offset+1],m_data[offset+2],m_data[offset+3]);
70  }
71  }
72  else
73  {
74  return Colour(0,0,0,0);
75  }
76 }
77 
78 
79 Colour Image::getColour(const Real _uvX, const Real _uvY ) const noexcept
80 {
81 
82  GLuint xx = static_cast<GLuint> (_uvX * (m_width-1));
83  GLuint yy = static_cast<GLuint> (_uvY * (m_height-1));
84 
85  NGL_ASSERT(xx<m_width && yy<m_height);
86 
87  if(m_data!=0)
88  {
89  auto offset = xx * m_channels + (yy * m_width * m_channels );
90  if(m_channels == 4)
91  {
92  return Colour(m_data[offset],m_data[offset+1],m_data[offset+2],m_data[offset+3]);
93  }
94  else
95  {
96  return Colour(m_data[offset],m_data[offset+1],m_data[offset+2],1.0);
97  }
98  }
99  else
100  {
101  return Colour(0,0,0,0);
102  }
103 }
104 
105 void Image::saveFrameBufferToFile(const std::string &_fname, int _x, int _y, int _width, int _height,ImageModes _mode)
106 {
108  int size=3;
109  if(_mode == ImageModes::RGBA)
110  {
111  size=4;
112  format=GL_RGBA;
113  }
114  int realWidth=_width-_x;
115  int realHeight=_height-_y;
116  NGL_ASSERT(_x<_width && _y<_height);
117  std::unique_ptr<unsigned char []> data( new unsigned char [realWidth * realHeight *size]);
118  glReadPixels(_x,_y,realWidth,realHeight,format,GL_UNSIGNED_BYTE,data.get());
119  #if defined(USEQIMAGE)
120  QImage::Format qformat=QImage::Format::Format_RGB888;
121  if(_mode == ImageModes::RGBA)
122  {
123  qformat=QImage::Format::Format_RGBA8888;
124  }
125  QImage image(data.get(),realWidth,realHeight,qformat);
126  image=image.mirrored(false,true);
127  image.save(_fname.c_str());
128 
129  #endif
130  #if defined(USEOIIO)
131 
132  OpenImageIO::ImageOutput *out = OpenImageIO::ImageOutput::create (_fname.c_str());
133  OpenImageIO::ImageSpec spec (realWidth, realHeight, size, OpenImageIO::TypeDesc::UINT8);
134  int scanlinesize = realWidth * size;
135  out->open (_fname.c_str(), spec);
136  // note this flips the image vertically on writing
137  // (see http://www.openimageio.org/openimageio.pdf pg 20 for details)
138  out->write_image (OpenImageIO::TypeDesc::UINT8,
139  data.get() + (realHeight-1)*scanlinesize,
140  OpenImageIO::AutoStride,
141  -scanlinesize,OpenImageIO::AutoStride);
142  out->close ();
143  #endif
144  #if defined(USEIMAGEMAGIC)
145  Magick::Image output(realWidth,realHeight,
146  size==3 ? "RGB" : "RGBA",
147  Magick::CharPixel,data.get()
148  );
149 
150  // set the output image depth to 16 bit
151  output.depth(16);
152  // write the file
153  output.write(_fname.c_str());
154  #endif
155 }
156 
157 
158 #if defined(USEQIMAGE)
159 
160 //----------------------------------------------------------------------------------------------------------------------
161 // Qt Image loading routines
162 //----------------------------------------------------------------------------------------------------------------------
163 bool Image::load( const std::string &_fName ) noexcept
164 {
165 #ifdef IMAGE_DEBUG_ON
166  std::cerr<<"loading with QImage"<<std::endl;
167 #endif
168  QImage image;
169  bool loaded=image.load(_fName.c_str());
170  if(loaded ==false)
171  {
172  std::cerr<<"error loading image "<<_fName.c_str()<<"\n";
173  }
174  if(loaded == true)
175  {
176  image=image.mirrored();
177  m_width=static_cast<GLuint> (image.width());
178  m_height=static_cast<GLuint> (image.height());
179  m_hasAlpha=image.hasAlphaChannel();
180  if(m_hasAlpha == true)
181  {
182  m_channels=4;
183  m_format = GL_RGBA;
184  }
185  else
186  {
187  m_channels=3;
188  m_format = GL_RGB;
189  }
190 
191  m_data.reset(new unsigned char[ m_width*m_height*m_channels]);
192  unsigned int index=0;
193  QRgb colour;
194  for(unsigned int y=0; y<m_height; ++y)
195  {
196  for(unsigned int x=0; x<m_width; ++x)
197  {
198  colour=image.pixel(x,y);
199 
200  m_data[index++]=static_cast<unsigned char> (qRed(colour));
201  m_data[index++]=static_cast<unsigned char> (qGreen(colour));
202  m_data[index++]=static_cast<unsigned char> (qBlue(colour));
203  if(m_hasAlpha)
204  {
205  m_data[index++]=static_cast<unsigned char> (qAlpha(colour));
206  }
207  }
208  }
209 #ifdef IMAGE_DEBUG_ON
210  std::cerr<<"size "<<m_width<<" "<<m_height<<std::endl;
211  std::cerr<<"channels "<<m_channels<<std::endl;
212 #endif
213 
214  return true;
215 
216  }
217 
218  else return false;
219 }
220 
221 #endif // end of QImage loading routines
222 
223 
224 #if defined(USEIMAGEMAGIC)
225 
226 //----------------------------------------------------------------------------------------------------------------------
227 // Image Magick Image loading routines
228 //----------------------------------------------------------------------------------------------------------------------
229 bool Image::load( const std::string &_fname ) noexcept
230 {
231  #ifdef IMAGE_DEBUG_ON
232  std::cerr<<"loading with ImageMagick"<<std::endl;
233  #endif
234  Magick::Image image;
235  Magick::Blob blob;
236 
237  try
238  {
239  image.read(_fname);
240  // need to flip image as OpenGL uses textures starting the other way round.
241  image.flip();
242  image.write(&blob, "RGBA");
243  }
244  catch (Magick::Error& Error)
245  {
246  std::cout << "Error loading texture '" << _fname << "': " << Error.what() << std::endl;
247  return false;
248  }
249  m_width=image.columns();
250  m_height=image.rows();
251  m_channels=4;
253  m_data.reset(new unsigned char[ m_width*m_height*m_channels]);
254  // simple memcpy of the blob data to our internal data, not worrying about RGB/RGBA
255  // here (as OpenGL doesn't really either).
256  memcpy(m_data.get(),blob.data(),blob.length());
257  return true;
258 }
259 #endif // end of image magick loading routines
260 
261 #if defined(USEOIIO)
262 
263 //----------------------------------------------------------------------------------------------------------------------
264 // Open Image I/O loading routines
265 //----------------------------------------------------------------------------------------------------------------------
266 bool Image::load( const std::string &_fname ) noexcept
267 {
268 #ifdef IMAGE_DEBUG_ON
269  std::cerr<<"loading with OpenImageIO"<<std::endl;
270 #endif
271  OpenImageIO::ImageInput *in = OpenImageIO::ImageInput::open (_fname);
272  if (! in)
273  {
274  return false;
275  }
276  const OpenImageIO::ImageSpec &spec = in->spec();
277  m_width = spec.width;
278  m_height = spec.height;
279  m_channels = spec.nchannels;
280  if(m_channels==3)
282  else if(m_channels==4)
284  m_data.reset(new unsigned char[ m_width*m_height*m_channels]);
285  // this will read an flip the pixel for OpenGL
286  int scanlinesize = spec.width * spec.nchannels * sizeof(m_data[0]);
287  in->read_image (OpenImageIO::TypeDesc::UINT8,
288  (char *)m_data.get() + (m_height-1)*scanlinesize, // offset to last
289  OpenImageIO::AutoStride, // default x stride
290  -scanlinesize, // special y stride
291  OpenImageIO::AutoStride); // default z stride
292  //in->read_image (OpenImageIO::TypeDesc::UINT8, &m_data[0]);
293  in->close ();
294  delete in;
295  return true;
296 }
297 
298 
299 #endif // end USEOIIO
300 
301 
302 } // end of namespace
unsigned int GLuint
Definition: glew.h:280
#define GL_RGBA
Definition: glew.h:681
simple class to hold colour information and set the basic opengl colour state. also has overloaded me...
Definition: Colour.h:40
bool m_loaded
loaded flag
Definition: Image.h:134
GLenum GLsizei GLenum GLenum const void * image
Definition: glew.h:4971
GLuint m_channels
bits per pixel (RGB / RGBA)
Definition: Image.h:126
#define GL_UNSIGNED_BYTE
Definition: glew.h:637
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1255
bool m_hasAlpha
do we have an alpha channel
Definition: Image.h:138
GLint GLenum GLsizei GLint GLsizei const void * data
Definition: glew.h:1382
unsigned int GLenum
Definition: glew.h:278
implementation files for RibExport class
Definition: AABB.cpp:22
GLuint in
Definition: glew.h:11550
PRECISION Real
create a variable called Real which is the main data type we use (GLfloat for most cases) ...
Definition: Types.h:127
GLintptr offset
Definition: glew.h:1685
static void saveFrameBufferToFile(const std::string &_fname, int _x, int _y, int _width, int _height, ImageModes _mode=ImageModes::RGB)
Definition: Image.cpp:105
#define GL_RGB
Definition: glew.h:680
GLuint m_height
the size of the image in the Y direction
Definition: Image.h:122
A generic Image loader / wrapper for different Image libs this allows us to load an image to be used ...
GLuint m_format
image format, use GL types for this as we are going to use this class mainly for OpenGL ...
Definition: Image.h:130
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: glew.h:1257
GLuint index
Definition: glew.h:1817
GLint GLint GLint GLint GLint x
Definition: glew.h:1255
#define NGL_ASSERT(X)
re-define the standard assert to work for ngl first check to see if assert is defined and undef it th...
Definition: NGLassert.h:53
GLsizeiptr size
Definition: glew.h:1684
Image()=default
default ctor
bool load(const std::string &_fname) noexcept
load the image data, this will clear the previous data and attempt to load the new image data ...
GLuint m_width
the size of the image in the X direction
Definition: Image.h:118
std::unique_ptr< unsigned char[] > m_data
the actual image data loaded packed in r,g,b,(a) format in contiguous memory stored in a smart_pointe...
Definition: Image.h:114
GLAPI void GLAPIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels)
re impliment asserts so we don&#39;t exit on failure
GLsizei const GLchar *const * string
Definition: glew.h:1847
Colour getColour(const GLuint _x, const GLuint _y) const noexcept
get the colour value from X,Y co-ordinates (image absolute 0,0 = top Left)
Definition: Image.cpp:56
ImageModes
save the FrameBuffer to file using current built in I/O
Definition: Image.h:74