diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index b5d7a423e0..04f92d921c 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -39050,7 +39050,7 @@ void Component::setBufferedToImage (const bool shouldBeBuffered) { if (shouldBeBuffered != flags.bufferToImageFlag) { - bufferedImage_ = Image(); + bufferedImage_ = Image::null; flags.bufferToImageFlag = shouldBeBuffered; } } @@ -40013,7 +40013,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); @@ -54839,7 +54839,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 (getParentComponent()); @@ -58154,7 +58154,7 @@ private: void clearIcon() { - icon = Image(); + icon = Image::null; } void updateIcon (const bool onlyUpdateIfCached) @@ -58959,7 +58959,7 @@ void ImagePreviewComponent::timerCallback() { stopTimer(); - currentThumbnail = Image(); + currentThumbnail = Image::null; currentDetails = String::empty; repaint(); @@ -69213,7 +69213,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, @@ -69247,7 +69247,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)); } @@ -73364,7 +73364,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) { @@ -73402,7 +73402,7 @@ public: if (lastHue != h) { lastHue = h; - colours = Image(); + colours = Image::null; repaint(); } @@ -73411,7 +73411,7 @@ public: void resized() { - colours = Image(); + colours = Image::null; updateMarker(); } @@ -74413,9 +74413,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) @@ -76650,7 +76648,7 @@ void CallOutBox::updatePosition (const Rectangle& newAreaToPointTo, const R void CallOutBox::refreshPath() { repaint(); - background = Image(); + background = Image::null; outline.clear(); const float gap = 4.5f; @@ -81492,7 +81490,7 @@ bool FillType::operator!= (const FillType& other) const void FillType::setColour (const Colour& newColour) throw() { gradient = 0; - image = Image(); + image = Image::null; colour = newColour; } @@ -81504,7 +81502,7 @@ void FillType::setGradient (const ColourGradient& newGradient) } else { - image = Image(); + image = Image::null; gradient = new ColourGradient (newGradient); colour = Colours::black; } @@ -81603,10 +81601,10 @@ bool Graphics::reduceClipRegion (const Path& path, const AffineTransform& transf return ! context->isClipEmpty(); } -bool Graphics::reduceClipRegion (const Image& image, const Rectangle& 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(); } @@ -82154,7 +82152,7 @@ void Graphics::drawImage (const Image& imageToDraw, if (imageToDraw.isValid() && context->clipRegionIntersects (Rectangle (dx, dy, dw, dh))) { - drawImageTransformed (imageToDraw, Rectangle (sx, sy, sw, sh), + drawImageTransformed (imageToDraw.getClippedImage (Rectangle (sx, sy, sw, sh)), AffineTransform::scale (dw / (float) sw, dh / (float) sh) .translated ((float) dx, (float) dy), fillAlphaChannelWithCurrentBrush); @@ -82162,24 +82160,21 @@ void Graphics::drawImage (const Image& imageToDraw, } void Graphics::drawImageTransformed (const Image& imageToDraw, - const Rectangle& imageSubRegion, const AffineTransform& transform, const bool fillAlphaChannelWithCurrentBrush) const { if (imageToDraw.isValid() && ! context->isClipEmpty()) { - const Rectangle 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); } } } @@ -82341,7 +82336,7 @@ void LowLevelGraphicsPostScriptRenderer::clipToPath (const Path& path, const Aff out << "clip\n"; } -void LowLevelGraphicsPostScriptRenderer::clipToImageAlpha (const Image& /*sourceImage*/, const Rectangle& /*srcClip*/, const AffineTransform& /*transform*/) +void LowLevelGraphicsPostScriptRenderer::clipToImageAlpha (const Image& /*sourceImage*/, const AffineTransform& /*transform*/) { needToClip = true; jassertfalse; // xxx @@ -82649,11 +82644,10 @@ void LowLevelGraphicsPostScriptRenderer::writeImage (const Image& im, out << "\n>}\n"; } -void LowLevelGraphicsPostScriptRenderer::drawImage (const Image& sourceImage, const Rectangle& 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(); @@ -82663,7 +82657,6 @@ void LowLevelGraphicsPostScriptRenderer::drawImage (const Image& sourceImage, co RectangleList imageClip; sourceImage.createSolidAreaMask (imageClip, 0.5f); - imageClip.clipTo (srcClip); out << "newpath "; int itemsOnLine = 0; @@ -82686,7 +82679,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; @@ -83672,7 +83665,7 @@ public: virtual const Ptr excludeClipRectangle (const Rectangle& 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& 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& r) const = 0; virtual const Rectangle getClipBounds() const = 0; @@ -83909,9 +83902,9 @@ public: return edgeTable.isEmpty() ? 0 : this; } - const Ptr clipToImageAlpha (const Image& image, const Rectangle& 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()) { @@ -84099,9 +84092,9 @@ public: return Ptr (new ClipRegion_EdgeTable (clip))->clipToEdgeTable (et); } - const Ptr clipToImageAlpha (const Image& image, const Rectangle& 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& r) const @@ -84483,20 +84476,20 @@ public: } } - void clipToImageAlpha (const Image& image, const Rectangle& 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); } } @@ -84518,7 +84511,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 @@ -84538,7 +84531,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 @@ -84577,7 +84570,7 @@ public: if (shapeToFill != 0) { - Image::BitmapData destData (image, 0, 0, image.getWidth(), image.getHeight(), true); + Image::BitmapData destData (image, true); if (fillType.isGradient()) { @@ -84602,7 +84595,7 @@ public: } else if (fillType.isTiledImage()) { - renderImage (image, fillType.image, fillType.image.getBounds(), fillType.transform, shapeToFill); + renderImage (image, fillType.image, fillType.transform, shapeToFill); } else { @@ -84611,13 +84604,12 @@ public: } } - void renderImage (Image& destImage, const Image& sourceImage, const Rectangle& 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); @@ -84638,7 +84630,7 @@ public: } else { - SoftwareRendererClasses::ClipRegionBase::Ptr c (new SoftwareRendererClasses::ClipRegion_EdgeTable (Rectangle (tx, ty, srcClip.getWidth(), srcClip.getHeight()).getIntersection (destImage.getBounds()))); + SoftwareRendererClasses::ClipRegionBase::Ptr c (new SoftwareRendererClasses::ClipRegion_EdgeTable (Rectangle (tx, ty, sourceImage.getWidth(), sourceImage.getHeight()).getIntersection (destImage.getBounds()))); c = clip->applyClipTo (c); if (c != 0) @@ -84659,7 +84651,7 @@ public: else { Path p; - p.addRectangle (srcClip); + p.addRectangle (sourceImage.getBounds()); SoftwareRendererClasses::ClipRegionBase::Ptr c (clip->clone()); c = c->clipToPath (p, transform); @@ -84732,9 +84724,9 @@ void LowLevelGraphicsSoftwareRenderer::clipToPath (const Path& path, const Affin currentState->clipToPath (path, transform); } -void LowLevelGraphicsSoftwareRenderer::clipToImageAlpha (const Image& sourceImage, const Rectangle& 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& r) @@ -84797,12 +84789,9 @@ void LowLevelGraphicsSoftwareRenderer::fillPath (const Path& path, const AffineT currentState->fillPath (image, path, transform); } -void LowLevelGraphicsSoftwareRenderer::drawImage (const Image& sourceImage, const Rectangle& 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); } @@ -86126,13 +86115,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); } } } @@ -88502,8 +88491,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); @@ -94305,6 +94294,55 @@ 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& 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; + const Rectangle area; +}; + +const Image Image::getClippedImage (const Rectangle& area) const +{ + if (area.contains (getBounds())) + return *this; + + const Rectangle validArea (area.getIntersection (getBounds())); + if (validArea.isEmpty()) + return Image::null; + + return Image (new SubsectionSharedImage (image, validArea)); +} + Image::Image() { } @@ -94337,6 +94375,8 @@ Image::~Image() { } +const Image Image::null; + LowLevelGraphicsContext* Image::createLowLevelContext() const { return image == 0 ? 0 : image->createLowLevelContext(); @@ -94439,6 +94479,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() { } @@ -94814,7 +94864,7 @@ public: return item->image; } - return Image(); + return Image::null; } void addImageToCache (const Image& image, const int64 hashCode) @@ -94885,7 +94935,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) @@ -95042,7 +95092,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) { @@ -95205,7 +95255,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&); @@ -95285,7 +95335,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) @@ -95298,7 +95348,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) @@ -95309,7 +95359,7 @@ const Image ImageFileFormat::loadFrom (const void* rawData, const int numBytes) return loadFrom (stream); } - return Image(); + return Image::null; } END_JUCE_NAMESPACE @@ -95320,8 +95370,7 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE GIFLoader::GIFLoader (InputStream& in) - : image (0), - input (in), + : input (in), dataBlockIsZero (false), fresh (false), finished (false) @@ -95386,9 +95435,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; } @@ -95648,8 +95695,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; @@ -95668,7 +95714,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(); @@ -95696,7 +95742,7 @@ bool GIFLoader::readImage (const int width, const int height, p += destData.pixelStride; ++xpos; - if (xpos == width) + if (xpos == destData.width) { xpos = 0; @@ -95710,7 +95756,7 @@ bool GIFLoader::readImage (const int width, const int height, case 3: ypos += 2; break; } - while (ypos >= height) + while (ypos >= destData.height) { ++pass; @@ -95731,7 +95777,7 @@ bool GIFLoader::readImage (const int width, const int height, p = destData.getPixelPointer (xpos, ypos); } - if (ypos >= height) + if (ypos >= destData.height) break; } @@ -210848,7 +210894,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) { @@ -210951,7 +210997,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) { @@ -236492,7 +236538,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 ); @@ -236550,7 +236596,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; @@ -236628,7 +236674,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) { @@ -240077,7 +240123,7 @@ private: void timerCallback() { stopTimer(); - image = Image(); + image = Image::null; } private: @@ -241527,7 +241573,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;) { @@ -241574,7 +241620,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) @@ -256552,7 +256598,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) { @@ -257742,7 +257788,7 @@ private: else if (Time::getApproximateMillisecondCounter() > lastTimeImageUsed + 3000) { stopTimer(); - image = Image(); + image = Image::null; } } @@ -259045,7 +259091,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) @@ -264741,7 +264787,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); @@ -264896,7 +264942,7 @@ public: lastClipRectIsValid = false; } - void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform) + void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) { if (! transform.isSingularity()) { @@ -264907,19 +264953,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()); @@ -265042,7 +265080,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); } } @@ -265075,33 +265113,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& 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) { @@ -265118,8 +265147,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; @@ -266252,7 +266279,7 @@ ComponentPeer* Component::createNewPeer (int styleFlags, void* windowToAttachTo) const Image juce_createIconForFile (const File& file) { - return Image(); + return Image::null; } void Desktop::createMouseInputSources() @@ -269388,7 +269415,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); @@ -269543,7 +269570,7 @@ public: lastClipRectIsValid = false; } - void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform) + void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) { if (! transform.isSingularity()) { @@ -269554,19 +269581,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()); @@ -269689,7 +269708,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); } } @@ -269722,33 +269741,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& 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) { @@ -269765,8 +269775,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; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 03a38856a9..3d73a6169f 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 39 +#define JUCE_BUILDNUMBER 40 /** Current Juce version number. @@ -535,7 +535,7 @@ @see Logger::outputDebugString */ - #define DBG(dbgtext) Logger::outputDebugString (dbgtext); + #define DBG(dbgtext) JUCE_NAMESPACE::Logger::outputDebugString (dbgtext); // Assertions.. @@ -24272,18 +24272,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. @@ -24291,10 +24284,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& imageSubRegion, const AffineTransform& transform, bool fillAlphaChannelWithCurrentBrush = false) const; @@ -24366,15 +24361,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& 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& rectangleToExclude); @@ -24582,6 +24573,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; } @@ -24647,6 +24643,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& area) const; + /** Returns the colour of one of the pixels in the image. If the co-ordinates given are beyond the image's boundaries, this will @@ -24715,6 +24724,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. @@ -24818,6 +24828,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; @@ -24827,8 +24844,6 @@ public: uint8* imageData; var userTag; - uint8* getPixelData (int x, int y) const throw(); - SharedImage (const SharedImage&); SharedImage& operator= (const SharedImage&); }; @@ -35203,7 +35218,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. @@ -35228,7 +35243,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. @@ -35266,7 +35281,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. @@ -44237,7 +44252,7 @@ public: */ void startDragging (const String& sourceDescription, Component* sourceComponent, - const Image& dragImage = Image(), + const Image& dragImage = Image::null, bool allowDraggingToOtherJuceWindows = false, const Point* imageOffsetFromMouse = 0); @@ -58778,7 +58793,7 @@ public: virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0; virtual void excludeClipRectangle (const Rectangle& r) = 0; virtual void clipToPath (const Path& path, const AffineTransform& transform) = 0; - virtual void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform) = 0; + virtual void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) = 0; virtual bool clipRegionIntersects (const Rectangle& r) = 0; virtual const Rectangle getClipBounds() const = 0; @@ -58794,8 +58809,7 @@ public: virtual void fillRect (const Rectangle& r, bool replaceExistingContents) = 0; virtual void fillPath (const Path& path, const AffineTransform& transform) = 0; - virtual void drawImage (const Image& sourceImage, const Rectangle& srcClip, - const AffineTransform& transform, bool fillEntireClipAsTiles) = 0; + virtual void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles) = 0; virtual void drawLine (const Line & line) = 0; virtual void drawVerticalLine (int x, float top, float bottom) = 0; @@ -58840,7 +58854,7 @@ public: bool clipToRectangleList (const RectangleList& clipRegion); void excludeClipRectangle (const Rectangle& r); void clipToPath (const Path& path, const AffineTransform& transform); - void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform); + void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform); void saveState(); void restoreState(); @@ -58856,8 +58870,7 @@ public: void fillRect (const Rectangle& r, bool replaceExistingContents); void fillPath (const Path& path, const AffineTransform& transform); - void drawImage (const Image& sourceImage, const Rectangle& srcClip, - const AffineTransform& transform, bool fillEntireClipAsTiles); + void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles); void drawLine (const Line & line); @@ -58938,7 +58951,7 @@ public: bool clipToRectangleList (const RectangleList& clipRegion); void excludeClipRectangle (const Rectangle& r); void clipToPath (const Path& path, const AffineTransform& transform); - void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform); + void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform); bool clipRegionIntersects (const Rectangle& r); const Rectangle getClipBounds() const; @@ -58954,8 +58967,7 @@ public: void fillRect (const Rectangle& r, bool replaceExistingContents); void fillPath (const Path& path, const AffineTransform& transform); - void drawImage (const Image& sourceImage, const Rectangle& srcClip, - const AffineTransform& transform, bool fillEntireClipAsTiles); + void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles); void drawLine (const Line & line);