diff --git a/libs/image/CMakeLists.txt b/libs/image/CMakeLists.txt index 0e7cbab6c3..50b1ad11fc 100644 --- a/libs/image/CMakeLists.txt +++ b/libs/image/CMakeLists.txt @@ -8,12 +8,13 @@ set(PUBLIC_HDR_DIR include) # Sources and headers # ================================================================================================== set(PUBLIC_HDRS - include/image/Image.h include/image/ColorTransform.h + include/image/LinearImage.h + include/image/ImageSampler.h + include/image/ImageOps.h ) set(SRCS - src/Image.cpp src/LinearImage.cpp src/ImageSampler.cpp src/ImageOps.cpp diff --git a/libs/image/include/image/ColorTransform.h b/libs/image/include/image/ColorTransform.h index dc90f49690..3cc0002912 100644 --- a/libs/image/include/image/ColorTransform.h +++ b/libs/image/include/image/ColorTransform.h @@ -17,7 +17,6 @@ #ifndef IMAGE_COLORTRANSFORM_H_ #define IMAGE_COLORTRANSFORM_H_ -#include #include #include @@ -142,65 +141,6 @@ inline math::float3 linearToSRGB(const math::float3& color) { return sRGBColor; } -template -std::unique_ptr fromLinearTosRGB(const Image& image) { - using math::float3; - size_t w = image.getWidth(); - size_t h = image.getHeight(); - size_t channels = image.getChannelsCount(); - std::unique_ptr dst(new uint8_t[w * h * 3 * sizeof(T)]); - T* d = reinterpret_cast(dst.get()); - for (size_t y = 0; y < h; ++y) { - float3 const* p = static_cast(image.getPixelRef(0, y)); - for (size_t x = 0; x < w; ++x, ++p, d += channels) { - float3 l(linearTosRGB(saturate(*p)) * std::numeric_limits::max()); - for (size_t i = 0; i < 3; i++) { - d[i] = T(l[i]); - } - } - } - return dst; -} - -template -std::unique_ptr fromLinearToRGB(const Image& image) { - using math::float3; - size_t w = image.getWidth(); - size_t h = image.getHeight(); - size_t channels = image.getChannelsCount(); - std::unique_ptr dst(new uint8_t[w * h * channels * sizeof(T)]); - T* d = reinterpret_cast(dst.get()); - for (size_t y = 0; y < h; ++y) { - float3 const* p = static_cast(image.getPixelRef(0, y)); - for (size_t x = 0; x < w; ++x, ++p, d += channels) { - float3 l(saturate(*p) * std::numeric_limits::max()); - for (size_t i = 0; i < channels; i++) { - d[i] = T(l[i]); - } - } - } - return dst; -} - -template -std::unique_ptr fromLinearToRGBM(const Image& image) { - using namespace math; - size_t w = image.getWidth(); - size_t h = image.getHeight(); - std::unique_ptr dst(new uint8_t[w * h * 4 * sizeof(T)]); - T* d = reinterpret_cast(dst.get()); - for (size_t y = 0; y < h; ++y) { - float3 const* p = static_cast(image.getPixelRef(0, y)); - for (size_t x = 0; x < w; ++x, ++p, d += 4) { - float4 l(linearToRGBM(*p) * std::numeric_limits::max()); - for (size_t i = 0; i < 4; i++) { - d[i] = T(l[i]); - } - } - } - return dst; -} - // Creates a 3-channel sRGB u8 image from a linear f32 image. // The source image can have three or more channels, but only the first three are honored. template @@ -357,6 +297,6 @@ inline LinearImage toLinearFromRGBM(math::float4 const* src, uint32_t w, uint32_ return result; } -} +} // namespace Image #endif // IMAGE_COLORTRANSFORM_H_ diff --git a/libs/image/include/image/Image.h b/libs/image/include/image/Image.h deleted file mode 100644 index 2c6b459fe6..0000000000 --- a/libs/image/include/image/Image.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef IMAGE_IMAGE_H_ -#define IMAGE_IMAGE_H_ - -#include -#include - -/** - * This namespace defines types and free functions for both the core "image" library (minimal - * dependencies) as well as the "imageio" library (for loading and saving files). - */ -namespace image { - -/** - * \deprecated - * We are phasing out this class in favor of LinearImage. The latter has a stable and well-defined - * pixel format, making it easier to implement image-based algorithms. - */ -class Image { -public: - Image(); - Image(std::unique_ptr data, size_t w, size_t h, - size_t bpr, size_t bpp, size_t channels = 3); - - enum { - FLIP_X = 0x1, - FLIP_Y = 0x2, - FLIP_XY = FLIP_X | FLIP_Y - }; - - void reset(); - - void set(Image const& image); - - void subset(Image const& image, size_t x, size_t y, size_t w, size_t h, uint32_t flags = 0); - - void flip(uint32_t flags); - - bool isValid() const { return mData != nullptr; } - size_t getWidth() const { return mWidth; } - size_t getHeight() const { return mHeight; } - size_t getBytesPerRow() const { return mBpr; } - size_t getBytesPerPixel() const { return mBpp; } - size_t getChannelsCount() const { return mChannels; } - void* getData() const { return mData; } - - void* getPixelRef(size_t x, size_t y) const; - -private: - std::unique_ptr mOwnedData; - void* mData = nullptr; - size_t mWidth = 0; - size_t mHeight = 0; - size_t mBpr = 0; - size_t mBpp = 0; - size_t mChannels = 0; -}; - -inline void* Image::getPixelRef(size_t x, size_t y) const { - return static_cast(mData) + y*mBpr + x*mBpp; -} - -} // namespace image - -#endif /* IMAGE_IMAGE_H_ */ diff --git a/libs/imageio/src/ImageDecoder.cpp b/libs/imageio/src/ImageDecoder.cpp index b2a11bf043..664df3d3ce 100644 --- a/libs/imageio/src/ImageDecoder.cpp +++ b/libs/imageio/src/ImageDecoder.cpp @@ -232,40 +232,6 @@ PNGDecoder::~PNGDecoder() { png_destroy_read_struct(&mPNG, &mInfo, NULL); } -// TODO: remove after migrating imageio to LinearImage -template -static Image toLinearDeprecated(size_t w, size_t h, size_t bpr, - const std::unique_ptr& src, PROCESS proc, TRANSFORM transform) { - std::unique_ptr dst(new uint8_t[w * h * sizeof(math::float3)]); - math::float3* d = reinterpret_cast(dst.get()); - for (size_t y = 0; y < h; ++y) { - T const* p = reinterpret_cast(src.get() + y * bpr); - for (size_t x = 0; x < w; ++x, p += 3) { - math::float3 sRGB(proc(p[0]), proc(p[1]), proc(p[2])); - sRGB /= std::numeric_limits::max(); - *d++ = transform(sRGB); - } - } - return Image(std::move(dst), w, h, w * sizeof(math::float3), sizeof(math::float3)); -} - -// TODO: remove after migrating imageio to LinearImage -template -static Image toLinearWithAlphaDeprecated(size_t w, size_t h, size_t bpr, - const std::unique_ptr& src, PROCESS proc, TRANSFORM transform) { - std::unique_ptr dst(new uint8_t[w * h * sizeof(math::float4)]); - math::float4* d = reinterpret_cast(dst.get()); - for (size_t y = 0; y < h; ++y) { - T const* p = reinterpret_cast(src.get() + y * bpr); - for (size_t x = 0; x < w; ++x, p += 4) { - math::float4 sRGB(proc(p[0]), proc(p[1]), proc(p[2]), proc(p[3])); - sRGB /= std::numeric_limits::max(); - *d++ = transform(sRGB); - } - } - return Image(std::move(dst), w, h, w * sizeof(math::float4), sizeof(math::float4), 4); -} - LinearImage PNGDecoder::decode() { std::unique_ptr imageData; try { diff --git a/tools/cmgen/CMakeLists.txt b/tools/cmgen/CMakeLists.txt index fcd7685cf6..8cc16954ea 100644 --- a/tools/cmgen/CMakeLists.txt +++ b/tools/cmgen/CMakeLists.txt @@ -12,6 +12,7 @@ set(HDRS src/CubemapIBL.h src/CubemapSH.h src/CubemapUtils.h + src/Image.h src/ProgressUpdater.h src/utilities.h ) @@ -22,6 +23,7 @@ set(SRCS src/CubemapIBL.cpp src/CubemapSH.cpp src/CubemapUtils.cpp + src/Image.cpp src/JobQueue.cpp src/ProgressUpdater.cpp ) diff --git a/tools/cmgen/src/Cubemap.cpp b/tools/cmgen/src/Cubemap.cpp index 88129ece56..f6ecb18779 100644 --- a/tools/cmgen/src/Cubemap.cpp +++ b/tools/cmgen/src/Cubemap.cpp @@ -38,7 +38,7 @@ void Cubemap::resetDimensions(size_t dim) { } } -void Cubemap::setImageForFace(Face face, const image::Image& image) { +void Cubemap::setImageForFace(Face face, const Image& image) { mFaces[size_t(face)].set(image); } @@ -145,7 +145,7 @@ void Cubemap::makeSeamless() { } } -Cubemap::Texel Cubemap::filterAt(const image::Image& image, double x, double y) { +Cubemap::Texel Cubemap::filterAt(const Image& image, double x, double y) { const size_t x0 = size_t(x); const size_t y0 = size_t(y); // we allow ourselves to read past the width/height of the Image because the data is valid @@ -167,12 +167,12 @@ Cubemap::Texel Cubemap::trilinearFilterAt(const Cubemap& l0, const Cubemap& l1, const double3& L) { Cubemap::Address addr(getAddressFor(L)); - const image::Image& i0 = l0.getImageForFace(addr.face); + const Image& i0 = l0.getImageForFace(addr.face); double x0 = std::min(addr.s * l0.mDimensions, l0.mUpperBound); double y0 = std::min(addr.t * l0.mDimensions, l0.mUpperBound); float3 c0(filterAt(i0, x0, y0)); if (&l0 != &l1) { - const image::Image& i1 = l1.getImageForFace(addr.face); + const Image& i1 = l1.getImageForFace(addr.face); double x1 = std::min(addr.s * l1.mDimensions, l1.mUpperBound); double y1 = std::min(addr.t * l1.mDimensions, l1.mUpperBound); c0 += lerp * (filterAt(i1, x1, y1) - c0); diff --git a/tools/cmgen/src/Cubemap.h b/tools/cmgen/src/Cubemap.h index 5a0c465458..dd994f2e35 100644 --- a/tools/cmgen/src/Cubemap.h +++ b/tools/cmgen/src/Cubemap.h @@ -23,10 +23,9 @@ #include #include -#include - #include +#include "Image.h" #include "utilities.h" class Cubemap { @@ -52,8 +51,8 @@ public: void resetDimensions(size_t dim); - void setImageForFace(Face face, const image::Image& image); - inline const image::Image& getImageForFace(Face face) const; + void setImageForFace(Face face, const Image& image); + inline const Image& getImageForFace(Face face) const; inline math::double2 center(size_t x, size_t y) const; @@ -63,7 +62,7 @@ public: inline Texel const& sampleAt(const math::double3& direction) const; inline Texel filterAt(const math::double3& direction) const; - static Texel filterAt(const image::Image& image, double x, double y); + static Texel filterAt(const Image& image, double x, double y); static Texel trilinearFilterAt(const Cubemap& c0, const Cubemap& c1, double lerp, const math::double3& direction); @@ -100,11 +99,11 @@ private: size_t mDimensions = 0; double mScale = 1; double mUpperBound = 0; - image::Image mFaces[6]; + Image mFaces[6]; Geometry mGeometry = Geometry::HORIZONTAL_CROSS; }; -inline const image::Image& Cubemap::getImageForFace(Face face) const { +inline const Image& Cubemap::getImageForFace(Face face) const { return mFaces[int(face)]; } diff --git a/tools/cmgen/src/CubemapIBL.h b/tools/cmgen/src/CubemapIBL.h index 6bcdbfe600..37c3d82b3b 100644 --- a/tools/cmgen/src/CubemapIBL.h +++ b/tools/cmgen/src/CubemapIBL.h @@ -23,9 +23,7 @@ class Cubemap; -namespace image { class Image; -} class CubemapIBL { public: @@ -35,7 +33,7 @@ public: static void roughnessFilter(Cubemap& dst, const std::vector& levels, double linearRoughness, size_t maxNumSamples = 1024); - static void DFG(image::Image& dst, bool multiscatter = false); + static void DFG(Image& dst, bool multiscatter = false); static void brdf(Cubemap& dst, double linearRoughness); }; diff --git a/tools/cmgen/src/CubemapUtils.cpp b/tools/cmgen/src/CubemapUtils.cpp index 0f1bd6ec12..d3e84b96cf 100644 --- a/tools/cmgen/src/CubemapUtils.cpp +++ b/tools/cmgen/src/CubemapUtils.cpp @@ -23,7 +23,7 @@ using namespace math; using namespace image; -void CubemapUtils::clamp(image::Image& src) { +void CubemapUtils::clamp(Image& src) { // We clamp all values to 256 which correspond to the maximum value (before // gamma compression) that we can store in RGBM. // This clamping is necessary because: @@ -42,7 +42,7 @@ void CubemapUtils::clamp(image::Image& src) { } } -void CubemapUtils::equirectangularToCubemap(Cubemap& dst, const image::Image& src) { +void CubemapUtils::equirectangularToCubemap(Cubemap& dst, const Image& src) { const size_t width = src.getWidth(); const size_t height = src.getHeight(); const double r = width * 0.5 * M_1_PI; @@ -90,7 +90,7 @@ void CubemapUtils::downsampleCubemapLevelBoxFilter(Cubemap& dst, const Cubemap& size_t scale = src.getDimensions() / dst.getDimensions(); process(dst, [&](EmptyState&, size_t y, Cubemap::Face f, Cubemap::Texel* data, size_t dim) { - const image::Image& image(src.getImageForFace(f)); + const Image& image(src.getImageForFace(f)); for (size_t x=0 ; x - #include #include "Cubemap.h" +#include "Image.h" class CubemapUtils { public: @@ -48,10 +47,10 @@ public: const STATE& prototype = STATE()); // Convert equirectangular Image to a Cubemap - static void equirectangularToCubemap(Cubemap& dst, const image::Image& src); + static void equirectangularToCubemap(Cubemap& dst, const Image& src); // clamp image to acceptable range - static void clamp(image::Image& src); + static void clamp(Image& src); // Downsample a cubemap static void downsampleCubemapLevelBoxFilter(Cubemap& dst, const Cubemap& src); @@ -60,13 +59,13 @@ public: static std::string getFaceName(Cubemap::Face face); // Create a cubemap object and its backing Image - static Cubemap create(image::Image& image, size_t dim, bool horizontal = true); + static Cubemap create(Image& image, size_t dim, bool horizontal = true); // Copy an image - static void copyImage(image::Image& dst, const image::Image& src); + static void copyImage(Image& dst, const Image& src); // Sets a Cubemap faces from a cross image - static void setAllFacesFromCross(Cubemap& cm, const image::Image& image); + static void setAllFacesFromCross(Cubemap& cm, const Image& image); static void mirrorCubemap(Cubemap& dst, const Cubemap& src); @@ -75,8 +74,8 @@ public: static void generateUVGrid(Cubemap const& cml, size_t gridFrequency); private: - static void setFaceFromCross(Cubemap& cm, Cubemap::Face face, const image::Image& image); - static image::Image createCubemapImage(size_t dim, bool horizontal = true); + static void setFaceFromCross(Cubemap& cm, Cubemap::Face face, const Image& image); + static Image createCubemapImage(size_t dim, bool horizontal = true); }; // ----------------------------------------------------------------------------------------------- @@ -106,7 +105,7 @@ void CubemapUtils::process( const Cubemap& cm, [ faceIndex, &states, f, &cm, &dim, &proc ] (utils::JobSystem& js, utils::JobSystem::Job* parent) { STATE& s = states[faceIndex]; - const image::Image& image(cm.getImageForFace(f)); + const Image& image(cm.getImageForFace(f)); auto parallelJobTask = [ &image, &proc, &s, dim, f ](size_t y0, size_t c) { for (size_t y = y0; y < y0 + c; y++) { diff --git a/libs/image/src/Image.cpp b/tools/cmgen/src/Image.cpp similarity index 97% rename from libs/image/src/Image.cpp rename to tools/cmgen/src/Image.cpp index a30bcfe1d6..29b6fc49f2 100644 --- a/libs/image/src/Image.cpp +++ b/tools/cmgen/src/Image.cpp @@ -16,9 +16,7 @@ #include -#include - -namespace image { +#include "Image.h" Image::Image() { } @@ -95,5 +93,3 @@ void Image::flip(uint32_t flags) { } } } - -} // namespace image diff --git a/tools/cmgen/src/Image.h b/tools/cmgen/src/Image.h new file mode 100644 index 0000000000..a87e0a99fa --- /dev/null +++ b/tools/cmgen/src/Image.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CMGEN_IMAGE_H_ +#define CMGEN_IMAGE_H_ + +#include + +#include +#include + +#include +#include +#include + +/** + * \deprecated + * We are phasing out this class in favor of LinearImage. The latter has a stable and well-defined + * pixel format, making it easier to implement image-based algorithms. + */ +class Image { +public: + Image(); + Image(std::unique_ptr data, size_t w, size_t h, + size_t bpr, size_t bpp, size_t channels = 3); + + enum { + FLIP_X = 0x1, + FLIP_Y = 0x2, + FLIP_XY = FLIP_X | FLIP_Y + }; + + void reset(); + + void set(Image const& image); + + void subset(Image const& image, size_t x, size_t y, size_t w, size_t h, uint32_t flags = 0); + + void flip(uint32_t flags); + + bool isValid() const { return mData != nullptr; } + size_t getWidth() const { return mWidth; } + size_t getHeight() const { return mHeight; } + size_t getBytesPerRow() const { return mBpr; } + size_t getBytesPerPixel() const { return mBpp; } + size_t getChannelsCount() const { return mChannels; } + void* getData() const { return mData; } + + void* getPixelRef(size_t x, size_t y) const; + +private: + std::unique_ptr mOwnedData; + void* mData = nullptr; + size_t mWidth = 0; + size_t mHeight = 0; + size_t mBpr = 0; + size_t mBpp = 0; + size_t mChannels = 0; +}; + +inline void* Image::getPixelRef(size_t x, size_t y) const { + return static_cast(mData) + y*mBpr + x*mBpp; +} + +template +std::unique_ptr fromLinearTosRGB(const Image& image) { + using math::float3; + size_t w = image.getWidth(); + size_t h = image.getHeight(); + size_t channels = image.getChannelsCount(); + std::unique_ptr dst(new uint8_t[w * h * 3 * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + float3 const* p = static_cast(image.getPixelRef(0, y)); + for (size_t x = 0; x < w; ++x, ++p, d += channels) { + float3 l(image::linearTosRGB(saturate(*p)) * std::numeric_limits::max()); + for (size_t i = 0; i < 3; i++) { + d[i] = T(l[i]); + } + } + } + return dst; +} + +template +std::unique_ptr fromLinearToRGB(const Image& image) { + using math::float3; + size_t w = image.getWidth(); + size_t h = image.getHeight(); + size_t channels = image.getChannelsCount(); + std::unique_ptr dst(new uint8_t[w * h * channels * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + float3 const* p = static_cast(image.getPixelRef(0, y)); + for (size_t x = 0; x < w; ++x, ++p, d += channels) { + float3 l(saturate(*p) * std::numeric_limits::max()); + for (size_t i = 0; i < channels; i++) { + d[i] = T(l[i]); + } + } + } + return dst; +} + +template +std::unique_ptr fromLinearToRGBM(const Image& image) { + using namespace math; + size_t w = image.getWidth(); + size_t h = image.getHeight(); + std::unique_ptr dst(new uint8_t[w * h * 4 * sizeof(T)]); + T* d = reinterpret_cast(dst.get()); + for (size_t y = 0; y < h; ++y) { + float3 const* p = static_cast(image.getPixelRef(0, y)); + for (size_t x = 0; x < w; ++x, ++p, d += 4) { + float4 l(image::linearToRGBM(*p) * std::numeric_limits::max()); + for (size_t i = 0; i < 4; i++) { + d[i] = T(l[i]); + } + } + } + return dst; +} + +#endif /* CMGEN_IMAGE_H_ */ diff --git a/tools/cmgen/src/cmgen.cpp b/tools/cmgen/src/cmgen.cpp index 0495a4c395..f3578a6f90 100644 --- a/tools/cmgen/src/cmgen.cpp +++ b/tools/cmgen/src/cmgen.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include @@ -36,6 +35,7 @@ #include "CubemapIBL.h" #include "CubemapSH.h" #include "CubemapUtils.h" +#include "Image.h" using namespace math; using namespace image;