First Commit

This commit is contained in:
Legaeli
2025-10-22 09:20:23 +02:00
commit a36f2ca925
4393 changed files with 1570219 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,758 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
class ImageType;
class ImagePixelData;
//==============================================================================
/**
Holds a fixed-size bitmap.
The image is stored in either 24-bit RGB or 32-bit premultiplied-ARGB format.
To draw into an image, create a Graphics object for it.
e.g. @code
// create a transparent 500x500 image..
Image myImage (Image::RGB, 500, 500, true);
Graphics g (myImage);
g.setColour (Colours::red);
g.fillEllipse (20, 20, 300, 200); // draws a red ellipse in our image.
@endcode
Other useful ways to create an image are with the ImageCache class, or the
ImageFileFormat, which provides a way to load common image files.
@see Graphics, ImageFileFormat, ImageCache, ImageConvolutionKernel
@tags{Graphics}
*/
class JUCE_API Image final
{
public:
//==============================================================================
/**
*/
enum PixelFormat
{
UnknownFormat,
RGB, /**<< each pixel is a 3-byte packed RGB colour value. For byte order, see the PixelRGB class. */
ARGB, /**<< each pixel is a 4-byte ARGB premultiplied colour value. For byte order, see the PixelARGB class. */
SingleChannel /**<< each pixel is a 1-byte alpha channel value. */
};
//==============================================================================
/** Creates a null image. */
Image() noexcept;
/** Creates an image with a specified size and format.
The image's internal type will be of the NativeImageType class - to specify a
different type, use the other constructor, which takes an ImageType to use.
@param format the preferred pixel format. Note that this is only a *hint* which
is passed to the ImageType class - different ImageTypes may not support
all formats, so may substitute e.g. ARGB for RGB.
@param imageWidth the desired width of the image, in pixels - this value must be
greater than zero (otherwise a width of 1 will be used)
@param imageHeight the desired width of the image, in pixels - this value must be
greater than zero (otherwise a height of 1 will be used)
@param clearImage if true, the image will initially be cleared to black (if it's RGB)
or transparent black (if it's ARGB). If false, the image may contain
junk initially, so you need to make sure you overwrite it thoroughly.
*/
Image (PixelFormat format, int imageWidth, int imageHeight, bool clearImage);
/** Creates an image with a specified size and format.
@param format the preferred pixel format. Note that this is only a *hint* which
is passed to the ImageType class - different ImageTypes may not support
all formats, so may substitute e.g. ARGB for RGB.
@param imageWidth the desired width of the image, in pixels - this value must be
greater than zero (otherwise a width of 1 will be used)
@param imageHeight the desired width of the image, in pixels - this value must be
greater than zero (otherwise a height of 1 will be used)
@param clearImage if true, the image will initially be cleared to black (if it's RGB)
or transparent black (if it's ARGB). If false, the image may contain
junk initially, so you need to make sure you overwrite it thoroughly.
@param type the type of image - this lets you specify the internal format that will
be used to allocate and manage the image data.
*/
Image (PixelFormat format, int imageWidth, int imageHeight, bool clearImage, const ImageType& type);
/** Creates a shared reference to another image.
This won't create a duplicate of the image - when Image objects are copied, they simply
point to the same shared image data. To make sure that an Image object has its own unique,
unshared internal data, call duplicateIfShared().
*/
Image (const Image&) noexcept;
/** Makes this image refer to the same underlying image as another object.
This won't create a duplicate of the image - when Image objects are copied, they simply
point to the same shared image data. To make sure that an Image object has its own unique,
unshared internal data, call duplicateIfShared().
*/
Image& operator= (const Image&);
/** Move constructor */
Image (Image&&) noexcept;
/** Move assignment operator */
Image& operator= (Image&&) noexcept;
/** Destructor. */
~Image();
/** Returns true if the two images are referring to the same internal, shared image. */
bool operator== (const Image& other) const noexcept { return image == other.image; }
/** Returns true if the two images are not referring to the same internal, shared image. */
bool operator!= (const Image& other) const noexcept { return image != other.image; }
/** Returns true if this image isn't null.
If you create an Image with the default constructor, it has no size or content, and is null
until you reassign it to an Image which contains some actual data.
The isNull() method is the opposite of isValid().
@see isNull
*/
bool isValid() const noexcept;
/** Returns true if this image is not valid.
If you create an Image with the default constructor, it has no size or content, and is null
until you reassign it to an Image which contains some actual data.
The isNull() method is the opposite of isValid().
@see isValid
*/
bool isNull() const noexcept { return ! isValid(); }
//==============================================================================
/** Returns the image's width (in pixels). */
int getWidth() const noexcept;
/** Returns the image's height (in pixels). */
int getHeight() const noexcept;
/** Returns a rectangle with the same size as this image.
The rectangle's origin is always (0, 0).
*/
Rectangle<int> getBounds() const noexcept;
/** Returns the image's pixel format. */
PixelFormat getFormat() const noexcept;
/** True if the image's format is ARGB. */
bool isARGB() const noexcept;
/** True if the image's format is RGB. */
bool isRGB() const noexcept;
/** True if the image's format is a single-channel alpha map. */
bool isSingleChannel() const noexcept;
/** True if the image contains an alpha-channel. */
bool hasAlphaChannel() const noexcept;
//==============================================================================
/** Clears a section of the image with a given colour.
This won't do any alpha-blending - it just sets all pixels in the image to
the given colour (which may be non-opaque if the image has an alpha channel).
*/
void clear (const Rectangle<int>& area, Colour colourToClearTo = Colour (0x00000000));
/** Returns a rescaled version of this image.
A new image is returned which is a copy of this one, rescaled to the given size.
Note that if the new size is identical to the existing image, this will just return
a reference to the original image, and won't actually create a duplicate.
*/
Image rescaled (int newWidth, int newHeight,
Graphics::ResamplingQuality quality = Graphics::mediumResamplingQuality) const;
/** Creates a copy of this image.
Note that it's usually more efficient to use duplicateIfShared(), because it may not be necessary
to copy an image if nothing else is using it.
@see getReferenceCount
*/
Image createCopy() const;
/** Returns a version of this image with a different image format.
A new image is returned which has been converted to the specified format.
Note that if the new format is no different to the current one, this will just return
a reference to the original image, and won't actually create a copy.
*/
Image convertedToFormat (PixelFormat newFormat) const;
/** Makes sure that no other Image objects share the same underlying data as this one.
If no other Image objects refer to the same shared data as this one, this method has no
effect. But if there are other references to the data, this will create a new copy of
the data internally.
Call this if you want to draw onto the image, but want to make sure that this doesn't
affect any other code that may be sharing the same data.
@see getReferenceCount
*/
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.
*/
Image getClippedImage (const Rectangle<int>& area) const;
//==============================================================================
/** Returns the colour of one of the pixels in the image.
If the coordinates given are beyond the image's boundaries, this will
return Colours::transparentBlack.
@see setPixelAt, Image::BitmapData::getPixelColour
*/
Colour getPixelAt (int x, int y) const;
/** Sets the colour of one of the image's pixels.
If the coordinates are beyond the image's boundaries, then nothing will happen.
Note that this won't do any alpha-blending, it'll just replace the existing pixel
with the given one. The colour's opacity will be ignored if this image doesn't have
an alpha-channel.
@see getPixelAt, Image::BitmapData::setPixelColour
*/
void setPixelAt (int x, int y, Colour colour);
/** Changes the opacity of a pixel.
This only has an effect if the image has an alpha channel and if the
given coordinates are inside the image's boundary.
The multiplier must be in the range 0 to 1.0, and the current alpha
at the given coordinates will be multiplied by this value.
@see setPixelAt
*/
void multiplyAlphaAt (int x, int y, float multiplier);
/** Changes the overall opacity of the image.
This will multiply the alpha value of each pixel in the image by the given
amount (limiting the resulting alpha values between 0 and 255). This allows
you to make an image more or less transparent.
If the image doesn't have an alpha channel, this won't have any effect.
*/
void multiplyAllAlphas (float amountToMultiplyBy);
/** Changes all the colours to be shades of grey, based on their current luminosity.
*/
void desaturate();
/** This is a shorthand for dereferencing the internal ImagePixelData's BackupExtensions
and calling setBackupEnabled() if the extensions exist.
@returns true if the extensions exist and the backup flag was updated, or false otherwise
@see ImagePixelDataBackupExtensions::setBackupEnabled()
*/
bool setBackupEnabled (bool);
//==============================================================================
/** Retrieves a section of an image as raw pixel data, so it can be read or written to.
You should only use this class as a last resort - messing about with the internals of
an image is only recommended for people who really know what they're doing!
A BitmapData object should be used as a temporary, stack-based object. Don't keep one
hanging around while the image is being used elsewhere.
Depending on the way the image class is implemented, this may create a temporary buffer
which is copied back to the image when the object is deleted, or it may just get a pointer
directly into the image's raw data.
You can use the stride and data values in this class directly, but don't alter them!
The actual format of the pixel data depends on the image's format - see Image::getFormat(),
and the PixelRGB, PixelARGB and PixelAlpha classes for more info.
*/
class JUCE_API BitmapData final
{
public:
enum ReadWriteMode
{
readOnly,
writeOnly,
readWrite
};
BitmapData (Image& image, int x, int y, int w, int h, ReadWriteMode mode);
BitmapData (const Image& image, Rectangle<int>, ReadWriteMode mode);
BitmapData (const Image& image, int x, int y, int w, int h);
BitmapData (const Image& image, ReadWriteMode mode);
/** Returns a pointer to the start of a line in the image.
The coordinate you provide here isn't checked, so it's the caller's responsibility to make
sure it's not out-of-range.
*/
inline uint8* getLinePointer (int y) const noexcept { return data + (size_t) y * (size_t) lineStride; }
/** Returns a pointer to a pixel in the image.
The coordinates you give here are not checked, so it's the caller's responsibility to make sure they're
not out-of-range.
*/
inline uint8* getPixelPointer (int x, int y) const noexcept { return data + (size_t) y * (size_t) lineStride + (size_t) x * (size_t) pixelStride; }
/** Returns the colour of a given pixel.
For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's
responsibility to make sure they're within the image's size.
*/
Colour getPixelColour (int x, int y) const noexcept;
/** Sets the colour of a given pixel.
For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's
responsibility to make sure they're within the image's size.
*/
void setPixelColour (int x, int y, Colour colour) const noexcept;
/** Returns the size of the bitmap. */
Rectangle<int> getBounds() const noexcept { return Rectangle<int> (width, height); }
/** Attempts to copy the contents of src into this bitmap data.
Returns true on success, and false otherwise.
The source BitmapData must be readable, and the destination (current) BitmapData must
be writeable. This function cannot check for this precondition, so you must ensure this
yourself!
*/
bool convertFrom (const Image::BitmapData& src);
uint8* data; /**< The raw pixel data, packed according to the image's pixel format. */
size_t size; /**< The number of valid/allocated bytes after data. May be smaller than "lineStride * height" if this is a section of a larger image. */
PixelFormat pixelFormat; /**< The format of the data. */
int lineStride; /**< The number of bytes between each line. */
int pixelStride; /**< The number of bytes between each pixel. */
int width, height;
//==============================================================================
/** Used internally by custom image types to manage pixel data lifetime. */
class BitmapDataReleaser
{
protected:
BitmapDataReleaser() = default;
public:
virtual ~BitmapDataReleaser() = default;
};
std::unique_ptr<BitmapDataReleaser> dataReleaser;
private:
JUCE_DECLARE_NON_COPYABLE (BitmapData)
};
//==============================================================================
/** Copies a section of the image to somewhere else within itself. */
void moveImageSection (int destX, int destY,
int sourceX, int sourceY,
int width, int height);
/** Creates a RectangleList containing rectangles for all non-transparent pixels
of the image.
@param result the list that will have the area added to it
@param alphaThreshold for a semi-transparent image, any pixels whose alpha is
above this level will be considered opaque
*/
void createSolidAreaMask (RectangleList<int>& result, float alphaThreshold) const;
//==============================================================================
/** Returns a NamedValueSet that is attached to the image and which can be used for
associating custom values with it.
If this is a null image, this will return a null pointer.
*/
NamedValueSet* getProperties() const;
//==============================================================================
/** Creates a context suitable for drawing onto this image.
Don't call this method directly! It's used internally by the Graphics class.
*/
std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() const;
/** Returns the number of Image objects which are currently referring to the same internal
shared image data.
@see duplicateIfShared
*/
int getReferenceCount() const noexcept;
//==============================================================================
/** @internal */
ReferenceCountedObjectPtr<ImagePixelData> getPixelData() const noexcept { return image; }
/** @internal */
explicit Image (ReferenceCountedObjectPtr<ImagePixelData>) noexcept;
//==============================================================================
#if JUCE_ALLOW_STATIC_NULL_VARIABLES && ! defined (DOXYGEN)
/* A null Image object that can be used when you need to return an invalid image. */
[[deprecated ("If you need a default-constructed var, just use Image() or {}.")]]
static const Image null;
#endif
private:
//==============================================================================
ReferenceCountedObjectPtr<ImagePixelData> image;
JUCE_LEAK_DETECTOR (Image)
};
//==============================================================================
/**
The methods on this interface allow clients of ImagePixelData to query and control
the automatic-backup process from graphics memory to main memory, if this mechanism is
relevant and supported.
Some image types (Direct2D, OpenGL) are backed by textures that live in graphics memory.
Such textures are quick to display, but they will be lost if the graphics device goes away.
Normally, a backup of the texture will be kept in main memory, so that the image can still
be used even if any graphics device goes away. While this has the benefit that programs are
automatically resilient to graphics devices going away, it also incurs some performance
overhead, because the texture content must be copied back to main memory after each
modification.
For performance-sensitive applications it can be beneficial to disable the automatic sync
behaviour, and to sync manually instead, which can be achieved using the methods of this type.
The following table shows how to interpret the results of this type's member functions.
needsBackup() | canBackup() | meaning
--------------------------------------------------------------------------------------------
true | true | the main-memory copy of the image is outdated, but there's an
| | up-to-date copy in graphics memory
| |
true | false | although main memory is out-of-date, the most recent copy of
| | the image in graphics memory has been lost
| |
false | true | main memory is up-to-date with graphics memory; graphics
| | memory is still available;
| |
false | false | main memory has an up-to-date copy of the image, but the most
| | recent copy of the image in graphics memory has been lost
@tags{Graphics}
*/
class ImagePixelDataBackupExtensions
{
public:
/** The automatic image backup mechanism can be disabled by passing false to this function, or
enabled by passing true.
If you disable automatic backup for a particular image, make sure you test that your
software behaves as expected when graphics devices are disconnected. One easy way to test
this on Windows is to use your program over a remote desktop session, and to end and
re-start the session while the image is being displayed.
The most common scenario where this flag is useful is when drawing single-use images.
e.g. for a drop shadow or other effect, the following series of steps might be carried
out on each paint call:
- Create a path that matches the shadowed component's outline
- Draw the path into a temporary image
- Blur the temporary image
- Draw the temporary image into some other context
- (destroy the temporary image)
In this case, where the image is created, modified, used, and destroyed in quick succession,
there's no need to keep a resilient backup of the image around, so it's reasonable to call
setBackupEnabled(false) after constructing the image.
@see isBackupEnabled(), backupNow()
*/
virtual void setBackupEnabled (bool) = 0;
/** @see setBackupEnabled(), backupNow() */
virtual bool isBackupEnabled() const = 0;
/** This function will attempt to make the image resilient to graphics device disconnection by
copying from graphics memory to main memory.
By default, backups happen automatically, so there's no need to call this function unless
auto-backup has been disabled on this image.
Flushing may fail if the graphics device goes away before its memory can be read.
If needsBackup() returns false, then backupNow() will always return true without doing any
work.
@returns true if the main-memory copy of the image is up-to-date, or false otherwise.
@see setBackupEnabled(), isBackupEnabled()
*/
virtual bool backupNow() = 0;
/** Returns true if the main-memory copy of the image is out-of-date, false if it's up-to-date.
@see canBackup()
*/
virtual bool needsBackup() const = 0;
/** Returns if there is an up-to-date copy of this image in graphics memory, or false otherwise.
@see needsBackup()
*/
virtual bool canBackup() const = 0;
protected:
// Not intended for virtual destruction
~ImagePixelDataBackupExtensions() = default;
};
/** @internal
@tags{Graphics}
*/
class ImagePixelDataNativeExtensions;
//==============================================================================
/**
This is a base class for holding image data in implementation-specific ways.
You may never need to use this class directly - it's used internally
by the Image class to store the actual image data. To access pixel data directly,
you should use Image::BitmapData rather than this class.
ImagePixelData objects are created indirectly, by subclasses of ImageType.
@see Image, ImageType
@tags{Graphics}
*/
class JUCE_API ImagePixelData : public ReferenceCountedObject
{
public:
using BackupExtensions = ImagePixelDataBackupExtensions;
using NativeExtensions = ImagePixelDataNativeExtensions;
ImagePixelData (Image::PixelFormat, int width, int height);
~ImagePixelData() override;
using Ptr = ReferenceCountedObjectPtr<ImagePixelData>;
/** Creates a context that will draw into this image. */
virtual std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() = 0;
/** Creates a copy of this image. */
virtual Ptr clone() = 0;
/** Creates an instance of the type of this image. */
virtual std::unique_ptr<ImageType> createType() const = 0;
/** Returns a raw pointer to an instance of ImagePixelDataBackupExtensions if this ImagePixelData
provides this extension, or nullptr otherwise.
*/
virtual BackupExtensions* getBackupExtensions() { return nullptr; }
virtual const BackupExtensions* getBackupExtensions() const { return nullptr; }
/** Initialises a BitmapData object. */
virtual void initialiseBitmapData (Image::BitmapData&, int x, int y, Image::BitmapData::ReadWriteMode) = 0;
/** Returns the number of Image objects which are currently referring to the same internal
shared image data. This is different to the reference count as an instance of ImagePixelData
can internally depend on another ImagePixelData via it's member variables.
*/
virtual int getSharedCount() const noexcept;
/** Applies a native blur effect to this image, if available.
This blur applies to all channels of the input image. It may be more expensive to
calculate than a box blur, but should produce higher-quality results.
The default implementation will modify the image pixel-by-pixel on the CPU, which will be slow.
Native image types may provide optimised implementations.
*/
virtual void applyGaussianBlurEffectInArea (Rectangle<int> bounds, float radius);
/** @see applyGaussianBlurEffectInArea() */
void applyGaussianBlurEffect (float radius)
{
applyGaussianBlurEffectInArea ({ width, height }, radius);
}
/** Applies a native blur effect to this image, if available.
This is intended for blurring single-channel images, which is useful when rendering drop
shadows. This is implemented as several box-blurs in series. The results should be visually
similar to a Gaussian blur, but less accurate.
The default implementation will modify the image pixel-by-pixel on the CPU, which will be slow.
Native image types may provide optimised implementations.
*/
virtual void applySingleChannelBoxBlurEffectInArea (Rectangle<int> bounds, int radius);
/** @see applySingleChannelBoxBlurEffectInArea() */
void applySingleChannelBoxBlurEffect (int radius)
{
applySingleChannelBoxBlurEffectInArea ({ width, height }, radius);
}
/** Multiples all alpha-channel values in the image by the specified amount.
The default implementation will modify the image pixel-by-pixel on the CPU, which will be slow.
Native image types may provide optimised implementations.
*/
virtual void multiplyAllAlphasInArea (Rectangle<int> bounds, float amount);
/** @see multiplyAllAlphasInArea() */
void multiplyAllAlphas (float amount)
{
multiplyAllAlphasInArea ({ width, height }, amount);
}
/** Changes all the colours to be shades of grey, based on their current luminosity.
The default implementation will modify the image pixel-by-pixel on the CPU, which will be slow.
Native image types may provide optimised implementations.
*/
virtual void desaturateInArea (Rectangle<int> bounds);
/** @see desaturateInArea() */
void desaturate()
{
desaturateInArea ({ width, height });
}
/** The pixel format of the image data. */
const Image::PixelFormat pixelFormat;
const int width, height;
/** User-defined settings that are attached to this image.
@see Image::getProperties().
*/
NamedValueSet userData;
//==============================================================================
/** Used to receive callbacks for image data changes */
struct Listener
{
virtual ~Listener() = default;
virtual void imageDataChanged (ImagePixelData*) = 0;
virtual void imageDataBeingDeleted (ImagePixelData*) = 0;
};
ListenerList<Listener> listeners;
void sendDataChangeMessage();
/** @internal intentionally not callable from user code */
virtual NativeExtensions getNativeExtensions();
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImagePixelData)
};
//==============================================================================
/**
This base class is for handlers that control a type of image manipulation format,
e.g. an in-memory bitmap, an OpenGL image, CoreGraphics image, etc.
@see SoftwareImageType, NativeImageType, OpenGLImageType
@tags{Graphics}
*/
class JUCE_API ImageType
{
public:
ImageType();
virtual ~ImageType();
/** Creates a new image of this type, and the specified parameters. */
virtual ImagePixelData::Ptr create (Image::PixelFormat, int width, int height, bool shouldClearImage) const = 0;
/** Must return a unique number to identify this type. */
virtual int getTypeID() const = 0;
/** Returns an image which is a copy of the source image, but using this type of storage mechanism.
For example, to make sure that an image is stored in-memory, you could use:
@code myImage = SoftwareImageType().convert (myImage); @endcode
*/
virtual Image convert (const Image& source) const;
};
//==============================================================================
/**
An image storage type which holds the pixels in-memory as a simple block of values.
@see ImageType, NativeImageType
@tags{Graphics}
*/
class JUCE_API SoftwareImageType : public ImageType
{
public:
SoftwareImageType();
~SoftwareImageType() override;
ImagePixelData::Ptr create (Image::PixelFormat, int width, int height, bool clearImage) const override;
int getTypeID() const override;
};
//==============================================================================
/**
An image storage type which holds the pixels using whatever is the default storage
format on the current platform.
@see ImageType, SoftwareImageType
@tags{Graphics}
*/
class JUCE_API NativeImageType : public ImageType
{
public:
NativeImageType();
~NativeImageType() override;
ImagePixelData::Ptr create (Image::PixelFormat, int width, int height, bool clearImage) const override;
int getTypeID() const override;
};
} // namespace juce
@@ -0,0 +1,180 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
struct ImageCache::Pimpl : private Timer,
private DeletedAtShutdown
{
Pimpl() = default;
~Pimpl() override
{
stopTimer();
clearSingletonInstance();
}
JUCE_DECLARE_SINGLETON_INLINE (ImageCache::Pimpl, false)
Image getFromHashCode (const int64 hashCode) noexcept
{
const ScopedLock sl (lock);
for (auto& item : images)
{
if (item.hashCode == hashCode)
{
item.lastUseTime = Time::getApproximateMillisecondCounter();
return item.image;
}
}
return {};
}
void addImageToCache (const Image& image, const int64 hashCode)
{
if (image.isValid())
{
if (! isTimerRunning())
startTimer (2000);
const ScopedLock sl (lock);
images.add ({ image, hashCode, Time::getApproximateMillisecondCounter() });
}
}
void timerCallback() override
{
auto now = Time::getApproximateMillisecondCounter();
const ScopedLock sl (lock);
for (int i = images.size(); --i >= 0;)
{
auto& item = images.getReference (i);
if (item.image.getReferenceCount() <= 1)
{
if (now > item.lastUseTime + cacheTimeout || now < item.lastUseTime - 1000)
images.remove (i);
}
else
{
item.lastUseTime = now; // multiply-referenced, so this image is still in use.
}
}
if (images.isEmpty())
stopTimer();
}
void releaseUnusedImages()
{
const ScopedLock sl (lock);
for (int i = images.size(); --i >= 0;)
if (images.getReference (i).image.getReferenceCount() <= 1)
images.remove (i);
}
struct Item
{
Image image;
int64 hashCode;
uint32 lastUseTime;
};
Array<Item> images;
CriticalSection lock;
unsigned int cacheTimeout = 5000;
JUCE_DECLARE_NON_COPYABLE (Pimpl)
};
//==============================================================================
Image ImageCache::getFromHashCode (const int64 hashCode)
{
if (Pimpl::getInstanceWithoutCreating() != nullptr)
return Pimpl::getInstanceWithoutCreating()->getFromHashCode (hashCode);
return {};
}
void ImageCache::addImageToCache (const Image& image, const int64 hashCode)
{
Pimpl::getInstance()->addImageToCache (image, hashCode);
}
Image ImageCache::getFromFile (const File& file)
{
auto hashCode = file.hashCode64();
auto image = getFromHashCode (hashCode);
if (image.isNull())
{
image = ImageFileFormat::loadFrom (file);
addImageToCache (image, hashCode);
}
return image;
}
Image ImageCache::getFromMemory (const void* imageData, const int dataSize)
{
auto hashCode = (int64) (pointer_sized_int) imageData;
auto image = getFromHashCode (hashCode);
if (image.isNull())
{
image = ImageFileFormat::loadFrom (imageData, (size_t) dataSize);
addImageToCache (image, hashCode);
}
return image;
}
void ImageCache::setCacheTimeout (const int millisecs)
{
jassert (millisecs >= 0);
Pimpl::getInstance()->cacheTimeout = (unsigned int) millisecs;
}
void ImageCache::releaseUnusedImages()
{
Pimpl::getInstance()->releaseUnusedImages();
}
} // namespace juce
@@ -0,0 +1,136 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A global cache of images that have been loaded from files or memory.
If you're loading an image and may need to use the image in more than one
place, this is used to allow the same image to be shared rather than loading
multiple copies into memory.
Another advantage is that after images are released, they will be kept in
memory for a few seconds before it is actually deleted, so if you're repeatedly
loading/deleting the same image, it'll reduce the chances of having to reload it
each time.
@see Image, ImageFileFormat
@tags{Graphics}
*/
class JUCE_API ImageCache
{
public:
//==============================================================================
/** Loads an image from a file, (or just returns the image if it's already cached).
If the cache already contains an image that was loaded from this file,
that image will be returned. Otherwise, this method will try to load the
file, add it to the cache, and return it.
Remember that the image returned is shared, so drawing into it might
affect other things that are using it! If you want to draw on it, first
call Image::duplicateIfShared()
@param file the file to try to load
@returns the image, or null if it there was an error loading it
@see getFromMemory, getFromCache, ImageFileFormat::loadFrom
*/
static Image getFromFile (const File& file);
/** Loads an image from an in-memory image file, (or just returns the image if it's already cached).
If the cache already contains an image that was loaded from this block of memory,
that image will be returned. Otherwise, this method will try to load the
file, add it to the cache, and return it.
Remember that the image returned is shared, so drawing into it might
affect other things that are using it! If you want to draw on it, first
call Image::duplicateIfShared()
@param imageData the block of memory containing the image data
@param dataSize the data size in bytes
@returns the image, or an invalid image if it there was an error loading it
@see getFromMemory, getFromCache, ImageFileFormat::loadFrom
*/
static Image getFromMemory (const void* imageData, int dataSize);
//==============================================================================
/** Checks the cache for an image with a particular hashcode.
If there's an image in the cache with this hashcode, it will be returned,
otherwise it will return an invalid image.
@param hashCode the hash code that was associated with the image by addImageToCache()
@see addImageToCache
*/
static Image getFromHashCode (int64 hashCode);
/** Adds an image to the cache with a user-defined hash-code.
The image passed-in will be referenced (not copied) by the cache, so it's probably
a good idea not to draw into it after adding it, otherwise this will affect all
instances of it that may be in use.
@param image the image to add
@param hashCode the hash-code to associate with it
@see getFromHashCode
*/
static void addImageToCache (const Image& image, int64 hashCode);
/** Changes the amount of time before an unused image will be removed from the cache.
By default this is about 5 seconds.
*/
static void setCacheTimeout (int millisecs);
/** Releases any images in the cache that aren't being referenced by active
Image objects.
*/
static void releaseUnusedImages();
private:
//==============================================================================
struct Pimpl;
friend struct Pimpl;
ImageCache();
~ImageCache();
JUCE_DECLARE_NON_COPYABLE (ImageCache)
};
} // namespace juce
@@ -0,0 +1,209 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
ImageConvolutionKernel::ImageConvolutionKernel (int sizeToUse)
: values ((size_t) (sizeToUse * sizeToUse)),
size (sizeToUse)
{
clear();
}
ImageConvolutionKernel::~ImageConvolutionKernel() = default;
//==============================================================================
float ImageConvolutionKernel::getKernelValue (const int x, const int y) const noexcept
{
if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size))
return values [x + y * size];
jassertfalse;
return 0;
}
void ImageConvolutionKernel::setKernelValue (const int x, const int y, const float value) noexcept
{
if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size))
{
values [x + y * size] = value;
}
else
{
jassertfalse;
}
}
void ImageConvolutionKernel::clear()
{
for (int i = size * size; --i >= 0;)
values[i] = 0;
}
void ImageConvolutionKernel::setOverallSum (const float desiredTotalSum)
{
double currentTotal = 0.0;
for (int i = size * size; --i >= 0;)
currentTotal += values[i];
rescaleAllValues ((float) (desiredTotalSum / currentTotal));
}
void ImageConvolutionKernel::rescaleAllValues (const float multiplier)
{
for (int i = size * size; --i >= 0;)
values[i] *= multiplier;
}
//==============================================================================
void ImageConvolutionKernel::createGaussianBlur (const float radius)
{
const double radiusFactor = -1.0 / (radius * radius * 2);
const int centre = size >> 1;
for (int y = size; --y >= 0;)
{
for (int x = size; --x >= 0;)
{
auto cx = x - centre;
auto cy = y - centre;
values [x + y * size] = (float) std::exp (radiusFactor * (cx * cx + cy * cy));
}
}
setOverallSum (1.0f);
}
//==============================================================================
void ImageConvolutionKernel::applyToImage (Image& destImage,
const Image& sourceImage,
const Rectangle<int>& destinationArea) const
{
if (sourceImage == destImage)
{
destImage.duplicateIfShared();
}
else
{
if (sourceImage.getWidth() != destImage.getWidth()
|| sourceImage.getHeight() != destImage.getHeight()
|| sourceImage.getFormat() != destImage.getFormat())
{
jassertfalse;
return;
}
}
auto area = destinationArea.getIntersection (destImage.getBounds());
if (area.isEmpty())
return;
auto right = area.getRight();
auto bottom = area.getBottom();
const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(),
Image::BitmapData::writeOnly);
uint8* line = destData.data;
const Image::BitmapData srcData (sourceImage, Image::BitmapData::readOnly);
const auto applyKernel = [&] (auto stride)
{
constexpr auto pixelStride = stride.value;
for (int y = area.getY(); y < bottom; ++y)
{
uint8* dest = line;
line += destData.lineStride;
for (int x = area.getX(); x < right; ++x)
{
float sum[pixelStride]{};
for (int yy = 0; yy < size; ++yy)
{
const int sy = y + yy - (size >> 1);
if (sy >= srcData.height)
break;
if (sy < 0)
continue;
int sx = x - (size >> 1);
const uint8* src = srcData.getPixelPointer (sx, sy);
for (int xx = 0; xx < size; ++xx)
{
if (sx >= srcData.width)
break;
if (sx >= 0)
{
const auto kernelMult = values[xx + yy * size];
for (auto& s : sum)
s += kernelMult * *src++;
}
else
{
src += pixelStride;
}
++sx;
}
}
for (const auto& s : sum)
*dest++ = (uint8) jmin (0xff, roundToInt (s));
}
}
};
switch (destData.pixelStride)
{
case 4:
return applyKernel (std::integral_constant<size_t, 4>{});
case 3:
return applyKernel (std::integral_constant<size_t, 3>{});
case 1:
return applyKernel (std::integral_constant<size_t, 1>{});
}
}
} // namespace juce
@@ -0,0 +1,121 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Represents a filter kernel to use in convoluting an image.
@see Image::applyConvolution
@tags{Graphics}
*/
class JUCE_API ImageConvolutionKernel
{
public:
//==============================================================================
/** Creates an empty convolution kernel.
@param size the length of each dimension of the kernel, so e.g. if the size
is 5, it will create a 5x5 kernel
*/
ImageConvolutionKernel (int size);
/** Destructor. */
~ImageConvolutionKernel();
//==============================================================================
/** Resets all values in the kernel to zero. */
void clear();
/** Returns one of the kernel values. */
float getKernelValue (int x, int y) const noexcept;
/** Sets the value of a specific cell in the kernel.
The x and y parameters must be in the range 0 < x < getKernelSize().
@see setOverallSum
*/
void setKernelValue (int x, int y, float value) noexcept;
/** Rescales all values in the kernel to make the total add up to a fixed value.
This will multiply all values in the kernel by (desiredTotalSum / currentTotalSum).
*/
void setOverallSum (float desiredTotalSum);
/** Multiplies all values in the kernel by a value. */
void rescaleAllValues (float multiplier);
/** Initialises the kernel for a gaussian blur.
@param blurRadius this may be larger or smaller than the kernel's actual
size but this will obviously be wasteful or clip at the
edges. Ideally the kernel should be just larger than
(blurRadius * 2).
*/
void createGaussianBlur (float blurRadius);
//==============================================================================
/** Returns the size of the kernel.
E.g. if it's a 3x3 kernel, this returns 3.
*/
int getKernelSize() const { return size; }
//==============================================================================
/** Applies the kernel to an image.
@param destImage the image that will receive the resultant convoluted pixels.
@param sourceImage the source image to read from - this can be the same image as
the destination, but if different, it must be exactly the same
size and format.
@param destinationArea the region of the image to apply the filter to
*/
void applyToImage (Image& destImage,
const Image& sourceImage,
const Rectangle<int>& destinationArea) const;
private:
//==============================================================================
HeapBlock<float> values;
const int size;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImageConvolutionKernel)
};
} // namespace juce
@@ -0,0 +1,120 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
struct DefaultImageFormats
{
static ImageFileFormat** get()
{
static DefaultImageFormats formats;
return formats.formats;
}
private:
DefaultImageFormats() noexcept
{
formats[0] = &png;
formats[1] = &jpg;
formats[2] = &gif;
formats[3] = nullptr;
}
PNGImageFormat png;
JPEGImageFormat jpg;
GIFImageFormat gif;
ImageFileFormat* formats[4];
};
ImageFileFormat* ImageFileFormat::findImageFormatForStream (InputStream& input)
{
const int64 streamPos = input.getPosition();
for (ImageFileFormat** i = DefaultImageFormats::get(); *i != nullptr; ++i)
{
const bool found = (*i)->canUnderstand (input);
input.setPosition (streamPos);
if (found)
return *i;
}
return nullptr;
}
ImageFileFormat* ImageFileFormat::findImageFormatForFileExtension (const File& file)
{
for (ImageFileFormat** i = DefaultImageFormats::get(); *i != nullptr; ++i)
if ((*i)->usesFileExtension (file))
return *i;
return nullptr;
}
//==============================================================================
Image ImageFileFormat::loadFrom (InputStream& input)
{
if (ImageFileFormat* format = findImageFormatForStream (input))
return format->decodeImage (input);
return Image();
}
Image ImageFileFormat::loadFrom (const File& file)
{
FileInputStream stream (file);
if (stream.openedOk())
{
BufferedInputStream b (stream, 8192);
return loadFrom (b);
}
return Image();
}
Image ImageFileFormat::loadFrom (const void* rawData, const size_t numBytes)
{
if (rawData != nullptr && numBytes > 4)
{
MemoryInputStream stream (rawData, numBytes, false);
return loadFrom (stream);
}
return Image();
}
} // namespace juce
@@ -0,0 +1,232 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Base-class for codecs that can read and write image file formats such
as PNG, JPEG, etc.
This class also contains static methods to make it easy to load images
from files, streams or from memory.
@see Image, ImageCache
@tags{Graphics}
*/
class JUCE_API ImageFileFormat
{
protected:
//==============================================================================
/** Creates an ImageFormat. */
ImageFileFormat() = default;
public:
/** Destructor. */
virtual ~ImageFileFormat() = default;
//==============================================================================
/** Returns a description of this file format.
E.g. "JPEG", "PNG"
*/
virtual String getFormatName() = 0;
/** Returns true if the given stream seems to contain data that this format understands.
The format class should only read the first few bytes of the stream and sniff
for header bytes that it understands.
Note that this will advance the stream and leave it in a new position, so if you're
planning on re-using it, you may want to rewind it after calling this method.
@see decodeImage
*/
virtual bool canUnderstand (InputStream& input) = 0;
/** Returns true if this format uses the file extension of the given file. */
virtual bool usesFileExtension (const File& possibleFile) = 0;
/** Tries to decode and return an image from the given stream.
This will be called for an image format after calling its canUnderStand() method
to see if it can handle the stream.
@param input the stream to read the data from. The stream will be positioned
at the start of the image data (but this may not necessarily
be position 0)
@returns the image that was decoded, or an invalid image if it fails.
@see loadFrom
*/
virtual Image decodeImage (InputStream& input) = 0;
//==============================================================================
/** Attempts to write an image to a stream.
To specify extra information like encoding quality, there will be appropriate parameters
in the subclasses of the specific file types.
@returns true if it nothing went wrong.
*/
virtual bool writeImageToStream (const Image& sourceImage,
OutputStream& destStream) = 0;
//==============================================================================
/** Tries the built-in formats to see if it can find one to read this stream.
There are currently built-in decoders for PNG, JPEG and GIF formats.
The object that is returned should not be deleted by the caller.
@see canUnderstand, decodeImage, loadFrom
*/
static ImageFileFormat* findImageFormatForStream (InputStream& input);
/** Looks for a format that can handle the given file extension.
There are currently built-in formats for PNG, JPEG and GIF formats.
The object that is returned should not be deleted by the caller.
*/
static ImageFileFormat* findImageFormatForFileExtension (const File& file);
//==============================================================================
/** Tries to load an image from a stream.
This will use the findImageFormatForStream() method to locate a suitable
codec, and use that to load the image.
@returns the image that was decoded, or an invalid image if it fails.
*/
static Image loadFrom (InputStream& input);
/** Tries to load an image from a file.
This will use the findImageFormatForStream() method to locate a suitable
codec, and use that to load the image.
@returns the image that was decoded, or an invalid image if it fails.
*/
static Image loadFrom (const File& file);
/** Tries to load an image from a block of raw image data.
This will use the findImageFormatForStream() method to locate a suitable
codec, and use that to load the image.
@returns the image that was decoded, or an invalid image if it fails.
*/
static Image loadFrom (const void* rawData,
size_t numBytesOfData);
};
//==============================================================================
/**
A subclass of ImageFileFormat for reading and writing PNG files.
@see ImageFileFormat, JPEGImageFormat
@tags{Graphics}
*/
class JUCE_API PNGImageFormat : public ImageFileFormat
{
public:
//==============================================================================
PNGImageFormat();
~PNGImageFormat() override;
//==============================================================================
String getFormatName() override;
bool usesFileExtension (const File&) override;
bool canUnderstand (InputStream&) override;
Image decodeImage (InputStream&) override;
bool writeImageToStream (const Image&, OutputStream&) override;
};
//==============================================================================
/**
A subclass of ImageFileFormat for reading and writing JPEG files.
@see ImageFileFormat, PNGImageFormat
@tags{Graphics}
*/
class JUCE_API JPEGImageFormat : public ImageFileFormat
{
public:
//==============================================================================
JPEGImageFormat();
~JPEGImageFormat() override;
//==============================================================================
/** Specifies the quality to be used when writing a JPEG file.
@param newQuality a value 0 to 1.0, where 0 is low quality, 1.0 is best, or
any negative value is "default" quality
*/
void setQuality (float newQuality);
//==============================================================================
String getFormatName() override;
bool usesFileExtension (const File&) override;
bool canUnderstand (InputStream&) override;
Image decodeImage (InputStream&) override;
bool writeImageToStream (const Image&, OutputStream&) override;
private:
float quality;
};
//==============================================================================
/**
A subclass of ImageFileFormat for reading GIF files.
@see ImageFileFormat, PNGImageFormat, JPEGImageFormat
@tags{Graphics}
*/
class JUCE_API GIFImageFormat : public ImageFileFormat
{
public:
//==============================================================================
GIFImageFormat();
~GIFImageFormat() override;
//==============================================================================
String getFormatName() override;
bool usesFileExtension (const File&) override;
bool canUnderstand (InputStream&) override;
Image decodeImage (InputStream&) override;
bool writeImageToStream (const Image&, OutputStream&) override;
};
} // namespace juce
@@ -0,0 +1,93 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
/**
An image that will be resampled before it is drawn.
A plain Image only stores plain pixels, but does not store any information
about how these pixels correspond to points. This means that if the image's
dimensions are interpreted as points, then the image will be blurry when
drawn on high resolution displays. If the image's dimensions are instead
interpreted as corresponding to exact pixel positions, then the logical
size of the image will change depending on the scale factor of the screen
used to draw it.
The ScaledImage class is designed to store an image alongside a scale
factor that informs a renderer how to convert between the image's pixels
and points.
@tags{GUI}
*/
class JUCE_API ScaledImage
{
public:
/** Creates a ScaledImage with an invalid image and unity scale.
*/
ScaledImage() = default;
/** Creates a ScaledImage from an Image, where the dimensions of the image
in pixels are exactly equal to its dimensions in points.
*/
explicit ScaledImage (const Image& imageIn)
: ScaledImage (imageIn, 1.0) {}
/** Creates a ScaledImage from an Image, using a custom scale factor.
A scale of 1.0 means that the image's dimensions in pixels is equal to
its dimensions in points.
A scale of 2.0 means that the image contains 2 pixels per point in each
direction.
*/
ScaledImage (const Image& imageIn, double scaleIn)
: image (imageIn), scaleFactor (scaleIn) {}
/** Returns the image at its original dimensions. */
Image getImage() const { return image; }
/** Returns the image's scale. */
double getScale() const { return scaleFactor; }
/** Returns the bounds of this image expressed in points. */
Rectangle<double> getScaledBounds() const { return image.getBounds().toDouble() / scaleFactor; }
private:
Image image;
double scaleFactor = 1.0;
};
} // namespace juce