Audacity 3.2.0
Functions
ImageManipulation.cpp File Reference
#include "ImageManipulation.h"
#include <wx/colour.h>
#include <wx/image.h>
#include "AllThemeResources.h"
#include "Theme.h"
Include dependency graph for ImageManipulation.cpp:

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)
 The index of a bitmap resource in Theme Resources. More...
 
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

◆ ChangeImageColour() [1/2]

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 37 of file ImageManipulation.cpp.

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

References ChangeImageColour().

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

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ChangeImageColour() [2/2]

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 47 of file ImageManipulation.cpp.

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

◆ CreateAquaBackground()

std::unique_ptr< wxImage > CreateAquaBackground ( int  width,
int  height,
int  offset 
)

Definition at line 289 of file ImageManipulation.cpp.

290{
291 auto image = std::make_unique<wxImage>(width, height);
292 unsigned char *ip = image->GetData();
293 unsigned char val[4] = {231, 239, 255, 239};
294 unsigned char v;
295 int x, y;
296
297 for(y=0; y<height; y++) {
298 v = val[(y+offset)%4];
299 for(x=0; x<width*3; x++)
300 *ip++ = v;
301 }
302
303 return image;
304}

Referenced by CreateSysBackground().

Here is the caller graph for this function:

◆ CreateBackground()

std::unique_ptr< wxImage > CreateBackground ( int  width,
int  height,
wxColour  colour 
)

Definition at line 266 of file ImageManipulation.cpp.

267{
268 auto i = std::make_unique<wxImage>(width, height);
269 unsigned char *ip;
270 int srcVal[3];
271 int x;
272
273 srcVal[0] = colour.Red();
274 srcVal[1] = colour.Green();
275 srcVal[2] = colour.Blue();
276
277 ip = i->GetData();
278 for(x=0; x<width*height; x++) {
279 *ip++ = srcVal[0];
280 *ip++ = srcVal[1];
281 *ip++ = srcVal[2];
282 }
283
284 return i;
285}

Referenced by CreateSysBackground().

Here is the caller graph for this function:

◆ CreateSysBackground()

std::unique_ptr< wxImage > CreateSysBackground ( int  width,
int  height,
int   WXUNUSEDoffset,
wxColour  colour 
)

Definition at line 306 of file ImageManipulation.cpp.

312{
313 #ifdef USE_AQUA_THEME
314 return CreateAquaBackground(width, height, offset);
315 #else
316 return CreateBackground(width, height, colour);
317 #endif
318}
std::unique_ptr< wxImage > CreateAquaBackground(int width, int height, int offset)
std::unique_ptr< wxImage > CreateBackground(int width, int height, wxColour colour)

References CreateAquaBackground(), and CreateBackground().

Here is the call graph for this function:

◆ GetSubImageWithAlpha()

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 381 of file ImageManipulation.cpp.

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

Referenced by ThemeBase::ReadImageCache().

Here is the caller graph for this function:

◆ OverlayImage() [1/2]

std::unique_ptr< wxImage > OverlayImage ( teBmps  eBack,
teBmps  eForeground,
int  xoff,
int  yoff 
)

The index of a bitmap resource in Theme Resources.

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

Definition at line 177 of file ImageManipulation.cpp.

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

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

Here is the call graph for this function:

◆ OverlayImage() [2/2]

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 a NEW image where the foreground has been overlaid onto the background using alpha-blending, at location (xoff, yoff).

Definition at line 111 of file ImageManipulation.cpp.

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

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

Here is the caller graph for this function:

◆ PasteSubImage()

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 324 of file ImageManipulation.cpp.

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

Referenced by ThemeBase::CreateOneImageCache().

Here is the caller graph for this function: