Audacity  2.2.2
Functions
ImageManipulation.cpp File Reference
#include <wx/image.h>
#include "Audacity.h"
#include "ImageManipulation.h"
#include "AllThemeResources.h"
#include "Theme.h"

Go to the source code of this file.

Functions

std::unique_ptr< wxImage > ChangeImageColour (wxImage *srcImage, wxColour &dstColour)
 
std::unique_ptr< wxImage > ChangeImageColour (wxImage *srcImage, wxColour &srcColour, wxColour &dstColour)
 
std::unique_ptr< wxImage > OverlayImage (wxImage *background, wxImage *foreground, wxImage *mask, int xoff, int yoff)
 
std::unique_ptr< wxImage > OverlayImage (teBmps eBack, teBmps eForeground, int xoff, int yoff)
 
std::unique_ptr< wxImage > CreateBackground (int width, int height, wxColour colour)
 
std::unique_ptr< wxImage > CreateAquaBackground (int width, int height, int offset)
 
std::unique_ptr< wxImage > CreateSysBackground (int width, int height, int WXUNUSED(offset), wxColour colour)
 
void PasteSubImage (wxImage *background, wxImage *foreground, int xoff, int yoff)
 
wxImage GetSubImageWithAlpha (const wxImage &Src, const wxRect &rect)
 

Detailed Description

Provides Image Manipulation functions.

wxWidgets misses some important functions involving cutting and pasting bitmaps, and (in version 2.6.1) is patchy in support of alpha channel. This collection of functions fills that gap.

Definition in file ImageManipulation.cpp.

Function Documentation

std::unique_ptr<wxImage> ChangeImageColour ( wxImage *  srcImage,
wxColour &  dstColour 
)

This looks at the first pixel in the image, and shifts the entire image by the vector difference between that pixel and the dstColour. For better control, use ChangeImageColour(wxImage, wxColour*, wxColour*) below

Definition at line 36 of file ImageManipulation.cpp.

References ChangeImageColour().

Referenced by ChangeImageColour(), and ThemeBase::RecolourBitmap().

37 {
38  unsigned char *src = srcImage->GetData();
39  wxColour c;
40  c.Set(src[0], src[1], src[2]);
41  return ChangeImageColour(srcImage, c, dstColour);
42 }
std::unique_ptr< wxImage > ChangeImageColour(wxImage *srcImage, wxColour &dstColour)
std::unique_ptr<wxImage> ChangeImageColour ( wxImage *  srcImage,
wxColour &  srcColour,
wxColour &  dstColour 
)

This will explicitly shift the image color from srcColour to dstColour.

Definition at line 46 of file ImageManipulation.cpp.

49 {
50  // This function takes a source image, which it assumes to
51  // be grayscale, and smoothly changes the overall color
52  // to the specified color, and returns the result as a
53  // NEW image. This works well for grayscale 3D images.
54  // Audacity uses this routines to make the buttons
55  // (skip-start, play, stop, record, skip-end) adapt to
56  // the color scheme of the user.
57 
58  unsigned char *src = srcImage->GetData();
59  int width = srcImage->GetWidth();
60  int height = srcImage->GetHeight();
61 
62  auto dstImage = std::make_unique<wxImage>(width, height);
63  unsigned char *dst = dstImage->GetData();
64 
65 
66  //Get the source color
67  int srcVal[3], srcOpp[3];
68  srcVal[0] = srcColour.Red();
69  srcVal[1] = srcColour.Green();
70  srcVal[2] = srcColour.Blue();
71 
72  int dstVal[3], dstOpp[3];
73  dstVal[0] = dstColour.Red();
74  dstVal[1] = dstColour.Green();
75  dstVal[2] = dstColour.Blue();
76 
77  int i;
78  for (i = 0; i < 3; i++) {
79  srcOpp[i] = 256 - srcVal[i]; // avoid zero!
80  dstOpp[i] = 255 - dstVal[i];
81  }
82 
83  int c = 0;
84  for (i = 0; i < width * height * 3; i++) {
85  int s = (int) *src;
86 
87  if (s >= srcVal[c])
88  *dst++ = dstVal[c] + dstOpp[c] * (s - srcVal[c]) / srcOpp[c];
89 
90  else
91  *dst++ = dstVal[c] * s / srcVal[c];
92  src++;
93  c = (c + 1) % 3;
94  }
95 
96  return dstImage;
97 }
std::unique_ptr<wxImage> CreateAquaBackground ( int  width,
int  height,
int  offset 
)

Definition at line 282 of file ImageManipulation.cpp.

Referenced by CreateSysBackground().

283 {
284  auto image = std::make_unique<wxImage>(width, height);
285  unsigned char *ip = image->GetData();
286  unsigned char val[4] = {231, 239, 255, 239};
287  unsigned char v;
288  int x, y;
289 
290  for(y=0; y<height; y++) {
291  v = val[(y+offset)%4];
292  for(x=0; x<width*3; x++)
293  *ip++ = v;
294  }
295 
296  return image;
297 }
std::unique_ptr<wxImage> CreateBackground ( int  width,
int  height,
wxColour  colour 
)

Definition at line 259 of file ImageManipulation.cpp.

Referenced by CreateSysBackground().

260 {
261  auto i = std::make_unique<wxImage>(width, height);
262  unsigned char *ip;
263  int srcVal[3];
264  int x;
265 
266  srcVal[0] = colour.Red();
267  srcVal[1] = colour.Green();
268  srcVal[2] = colour.Blue();
269 
270  ip = i->GetData();
271  for(x=0; x<width*height; x++) {
272  *ip++ = srcVal[0];
273  *ip++ = srcVal[1];
274  *ip++ = srcVal[2];
275  }
276 
277  return i;
278 }
std::unique_ptr<wxImage> CreateSysBackground ( int  width,
int  height,
int   WXUNUSEDoffset,
wxColour  colour 
)

Definition at line 303 of file ImageManipulation.cpp.

References CreateAquaBackground(), and CreateBackground().

305 {
306  #ifdef USE_AQUA_THEME
307  return CreateAquaBackground(width, height, offset);
308  #else
309  return CreateBackground(width, height, colour);
310  #endif
311 }
std::unique_ptr< wxImage > CreateBackground(int width, int height, wxColour colour)
std::unique_ptr< wxImage > CreateAquaBackground(int width, int height, int offset)
wxImage GetSubImageWithAlpha ( const wxImage &  Src,
const wxRect &  rect 
)

Gets a rectangle from within another image, INCLUDING the alpha channel

Bug:
in wxWidgets, wxImage::GetSubImage should do this itself.

Definition at line 374 of file ImageManipulation.cpp.

Referenced by ThemeBase::ReadImageCache().

375 {
376  //First part of this code is lifted from wxImage::GetSubImage() source code.
377  wxImage image;
378 
379  wxCHECK_MSG( Src.Ok(), image, wxT("invalid image") );
380 
381  wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && (
382  rect.GetRight()<=Src.GetWidth()) && (rect.GetBottom()<=Src.GetHeight()),
383  image, wxT("invalid subimage size") );
384 
385  int subwidth=rect.GetWidth();
386  const int subheight=rect.GetHeight();
387 
388  image.Create( subwidth, subheight, false );
389 
390  unsigned char *subdata = image.GetData(), *data=Src.GetData();
391 
392  wxCHECK_MSG( subdata, image, wxT("unable to create image") );
393 
394  // JKC: Quick hack - don't deal with masks - need to understand macro M_IMGDATA first.
395 // if (Src.M_IMGDATA->m_hasMask)
396 // image.SetMaskColour( Src.M_IMGDATA->m_maskRed, Src.M_IMGDATA->m_maskGreen, Src.M_IMGDATA->m_maskBlue );
397 
398  int subleft=3*rect.GetLeft();
399  int width=3*Src.GetWidth();
400  subwidth*=3;
401 
402  data+=rect.GetTop()*width+subleft;
403 
404  for (long j = 0; j < subheight; ++j)
405  {
406  memcpy( subdata, data, subwidth);
407  subdata+=subwidth;
408  data+=width;
409  }
410 
411  // OK, so we've copied the RGB data.
412  // Now do the Alpha channel.
413  wxASSERT( Src.HasAlpha() );
414  image.InitAlpha();
415 
416  subleft/=3;
417  width/=3;
418  subwidth/=3;
419 
420  data =Src.GetAlpha();
421  subdata =image.GetAlpha();
422 
423  data+=rect.GetTop()*width+subleft;
424 
425  for (long j = 0; j < subheight; ++j)
426  {
427  memcpy( subdata, data, subwidth);
428  subdata+=subwidth;
429  data+=width;
430  }
431  return image;
432 }
std::unique_ptr<wxImage> OverlayImage ( wxImage *  background,
wxImage *  foreground,
wxImage *  mask,
int  xoff,
int  yoff 
)

Takes a background image, foreground image, and mask (i.e. the alpha channel for the foreground), and returns an NEW image where the foreground has been overlaid onto the background using alpha-blending, at location (xoff, yoff).

Definition at line 104 of file ImageManipulation.cpp.

Referenced by ToolBar::MakeAlternateImages(), and ToolBar::MakeButton().

106 {
107  unsigned char *bg = background->GetData();
108  unsigned char *fg = foreground->GetData();
109  unsigned char *mk = mask->GetData();
110 
111  int bgWidth = background->GetWidth();
112  int bgHeight = background->GetHeight();
113  int fgWidth = foreground->GetWidth();
114  int fgHeight = foreground->GetHeight();
115  int mkWidth = mask->GetWidth();
116  int mkHeight = mask->GetHeight();
117 
118 
119  //Now, determine the dimensions of the images to be masked together
120  //on top of the background. This should be equal to the area of the
121  //smaller of the foreground and the mask, as long as it is
122  //within the area of the background, given the offset.
123 
124  //Make sure the foreground size is no bigger than the mask
125  int wCutoff = (fgWidth < mkWidth) ? fgWidth : mkWidth;
126  int hCutoff = (fgHeight < mkHeight) ? fgHeight : mkHeight;
127 
128 
129  // If the masked foreground + offset is bigger than the background, masking
130  // should only occur within these bounds of the foreground image
131  wCutoff = (bgWidth - xoff > wCutoff) ? wCutoff : bgWidth - xoff;
132  hCutoff = (bgHeight - yoff > hCutoff) ? hCutoff : bgHeight - yoff;
133 
134 
135  //Make a NEW image the size of the background
136  auto dstImage = std::make_unique<wxImage>(bgWidth, bgHeight);
137  unsigned char *dst = dstImage->GetData();
138  memcpy(dst, bg, bgWidth * bgHeight * 3);
139 
140 
141  // Go through the foreground image bit by bit and mask it on to the
142  // background, at an offset of xoff,yoff.
143  // BUT...Don't go beyond the size of the background image,
144  // the foreground image, or the mask
145  int x, y;
146  for (y = 0; y < hCutoff; y++) {
147 
148  unsigned char *bkp = bg + 3 * ((y + yoff) * bgWidth + xoff);
149  unsigned char *dstp = dst + 3 * ((y + yoff) * bgWidth + xoff);
150 
151  for (x = 0; x < wCutoff; x++) {
152 
153  int value = mk[3 * (y * mkWidth + x)];
154  int opp = 255 - value;
155 
156  for (int c = 0; c < 3; c++)
157  dstp[x * 3 + c] =
158  ((bkp[x * 3 + c] * opp) +
159  (fg[3 * (y * fgWidth + x) + c] * value)) / 255;
160  }
161  }
162  return dstImage;
163 }
std::unique_ptr<wxImage> OverlayImage ( teBmps  eBack,
teBmps  eForeground,
int  xoff,
int  yoff 
)

Takes a background image, foreground image, and mask (i.e. the alpha channel for the foreground), and returns an NEW image where the foreground has been overlaid onto the background using alpha-blending, at location (xoff, yoff).

Definition at line 170 of file ImageManipulation.cpp.

References ThemeBase::Colour(), ThemeBase::Image(), and theTheme.

172 {
173  wxImage imgBack(theTheme.Image( eBack ));
174  wxImage imgFore(theTheme.Image( eForeground ));
175 
176 
177  // TMP: dmazzoni - just so the code runs even though not all of
178  // our images have transparency...
179  if (!imgFore.HasAlpha())
180  return std::make_unique<wxImage>(imgBack);
181 
182 
183  wxASSERT( imgFore.HasAlpha() );
184 
185  unsigned char *bg = imgBack.GetData();
186  unsigned char *fg = imgFore.GetData();
187  unsigned char *mk = imgFore.GetAlpha();
188 
189  int bgWidth = imgBack.GetWidth();
190  int bgHeight = imgBack.GetHeight();
191  int fgWidth = imgFore.GetWidth();
192  int fgHeight = imgFore.GetHeight();
193 
194 
195  //Now, determine the dimensions of the images to be masked together
196  //on top of the background. This should be equal to the area of the
197  //smaller of the foreground and the mask, as long as it is
198  //within the area of the background, given the offset.
199 
200  //Make sure the foreground size is no bigger than the mask
201  int wCutoff = fgWidth;
202  int hCutoff = fgHeight;
203 
204 
205  // If the masked foreground + offset is bigger than the background, masking
206  // should only occur within these bounds of the foreground image
207  wCutoff = (bgWidth - xoff > wCutoff) ? wCutoff : bgWidth - xoff;
208  hCutoff = (bgHeight - yoff > hCutoff) ? hCutoff : bgHeight - yoff;
209 
210  //Make a NEW image the size of the background
211  auto dstImage = std::make_unique<wxImage>(bgWidth, bgHeight);
212  unsigned char *dst = dstImage->GetData();
213  memcpy(dst, bg, bgWidth * bgHeight * 3);
214 
215  // If background image has tranparency, then we want to blend with the
216  // current backgorund colour.
217  if( imgBack.HasAlpha() ){
218  unsigned char *pAlpha = imgBack.GetAlpha();
219  wxColour c = theTheme.Colour( clrMedium );
220  unsigned char onePixImage[3];
221  // GetData() guarantees RGB order [wxWidgets does the ocnversion]
222  onePixImage[ 0 ] = c.Red();
223  onePixImage[ 1 ] = c.Green();
224  onePixImage[ 2 ] = c.Blue();
225  for( int i=0;i< bgWidth*bgHeight;i++){
226  unsigned char * pPix = &dst[ 3*i];
227  float alpha = 1.0 - (pAlpha[i]/255.0);
228  pPix[0] = pPix[0] + alpha *( (int)onePixImage[0]-(int)pPix[0]);
229  pPix[1] = pPix[1] + alpha *( (int)onePixImage[1]-(int)pPix[1]);
230  pPix[2] = pPix[2] + alpha *( (int)onePixImage[2]-(int)pPix[2]);
231  }
232  }
233 
234  // Go through the foreground image bit by bit and mask it on to the
235  // background, at an offset of xoff,yoff.
236  // BUT...Don't go beyond the size of the background image,
237  // the foreground image, or the mask
238  int x, y;
239  for (y = 0; y < hCutoff; y++) {
240 
241  unsigned char *bkp = bg + 3 * ((y + yoff) * bgWidth + xoff);
242  unsigned char *dstp = dst + 3 * ((y + yoff) * bgWidth + xoff);
243 
244  for (x = 0; x < wCutoff; x++) {
245 
246  int value = mk[(y * fgWidth + x)];// Don't multiply by 3...
247  int opp = 255 - value;
248 
249  for (int c = 0; c < 3; c++)
250  dstp[x * 3 + c] =
251  ((bkp[x * 3 + c] * opp) +
252  (fg[3 * (y * fgWidth + x) + c] * value)) / 255;
253  }
254  }
255  return dstImage;
256 }
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
wxImage & Image(int iIndex)
Definition: Theme.cpp:1234
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1208
void PasteSubImage ( wxImage *  background,
wxImage *  foreground,
int  xoff,
int  yoff 
)

Pastes one image into another including the alpha channel. Differs from OverlayImage in that: Happens in place to existing background image. Pastes image on top; no blending with existing background is done.

Definition at line 317 of file ImageManipulation.cpp.

Referenced by ThemeBase::CreateImageCache().

318 {
319 
320  unsigned char *bg = background->GetData();
321  unsigned char *fg = foreground->GetData();
322  unsigned char *bgAlpha = background->HasAlpha() ? background->GetAlpha() : NULL;
323  unsigned char *fgAlpha = foreground->HasAlpha() ? foreground->GetAlpha() : NULL;
324  // For testing... Set as if no alpha in foreground....
325  // fgAlpha = NULL;
326 
327  int bgWidth = background->GetWidth();
328  int bgHeight = background->GetHeight();
329  int fgWidth = foreground->GetWidth();
330  int fgHeight = foreground->GetHeight();
331 
332  int wCutoff = fgWidth;
333  int hCutoff = fgHeight;
334 
335  // If the masked foreground + offset is bigger than the background, masking
336  // should only occur within these bounds of the foreground image
337  wCutoff = (bgWidth - xoff > wCutoff) ? wCutoff : bgWidth - xoff;
338  hCutoff = (bgHeight - yoff > hCutoff) ? hCutoff : bgHeight - yoff;
339 
340  // Go through the foreground image bit by bit and place it on to the
341  // background, at an offset of xoff,yoff.
342  // Don't go beyond the size of the background image,
343  // or the foreground image.
344  int y;
345  unsigned char *bkp;
346  unsigned char *fgp;
347  unsigned char *bgAlphap;
348  unsigned char *fgAlphap;
349  for (y = 0; y < hCutoff; y++) {
350  // RGB bytes
351  bkp = bg + 3 * ((y + yoff) * bgWidth + xoff);
352  fgp = fg + 3 * ( y * fgWidth);
353  memcpy( bkp, fgp, 3 * wCutoff );
354 
355  // Alpha bytes.
356  if( bgAlpha )
357  {
358  bgAlphap = bgAlpha + ((y+yoff) * bgWidth + xoff );
359  if( fgAlpha )
360  {
361  fgAlphap = fgAlpha + (y * fgWidth );
362  memcpy( bgAlphap, fgAlphap, wCutoff );
363  }
364  else
365  {
366  memset( bgAlphap, 255, wCutoff );
367  }
368  }
369  }
370 }