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< wxImageChangeImageColour (wxImage *srcImage, wxColour &dstColour)
 
std::unique_ptr< wxImageChangeImageColour (wxImage *srcImage, wxColour &srcColour, wxColour &dstColour)
 
std::unique_ptr< wxImageOverlayImage (wxImage *background, wxImage *foreground, wxImage *mask, int xoff, int yoff)
 
std::unique_ptr< wxImageOverlayImage (teBmps eBack, teBmps eForeground, int xoff, int yoff)
 The index of a bitmap resource in Theme Resources. More...
 
std::unique_ptr< wxImageCreateBackground (int width, int height, wxColour colour)
 
std::unique_ptr< wxImageCreateSysBackground (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}

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

289{
290 return CreateBackground(width, height, colour);
291}
std::unique_ptr< wxImage > CreateBackground(int width, int height, wxColour colour)

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

355{
356 //First part of this code is lifted from wxImage::GetSubImage() source code.
357 wxImage image;
358
359 wxCHECK_MSG( Src.Ok(), image, wxT("invalid image") );
360
361 wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && (
362 rect.GetRight()<=Src.GetWidth()) && (rect.GetBottom()<=Src.GetHeight()),
363 image, wxT("invalid subimage size") );
364
365 int subwidth=rect.GetWidth();
366 const int subheight=rect.GetHeight();
367
368 image.Create( subwidth, subheight, false );
369
370 unsigned char *subdata = image.GetData(), *data=Src.GetData();
371
372 wxCHECK_MSG( subdata, image, wxT("unable to create image") );
373
374 // JKC: Quick hack - don't deal with masks - need to understand macro M_IMGDATA first.
375// if (Src.M_IMGDATA->m_hasMask)
376// image.SetMaskColour( Src.M_IMGDATA->m_maskRed, Src.M_IMGDATA->m_maskGreen, Src.M_IMGDATA->m_maskBlue );
377
378 int subleft=3*rect.GetLeft();
379 int width=3*Src.GetWidth();
380 subwidth*=3;
381
382 data+=rect.GetTop()*width+subleft;
383
384 for (long j = 0; j < subheight; ++j)
385 {
386 memcpy( subdata, data, subwidth);
387 subdata+=subwidth;
388 data+=width;
389 }
390
391 image.InitAlpha();
392 if( !Src.HasAlpha() )
393 return image;
394 // OK, so we've copied the RGB data.
395 // Now do the Alpha channel.
396 //wxASSERT( Src.HasAlpha() );
397
398 subleft/=3;
399 width/=3;
400 subwidth/=3;
401
402 data =Src.GetAlpha();
403 subdata =image.GetAlpha();
404
405 data+=rect.GetTop()*width+subleft;
406
407 for (long j = 0; j < subheight; ++j)
408 {
409 memcpy( subdata, data, subwidth);
410 subdata+=subwidth;
411 data+=width;
412 }
413 return image;
414}
wxImage(22, 22)
wxT("CloseDown"))

References wxImage(), and wxT().

Referenced by ThemeBase::ReadImageCache().

Here is the call graph for this function:
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(), theTheme, and wxImage().

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

298{
299
300 unsigned char *bg = background->GetData();
301 unsigned char *fg = foreground->GetData();
302 unsigned char *bgAlpha = background->HasAlpha() ? background->GetAlpha() : NULL;
303 unsigned char *fgAlpha = foreground->HasAlpha() ? foreground->GetAlpha() : NULL;
304 // For testing... Set as if no alpha in foreground....
305 // fgAlpha = NULL;
306
307 int bgWidth = background->GetWidth();
308 int bgHeight = background->GetHeight();
309 int fgWidth = foreground->GetWidth();
310 int fgHeight = foreground->GetHeight();
311
312 int wCutoff = fgWidth;
313 int hCutoff = fgHeight;
314
315 // If the masked foreground + offset is bigger than the background, masking
316 // should only occur within these bounds of the foreground image
317 wCutoff = (bgWidth - xoff > wCutoff) ? wCutoff : bgWidth - xoff;
318 hCutoff = (bgHeight - yoff > hCutoff) ? hCutoff : bgHeight - yoff;
319
320 // Go through the foreground image bit by bit and place it on to the
321 // background, at an offset of xoff,yoff.
322 // Don't go beyond the size of the background image,
323 // or the foreground image.
324 int y;
325 unsigned char *bkp;
326 unsigned char *fgp;
327 unsigned char *bgAlphap;
328 unsigned char *fgAlphap;
329 for (y = 0; y < hCutoff; y++) {
330 // RGB bytes
331 bkp = bg + 3 * ((y + yoff) * bgWidth + xoff);
332 fgp = fg + 3 * ( y * fgWidth);
333 memcpy( bkp, fgp, 3 * wCutoff );
334
335 // Alpha bytes.
336 if( bgAlpha )
337 {
338 bgAlphap = bgAlpha + ((y+yoff) * bgWidth + xoff );
339 if( fgAlpha )
340 {
341 fgAlphap = fgAlpha + (y * fgWidth );
342 memcpy( bgAlphap, fgAlphap, wCutoff );
343 }
344 else
345 {
346 memset( bgAlphap, 255, wCutoff );
347 }
348 }
349 }
350}

Referenced by ThemeBase::CreateOneImageCache().

Here is the caller graph for this function: