Browse Source

Added method Image::getClippedImage(), which allows the use of images that refer to subsections of another image. This means that the the parameters to a couple of Graphics methods no longer need a clipping rectangle. Also dded a static Image::null object and another constructor for Image::BitmapData.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
9f0c91196f
39 changed files with 198 additions and 160 deletions
  1. +1
    -1
      extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_MSVC.h
  2. +1
    -1
      extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_XCode.h
  3. +1
    -1
      extras/juce demo/Source/demos/OpenGLDemo.cpp
  4. +2
    -5
      extras/juce demo/Source/demos/RenderingTestComponent.cpp
  5. +1
    -1
      src/core/juce_PlatformDefs.h
  6. +1
    -1
      src/core/juce_StandardHeader.h
  7. +1
    -1
      src/gui/components/controls/juce_ToolbarItemComponent.cpp
  8. +1
    -1
      src/gui/components/filebrowser/juce_FileListComponent.cpp
  9. +1
    -1
      src/gui/components/filebrowser/juce_ImagePreviewComponent.cpp
  10. +2
    -2
      src/gui/components/juce_Component.cpp
  11. +2
    -2
      src/gui/components/menus/juce_PopupMenu.cpp
  12. +3
    -3
      src/gui/components/menus/juce_PopupMenu.h
  13. +1
    -1
      src/gui/components/mouse/juce_DragAndDropContainer.h
  14. +3
    -3
      src/gui/components/special/juce_ColourSelector.cpp
  15. +1
    -3
      src/gui/components/special/juce_MagnifierComponent.cpp
  16. +1
    -1
      src/gui/components/windows/juce_CallOutBox.cpp
  17. +2
    -2
      src/gui/graphics/contexts/juce_FillType.cpp
  18. +5
    -8
      src/gui/graphics/contexts/juce_Graphics.cpp
  19. +5
    -14
      src/gui/graphics/contexts/juce_Graphics.h
  20. +2
    -3
      src/gui/graphics/contexts/juce_LowLevelGraphicsContext.h
  21. +5
    -7
      src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp
  22. +2
    -3
      src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h
  23. +21
    -25
      src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp
  24. +2
    -3
      src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h
  25. +2
    -2
      src/gui/graphics/drawables/juce_DrawableImage.cpp
  26. +2
    -2
      src/gui/graphics/effects/juce_DropShadowEffect.cpp
  27. +7
    -11
      src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp
  28. +1
    -1
      src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.h
  29. +2
    -2
      src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp
  30. +3
    -3
      src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp
  31. +63
    -0
      src/gui/graphics/imaging/juce_Image.cpp
  32. +26
    -2
      src/gui/graphics/imaging/juce_Image.h
  33. +2
    -2
      src/gui/graphics/imaging/juce_ImageCache.cpp
  34. +1
    -1
      src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp
  35. +3
    -3
      src/gui/graphics/imaging/juce_ImageFileFormat.cpp
  36. +3
    -3
      src/native/linux/juce_linux_Windowing.cpp
  37. +1
    -1
      src/native/mac/juce_iphone_UIViewComponentPeer.mm
  38. +12
    -31
      src/native/mac/juce_mac_CoreGraphicsContext.mm
  39. +3
    -3
      src/native/windows/juce_win32_Windowing.cpp

+ 1
- 1
extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_MSVC.h View File

@@ -296,7 +296,7 @@ protected:
dataBlock.writeInt (0); // clr used
dataBlock.writeInt (0); // clr important
const Image::BitmapData bitmap (image, 0, 0, w, h);
const Image::BitmapData bitmap (image, false);
const int alphaThreshold = 5;
int y;


+ 1
- 1
extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_XCode.h View File

@@ -266,7 +266,7 @@ private:
data.write (type, 4);
data.writeIntBigEndian (8 + 4 * w * h);
const Image::BitmapData bitmap (image, 0, 0, w, h);
const Image::BitmapData bitmap (image, false);
int y;
for (y = 0; y < h; ++y)


+ 1
- 1
extras/juce demo/Source/demos/OpenGLDemo.cpp View File

@@ -132,7 +132,7 @@ public:
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
Image::BitmapData srcData (image, 0, 0, image.getWidth(), image.getHeight());
Image::BitmapData srcData (image, false);
glTexImage2D (GL_TEXTURE_2D, 0, 4, image.getWidth(), image.getHeight(),
0, GL_RGB,


+ 2
- 5
extras/juce demo/Source/demos/RenderingTestComponent.cpp View File

@@ -192,9 +192,7 @@ private:
.rotated (bouncingNumber[3])
.scaled (bouncingNumber[2] + 4.0f, bouncingNumber[2] + 4.0f)
.translated (bouncingPointX[2], bouncingPointY[2]));
g.reduceClipRegion (argbImage,
Rectangle<int> (0, 0, argbImage.getWidth(), argbImage.getHeight()),
transform);
g.reduceClipRegion (argbImage, transform);
}
void drawPaths (Graphics& g, bool /*solid*/, bool linearGradient, bool radialGradient)
@@ -268,8 +266,7 @@ private:
.followedBy (getTransform()));
g.setOpacity ((float) owner.opacitySlider->getValue());
g.drawImageTransformed (image, image.getBounds(),
transform, false);
g.drawImageTransformed (image, transform, false);
}
void drawTiling (Graphics& g, const Image& image)


+ 1
- 1
src/core/juce_PlatformDefs.h View File

@@ -68,7 +68,7 @@
@see Logger::outputDebugString
*/
#define DBG(dbgtext) Logger::outputDebugString (dbgtext);
#define DBG(dbgtext) JUCE_NAMESPACE::Logger::outputDebugString (dbgtext);
//==============================================================================
// Assertions..


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 39
#define JUCE_BUILDNUMBER 40
/** Current Juce version number.


+ 1
- 1
src/gui/components/controls/juce_ToolbarItemComponent.cpp View File

@@ -96,7 +96,7 @@ public:
if (dnd != 0)
{
dnd->startDragging (Toolbar::toolbarDragDescriptor, getParentComponent(), Image(), true);
dnd->startDragging (Toolbar::toolbarDragDescriptor, getParentComponent(), Image::null, true);
ToolbarItemComponent* const tc = dynamic_cast <ToolbarItemComponent*> (getParentComponent());


+ 1
- 1
src/gui/components/filebrowser/juce_FileListComponent.cpp View File

@@ -199,7 +199,7 @@ private:
void clearIcon()
{
icon = Image();
icon = Image::null;
}
void updateIcon (const bool onlyUpdateIfCached)


+ 1
- 1
src/gui/components/filebrowser/juce_ImagePreviewComponent.cpp View File

@@ -68,7 +68,7 @@ void ImagePreviewComponent::timerCallback()
{
stopTimer();
currentThumbnail = Image();
currentThumbnail = Image::null;
currentDetails = String::empty;
repaint();


+ 2
- 2
src/gui/components/juce_Component.cpp View File

@@ -502,7 +502,7 @@ void Component::setBufferedToImage (const bool shouldBeBuffered)
{
if (shouldBeBuffered != flags.bufferToImageFlag)
{
bufferedImage_ = Image();
bufferedImage_ = Image::null;
flags.bufferToImageFlag = shouldBeBuffered;
}
}
@@ -1478,7 +1478,7 @@ void Component::repaint()
void Component::repaint (const int x, const int y,
const int w, const int h)
{
bufferedImage_ = Image();
bufferedImage_ = Image::null;
if (flags.visibleFlag)
internalRepaint (x, y, w, h);


+ 2
- 2
src/gui/components/menus/juce_PopupMenu.cpp View File

@@ -1334,7 +1334,7 @@ void PopupMenu::addCommandItem (ApplicationCommandManager* commandManager,
: info.shortName,
target != 0 && (info.flags & ApplicationCommandInfo::isDisabled) == 0,
(info.flags & ApplicationCommandInfo::isTicked) != 0,
Image(),
Image::null,
Colours::black,
false,
0, 0,
@@ -1369,7 +1369,7 @@ void PopupMenu::addCustomItem (const int itemResultId,
addSeparatorIfPending();
items.add (new Item (itemResultId, String::empty, true, false, Image(),
items.add (new Item (itemResultId, String::empty, true, false, Image::null,
Colours::black, false, customComponent, 0, 0));
}


+ 3
- 3
src/gui/components/menus/juce_PopupMenu.h View File

@@ -119,7 +119,7 @@ public:
const String& itemText,
bool isActive = true,
bool isTicked = false,
const Image& iconToUse = Image());
const Image& iconToUse = Image::null);
/** Adds an item that represents one of the commands in a command manager object.
@@ -145,7 +145,7 @@ public:
const Colour& itemTextColour,
bool isActive = true,
bool isTicked = false,
const Image& iconToUse = Image());
const Image& iconToUse = Image::null);
/** Appends a custom menu item.
@@ -183,7 +183,7 @@ public:
void addSubMenu (const String& subMenuName,
const PopupMenu& subMenu,
bool isActive = true,
const Image& iconToUse = Image(),
const Image& iconToUse = Image::null,
bool isTicked = false);
/** Appends a separator to the menu, to help break it up into sections.


+ 1
- 1
src/gui/components/mouse/juce_DragAndDropContainer.h View File

@@ -90,7 +90,7 @@ public:
*/
void startDragging (const String& sourceDescription,
Component* sourceComponent,
const Image& dragImage = Image(),
const Image& dragImage = Image::null,
bool allowDraggingToOtherJuceWindows = false,
const Point<int>* imageOffsetFromMouse = 0);


+ 3
- 3
src/gui/components/special/juce_ColourSelector.cpp View File

@@ -117,7 +117,7 @@ public:
const int height = getHeight() / 2;
colours = Image (Image::RGB, width, height, false);
Image::BitmapData pixels (colours, 0, 0, width, height, true);
Image::BitmapData pixels (colours, true);
for (int y = 0; y < height; ++y)
{
@@ -155,7 +155,7 @@ public:
if (lastHue != h)
{
lastHue = h;
colours = Image();
colours = Image::null;
repaint();
}
@@ -164,7 +164,7 @@ public:
void resized()
{
colours = Image();
colours = Image::null;
updateMarker();
}


+ 1
- 3
src/gui/components/special/juce_MagnifierComponent.cpp View File

@@ -275,9 +275,7 @@ void MagnifierComponent::paint (Graphics& g)
}
g.setImageResamplingQuality (quality);
g.drawImageTransformed (temp, temp.getBounds(),
AffineTransform::scale ((float) scaleFactor, (float) scaleFactor),
false);
g.drawImageTransformed (temp, AffineTransform::scale ((float) scaleFactor, (float) scaleFactor), false);
}
void MagnifierComponent::childBoundsChanged (Component* c)


+ 1
- 1
src/gui/components/windows/juce_CallOutBox.cpp View File

@@ -201,7 +201,7 @@ void CallOutBox::updatePosition (const Rectangle<int>& newAreaToPointTo, const R
void CallOutBox::refreshPath()
{
repaint();
background = Image();
background = Image::null;
outline.clear();
const float gap = 4.5f;


+ 2
- 2
src/gui/graphics/contexts/juce_FillType.cpp View File

@@ -92,7 +92,7 @@ bool FillType::operator!= (const FillType& other) const
void FillType::setColour (const Colour& newColour) throw()
{
gradient = 0;
image = Image();
image = Image::null;
colour = newColour;
}
@@ -104,7 +104,7 @@ void FillType::setGradient (const ColourGradient& newGradient)
}
else
{
image = Image();
image = Image::null;
gradient = new ColourGradient (newGradient);
colour = Colours::black;
}


+ 5
- 8
src/gui/graphics/contexts/juce_Graphics.cpp View File

@@ -105,10 +105,10 @@ bool Graphics::reduceClipRegion (const Path& path, const AffineTransform& transf
return ! context->isClipEmpty();
}
bool Graphics::reduceClipRegion (const Image& image, const Rectangle<int>& sourceClipRegion, const AffineTransform& transform)
bool Graphics::reduceClipRegion (const Image& image, const AffineTransform& transform)
{
saveStateIfPending();
context->clipToImageAlpha (image, sourceClipRegion, transform);
context->clipToImageAlpha (image, transform);
return ! context->isClipEmpty();
}
@@ -667,7 +667,7 @@ void Graphics::drawImage (const Image& imageToDraw,
if (imageToDraw.isValid() && context->clipRegionIntersects (Rectangle<int> (dx, dy, dw, dh)))
{
drawImageTransformed (imageToDraw, Rectangle<int> (sx, sy, sw, sh),
drawImageTransformed (imageToDraw.getClippedImage (Rectangle<int> (sx, sy, sw, sh)),
AffineTransform::scale (dw / (float) sw, dh / (float) sh)
.translated ((float) dx, (float) dy),
fillAlphaChannelWithCurrentBrush);
@@ -675,24 +675,21 @@ void Graphics::drawImage (const Image& imageToDraw,
}
void Graphics::drawImageTransformed (const Image& imageToDraw,
const Rectangle<int>& imageSubRegion,
const AffineTransform& transform,
const bool fillAlphaChannelWithCurrentBrush) const
{
if (imageToDraw.isValid() && ! context->isClipEmpty())
{
const Rectangle<int> srcClip (imageSubRegion.getIntersection (imageToDraw.getBounds()));
if (fillAlphaChannelWithCurrentBrush)
{
context->saveState();
context->clipToImageAlpha (imageToDraw, srcClip, transform);
context->clipToImageAlpha (imageToDraw, transform);
fillAll();
context->restoreState();
}
else
{
context->drawImage (imageToDraw, srcClip, transform, false);
context->drawImage (imageToDraw, transform, false);
}
}
}


+ 5
- 14
src/gui/graphics/contexts/juce_Graphics.h View File

@@ -492,18 +492,11 @@ public:
int sourceX, int sourceY, int sourceWidth, int sourceHeight,
bool fillAlphaChannelWithCurrentBrush = false) const;
/** Draws part of an image, having applied an affine transform to it.
/** Draws an image, having applied an affine transform to it.
This lets you throw the image around in some wacky ways, rotate it, shear,
scale it, etc.
A subregion is specified within the source image, and all transformations
will be treated as relative to the origin of this sub-region. So, for example if
your subregion is (50, 50, 100, 100), and your transform is a translation of (20, 20),
the resulting pixel drawn at (20, 20) in the destination context is from (50, 50) in
your image. If you want to use the whole image, then Image::getBounds() returns a
suitable rectangle to use as the imageSubRegion parameter.
Images are composited using the context's current opacity, so if you
don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f)
(or setColour() with an opaque colour) before drawing images.
@@ -511,10 +504,12 @@ public:
If fillAlphaChannelWithCurrentBrush is set to true, then the image's RGB channels
are ignored and it is filled with the current brush, masked by its alpha channel.
If you want to render only a subsection of an image, use Image::getClippedImage() to
create the section that you need.
@see setImageResamplingQuality, drawImage
*/
void drawImageTransformed (const Image& imageToDraw,
const Rectangle<int>& imageSubRegion,
const AffineTransform& transform,
bool fillAlphaChannelWithCurrentBrush = false) const;
@@ -588,15 +583,11 @@ public:
@param image the image whose alpha-channel should be used. If the image doesn't
have an alpha-channel, it is treated as entirely opaque.
@param sourceClipRegion a subsection of the image that should be used. To use the
entire image, just pass a rectangle of bounds
(0, 0, image.getWidth(), image.getHeight()).
@param transform a matrix to apply to the image
@returns true if the resulting clipping region is non-zero in size
@see reduceClipRegion
*/
bool reduceClipRegion (const Image& image, const Rectangle<int>& sourceClipRegion,
const AffineTransform& transform);
bool reduceClipRegion (const Image& image, const AffineTransform& transform);
/** Excludes a rectangle to stop it being drawn into. */
void excludeClipRegion (const Rectangle<int>& rectangleToExclude);


+ 2
- 3
src/gui/graphics/contexts/juce_LowLevelGraphicsContext.h View File

@@ -71,7 +71,7 @@ public:
virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0;
virtual void excludeClipRectangle (const Rectangle<int>& r) = 0;
virtual void clipToPath (const Path& path, const AffineTransform& transform) = 0;
virtual void clipToImageAlpha (const Image& sourceImage, const Rectangle<int>& srcClip, const AffineTransform& transform) = 0;
virtual void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) = 0;
virtual bool clipRegionIntersects (const Rectangle<int>& r) = 0;
virtual const Rectangle<int> getClipBounds() const = 0;
@@ -89,8 +89,7 @@ public:
virtual void fillRect (const Rectangle<int>& r, bool replaceExistingContents) = 0;
virtual void fillPath (const Path& path, const AffineTransform& transform) = 0;
virtual void drawImage (const Image& sourceImage, const Rectangle<int>& srcClip,
const AffineTransform& transform, bool fillEntireClipAsTiles) = 0;
virtual void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles) = 0;
virtual void drawLine (const Line <float>& line) = 0;
virtual void drawVerticalLine (int x, float top, float bottom) = 0;


+ 5
- 7
src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp View File

@@ -140,7 +140,7 @@ void LowLevelGraphicsPostScriptRenderer::clipToPath (const Path& path, const Aff
out << "clip\n";
}
void LowLevelGraphicsPostScriptRenderer::clipToImageAlpha (const Image& /*sourceImage*/, const Rectangle<int>& /*srcClip*/, const AffineTransform& /*transform*/)
void LowLevelGraphicsPostScriptRenderer::clipToImageAlpha (const Image& /*sourceImage*/, const AffineTransform& /*transform*/)
{
needToClip = true;
jassertfalse; // xxx
@@ -454,11 +454,10 @@ void LowLevelGraphicsPostScriptRenderer::writeImage (const Image& im,
out << "\n>}\n";
}
void LowLevelGraphicsPostScriptRenderer::drawImage (const Image& sourceImage, const Rectangle<int>& srcClip,
const AffineTransform& transform, const bool /*fillEntireClipAsTiles*/)
void LowLevelGraphicsPostScriptRenderer::drawImage (const Image& sourceImage, const AffineTransform& transform, const bool /*fillEntireClipAsTiles*/)
{
const int w = jmin (sourceImage.getWidth(), srcClip.getRight());
const int h = jmin (sourceImage.getHeight(), srcClip.getBottom());
const int w = sourceImage.getWidth();
const int h = sourceImage.getHeight();
writeClip();
@@ -468,7 +467,6 @@ void LowLevelGraphicsPostScriptRenderer::drawImage (const Image& sourceImage, co
RectangleList imageClip;
sourceImage.createSolidAreaMask (imageClip, 0.5f);
imageClip.clipTo (srcClip);
out << "newpath ";
int itemsOnLine = 0;
@@ -491,7 +489,7 @@ void LowLevelGraphicsPostScriptRenderer::drawImage (const Image& sourceImage, co
out << w << ' ' << h << " scale\n";
out << w << ' ' << h << " 8 [" << w << " 0 0 -" << h << ' ' << (int) 0 << ' ' << h << " ]\n";
writeImage (sourceImage, srcClip.getX(), srcClip.getY(), srcClip.getWidth(), srcClip.getHeight());
writeImage (sourceImage, 0, 0, w, h);
out << "false 3 colorimage grestore\n";
needToClip = true;


+ 2
- 3
src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h View File

@@ -54,7 +54,7 @@ public:
bool clipToRectangleList (const RectangleList& clipRegion);
void excludeClipRectangle (const Rectangle<int>& r);
void clipToPath (const Path& path, const AffineTransform& transform);
void clipToImageAlpha (const Image& sourceImage, const Rectangle<int>& srcClip, const AffineTransform& transform);
void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform);
void saveState();
void restoreState();
@@ -72,8 +72,7 @@ public:
void fillRect (const Rectangle<int>& r, bool replaceExistingContents);
void fillPath (const Path& path, const AffineTransform& transform);
void drawImage (const Image& sourceImage, const Rectangle<int>& srcClip,
const AffineTransform& transform, bool fillEntireClipAsTiles);
void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles);
void drawLine (const Line <float>& line);


+ 21
- 25
src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp View File

@@ -986,7 +986,7 @@ public:
virtual const Ptr excludeClipRectangle (const Rectangle<int>& r) = 0;
virtual const Ptr clipToPath (const Path& p, const AffineTransform& transform) = 0;
virtual const Ptr clipToEdgeTable (const EdgeTable& et) = 0;
virtual const Ptr clipToImageAlpha (const Image& image, const Rectangle<int>& srcClip, const AffineTransform& t, const bool betterQuality) = 0;
virtual const Ptr clipToImageAlpha (const Image& image, const AffineTransform& t, const bool betterQuality) = 0;
virtual bool clipRegionIntersects (const Rectangle<int>& r) const = 0;
virtual const Rectangle<int> getClipBounds() const = 0;
@@ -1224,9 +1224,9 @@ public:
return edgeTable.isEmpty() ? 0 : this;
}
const Ptr clipToImageAlpha (const Image& image, const Rectangle<int>& srcClip, const AffineTransform& transform, const bool betterQuality)
const Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, const bool betterQuality)
{
const Image::BitmapData srcData (image, srcClip.getX(), srcClip.getY(), srcClip.getWidth(), srcClip.getHeight());
const Image::BitmapData srcData (image, false);
if (transform.isOnlyTranslation())
{
@@ -1416,9 +1416,9 @@ public:
return Ptr (new ClipRegion_EdgeTable (clip))->clipToEdgeTable (et);
}
const Ptr clipToImageAlpha (const Image& image, const Rectangle<int>& srcClip, const AffineTransform& transform, const bool betterQuality)
const Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, const bool betterQuality)
{
return Ptr (new ClipRegion_EdgeTable (clip))->clipToImageAlpha (image, srcClip, transform, betterQuality);
return Ptr (new ClipRegion_EdgeTable (clip))->clipToImageAlpha (image, transform, betterQuality);
}
bool clipRegionIntersects (const Rectangle<int>& r) const
@@ -1803,20 +1803,20 @@ public:
}
}
void clipToImageAlpha (const Image& image, const Rectangle<int>& srcClip, const AffineTransform& t)
void clipToImageAlpha (const Image& image, const AffineTransform& t)
{
if (clip != 0)
{
if (image.hasAlphaChannel())
{
cloneClipIfMultiplyReferenced();
clip = clip->clipToImageAlpha (image, srcClip, t.translated ((float) xOffset, (float) yOffset),
clip = clip->clipToImageAlpha (image, t.translated ((float) xOffset, (float) yOffset),
interpolationQuality != Graphics::lowResamplingQuality);
}
else
{
Path p;
p.addRectangle (srcClip);
p.addRectangle (image.getBounds());
clipToPath (p, t);
}
}
@@ -1839,7 +1839,7 @@ public:
{
if (fillType.isColour())
{
Image::BitmapData destData (image, 0, 0, image.getWidth(), image.getHeight(), true);
Image::BitmapData destData (image, true);
clip->fillRectWithColour (destData, r.translated (xOffset, yOffset), fillType.colour.getPixelARGB(), replaceContents);
}
else
@@ -1859,7 +1859,7 @@ public:
{
if (fillType.isColour())
{
Image::BitmapData destData (image, 0, 0, image.getWidth(), image.getHeight(), true);
Image::BitmapData destData (image, true);
clip->fillRectWithColour (destData, r.translated ((float) xOffset, (float) yOffset), fillType.colour.getPixelARGB());
}
else
@@ -1898,7 +1898,7 @@ public:
if (shapeToFill != 0)
{
Image::BitmapData destData (image, 0, 0, image.getWidth(), image.getHeight(), true);
Image::BitmapData destData (image, true);
if (fillType.isGradient())
{
@@ -1923,7 +1923,7 @@ public:
}
else if (fillType.isTiledImage())
{
renderImage (image, fillType.image, fillType.image.getBounds(), fillType.transform, shapeToFill);
renderImage (image, fillType.image, fillType.transform, shapeToFill);
}
else
{
@@ -1933,13 +1933,12 @@ public:
}
//==============================================================================
void renderImage (Image& destImage, const Image& sourceImage, const Rectangle<int>& srcClip,
const AffineTransform& t, const SoftwareRendererClasses::ClipRegionBase* const tiledFillClipRegion)
void renderImage (Image& destImage, const Image& sourceImage, const AffineTransform& t, const SoftwareRendererClasses::ClipRegionBase* const tiledFillClipRegion)
{
const AffineTransform transform (t.translated ((float) xOffset, (float) yOffset));
const Image::BitmapData destData (destImage, 0, 0, destImage.getWidth(), destImage.getHeight(), true);
const Image::BitmapData srcData (sourceImage, srcClip.getX(), srcClip.getY(), srcClip.getWidth(), srcClip.getHeight());
const Image::BitmapData destData (destImage, true);
const Image::BitmapData srcData (sourceImage, false);
const int alpha = fillType.colour.getAlpha();
const bool betterQuality = (interpolationQuality != Graphics::lowResamplingQuality);
@@ -1960,7 +1959,7 @@ public:
}
else
{
SoftwareRendererClasses::ClipRegionBase::Ptr c (new SoftwareRendererClasses::ClipRegion_EdgeTable (Rectangle<int> (tx, ty, srcClip.getWidth(), srcClip.getHeight()).getIntersection (destImage.getBounds())));
SoftwareRendererClasses::ClipRegionBase::Ptr c (new SoftwareRendererClasses::ClipRegion_EdgeTable (Rectangle<int> (tx, ty, sourceImage.getWidth(), sourceImage.getHeight()).getIntersection (destImage.getBounds())));
c = clip->applyClipTo (c);
if (c != 0)
@@ -1981,7 +1980,7 @@ public:
else
{
Path p;
p.addRectangle (srcClip);
p.addRectangle (sourceImage.getBounds());
SoftwareRendererClasses::ClipRegionBase::Ptr c (clip->clone());
c = c->clipToPath (p, transform);
@@ -2058,9 +2057,9 @@ void LowLevelGraphicsSoftwareRenderer::clipToPath (const Path& path, const Affin
currentState->clipToPath (path, transform);
}
void LowLevelGraphicsSoftwareRenderer::clipToImageAlpha (const Image& sourceImage, const Rectangle<int>& srcClip, const AffineTransform& transform)
void LowLevelGraphicsSoftwareRenderer::clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform)
{
currentState->clipToImageAlpha (sourceImage, srcClip, transform);
currentState->clipToImageAlpha (sourceImage, transform);
}
bool LowLevelGraphicsSoftwareRenderer::clipRegionIntersects (const Rectangle<int>& r)
@@ -2126,12 +2125,9 @@ void LowLevelGraphicsSoftwareRenderer::fillPath (const Path& path, const AffineT
currentState->fillPath (image, path, transform);
}
void LowLevelGraphicsSoftwareRenderer::drawImage (const Image& sourceImage, const Rectangle<int>& srcClip,
const AffineTransform& transform, const bool fillEntireClipAsTiles)
void LowLevelGraphicsSoftwareRenderer::drawImage (const Image& sourceImage, const AffineTransform& transform, const bool fillEntireClipAsTiles)
{
jassert (sourceImage.getBounds().contains (srcClip));
currentState->renderImage (image, sourceImage, srcClip, transform,
currentState->renderImage (image, sourceImage, transform,
fillEntireClipAsTiles ? currentState->clip : 0);
}


+ 2
- 3
src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h View File

@@ -54,7 +54,7 @@ public:
bool clipToRectangleList (const RectangleList& clipRegion);
void excludeClipRectangle (const Rectangle<int>& r);
void clipToPath (const Path& path, const AffineTransform& transform);
void clipToImageAlpha (const Image& sourceImage, const Rectangle<int>& srcClip, const AffineTransform& transform);
void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform);
bool clipRegionIntersects (const Rectangle<int>& r);
const Rectangle<int> getClipBounds() const;
@@ -72,8 +72,7 @@ public:
void fillRect (const Rectangle<int>& r, bool replaceExistingContents);
void fillPath (const Path& path, const AffineTransform& transform);
void drawImage (const Image& sourceImage, const Rectangle<int>& srcClip,
const AffineTransform& transform, bool fillEntireClipAsTiles);
void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles);
void drawLine (const Line <float>& line);


+ 2
- 2
src/gui/graphics/drawables/juce_DrawableImage.cpp View File

@@ -108,13 +108,13 @@ void DrawableImage::render (const Drawable::RenderingContext& context) const
if (opacity > 0.0f && ! overlayColour.isOpaque())
{
context.g.setOpacity (context.opacity * opacity);
context.g.drawImageTransformed (image, image.getBounds(), t, false);
context.g.drawImageTransformed (image, t, false);
}
if (! overlayColour.isTransparent())
{
context.g.setColour (overlayColour.withMultipliedAlpha (context.opacity));
context.g.drawImageTransformed (image, image.getBounds(), t, true);
context.g.drawImageTransformed (image, t, true);
}
}
}


+ 2
- 2
src/gui/graphics/effects/juce_DropShadowEffect.cpp View File

@@ -66,8 +66,8 @@ void DropShadowEffect::applyEffect (Image& image, Graphics& g)
Image shadowImage (Image::SingleChannel, w, h, false);
const Image::BitmapData srcData (image, 0, 0, w, h);
const Image::BitmapData destData (shadowImage, 0, 0, w, h, true);
const Image::BitmapData srcData (image, false);
const Image::BitmapData destData (shadowImage, true);
const int filter = roundToInt (63.0f / radius);
const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f);


+ 7
- 11
src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp View File

@@ -33,8 +33,7 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
GIFLoader::GIFLoader (InputStream& in)
: image (0),
input (in),
: input (in),
dataBlockIsZero (false),
fresh (false),
finished (false)
@@ -99,9 +98,7 @@ GIFLoader::GIFLoader (InputStream& in)
image = Image ((transparent >= 0) ? Image::ARGB : Image::RGB,
imageWidth, imageHeight, (transparent >= 0));
readImage (imageWidth, imageHeight,
(buf[8] & 0x40) != 0,
transparent);
readImage ((buf[8] & 0x40) != 0, transparent);
break;
}
@@ -361,8 +358,7 @@ int GIFLoader::readLZWByte (const bool initialise, const int inputCodeSize)
return code;
}
bool GIFLoader::readImage (const int width, const int height,
const int interlace, const int transparent)
bool GIFLoader::readImage (const int interlace, const int transparent)
{
unsigned char c;
@@ -381,7 +377,7 @@ bool GIFLoader::readImage (const int width, const int height,
int index;
int xpos = 0, ypos = 0, pass = 0;
const Image::BitmapData destData (image, 0, 0, width, height, true);
const Image::BitmapData destData (image, true);
uint8* p = destData.data;
const bool hasAlpha = image.hasAlphaChannel();
@@ -409,7 +405,7 @@ bool GIFLoader::readImage (const int width, const int height,
p += destData.pixelStride;
++xpos;
if (xpos == width)
if (xpos == destData.width)
{
xpos = 0;
@@ -423,7 +419,7 @@ bool GIFLoader::readImage (const int width, const int height,
case 3: ypos += 2; break;
}
while (ypos >= height)
while (ypos >= destData.height)
{
++pass;
@@ -444,7 +440,7 @@ bool GIFLoader::readImage (const int width, const int height,
p = destData.getPixelPointer (xpos, ypos);
}
if (ypos >= height)
if (ypos >= destData.height)
break;
}


+ 1
- 1
src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.h View File

@@ -69,7 +69,7 @@ private:
int processExtension (int type, int& transparent);
int readLZWByte (bool initialise, int input_code_size);
int getCode (int code_size, bool initialise);
bool readImage (int width, int height, int interlace, int transparent);
bool readImage (int interlace, int transparent);
static inline int makeWord (const uint8 a, const uint8 b) { return (b << 8) | a; }
GIFLoader (const GIFLoader&);


+ 2
- 2
src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp View File

@@ -302,7 +302,7 @@ const Image JPEGImageFormat::decodeImage (InputStream& in)
image = Image (Image::RGB, width, height, false);
const bool hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect)
const Image::BitmapData destData (image, 0, 0, width, height, true);
const Image::BitmapData destData (image, true);
for (int y = 0; y < height; ++y)
{
@@ -405,7 +405,7 @@ bool JPEGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
JSAMPARRAY buffer = (*jpegCompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegCompStruct,
JPOOL_IMAGE, strideBytes, 1);
const Image::BitmapData srcData (image, 0, 0, jpegCompStruct.image_width, jpegCompStruct.image_height);
const Image::BitmapData srcData (image, false);
while (jpegCompStruct.next_scanline < jpegCompStruct.image_height)
{


+ 3
- 3
src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp View File

@@ -168,7 +168,7 @@ const Image PNGImageFormat::decodeImage (InputStream& in)
if (pngInfoStruct == 0)
{
png_destroy_read_struct (&pngReadStruct, 0, 0);
return Image();
return Image::null;
}
png_set_error_fn (pngReadStruct, 0, PNGHelpers::errorCallback, PNGHelpers::errorCallback );
@@ -226,7 +226,7 @@ const Image PNGImageFormat::decodeImage (InputStream& in)
hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect)
const Image::BitmapData destData (image, 0, 0, (int) width, (int) height, true);
const Image::BitmapData destData (image, true);
uint8* srcRow = tempBuffer;
uint8* destRow = destData.data;
@@ -304,7 +304,7 @@ bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
png_set_shift (pngWriteStruct, &sig_bit);
png_set_packing (pngWriteStruct);
const Image::BitmapData srcData (image, 0, 0, width, height);
const Image::BitmapData srcData (image, false);
for (int y = 0; y < height; ++y)
{


+ 63
- 0
src/gui/graphics/imaging/juce_Image.cpp View File

@@ -95,6 +95,57 @@ Image::SharedImage* Image::SharedImage::createSoftwareImage (Image::PixelFormat
return new SoftwareSharedImage (format, width, height, clearImage);
}
//==============================================================================
class SubsectionSharedImage : public Image::SharedImage
{
public:
SubsectionSharedImage (Image::SharedImage* const image_, const Rectangle<int>& area_)
: Image::SharedImage (image_->getPixelFormat(), area_.getWidth(), area_.getHeight()),
image (image_), area (area_)
{
pixelStride = image_->getPixelStride();
lineStride = image_->getLineStride();
imageData = image_->getPixelData (area_.getX(), area_.getY());
}
~SubsectionSharedImage() {}
Image::ImageType getType() const
{
return Image::SoftwareImage;
}
LowLevelGraphicsContext* createLowLevelContext()
{
LowLevelGraphicsContext* g = image->createLowLevelContext();
g->clipToRectangle (area);
g->setOrigin (area.getX(), area.getY());
return g;
}
SharedImage* clone()
{
return new SubsectionSharedImage (image->clone(), area);
}
private:
const ReferenceCountedObjectPtr<Image::SharedImage> image;
const Rectangle<int> area;
};
const Image Image::getClippedImage (const Rectangle<int>& area) const
{
if (area.contains (getBounds()))
return *this;
const Rectangle<int> validArea (area.getIntersection (getBounds()));
if (validArea.isEmpty())
return Image::null;
return Image (new SubsectionSharedImage (image, validArea));
}
//==============================================================================
Image::Image()
{
@@ -128,6 +179,8 @@ Image::~Image()
{
}
const Image Image::null;
LowLevelGraphicsContext* Image::createLowLevelContext() const
{
return image == 0 ? 0 : image->createLowLevelContext();
@@ -231,6 +284,16 @@ Image::BitmapData::BitmapData (const Image& image, const int x, const int y, con
jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= image.getWidth() && y + h <= image.getHeight());
}
Image::BitmapData::BitmapData (const Image& image, bool /*needsToBeWritable*/)
: data (image.image == 0 ? 0 : image.image->imageData),
pixelFormat (image.getFormat()),
lineStride (image.image == 0 ? 0 : image.image->lineStride),
pixelStride (image.image == 0 ? 0 : image.image->pixelStride),
width (image.getWidth()),
height (image.getHeight())
{
}
Image::BitmapData::~BitmapData()
{
}


+ 26
- 2
src/gui/graphics/imaging/juce_Image.h View File

@@ -139,6 +139,11 @@ public:
*/
inline bool isNull() const throw() { return image == 0; }
/** A null Image object that can be used when you need to return an invalid image.
This object is the equivalient to an Image created with the default constructor.
*/
static const Image null;
//==============================================================================
/** Returns the image's width (in pixels). */
int getWidth() const throw() { return image == 0 ? 0 : image->width; }
@@ -206,6 +211,19 @@ public:
*/
void duplicateIfShared();
/** Returns an image which refers to a subsection of this image.
This will not make a copy of the original - the new image will keep a reference to it, so that
if the original image is changed, the contents of the subsection will also change. Likewise if you
draw into the subimage, you'll also be drawing onto that area of the original image. Note that if
you use operator= to make the original Image object refer to something else, the subsection image
won't pick up this change, it'll remain pointing at the original.
The area passed-in will be clipped to the bounds of this image, so this may return a smaller
image than the area you asked for, or even a null image if the area was out-of-bounds.
*/
const Image getClippedImage (const Rectangle<int>& area) const;
//==============================================================================
/** Returns the colour of one of the pixels in the image.
@@ -276,6 +294,7 @@ public:
public:
BitmapData (Image& image, int x, int y, int w, int h, bool needsToBeWritable);
BitmapData (const Image& image, int x, int y, int w, int h);
BitmapData (const Image& image, bool needsToBeWritable);
~BitmapData();
/** Returns a pointer to the start of a line in the image.
@@ -382,6 +401,13 @@ public:
static SharedImage* createNativeImage (PixelFormat format, int width, int height, bool clearImage);
static SharedImage* createSoftwareImage (PixelFormat format, int width, int height, bool clearImage);
const PixelFormat getPixelFormat() const throw() { return format; }
int getWidth() const throw() { return width; }
int getHeight() const throw() { return height; }
int getPixelStride() const throw() { return pixelStride; }
int getLineStride() const throw() { return lineStride; }
uint8* getPixelData (int x, int y) const throw();
protected:
friend class Image;
friend class Image::BitmapData;
@@ -391,8 +417,6 @@ public:
uint8* imageData;
var userTag;
uint8* getPixelData (int x, int y) const throw();
SharedImage (const SharedImage&);
SharedImage& operator= (const SharedImage&);
};


+ 2
- 2
src/gui/graphics/imaging/juce_ImageCache.cpp View File

@@ -63,7 +63,7 @@ public:
return item->image;
}
return Image();
return Image::null;
}
void addImageToCache (const Image& image, const int64 hashCode)
@@ -136,7 +136,7 @@ const Image ImageCache::getFromHashCode (const int64 hashCode)
if (Pimpl::getInstanceWithoutCreating() != 0)
return Pimpl::getInstanceWithoutCreating()->getFromHashCode (hashCode);
return Image();
return Image::null;
}
void ImageCache::addImageToCache (const Image& image, const int64 hashCode)


+ 1
- 1
src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp View File

@@ -143,7 +143,7 @@ void ImageConvolutionKernel::applyToImage (Image& destImage,
const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(), true);
uint8* line = destData.data;
const Image::BitmapData srcData (sourceImage, 0, 0, sourceImage.getWidth(), sourceImage.getHeight());
const Image::BitmapData srcData (sourceImage, false);
if (destData.pixelStride == 4)
{


+ 3
- 3
src/gui/graphics/imaging/juce_ImageFileFormat.cpp View File

@@ -106,7 +106,7 @@ const Image ImageFileFormat::loadFrom (InputStream& input)
if (format != 0)
return format->decodeImage (input);
return Image();
return Image::null;
}
const Image ImageFileFormat::loadFrom (const File& file)
@@ -119,7 +119,7 @@ const Image ImageFileFormat::loadFrom (const File& file)
return loadFrom (b);
}
return Image();
return Image::null;
}
const Image ImageFileFormat::loadFrom (const void* rawData, const int numBytes)
@@ -130,7 +130,7 @@ const Image ImageFileFormat::loadFrom (const void* rawData, const int numBytes)
return loadFrom (stream);
}
return Image();
return Image::null;
}
END_JUCE_NAMESPACE

+ 3
- 3
src/native/linux/juce_linux_Windowing.cpp View File

@@ -622,7 +622,7 @@ public:
const uint32 bShiftL = jmax (0, getShiftNeeded (bMask));
const uint32 bShiftR = jmax (0, -getShiftNeeded (bMask));
const Image::BitmapData srcData (Image (this), 0, 0, width, height);
const Image::BitmapData srcData (Image (this), false);
for (int y = sy; y < sy + dh; ++y)
{
@@ -1819,7 +1819,7 @@ private:
else if (Time::getApproximateMillisecondCounter() > lastTimeImageUsed + 3000)
{
stopTimer();
image = Image();
image = Image::null;
}
}
@@ -3137,7 +3137,7 @@ void MouseCursor::showInAllWindows() const
//==============================================================================
const Image juce_createIconForFile (const File& file)
{
return Image();
return Image::null;
}
Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage)


+ 1
- 1
src/native/mac/juce_iphone_UIViewComponentPeer.mm View File

@@ -878,7 +878,7 @@ ComponentPeer* Component::createNewPeer (int styleFlags, void* windowToAttachTo)
//==============================================================================
const Image juce_createIconForFile (const File& file)
{
return Image();
return Image::null;
}
//==============================================================================


+ 12
- 31
src/native/mac/juce_mac_CoreGraphicsContext.mm View File

@@ -76,7 +76,7 @@ public:
}
else
{
const Image::BitmapData srcData (juceImage, 0, 0, juceImage.getWidth(), juceImage.getHeight());
const Image::BitmapData srcData (juceImage, false);
CGDataProviderRef provider = CGDataProviderCreateWithData (0, srcData.data, srcData.lineStride * srcData.height, 0);
@@ -234,7 +234,7 @@ public:
lastClipRectIsValid = false;
}
void clipToImageAlpha (const Image& sourceImage, const Rectangle<int>& srcClip, const AffineTransform& transform)
void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform)
{
if (! transform.isSingularity())
{
@@ -245,19 +245,11 @@ public:
CGImageRef image = CoreGraphicsImage::createImage (singleChannelImage, true, greyColourSpace);
if (srcClip != sourceImage.getBounds())
{
CGImageRef fullImage = image;
image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), srcClip.getY(),
srcClip.getWidth(), srcClip.getHeight()));
CGImageRelease (fullImage);
}
flip();
AffineTransform t (AffineTransform::scale (1.0f, -1.0f).translated (0, srcClip.getHeight()).followedBy (transform));
AffineTransform t (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform));
applyTransform (t);
CGRect r = CGRectMake (0, 0, srcClip.getWidth(), srcClip.getHeight());
CGRect r = CGRectMake (0, 0, sourceImage.getWidth(), sourceImage.getHeight());
CGContextClipToMask (context, r, image);
applyTransform (t.inverted());
@@ -383,7 +375,7 @@ public:
{
CGContextSaveGState (context);
CGContextClipToRect (context, cgRect);
drawImage (state->fillType.image, state->fillType.image.getBounds(), state->fillType.transform, true);
drawImage (state->fillType.image, state->fillType.transform, true);
CGContextRestoreGState (context);
}
}
@@ -416,33 +408,24 @@ public:
if (state->fillType.isGradient())
drawGradient();
else
drawImage (state->fillType.image, state->fillType.image.getBounds(), state->fillType.transform, true);
drawImage (state->fillType.image, state->fillType.transform, true);
}
CGContextRestoreGState (context);
}
void drawImage (const Image& sourceImage, const Rectangle<int>& srcClip,
const AffineTransform& transform, const bool fillEntireClipAsTiles)
void drawImage (const Image& sourceImage, const AffineTransform& transform, const bool fillEntireClipAsTiles)
{
jassert (sourceImage.getBounds().contains (srcClip));
CGImageRef fullImage = CoreGraphicsImage::createImage (sourceImage, false, rgbColourSpace);
CGImageRef image = fullImage;
if (srcClip != sourceImage.getBounds())
{
image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), srcClip.getY(),
srcClip.getWidth(), srcClip.getHeight()));
CGImageRelease (fullImage);
}
const int iw = sourceImage.getWidth();
const int ih = sourceImage.getHeight();
CGImageRef image = CoreGraphicsImage::createImage (sourceImage, false, rgbColourSpace);
CGContextSaveGState (context);
CGContextSetAlpha (context, state->fillType.getOpacity());
flip();
applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, srcClip.getHeight()).followedBy (transform));
CGRect imageRect = CGRectMake (0, 0, srcClip.getWidth(), srcClip.getHeight());
applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, ih).followedBy (transform));
CGRect imageRect = CGRectMake (0, 0, iw, ih);
if (fillEntireClipAsTiles)
{
@@ -459,8 +442,6 @@ public:
{
// Fallback to manually doing a tiled fill on 10.4
CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context));
const int iw = srcClip.getWidth();
const int ih = srcClip.getHeight();
int x = 0, y = 0;
while (x > clip.origin.x) x -= iw;


+ 3
- 3
src/native/windows/juce_win32_Windowing.cpp View File

@@ -877,7 +877,7 @@ private:
void timerCallback()
{
stopTimer();
image = Image();
image = Image::null;
}
private:
@@ -2356,7 +2356,7 @@ static const Image createImageFromHBITMAP (HBITMAP bitmap)
SelectObject (dc, bitmap);
im = Image (Image::ARGB, bm.bmWidth, bm.bmHeight, true);
Image::BitmapData imageData (im, 0, 0, bm.bmWidth, bm.bmHeight, true);
Image::BitmapData imageData (im, true);
for (int y = bm.bmHeight; --y >= 0;)
{
@@ -2403,7 +2403,7 @@ static const Image createImageFromHICON (HICON icon)
}
}
return Image();
return Image::null;
}
static HICON createHICONFromImage (const Image& image, const BOOL isIcon, int hotspotX, int hotspotY)


Loading…
Cancel
Save