NCBI C++ ToolKit
image.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: image.cpp 91363 2020-10-19 14:54:50Z grichenk $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Mike DiCuccio
27  *
28  * File Description:
29  * CImage -- interface for manipulating image data
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <util/image/image.hpp>
35 #include <util/error_codes.hpp>
36 
37 
38 #define NCBI_USE_ERRCODE_X Util_Image
39 
40 
42 
43 
45  : m_Width(0),
46  m_Height(0),
47  m_Depth(3)
48 {
49  return;
50 }
51 
52 
53 CImage::CImage(size_t width, size_t height, size_t depth)
54  : m_Width(0),
55  m_Height(0),
56  m_Depth(depth)
57 {
58  Init(width, height, depth);
59 }
60 
61 
62 void CImage::Init(size_t width, size_t height, size_t depth)
63 {
64  _TRACE("CImage::Init(): " << width << ", " << height << ", " << depth);
65  switch (depth) {
66  case 3:
67  case 4:
68  m_Data.resize(width * height * depth);
69  break;
70 
71  default:
72  {{
73  string msg("CImage::Init(): depth = ");
75  msg += " not implemented";
76  NCBI_THROW(CImageException, eInvalidDimension, msg);
77  }}
78  }
79  m_Width = width;
80  m_Height = height;
81  m_Depth = depth;
82 }
83 
84 
85 const unsigned char* CImage::GetData(void) const
86 {
87  _ASSERT(m_Data.size());
88  return &(m_Data[0]);
89 }
90 
91 
92 unsigned char* CImage::SetData(void)
93 {
94  _ASSERT(m_Data.size());
95  return &(m_Data[0]);
96 }
97 
98 
99 //
100 // GetAspectRatio()
101 // This computes the aspect ratio for the image (width / height)
102 //
103 float CImage::GetAspectRatio(void) const
104 {
105  return float (m_Width) / float (m_Height);
106 }
107 
108 
109 //
110 // set the alpha channel to a given value. The red channel is channel 3.
111 // This will optionnally add the channel if it doesn't exist.
112 //
113 void CImage::SetAlpha(unsigned char val, bool add_if_unavailable)
114 {
115  if (GetDepth() == 3) {
116  if (add_if_unavailable) {
117  SetDepth(4);
118  } else {
119  NCBI_THROW(CImageException, eInvalidDimension,
120  "CImage::SetAlpha(): attempt to set alpha in "
121  "24-bit image");
122  }
123  }
125 }
126 
127 
128 //
129 // SetDepth()
130 // This will force the image to be 24-bit or 32-bit
131 //
132 void CImage::SetDepth(size_t depth, bool update_image)
133 {
134  if ( !m_Data.size() ) {
135  return;
136  }
137 
138  switch (depth) {
139  case 3:
140  if (m_Depth == 4) {
141  if (update_image) {
142  // squash our data. we can do this without explicitly reallocating
143  // our buffer - we just have junk on the end
144  TImageStrip::const_iterator from_data = m_Data.begin();
145  TImageStrip::iterator to_data = m_Data.begin();
146  for ( ; from_data != m_Data.end(); ) {
147  *to_data++ = *from_data++;
148  *to_data++ = *from_data++;
149  *to_data++ = *from_data++;
150 
151  // skip the alpha channel
152  ++from_data;
153  }
154  }
155 
156  m_Data.resize(m_Width * m_Height * 3);
157  m_Depth = 3;
158  }
159  break;
160 
161  case 4:
162  if (m_Depth == 3) {
163  // expand our data.
164  // we do this by expanding in-place
165  m_Data.resize(m_Width * m_Height * 4);
166  m_Depth = 4;
167 
168  if (update_image) {
169  // now we need to expand our data
170  // we can do this by marching backwares through the data
171  TImageStrip::const_reverse_iterator from_data(m_Data.end());
172  TImageStrip::const_reverse_iterator end_data (m_Data.begin());
173  TImageStrip::reverse_iterator to_data (m_Data.end());
174 
175  // march to the actual end of the data
176  from_data += m_Width * m_Height;
177 
178  for ( ; from_data != end_data; ) {
179  // insert an alpha channel - this is the first because we're
180  // marching backwards
181  *to_data++ = 255;
182 
183  // copy (in reverse order) BGR data
184  *to_data++ = *from_data++;
185  *to_data++ = *from_data++;
186  *to_data++ = *from_data++;
187  }
188  }
189  }
190  break;
191 
192  default:
193  {{
194  string msg("CImage::SetDepth(): invalid depth: ");
196  NCBI_THROW(CImageException, eInvalidDimension, msg);
197  }}
198  }
199 }
200 
201 
202 //
203 // SetChannel()
204 // Sets a given channel to a certain value
205 //
206 void CImage::SetChannel(size_t channel, unsigned char val)
207 {
208  if ( !m_Data.size() ) {
209  return;
210  }
211 
212  if (channel > 3) {
213  NCBI_THROW(CImageException, eInvalidDimension,
214  "CImage::SetChannel(): channel out of bounds");
215  }
216 
217  TImageStrip::iterator data = m_Data.begin() + channel;
218  TImageStrip::iterator end =
219  m_Data.begin() + m_Width * m_Height * m_Depth + channel;
220  for ( ; data != end; data += m_Depth) {
221  *data = val;
222  }
223 }
224 
225 
226 //
227 // GetSubImage()
228 // This function returns a new image that is a subimage of the current image
229 // the width and height will be clamped to the left / bottom margins; the x and
230 // y positions must be valid.
231 //
232 CImage* CImage::GetSubImage(size_t x, size_t y, size_t w, size_t h) const
233 {
234  if ( !m_Data.size() ) {
235  NCBI_THROW(CImageException, eInvalidImage,
236  "CImage::GetSubImage(): image is empty");
237  }
238 
239  if (x >= m_Width || y >= m_Height) {
240  string msg("CImage::GetSubImage(): invalid starting pos: ");
242  msg += ", ";
244  NCBI_THROW(CImageException, eInvalidImage, msg);
245  }
246 
247  if (x + w > m_Width) {
248  w = m_Width - x;
249  ERR_POST_X(1, Warning << "CImage::GetSubImage(): clamping width to " << w);
250  }
251 
252  if (y + h > m_Height) {
253  h = m_Height - y;
254  ERR_POST_X(2, Warning << "CImage::GetSubImage(): clamping height to " << h);
255  }
256 
257  CRef<CImage> image(new CImage(w, h, m_Depth));
258  const unsigned char* from_data = GetData() +
259  y * m_Width * m_Depth + x * m_Depth;
260  unsigned char* to_data = image->SetData();
261 
262  size_t from_stride = m_Width * m_Depth;
263  size_t to_stride = w * m_Depth;
264 
265  for (size_t i = 0; i < h; ++i) {
266  memcpy(to_data, from_data, w * m_Depth);
267  to_data += to_stride;
268  from_data += from_stride;
269  }
270 
271  return image.Release();
272 }
273 
274 
275 void CImage::Flip(void)
276 {
277  if ( !m_Data.size() ) {
278  return;
279  }
280 
281  unsigned char* from = SetData();
282  unsigned char* to = from + (m_Height - 1) * m_Width * m_Depth;
283  size_t stride = m_Width * m_Depth;
284 
285  while (to > from) {
286  for (size_t pos = 0; pos < stride; ++pos) {
287  std::swap(from[pos], to[pos]);
288  }
289  from += stride;
290  to -= stride;
291  }
292 }
293 
294 
CImage –.
Definition: Image.hpp:66
size_t GetDepth(void) const
Definition: image.hpp:108
size_t m_Height
Definition: image.hpp:134
size_t m_Width
Definition: image.hpp:133
const unsigned char * GetData(void) const
Definition: image.cpp:85
float GetAspectRatio(void) const
Definition: image.cpp:103
size_t m_Depth
Definition: image.hpp:135
void SetAlpha(unsigned char val, bool add_channel=false)
Definition: image.cpp:113
void Flip(void)
Definition: image.cpp:275
CImage * GetSubImage(size_t x, size_t y, size_t w, size_t h) const
Definition: image.cpp:232
void Init(size_t width, size_t height, size_t depth)
Definition: image.cpp:62
TImageStrip m_Data
Definition: image.hpp:137
void SetChannel(size_t channel, unsigned char val)
Definition: image.cpp:206
void SetDepth(size_t depth, bool update_image=true)
Definition: image.cpp:132
unsigned char * SetData(void)
Definition: image.cpp:92
@ eAlpha
Definition: image.hpp:81
static unsigned char depth[2 *(256+1+29)+1]
char data[12]
Definition: iconv.c:80
void swap(NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair1, NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair2)
Definition: ncbimisc.hpp:1508
#define _TRACE(message)
Definition: ncbidbg.hpp:122
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
TObjectType * Release(void)
Release a reference to the object and return a pointer to the object.
Definition: ncbiobj.hpp:846
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
CImage(void)
Definition: Image.hpp:86
Definition of all error codes used in util (xutil.lib).
int i
static SLJIT_INLINE sljit_ins msg(sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b)
#define _ASSERT
Modified on Fri Sep 20 14:57:34 2024 by modify_doxy.py rev. 669887