├── LICENSE.md ├── Processing ├── foleys_ColourLookuptables.h ├── foleys_Definitions.h └── foleys_ImageProcessing.h ├── README.md ├── Widgets ├── foleys_CurveView.cpp ├── foleys_CurveView.h ├── foleys_HistogramView.cpp └── foleys_HistogramView.h ├── foleys_image_processing.cpp └── foleys_image_processing.h /LICENSE.md: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | 3 | Copyright (c) 2019, Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ============================================================================== 29 | 30 | -------------------------------------------------------------------------------- /Processing/foleys_ColourLookuptables.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | Copyright (c) 2019, Foleys Finest Audio - Daniel Walz 5 | All rights reserved. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 8 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 10 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 11 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 12 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 13 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 14 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 15 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 16 | OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | ============================================================================== 19 | */ 20 | 21 | #pragma once 22 | 23 | 24 | namespace foleys 25 | { 26 | 27 | /** 28 | The ColourCurve provides an 8-bit lookup table to manipulate brightness, contrast 29 | and gamma correction per channel. 30 | */ 31 | class ColourCurve 32 | { 33 | public: 34 | ColourCurve() 35 | { 36 | calculateColourMap (0.0, 0.0, 1.0); 37 | } 38 | 39 | /** 40 | calculateColourMap will set up the lookup table. 41 | @param newBrightness will add or subtract a normalised value (-1..1) 42 | @param newContrast multiplies the slope of the curve (-1..1) 43 | @param newGamma the gamma value for the curve (0.1..10.0) 44 | */ 45 | void calculateColourMap (double newBrightness, double newContrast, double newGamma) 46 | { 47 | if (newBrightness == brightness && newContrast == contrast && newGamma == gamma) 48 | return; 49 | 50 | brightness = newBrightness; 51 | contrast = newContrast; 52 | gamma = newGamma; 53 | 54 | if (isLinear()) 55 | { 56 | for (size_t i = 0; i < 256; ++i) 57 | map [i] = i; 58 | } 59 | else 60 | { 61 | if (contrast == 1.0) 62 | { 63 | const auto mid = (brightness + 1.0) * 128.0; 64 | for (size_t i = 0; i < 256; ++i) 65 | map [i] = i < mid ? 0 : 255; 66 | } 67 | else 68 | { 69 | const auto slope = contrast <= 0.0 ? contrast + 1.0 : 1.0 / (1.0 - contrast); 70 | for (size_t i = 0; i < 256; ++i) 71 | map [i] = juce::uint8 (juce::jlimit (0, 255, 72 | juce::roundToInt (((std::pow (i / 255.0, gamma) - 0.5) * slope + 0.5 73 | + brightness) * 255.0))); 74 | } 75 | } 76 | } 77 | 78 | /** 79 | The method isLinear returns true, if the curve is the identity function. 80 | */ 81 | bool isLinear() const 82 | { 83 | return (brightness == 0.0 && contrast == 0.0 && gamma == 1.0); 84 | } 85 | 86 | /** 87 | Applies a ColourCurve to a channel of an image. 88 | 89 | @param image the image to apply the ColourCurve 90 | @param component is the index of the channel in the packed pixel 91 | */ 92 | void applyLUT (juce::Image& image, int component) const 93 | { 94 | juce::Image::BitmapData data (image, 0, 0, 95 | image.getWidth(), 96 | image.getHeight()); 97 | 98 | // The image you are about to apply this colour curve has 99 | // not enough colour channels as you requested 100 | jassert (component < data.pixelStride); 101 | 102 | for (int y=0; y < data.height; ++y) 103 | { 104 | auto* p = data.getLinePointer (y); 105 | for (int x=0; x < data.width; ++x) 106 | { 107 | p += component; 108 | *p = map [*p]; 109 | p += data.pixelStride - component; 110 | } 111 | } 112 | } 113 | 114 | /** 115 | Applies a set of ColourCurves to an image. 116 | This method assumes BGR or BGRA format. 117 | 118 | @param image the image to apply the ColourCurve 119 | @param red is the ColourCurve for the red channel 120 | @param green is the ColourCurve for the green channel 121 | @param blue is the ColourCurve for the blue channel 122 | */ 123 | static void applyLUTs (juce::Image& image, const ColourCurve& red, const ColourCurve& green, const ColourCurve& blue) 124 | { 125 | juce::Image::BitmapData data (image, 0, 0, 126 | image.getWidth(), 127 | image.getHeight()); 128 | 129 | const juce::uint8* maps [4] = { nullptr, nullptr, nullptr, nullptr }; 130 | 131 | if (data.pixelStride == 4) 132 | { 133 | maps [juce::PixelARGB::indexR] = red.getLookupTable(); 134 | maps [juce::PixelARGB::indexG] = green.getLookupTable(); 135 | maps [juce::PixelARGB::indexB] = blue.getLookupTable(); 136 | } 137 | else if (data.pixelStride == 3) 138 | { 139 | maps [juce::PixelRGB::indexR] = red.getLookupTable(); 140 | maps [juce::PixelRGB::indexG] = green.getLookupTable(); 141 | maps [juce::PixelRGB::indexB] = blue.getLookupTable(); 142 | } 143 | 144 | for (int y=0; y < data.height; ++y) 145 | { 146 | auto* p = data.getLinePointer (y); 147 | for (int x=0; x < data.width; ++x) 148 | { 149 | if (maps [0] != nullptr) *p = maps [0][*p]; ++p; 150 | if (maps [1] != nullptr) *p = maps [1][*p]; ++p; 151 | if (maps [2] != nullptr) *p = maps [2][*p]; ++p; 152 | if (maps [3] != nullptr) *p = maps [3][*p]; ++p; 153 | } 154 | } 155 | } 156 | 157 | /** 158 | Applies a set of ColourCurves to an image. 159 | This method assumes BGRA format. 160 | 161 | @param image the image to apply the ColourCurve 162 | @param red is the ColourCurve for the red channel 163 | @param green is the ColourCurve for the green channel 164 | @param blue is the ColourCurve for the blue channel 165 | @param alpha is the ColourCurve for the alpha channel 166 | */ 167 | static void applyLUTs (juce::Image& image, 168 | const ColourCurve& red, 169 | const ColourCurve& green, 170 | const ColourCurve& blue, 171 | const ColourCurve& alpha) 172 | { 173 | juce::Image::BitmapData data (image, 0, 0, 174 | image.getWidth(), 175 | image.getHeight()); 176 | 177 | // You need pixels with 4 components to apply 4 LUTs 178 | jassert (data.pixelStride == 4); 179 | 180 | if (data.pixelStride != 4) 181 | return; 182 | 183 | const auto* redMap = red.getLookupTable(); 184 | const auto* greenMap = green.getLookupTable(); 185 | const auto* blueMap = blue.getLookupTable(); 186 | const auto* alphaMap = alpha.getLookupTable(); 187 | 188 | for (int y=0; y < data.height; ++y) 189 | { 190 | auto* p = data.getLinePointer (y); 191 | for (int x=0; x < data.width; ++x) 192 | { 193 | *p = blueMap [*p]; ++p; 194 | *p = greenMap [*p]; ++p; 195 | *p = redMap [*p]; ++p; 196 | *p = alphaMap [*p]; ++p; 197 | } 198 | } 199 | } 200 | 201 | /** 202 | This methods gives you reading access to the lookup table. 203 | */ 204 | const uint8_t* getLookupTable() const 205 | { 206 | return map; 207 | } 208 | 209 | double getBrightness() const 210 | { 211 | return brightness; 212 | } 213 | 214 | double getContrast() const 215 | { 216 | return contrast; 217 | } 218 | 219 | double getGamma() const 220 | { 221 | return gamma; 222 | } 223 | 224 | private: 225 | double brightness = -1.0; 226 | double contrast = -1.0; 227 | double gamma = -1.0; 228 | 229 | uint8_t map[256]; 230 | 231 | JUCE_LEAK_DETECTOR (ColourCurve) 232 | }; 233 | 234 | } // foleys 235 | -------------------------------------------------------------------------------- /Processing/foleys_Definitions.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | Copyright (c) 2019, Foleys Finest Audio - Daniel Walz 5 | All rights reserved. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 8 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 10 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 11 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 12 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 13 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 14 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 15 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 16 | OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | ============================================================================== 19 | */ 20 | 21 | #pragma once 22 | 23 | 24 | namespace foleys 25 | { 26 | 27 | namespace Definitions 28 | { 29 | 30 | /** 31 | Returns the names for a pixel format. Note that they are in spoken order and not in memory order. 32 | */ 33 | static inline juce::StringArray getChannelNames (juce::Image::PixelFormat format) 34 | { 35 | switch (format) 36 | { 37 | case juce::Image::ARGB: 38 | return { NEEDS_TRANS ("Red"), NEEDS_TRANS ("Green"), NEEDS_TRANS ("Blue"), NEEDS_TRANS ("Alpha") }; 39 | 40 | case juce::Image::RGB: 41 | return { NEEDS_TRANS ("Red"), NEEDS_TRANS ("Green"), NEEDS_TRANS ("Blue") }; 42 | 43 | case juce::Image::SingleChannel: 44 | return { NEEDS_TRANS ("Alpha") }; 45 | 46 | default: 47 | return {}; 48 | } 49 | } 50 | 51 | /** 52 | Returns the colours for a pixel format. Note that they are in spoken order and not in memory order. 53 | */ 54 | static inline juce::Array getChannelColours (juce::Image::PixelFormat format) 55 | { 56 | switch (format) 57 | { 58 | case juce::Image::ARGB: 59 | return { juce::Colours::red, juce::Colours::green, juce::Colours::blue, juce::Colours::white }; 60 | 61 | case juce::Image::RGB: 62 | return { juce::Colours::red, juce::Colours::green, juce::Colours::blue }; 63 | 64 | case juce::Image::SingleChannel: 65 | return { juce::Colours::white }; 66 | 67 | default: 68 | return {}; 69 | } 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /Processing/foleys_ImageProcessing.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | Copyright (c) 2019, Foleys Finest Audio - Daniel Walz 5 | All rights reserved. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 8 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 10 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 11 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 12 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 13 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 14 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 15 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 16 | OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | ============================================================================== 19 | */ 20 | 21 | #pragma once 22 | 23 | 24 | namespace foleys 25 | { 26 | 27 | 28 | /** 29 | This method multiplies the value of one channel value of one image with the 30 | value of a specific colour channel in an other image. 31 | */ 32 | static inline void multiplyChannel (juce::Image& imageToApply, int targetChannel, const juce::Image& alphaImage, int sourceChannel) 33 | { 34 | const auto rescaledAlpha = (alphaImage.getWidth() == imageToApply.getWidth() && 35 | alphaImage.getHeight() == imageToApply.getHeight()) ? alphaImage : alphaImage.rescaled (imageToApply.getWidth(), imageToApply.getHeight()); 36 | 37 | juce::Image::BitmapData target (imageToApply, juce::Image::BitmapData::readWrite); 38 | const juce::Image::BitmapData alpha (rescaledAlpha, juce::Image::BitmapData::readOnly); 39 | 40 | jassert (juce::isPositiveAndBelow (targetChannel, target.pixelStride)); 41 | jassert (juce::isPositiveAndBelow (sourceChannel, alpha.pixelStride)); 42 | 43 | for (int y = 0; y < target.height; ++y) 44 | { 45 | auto* ptr = target.getLinePointer (y) + targetChannel; 46 | const auto* mult = alpha.getLinePointer (y) + sourceChannel; 47 | 48 | for (int x = 0; x < target.width; ++x) 49 | { 50 | const auto value = juce::uint16 (*ptr) * juce::uint16 (*mult); 51 | *ptr = juce::uint8 (value >> 8); 52 | ptr += target.pixelStride; 53 | mult += alpha.pixelStride; 54 | } 55 | } 56 | } 57 | 58 | /** 59 | This method multiplies the alpha values of the alphaImage to the imageToApply 60 | */ 61 | static inline void multiplyAlpha (juce::Image& imageToApply, const juce::Image& alphaImage) 62 | { 63 | jassert (imageToApply.hasAlphaChannel()); 64 | const int sourceChannel = alphaImage.isSingleChannel() ? 0 : juce::PixelARGB::indexA; 65 | const int targetChannel = imageToApply.isSingleChannel() ? 0 : juce::PixelARGB::indexA; 66 | 67 | multiplyChannel (imageToApply, targetChannel, alphaImage, sourceChannel); 68 | } 69 | 70 | /** 71 | Sums all pixels to histograms per each colour channel 72 | */ 73 | static inline std::vector> getHistogram (const juce::Image& image) 74 | { 75 | const juce::Image::BitmapData data (image, juce::Image::BitmapData::readOnly); 76 | 77 | std::vector> histogram (data.pixelStride, std::vector(256, 0)); 78 | 79 | for (int y=0; y < data.height; ++y) 80 | { 81 | auto* ptr = data.getLinePointer (y); 82 | 83 | for (int x=0; x < data.width; ++x) 84 | for (int c=0; c < data.pixelStride; ++c) 85 | ++histogram [c][*ptr++]; 86 | } 87 | 88 | if (image.isARGB()) 89 | return { histogram [juce::PixelARGB::indexR], histogram [juce::PixelARGB::indexG], histogram [juce::PixelARGB::indexB], histogram [juce::PixelARGB::indexA] }; 90 | 91 | if (image.isRGB()) 92 | return { histogram [juce::PixelRGB::indexR], histogram [juce::PixelRGB::indexG], histogram [juce::PixelRGB::indexB]}; 93 | 94 | return histogram; 95 | } 96 | 97 | 98 | } // namespace foleys 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | foleys_image_processing 2 | ======================= 3 | 4 | Copyright (c) 2019, Foleys Finest Audio Ltd. - Daniel Walz All rights reserved. 5 | 6 | This is a module to be used together with JUCE (www.juce.com) containing helpful modules for image processing. 7 | 8 | The current functionality: 9 | 10 | Processing: 11 | ----------- 12 | 13 | - Multiply alpha masks of images 14 | - Lookup tables 15 | 16 | Widgets: 17 | -------- 18 | 19 | - Histogram view 20 | - Curve editor for LookupTables 21 | 22 | 23 | It's licensed permessively under BSD 3 clause, see LICENSE.md 24 | 25 | 26 | Let me know, what functionality you would hope to see. 27 | 28 | 29 | https://foleysfinest.com - Brighton, 2019 30 | -------------------------------------------------------------------------------- /Widgets/foleys_CurveView.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | Copyright (c) 2019, Foleys Finest Audio - Daniel Walz 5 | All rights reserved. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 8 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 10 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 11 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 12 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 13 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 14 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 15 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 16 | OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | ============================================================================== 19 | */ 20 | 21 | namespace foleys 22 | { 23 | 24 | CurveView::CurveView() 25 | { 26 | channelSelect.onChange = [&] 27 | { 28 | const auto& curve = curves [channelSelect.getSelectedItemIndex()]; 29 | brightness.setValue (curve.getBrightness(), juce::dontSendNotification); 30 | contrast.setValue (curve.getContrast(), juce::dontSendNotification); 31 | gamma.setValue (curve.getGamma(), juce::dontSendNotification); 32 | }; 33 | addAndMakeVisible (channelSelect); 34 | 35 | contrast.setRange (-1.0, 1.0, 0.01); 36 | brightness.setRange (-1.0, 1.0, 0.01); 37 | gamma.setRange (0.1, 10.0, 0.01); 38 | gamma.setSkewFactorFromMidPoint (1.0); 39 | 40 | contrast.onValueChange = [&] { updateCurve (false); }; 41 | brightness.onValueChange = [&] { updateCurve (false); }; 42 | gamma.onValueChange = [&] { updateCurve (false); }; 43 | 44 | contrast.onDragEnd = [&] { updateCurve (true); }; 45 | brightness.onDragEnd = [&] { updateCurve (true); }; 46 | gamma.onDragEnd = [&] { updateCurve (true); }; 47 | 48 | addAndMakeVisible (brightness); 49 | addAndMakeVisible (contrast); 50 | addAndMakeVisible (gamma); 51 | } 52 | 53 | void CurveView::updateCurve (bool sendUpdate) 54 | { 55 | auto& curve = curves [channelSelect.getSelectedItemIndex()]; 56 | curve.calculateColourMap (brightness.getValue(), contrast.getValue(), gamma.getValue()); 57 | repaint(); 58 | if (sendUpdate) 59 | sendChangeMessage(); 60 | } 61 | 62 | const std::vector& CurveView::getColourCurves() const 63 | { 64 | return curves; 65 | } 66 | 67 | void CurveView::setColourCurves (std::vector colourCurves) 68 | { 69 | curves = colourCurves; 70 | sendChangeMessage(); 71 | } 72 | 73 | void CurveView::setPixelFormat (juce::Image::PixelFormat format) 74 | { 75 | pixelFormat = format; 76 | 77 | setChannelNames (Definitions::getChannelNames (format)); 78 | setChannelColours (Definitions::getChannelColours (format)); 79 | 80 | curves.resize (channelNames.size()); 81 | } 82 | 83 | void CurveView::setChannelNames (const juce::StringArray& names) 84 | { 85 | channelNames = names; 86 | channelSelect.clear(); 87 | channelSelect.addItemList (names, 100); 88 | channelSelect.setSelectedItemIndex (0); 89 | } 90 | 91 | void CurveView::setChannelColours (const juce::Array& colours) 92 | { 93 | channelColours = colours; 94 | } 95 | 96 | void CurveView::paint (juce::Graphics& g) 97 | { 98 | g.setColour (juce::Colours::silver); 99 | g.drawRect (plotFrame); 100 | 101 | for (int c = 0; c < curves.size(); ++c) 102 | { 103 | const auto* table = curves [c].getLookupTable(); 104 | juce::Path p; 105 | float x = plotFrame.getX() + 1.0f; 106 | p.startNewSubPath (x, juce::jmap (float (table [0]), 0.0f, 255.0f, float (plotFrame.getBottom()), float (plotFrame.getY()))); 107 | 108 | const auto dx = (plotFrame.getWidth() - 2.0f) / 256.0f; 109 | for (int i = 1; i < 256; ++i) 110 | { 111 | x += dx; 112 | p.lineTo (x, juce::jmap (float (table [i]), 0.0f, 255.0f, float (plotFrame.getBottom()), float (plotFrame.getY()))); 113 | } 114 | 115 | g.setColour (juce::isPositiveAndBelow (c, channelColours.size()) ? channelColours.getUnchecked (c) : juce::Colours::white); 116 | g.strokePath (p, juce::PathStrokeType (1.0f)); 117 | } 118 | } 119 | 120 | void CurveView::resized() 121 | { 122 | auto area = getLocalBounds(); 123 | 124 | channelSelect.setBounds (area.removeFromTop (30).reduced (10, 3)); 125 | 126 | gamma.setBounds (area.removeFromBottom (20).reduced (8, 3)); 127 | contrast.setBounds (area.removeFromBottom (20).reduced (8, 3)); 128 | brightness.setBounds (area.removeFromBottom (20).reduced (8, 3)); 129 | 130 | plotFrame = area.reduced (8); 131 | } 132 | 133 | 134 | } // namespace foleys 135 | -------------------------------------------------------------------------------- /Widgets/foleys_CurveView.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | Copyright (c) 2019, Foleys Finest Audio - Daniel Walz 5 | All rights reserved. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 8 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 10 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 11 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 12 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 13 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 14 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 15 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 16 | OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | ============================================================================== 19 | */ 20 | 21 | 22 | #pragma once 23 | 24 | 25 | namespace foleys 26 | { 27 | 28 | class CurveView : public juce::Component, 29 | public juce::ChangeBroadcaster 30 | { 31 | public: 32 | CurveView(); 33 | 34 | /** 35 | Setting a pixel format will set the channel names and the colours per channel accordingly. 36 | You can override the default channel names and colours by calling @see setChannelNames() 37 | and @see setChannelColours(). 38 | */ 39 | void setPixelFormat (juce::Image::PixelFormat format); 40 | 41 | /** 42 | Set the channel names to display. They will be set by setPixelFormat, so if you want different 43 | names, you should call it after or instead of setPixelFormat. 44 | */ 45 | void setChannelNames (const juce::StringArray& names); 46 | 47 | /** 48 | Set the channel colours to display. They will be set by setPixelFormat, so if you want different 49 | colours, you should call it after or instead of setPixelFormat. 50 | */ 51 | void setChannelColours (const juce::Array& colours); 52 | 53 | /** 54 | Set the colour curves to use, e.g. when loading from a saved session. 55 | */ 56 | void setColourCurves (std::vector colourCurves); 57 | 58 | /** 59 | Access the colour curves e.g. to apply to an Image @see applyLUTs() 60 | */ 61 | const std::vector& getColourCurves() const; 62 | 63 | void paint (juce::Graphics& g) override; 64 | void resized() override; 65 | 66 | private: 67 | 68 | void updateCurve (bool sendUpdate); 69 | 70 | juce::Image::PixelFormat pixelFormat; 71 | juce::StringArray channelNames; 72 | juce::Array channelColours; 73 | 74 | std::vector curves; 75 | juce::ComboBox channelSelect; 76 | juce::Rectangle plotFrame; 77 | 78 | juce::Slider brightness { juce::Slider::LinearHorizontal, juce::Slider::TextBoxRight }; 79 | juce::Slider contrast { juce::Slider::LinearHorizontal, juce::Slider::TextBoxRight }; 80 | juce::Slider gamma { juce::Slider::LinearHorizontal, juce::Slider::TextBoxRight }; 81 | 82 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CurveView) 83 | }; 84 | 85 | } // namespace foleys 86 | -------------------------------------------------------------------------------- /Widgets/foleys_HistogramView.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | Copyright (c) 2019, Foleys Finest Audio - Daniel Walz 5 | All rights reserved. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 8 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 10 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 11 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 12 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 13 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 14 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 15 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 16 | OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | ============================================================================== 19 | */ 20 | 21 | namespace foleys 22 | { 23 | 24 | //============================================================================== 25 | 26 | 27 | void HistogramView::setPixelFormat (juce::Image::PixelFormat format) 28 | { 29 | pixelFormat = format; 30 | 31 | setChannelNames (Definitions::getChannelNames (format)); 32 | setChannelColours (Definitions::getChannelColours (format)); 33 | } 34 | 35 | void HistogramView::setChannelNames (const juce::StringArray& names) 36 | { 37 | channelNames = names; 38 | } 39 | 40 | void HistogramView::setChannelColours (const juce::Array& colours) 41 | { 42 | channelColours = colours; 43 | } 44 | 45 | void HistogramView::setHistogram (std::vector> histogramToUse, unsigned int max) 46 | { 47 | histogram = std::move (histogramToUse); 48 | maxNumberPixels = max; 49 | } 50 | 51 | void HistogramView::paint (juce::Graphics& g) 52 | { 53 | g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); // clear the background 54 | 55 | g.setColour (juce::Colours::white); 56 | g.setFont (16.0f); 57 | g.drawText ("Histogram", getLocalBounds().reduced (8), 58 | juce::Justification::top, true); 59 | 60 | auto area = getLocalBounds().withTop (20).reduced (8); 61 | g.setFont (14.0f); 62 | 63 | for (int channel = 0; channel < histogram.size(); ++channel) 64 | { 65 | g.setColour (juce::Colours::white); 66 | if (juce::isPositiveAndBelow (channel, channelNames.size())) 67 | g.drawText (channelNames [channel], area.removeFromTop (20), juce::Justification::left); 68 | 69 | const auto colour = (juce::isPositiveAndBelow (channel, channelColours.size())) ? channelColours [channel] : juce::Colours::white; 70 | 71 | drawHistogramChart (g, histogram [channel], maxNumberPixels, area.removeFromTop (100).toFloat(), colour); 72 | } 73 | } 74 | 75 | void HistogramView::drawHistogramChart (juce::Graphics& g, std::vector bins, unsigned int max, juce::Rectangle bounds, juce::Colour colour) 76 | { 77 | juce::Graphics::ScopedSaveState saveState (g); 78 | g.drawRect (bounds); 79 | 80 | if (bins.empty()) 81 | { 82 | g.setFont (16.0f); 83 | g.drawText ("No Data", bounds, juce::Justification::centred, true); 84 | return; 85 | } 86 | 87 | g.setColour (colour); 88 | bounds.reduce (1, 1); 89 | 90 | const float binWidth = bounds.getWidth() / bins.size(); 91 | for (int i=0; i < bins.size(); ++i) 92 | { 93 | const auto binHeight = juce::jlimit (0.0f, bounds.getHeight(), juce::jmap (float (bins [i]), 0.0f, float (max), 0.0f, bounds.getHeight())); 94 | const juce::Rectangle rect { bounds.getX() + i * binWidth, bounds.getY() + bounds.getHeight() - binHeight, binWidth, binHeight }; 95 | g.drawRect (rect.getSmallestIntegerContainer()); 96 | } 97 | 98 | } 99 | 100 | } // namespace foleys 101 | -------------------------------------------------------------------------------- /Widgets/foleys_HistogramView.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | Copyright (c) 2019, Foleys Finest Audio - Daniel Walz 5 | All rights reserved. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 8 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 10 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 11 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 12 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 13 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 14 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 15 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 16 | OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | ============================================================================== 19 | */ 20 | 21 | #pragma once 22 | 23 | 24 | namespace foleys 25 | { 26 | 27 | /* 28 | This class will display the histogram of a given Image 29 | */ 30 | class HistogramView : public juce::Component 31 | { 32 | public: 33 | HistogramView() = default; 34 | 35 | /** 36 | Setting a pixel format will set the channel names and the colours per channel accordingly. 37 | You can override the default channel names and colours by calling @see setChannelNames() 38 | and @see setChannelColours(). 39 | */ 40 | void setPixelFormat (juce::Image::PixelFormat format); 41 | 42 | /** 43 | Set the histogram data to display. 44 | @param histogram is a vector containing a vector per channel holding the sum of pixels per value 45 | @param max is the maximum number of pixels to display. width * height / 64 seems to be a good value. 46 | */ 47 | void setHistogram (std::vector> histogram, unsigned int max); 48 | 49 | /** 50 | Set the channel names to display. They will be set by setPixelFormat, so if you want different 51 | names, you should call it after or instead of setPixelFormat. 52 | */ 53 | void setChannelNames (const juce::StringArray& names); 54 | 55 | /** 56 | Set the channel colours to display. They will be set by setPixelFormat, so if you want different 57 | colours, you should call it after or instead of setPixelFormat. 58 | */ 59 | void setChannelColours (const juce::Array& colours); 60 | 61 | void paint (juce::Graphics&) override; 62 | 63 | private: 64 | 65 | void drawHistogramChart (juce::Graphics& g, std::vector bins, unsigned int max, juce::Rectangle bounds, juce::Colour colour); 66 | 67 | juce::Image::PixelFormat pixelFormat; 68 | juce::StringArray channelNames; 69 | juce::Array channelColours; 70 | 71 | std::vector> histogram; 72 | unsigned int maxNumberPixels = 0; 73 | 74 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HistogramView) 75 | }; 76 | 77 | } // namespace foleys 78 | -------------------------------------------------------------------------------- /foleys_image_processing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | Copyright (c) 2019, Foleys Finest Audio - Daniel Walz 5 | All rights reserved. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 8 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 10 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 11 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 12 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 13 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 14 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 15 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 16 | OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | ============================================================================== 19 | */ 20 | 21 | #include "foleys_image_processing.h" 22 | 23 | #include "Widgets/foleys_HistogramView.cpp" 24 | #include "Widgets/foleys_CurveView.cpp" 25 | -------------------------------------------------------------------------------- /foleys_image_processing.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | Copyright (c) 2019, Foleys Finest Audio - Daniel Walz 5 | All rights reserved. 6 | 7 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 8 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 10 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 11 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 12 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 13 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 14 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 15 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 16 | OF THE POSSIBILITY OF SUCH DAMAGE. 17 | 18 | ============================================================================== 19 | 20 | The block below describes the properties of this module, and is read by 21 | the Projucer to automatically generate project code that uses it. 22 | For details about the syntax and how to create or use a module, see the 23 | JUCE Module Format.txt file. 24 | 25 | BEGIN_JUCE_MODULE_DECLARATION 26 | 27 | ID: foleys_image_processing 28 | vendor: Foleys Finest Audio 29 | version: 1.0.0 30 | name: Foleys Finest Image Processing 31 | description: A collection to do image processing and some widgets to inspect and modify image data 32 | website: https://foleysfinest.com 33 | license: BSD 3-clause 34 | 35 | dependencies: juce_core, juce_graphics, juce_gui_basics 36 | 37 | END_JUCE_MODULE_DECLARATION 38 | 39 | ============================================================================== 40 | */ 41 | 42 | #pragma once 43 | 44 | #include 45 | #include 46 | #include 47 | 48 | #include "Processing/foleys_Definitions.h" 49 | #include "Processing/foleys_ColourLookuptables.h" 50 | #include "Processing/foleys_ImageProcessing.h" 51 | #include "Widgets/foleys_HistogramView.h" 52 | #include "Widgets/foleys_CurveView.h" 53 | --------------------------------------------------------------------------------