Make some way to load image from raw-buffer stream.
This raw-buffer will alive when some actor contain this buffer.
Limitation : animated-image, vector-image, animated-vector-image not working now. Will support another patch
1. Generate url from encoded raw buffer like this
ImageUrl url = Toolkit::Image::GenerateUrl(const EncodedImageBuffer &);
2. When we use URL as this string, we can load it like normal LOCAL file.
ImageView imageView = Toolkit::ImageView::New(url.GetUrl());
3. Buffer will automatically removed when ImageUrl scope is out-of-date, and no actor use it.
NOTE : even ImageUrl lifecycle is done, cached texture can use internally.
Change-Id: I517d9526d13a6b761792dcb7054864643f209b67
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
../dali-toolkit/dali-toolkit-test-utils/test-animation-data.cpp
../dali-toolkit/dali-toolkit-test-utils/test-application.cpp
../dali-toolkit/dali-toolkit-test-utils/test-button.cpp
+ ../dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.cpp
../dali-toolkit/dali-toolkit-test-utils/test-harness.cpp
../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.cpp
#include <dali-toolkit/internal/visuals/texture-upload-observer.h>
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h> ///< For VisualFactory's member TextureManager.
+
+#include <test-encoded-image-buffer.h>
#if defined(ELDBUS_ENABLED)
#include <automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.h>
END_TEST;
}
+int UtcTextureManagerEncodedImageBuffer(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcTextureManagerEncodedImageBuffer" );
+
+ auto visualFactory = Toolkit::VisualFactory::Get();
+ auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); // Use VisualFactory's texture manager
+
+ // Get encoded raw-buffer image and generate url
+ EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
+ EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
+
+ std::string url1 = textureManager.AddExternalTexture(buffer1);
+ std::string url2 = textureManager.AddExternalTexture(buffer1);
+ std::string url3 = VisualUrl::CreateBufferUrl(""); ///< Impossible Buffer URL. for coverage
+
+ // Check if same EncodedImageBuffer get same url
+ DALI_TEST_CHECK(url1 == url2);
+ // Reduce reference count
+ textureManager.RemoveExternalTexture(url1);
+ // Check whethere url1 still valid
+ DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
+
+ url2 = textureManager.AddExternalTexture(buffer2);
+ // Check if difference EncodedImageBuffer get difference url
+ DALI_TEST_CHECK(url1 != url2);
+
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+ TestObserver observer1;
+ textureManager.RequestLoad(
+ url1,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ TextureManager::NO_ATLAS,
+ &observer1,
+ true, ///< orientationCorrection
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
+
+ DALI_TEST_EQUALS( observer1.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer1.mObserverCalled, false, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( observer1.mLoaded, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer1.mObserverCalled, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer1.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION );
+
+ TestObserver observer2;
+ // Syncload
+ Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer(
+ url2,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ true, ///< synchronousLoading
+ &observer2,
+ true, ///< orientationCorrection
+ preMultiply);
+
+ DALI_TEST_CHECK( pixelBuffer );
+ DALI_TEST_EQUALS( observer2.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer2.mObserverCalled, false, TEST_LOCATION );
+
+ // Asyncload
+ pixelBuffer = textureManager.LoadPixelBuffer(
+ url2,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ false, ///< synchronousLoading
+ &observer2,
+ true, ///< orientationCorrection
+ preMultiply);
+
+ DALI_TEST_EQUALS( observer2.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer2.mObserverCalled, false, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( observer2.mLoaded, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer2.mObserverCalled, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION );
+
+ textureManager.RemoveExternalTexture(url1);
+ textureManager.RemoveExternalTexture(url2);
+
+ // Now url1 and url2 is invalid type. mLoaded will return false
+
+ TestObserver observer3;
+ textureManager.RequestLoad(
+ url1,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ TextureManager::NO_ATLAS,
+ &observer3,
+ true, ///< orientationCorrection
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
+
+ // Load will be success because url1 is cached
+ DALI_TEST_EQUALS( observer3.mLoaded, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer3.mObserverCalled, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer3.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION );
+
+ TestObserver observer4;
+ textureManager.RequestLoad(
+ url2,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ TextureManager::NO_ATLAS,
+ &observer4,
+ true, ///< orientationCorrection
+ TextureManager::ReloadPolicy::FORCED,
+ preMultiply);
+
+ DALI_TEST_EQUALS( observer4.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer4.mObserverCalled, false, TEST_LOCATION );
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ // Load will be failed becuase reloadpolicy is forced
+ DALI_TEST_EQUALS( observer4.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer4.mObserverCalled, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer4.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION );
+
+ TestObserver observer5;
+ pixelBuffer = textureManager.LoadPixelBuffer(
+ url2,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ true, ///< synchronousLoading
+ &observer5,
+ true, ///< orientationCorrection
+ preMultiply);
+
+ // Load will be faild because synchronousLoading doesn't use cached texture
+ DALI_TEST_CHECK( !pixelBuffer );
+ DALI_TEST_EQUALS( observer5.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer5.mObserverCalled, false, TEST_LOCATION );
+
+ TestObserver observer6;
+ pixelBuffer = textureManager.LoadPixelBuffer(
+ url3,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ false, ///< synchronousLoading
+ &observer6,
+ true, ///< orientationCorrection
+ preMultiply);
+
+ DALI_TEST_EQUALS( observer6.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer6.mObserverCalled, false, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ // Load will be failed because url3 is invalid URL
+ DALI_TEST_EQUALS( observer6.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer6.mObserverCalled, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer6.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcTextureManagerEncodedImageBufferReferenceCount(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcTextureManagerEncodedImageBuffer check reference count works well" );
+
+ auto visualFactory = Toolkit::VisualFactory::Get();
+ auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); // Use VisualFactory's texture manager
+
+ // Get encoded raw-buffer image and generate url
+ EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
+ EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME);
+
+ std::string url1 = textureManager.AddExternalTexture(buffer1);
+ std::string url2 = textureManager.AddExternalTexture(buffer1);
+
+ // Check if same EncodedImageBuffer get same url
+ DALI_TEST_CHECK(url1 == url2);
+
+ // Reduce reference count
+ textureManager.RemoveExternalTexture(url1);
+ // Check whethere url1 still valid
+ DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
+
+ // Reduce reference count
+ textureManager.RemoveExternalTexture(url1);
+ // Check whethere url1 is not valid anymore
+ DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
+
+ // UseExternalTexture doesn't create new buffer.
+ // So, reference count is still zero.
+ textureManager.UseExternalTexture(url1);
+ DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
+
+ url1 = textureManager.AddExternalTexture(buffer1);
+ // Check if difference EncodedImageBuffer get difference url
+ // Previous EncodedImageBuffer was deleted, so we get new url even same buffer.
+ DALI_TEST_CHECK(url1 != url2);
+
+ url2 = textureManager.AddExternalTexture(buffer2);
+ // Check if difference EncodedImageBuffer get difference url
+ DALI_TEST_CHECK(url1 != url2);
+
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+ // url1 load image by cache
+ TestObserver observer1;
+ textureManager.RequestLoad(
+ url1,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ TextureManager::NO_ATLAS,
+ &observer1,
+ true, ///< orientationCorrection
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
+
+ DALI_TEST_EQUALS( observer1.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer1.mObserverCalled, false, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( observer1.mLoaded, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer1.mObserverCalled, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer1.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION );
+
+ // LoadPixelBuffer doen't use cache. url2 will not be cached
+ TestObserver observer2;
+ Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer(
+ url2,
+ ImageDimensions(),
+ FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR,
+ false, ///< synchronousLoading
+ &observer2,
+ true, ///< orientationCorrection
+ preMultiply);
+
+ DALI_TEST_EQUALS( observer2.mLoaded, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer2.mObserverCalled, false, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( observer2.mLoaded, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer2.mObserverCalled, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION );
+
+ // Decrease each url's reference count.
+ textureManager.RemoveExternalTexture(url1);
+ textureManager.RemoveExternalTexture(url2);
+
+ // url1 buffer is still have 1 reference count because it is cached.
+ // But url2 not valid because it is not cached.
+ DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1));
+ DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url2));
+
+ // Check url1 buffer have 1 reference count because it is cached.
+ textureManager.RemoveExternalTexture(url1);
+ DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1));
+
+ END_TEST;
+}
+
+
int UtcTextureManagerCachingForDifferentLoadingType(void)
{
ToolkitTestApplication application;
DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://1234").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("ENBUF://1234").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://.gif").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
END_TEST;
}
DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ssh:a/bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("shh://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("sss://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("fsh://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("stp://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:/bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("h1tps://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ht2ps://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali:5/1").GetProtocolType(), TEST_LOCATION );
DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali:/61").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("eunki://1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbu://1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("eubnf://1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("1nbuf://1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("e2bun://1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("en3uf://1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enb4f://1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbu5://1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbuf6//1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbuf:7/1").GetProtocolType(), TEST_LOCATION );
+ DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbuf:/81").GetProtocolType(), TEST_LOCATION );
+
END_TEST;
}
DALI_TEST_EQUAL( "a", VisualUrl("http://a").GetLocation() );
DALI_TEST_EQUAL( "1", VisualUrl("dali://1").GetLocation() );
+ DALI_TEST_EQUAL( "4", VisualUrl("enbuf://4").GetLocation() );
DALI_TEST_EQUAL( "", VisualUrl("ftp://").GetLocation() );
DALI_TEST_EQUAL( "http://", VisualUrl("http://http://").GetLocation() );
DALI_TEST_EQUAL( "a", VisualUrl("a").GetLocation() );
DALI_TEST_EQUAL( "dali:/1", VisualUrl("dali:/1").GetLocation() );
DALI_TEST_EQUAL( "dali//1", VisualUrl("dali//1").GetLocation() );
+ DALI_TEST_EQUAL( "enbuf:/2", VisualUrl("enbuf:/2").GetLocation() );
DALI_TEST_EQUAL( "", VisualUrl("http:/http://").GetLocation() );
END_TEST;
END_TEST;
}
+
+int UtcDaliVisualUrlCreateBufferUrl(void)
+{
+ tet_infoline( "UtcDaliVisualUrl CreateBufferUrl" );
+
+ DALI_TEST_EQUAL( "enbuf://a", VisualUrl::CreateBufferUrl( "a" ) );
+ DALI_TEST_EQUAL( "enbuf://1234", VisualUrl::CreateBufferUrl( "1234" ) );
+ DALI_TEST_EQUAL( "enbuf://", VisualUrl::CreateBufferUrl( "" ) );
+
+ END_TEST;
+}
dali-toolkit-test-utils/test-animation-data.cpp
dali-toolkit-test-utils/test-application.cpp
dali-toolkit-test-utils/test-button.cpp
+ dali-toolkit-test-utils/test-encoded-image-buffer.cpp
dali-toolkit-test-utils/test-harness.cpp
dali-toolkit-test-utils/test-gesture-generator.cpp
dali-toolkit-test-utils/test-gl-abstraction.cpp
--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+#include "test-application.h"
+
+#include "test-encoded-image-buffer.h"
+
+namespace Dali
+{
+EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url)
+{
+ EncodedImageBuffer buffer;
+ FILE *fp;
+ fp = fopen(url, "rb");
+ if(fp != NULL)
+ {
+ fseek(fp, 0, SEEK_END);
+ size_t size = ftell(fp);
+ Dali::Vector<uint8_t> data;
+ data.Resize(size);
+ fseek(fp, 0, SEEK_SET);
+ fread(data.Begin(), size, sizeof(uint8_t), fp);
+ fclose(fp);
+ buffer = EncodedImageBuffer::New(data);
+ }
+ return buffer;
+}
+
+} // namespace Dali
--- /dev/null
+#ifndef TEST_ENCODED_IMAGE_BUFFER_H
+#define TEST_ENCODED_IMAGE_BUFFER_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
+
+namespace Dali
+{
+
+// util function to convert local file to EncodedImageBuffer
+EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url);
+
+} // namespace Dali
+
+#endif // TEST_ENCODED_IMAGE_BUFFER_H
END_TEST;
}
+
+int UtcDaliImageConvertEncodedImageBufferToUrl(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcDaliImageConvertEncodedImageBufferToUrl" );
+
+ Dali::Vector<uint8_t> buffer;
+ buffer.PushBack(0x11);
+ buffer.PushBack(0x22);
+ buffer.PushBack(0x33);
+
+ DALI_TEST_CHECK( Dali::Toolkit::Image::GenerateUrl( EncodedImageBuffer::New(buffer) ).GetUrl().size() > 0u );
+
+ END_TEST;
+}
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/public-api/image-loader/image.h>
+#include <dali-toolkit/public-api/image-loader/image-url.h>
#include <test-native-image.h>
+#include <test-encoded-image-buffer.h>
#include <sstream>
#include <unistd.h>
const std::vector<GLuint>& textures2 = gl.GetBoundTextures();
DALI_TEST_GREATER( textures2.size(), numTextures, TEST_LOCATION );
-
-
END_TEST;
}
END_TEST;
}
+int UtcDaliImageViewAsyncLoadingEncodedBuffer(void)
+{
+ ToolkitTestApplication application;
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ const std::vector<GLuint>& textures = gl.GetBoundTextures();
+ size_t numTextures = textures.size();
+
+ // Get encoded raw-buffer image and generate url
+ EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(gImage_600_RGB);
+ ImageUrl url = Toolkit::Image::GenerateUrl(buffer);
+
+ // Async loading, no atlasing for big size image
+ ImageView imageView = ImageView::New(url.GetUrl());
+
+ // By default, Aysnc loading is used
+ application.GetScene().Add(imageView);
+ imageView.SetProperty( Actor::Property::SIZE, Vector2(100, 100) );
+ imageView.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render(16);
+ application.SendNotification();
+
+ const std::vector<GLuint>& textures2 = gl.GetBoundTextures();
+ DALI_TEST_GREATER( textures2.size(), numTextures, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliImageViewAsyncLoadingEncodedBufferWithAtlasing(void)
+{
+ ToolkitTestApplication application;
+
+ // Get encoded raw-buffer image and generate url
+ EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(gImage_600_RGB);
+ ImageUrl url = Toolkit::Image::GenerateUrl(buffer);
+ ImageUrl url2 = Toolkit::Image::GenerateUrl(buffer);
+
+ // Generate url is not equal to url2
+ // NOTE : This behavior may changed when ImageUrl compare operator changed.
+ DALI_TEST_CHECK(url != url2);
+ // Generate url's string is equal to url2's string
+ DALI_TEST_CHECK(url.GetUrl() == url2.GetUrl());
+
+ EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(gImage_600_RGB);
+ url2 = Toolkit::Image::GenerateUrl(buffer2);
+
+ // Check whethere two url are not equal
+ DALI_TEST_CHECK(url.GetUrl() != url2.GetUrl());
+
+ // Async loading, automatic atlasing for small size image
+ TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+ callStack.Reset();
+ callStack.Enable(true);
+
+ Property::Map imageMap;
+
+ imageMap[ ImageVisual::Property::URL ] = url.GetUrl();
+ imageMap[ ImageVisual::Property::DESIRED_HEIGHT ] = 34;
+ imageMap[ ImageVisual::Property::DESIRED_WIDTH ] = 34;
+ imageMap[ ImageVisual::Property::ATLASING] = true;
+
+ ImageView imageView = ImageView::New();
+ imageView.SetProperty( ImageView::Property::IMAGE, imageMap );
+ imageView.SetProperty( Toolkit::Control::Property::PADDING, Extents( 10u, 10u, 10u, 10u ) );
+
+ // By default, Aysnc loading is used
+ // loading is not started if the actor is offScene
+
+ application.GetScene().Add( imageView );
+ application.SendNotification();
+ application.Render(16);
+ application.Render(16);
+ application.SendNotification();
+
+ // Change url to url2
+ imageMap[ ImageVisual::Property::URL ] = url2.GetUrl();
+ imageView.SetProperty( ImageView::Property::IMAGE, imageMap );
+
+ imageView.SetProperty( Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT );
+ application.SendNotification();
+ application.Render(16);
+ application.Render(16);
+ application.SendNotification();
+
+ // loading started, this waits for the loader thread for max 30 seconds
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render(16);
+
+ callStack.Enable(false);
+
+ TraceCallStack::NamedParams params;
+ params["width"] << 34;
+ params["height"] << 34;
+ DALI_TEST_EQUALS( callStack.FindMethodAndParams( "TexSubImage2D", params ), true, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliImageViewSyncLoadingEncodedBuffer(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline("ImageView Testing sync loading from EncodedImageBuffer");
+
+ // Get encoded raw-buffer image and generate url
+ EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(gImage_34_RGBA);
+ ImageUrl url = Toolkit::Image::GenerateUrl(buffer);
+
+ // Sync loading, automatic atlasing for small size image
+ {
+ TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+ callStack.Reset();
+ callStack.Enable(true);
+
+ ImageView imageView = ImageView::New( );
+
+ // Sync loading is used
+ Property::Map syncLoadingMap;
+ syncLoadingMap[ "url" ] = url.GetUrl();
+ syncLoadingMap[ "desiredHeight" ] = 34;
+ syncLoadingMap[ "desiredWidth" ] = 34;
+ syncLoadingMap[ "synchronousLoading" ] = true;
+ syncLoadingMap[ "atlasing" ] = true;
+ imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap );
+
+ application.GetScene().Add( imageView );
+ application.SendNotification();
+ application.Render(16);
+
+ TraceCallStack::NamedParams params;
+ params["width"] << 34;
+ params["height"] << 34;
+ DALI_TEST_EQUALS( callStack.FindMethodAndParams( "TexSubImage2D", params ),
+ true, TEST_LOCATION );
+ }
+
+ END_TEST;
+}
+
int UtcDaliImageViewAddedTexture(void)
{
ToolkitTestApplication application;
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
#include <dali-toolkit/public-api/image-loader/image.h>
#include <dali-toolkit/public-api/image-loader/image-url.h>
#include <dali-toolkit/dali-toolkit.h>
+
+#include <test-encoded-image-buffer.h>
#include "dummy-control.h"
using namespace Dali;
END_TEST;
}
+int UtcDaliImageVisualWithEncodedImageBuffer(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Use Encoded Image Buffer as url" );
+
+ EncodedImageBuffer rawBuffer = ConvertFileToEncodedImageBuffer(TEST_LARGE_IMAGE_FILE_NAME);
+ ImageUrl url = Dali::Toolkit::Image::GenerateUrl(rawBuffer);
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK( factory );
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, url.GetUrl() );
+
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+ actor.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+ application.GetScene().Add( actor );
+ application.SendNotification();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+ application.GetScene().Remove( actor );
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+ END_TEST;
+}
+
int UtcDaliImageVisualTextureReuse1(void)
{
ToolkitTestApplication application;
#define DALI_TOOLKIT_DEVEL_API_IMAGE_LOADER_ASYNC_IMAGE_LOADER_DEVEL_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#ifndef DALI_TOOLKIT_IMAGE_ATLAS_H
#define DALI_TOOLKIT_IMAGE_ATLAS_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* @param [in] size The width and height to fit the loaded image to.
* @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
* @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
- * @param[in] atlasUploadObserver The observer to observe the upload state inside the ImageAtlas.
+ * @param [in] atlasUploadObserver The observer to observe the upload state inside the ImageAtlas.
* @return True if there is enough space to fit this image in,false otherwise.
* @note The valid callback function here is required to have the signature of void( void ).
*/
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
return textureMgr.AddExternalTexture(textureSet);
}
+std::string AddTexture(const Dali::EncodedImageBuffer& encodedImageBuffer)
+{
+ auto visualFactory = Toolkit::VisualFactory::Get();
+ auto& textureMgr = GetImplementation(visualFactory).GetTextureManager();
+ return textureMgr.AddExternalTexture(encodedImageBuffer);
+}
+
TextureSet RemoveTexture(const std::string& textureUrl)
{
auto visualFactory = Toolkit::VisualFactory::Get();
#define DALI_TOOLKIT_DEVEL_API_TEXTURE_MANAGER_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// EXTERNAL INCLUDES
#include <dali/public-api/rendering/texture-set.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
// INTERNAL INCLUDES
#include <dali-toolkit/public-api/dali-toolkit-common.h>
DALI_TOOLKIT_API std::string AddTexture(TextureSet& textureSet);
/**
+ * @brief Add a EncodedImageBuffer to texture manager
+ * Toolkit keeps the EncodedImageBuffer handle until RemoveTexture is called.
+ * @note this method check for duplicates reference,
+ * if same EncodedImageBuffer is added multiple times, a same URL is returned
+ * @param[in] encodedImageBuffer the image buffer to add
+ * @return the Url string representing this texture
+ */
+DALI_TOOLKIT_API std::string AddTexture(const Dali::EncodedImageBuffer& encodedImageBuffer);
+
+/**
* @brief Removes a TextureSet from toolkit
* @note TextureSet may still be used by visuals and kept alive by them
* @param[in] textureUrl to remove
// EXTERNAL INCLUDES
#include <dali/integration-api/adaptor-framework/adaptor.h>
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+
namespace Dali
{
namespace Toolkit
mLoadThread.Start();
mIsLoadThreadStarted = true;
}
- mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad));
+ if(url.IsBufferResource())
+ {
+ auto visualFactory = Toolkit::VisualFactory::Get();
+ if(visualFactory)
+ {
+ // Get EncodedImageBuffer from texturemanager
+ // and make new LoadingTask with buffer
+ auto& textureManager = GetImplementation(visualFactory).GetTextureManager();
+
+ const EncodedImageBuffer& encodedBuffer = textureManager.GetEncodedImageBuffer(url);
+
+ mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, url, encodedBuffer, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad));
+ }
+ }
+ else
+ {
+ mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad));
+ }
return mLoadTaskId;
}
#include "image-load-thread.h"
// EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/devel-api/adaptor-framework/thread-settings.h>
#include <dali/integration-api/adaptor-framework/adaptor.h>
LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex)
: pixelBuffer(),
url(),
+ encodedImageBuffer(),
id(id),
dimensions(),
fittingMode(),
LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
: pixelBuffer(),
url(url),
+ encodedImageBuffer(),
+ id(id),
+ dimensions(dimensions),
+ fittingMode(fittingMode),
+ samplingMode(samplingMode),
+ orientationCorrection(orientationCorrection),
+ preMultiplyOnLoad(preMultiplyOnLoad),
+ isMaskTask(false),
+ maskPixelBuffer(),
+ contentScale(1.0f),
+ cropToMask(false),
+ animatedImageLoading(),
+ frameIndex(0u)
+{
+}
+
+LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, const EncodedImageBuffer& encodedImageBuffer, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
+: pixelBuffer(),
+ url(url),
+ encodedImageBuffer(encodedImageBuffer),
id(id),
dimensions(dimensions),
fittingMode(fittingMode),
LoadingTask::LoadingTask(uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::PixelBuffer maskPixelBuffer, float contentScale, bool cropToMask, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
: pixelBuffer(pixelBuffer),
url(""),
+ encodedImageBuffer(),
id(id),
dimensions(),
fittingMode(),
{
pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection);
}
+ else if(url.IsBufferResource())
+ {
+ if(encodedImageBuffer)
+ {
+ pixelBuffer = Dali::LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), dimensions, fittingMode, samplingMode, orientationCorrection);
+ }
+ }
else
{
pixelBuffer = Dali::DownloadImageSynchronously(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection);
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/images/image-operations.h>
#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
namespace Dali
{
/**
* Constructor.
* @param [in] id of the task
+ * @param [in] url The URL of the image file to load.
+ * @param [in] encodedImageBuffer The encoded buffer of the image to load.
+ * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image
+ * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+ * @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
+ * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+ * @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+ */
+ LoadingTask(uint32_t id,
+ const VisualUrl& url,
+ const EncodedImageBuffer& encodedImageBuffer,
+ ImageDimensions dimensions,
+ FittingMode::Type fittingMode,
+ SamplingMode::Type samplingMode,
+ bool orientationCorrection,
+ DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+
+ /**
+ * Constructor.
+ * @param [in] id of the task
* @param [in] pixelBuffer of the to be masked image
* @param [in] maskPixelBuffer of the mask image
* @param [in] contentScale The factor to scale the content
Devel::PixelBuffer pixelBuffer; ///< pixelBuffer handle after successful load
///< or pixelBuffer to be masked image in the mask task
VisualUrl url; ///< url of the image to load
+ EncodedImageBuffer encodedImageBuffer; ///< encoded buffer of the image to load
uint32_t id; ///< The unique id associated with this task.
ImageDimensions dimensions; ///< dimensions to load
FittingMode::Type fittingMode; ///< fitting options
mUrl = Dali::Toolkit::TextureManager::AddTexture(texture);
}
+ImageUrl::ImageUrl(const EncodedImageBuffer& encodedImageBuffer)
+: mUrl("")
+{
+ mUrl = Dali::Toolkit::TextureManager::AddTexture(encodedImageBuffer);
+}
+
ImageUrl::~ImageUrl()
{
Dali::Toolkit::TextureManager::RemoveTexture(mUrl);
return imageUrlPtr;
}
+ImageUrlPtr ImageUrl::New(const EncodedImageBuffer& encodedImageBuffer)
+{
+ ImageUrlPtr imageUrlPtr = new ImageUrl(encodedImageBuffer);
+ return imageUrlPtr;
+}
+
const std::string& ImageUrl::GetUrl() const
{
return mUrl;
// EXTERNAL INCLUDES
#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
#include <string>
// INTERNAL INCLUDES
ImageUrl(Texture& texture);
/**
+ * @brief Constructor.
+ */
+ ImageUrl(const EncodedImageBuffer& encodedImageBuffer);
+
+ /**
* @copydoc Dali::Toolkit::ImageUrl::New
*/
static ImageUrlPtr New(Texture& texture);
/**
+ * @copydoc Dali::Toolkit::ImageUrl::New
+ */
+ static ImageUrlPtr New(const EncodedImageBuffer& encodedImageBuffer);
+
+ /**
* @copydoc Dali::Toolkit::ImageUrl::GetUrl
*/
const std::string& GetUrl() const;
bool ImageVisual::AttemptAtlasing()
{
- return (!mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL && mAttemptAtlasing);
+ return (!mImpl->mCustomShader && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()) && mAttemptAtlasing);
}
void ImageVisual::InitializeRenderer()
TextureManager& textureManager = mFactoryCache.GetTextureManager();
bool synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
- if(mId == NPatchData::INVALID_NPATCH_DATA_ID && mImageUrl.IsLocalResource())
+ if(mId == NPatchData::INVALID_NPATCH_DATA_ID && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()))
{
bool preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? true : false;
mId = mLoader.Load(textureManager, this, mImageUrl.GetUrl(), mBorder, preMultiplyOnLoad, synchronousLoading);
}
}
- if(!mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && mAuxiliaryUrl.IsLocalResource())
+ if(!mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && (mAuxiliaryUrl.IsLocalResource() || mAuxiliaryUrl.IsBufferResource()))
{
// Load the auxiliary image
auto preMultiplyOnLoading = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
{
if(url.IsValid())
{
- pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ if(url.IsBufferResource())
+ {
+ const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url);
+ if(encodedImageBuffer)
+ {
+ pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ }
+ }
+ else
+ {
+ pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ }
if(pixelBuffer && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
{
PreMultiply(pixelBuffer, preMultiplyOnLoad);
PixelData data;
if(url.IsValid())
{
- Devel::PixelBuffer pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ Devel::PixelBuffer pixelBuffer;
+ if(url.IsBufferResource())
+ {
+ const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url);
+ if(encodedImageBuffer)
+ {
+ pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ }
+ }
+ else
+ {
+ pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection);
+ }
if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
{
Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true);
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
}
+ // Check if the requested Texture exist in Encoded Buffer
+ // This mean, that buffer is not cached, and need to be decoded.
+ if(textureId == INVALID_TEXTURE_ID && VisualUrl::BUFFER == url.GetProtocolType())
+ {
+ std::string location = url.GetLocation();
+ if(location.size() > 0u)
+ {
+ TextureId targetId = std::stoi(location);
+ const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(targetId);
+ if(encodedImageBuffer)
+ {
+ textureId = targetId;
+ // Insert this buffer at mTextureInfoContainer.
+ // This buffer will decode at ImageLoaderThread.
+ bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
+ mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex));
+ cacheIndex = mTextureInfoContainer.size() - 1u;
+
+ DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New buffered texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
+ }
+ }
+ }
+
if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required
{
// We need a new Texture.
textureId = GenerateUniqueTextureId();
bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
- mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url.GetUrl(), desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex));
+ mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex));
cacheIndex = mTextureInfoContainer.size() - 1u;
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId);
return textureSet;
}
+EncodedImageBuffer TextureManager::GetEncodedImageBuffer(TextureId textureId)
+{
+ EncodedImageBuffer encodedImageBuffer; // empty handle
+ for(auto&& elem : mEncodedBufferTextures)
+ {
+ if(elem.textureId == textureId)
+ {
+ encodedImageBuffer = elem.encodedImageBuffer;
+ break;
+ }
+ }
+ return encodedImageBuffer;
+}
+
+EncodedImageBuffer TextureManager::GetEncodedImageBuffer(const VisualUrl& url)
+{
+ EncodedImageBuffer encodedImageBuffer; // empty handle
+ if(url.IsValid() && url.IsBufferResource())
+ {
+ std::string location = url.GetLocation();
+ if(location.size() > 0u)
+ {
+ TextureId targetId = std::stoi(location);
+ return GetEncodedImageBuffer(targetId);
+ }
+ }
+ return encodedImageBuffer;
+}
+
std::string TextureManager::AddExternalTexture(TextureSet& textureSet)
{
TextureManager::ExternalTextureInfo info;
return VisualUrl::CreateTextureUrl(std::to_string(info.textureId));
}
+std::string TextureManager::AddExternalTexture(const EncodedImageBuffer& encodedImageBuffer)
+{
+ // Duplication check
+ for(auto&& elem : mEncodedBufferTextures)
+ {
+ if(elem.encodedImageBuffer == encodedImageBuffer)
+ {
+ // If same buffer added, increase reference count and return.
+ elem.referenceCount++;
+ return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId));;
+ }
+ }
+ TextureManager::EncodedBufferTextureInfo info(GenerateUniqueTextureId(), encodedImageBuffer);
+ mEncodedBufferTextures.emplace_back(info);
+ return VisualUrl::CreateBufferUrl(std::to_string(info.textureId));
+}
+
TextureSet TextureManager::RemoveExternalTexture(const std::string& url)
{
if(url.size() > 0u)
}
}
}
+ else if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(url))
+ {
+ std::string location = VisualUrl::GetLocation(url);
+ if(location.size() > 0u)
+ {
+ TextureId id = std::stoi(location);
+ const auto end = mEncodedBufferTextures.end();
+ for(auto iter = mEncodedBufferTextures.begin(); iter != end; ++iter)
+ {
+ if(iter->textureId == id)
+ {
+ if(--(iter->referenceCount) <= 0)
+ {
+ mEncodedBufferTextures.erase(iter);
+ }
+ // It doesn't have texture set.
+ return TextureSet();
+ }
+ }
+ }
+ }
}
return TextureSet();
}
}
}
}
+ else if(VisualUrl::BUFFER == url.GetProtocolType())
+ {
+ std::string location = url.GetLocation();
+ if(location.size() > 0u)
+ {
+ TextureId id = std::stoi(location);
+ for(auto&& elem : mEncodedBufferTextures)
+ {
+ if(elem.textureId == id)
+ {
+ elem.referenceCount++;
+ return;
+ }
+ }
+ }
+ }
}
void TextureManager::AddObserver(TextureManager::LifecycleObserver& observer)
textureInfo.loadState = LoadState::LOADING;
if(!textureInfo.loadSynchronously)
{
- auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
+ auto& loadersContainer = (textureInfo.url.IsLocalResource() || textureInfo.url.IsBufferResource()) ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
auto loadingHelperIt = loadersContainer.GetNext();
auto premultiplyOnLoad = (textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID) ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::ApplyMask(): url:%s sync:%s\n", textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously ? "T" : "F");
textureInfo.loadState = LoadState::MASK_APPLYING;
- auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
+ auto& loadersContainer = (textureInfo.url.IsLocalResource() || textureInfo.url.IsBufferResource()) ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
auto loadingHelperIt = loadersContainer.GetNext();
auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
// EXTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
#include <dali/devel-api/common/owner-container.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/object/ref-object.h>
#include <dali/public-api/rendering/geometry.h>
TextureSet GetTextureSet(TextureId textureId);
/**
+ * @brief Get the encoded image buffer
+ * @param[in] textureId The textureId to look up
+ * @return the encoded image buffer, or an empty handle if textureId is not valid
+ */
+ EncodedImageBuffer GetEncodedImageBuffer(TextureId textureId);
+
+ /**
+ * @brief Get the encoded image buffer by VisualUrl
+ * @param[in] url The url to look up
+ * @return the encoded image buffer, or an empty handle if url is not buffer resource or buffer is not valid
+ */
+ EncodedImageBuffer GetEncodedImageBuffer(const VisualUrl& url);
+
+ /**
* Adds an external texture to the texture manager
* @param[in] texture The texture to add
* @return string containing the URL for the texture
std::string AddExternalTexture(TextureSet& texture);
/**
- * Removes an external texture from texture manager
+ * Adds an external encoded image buffer to the texture manager
+ * @param[in] encodedImageBuffer The image buffer to add
+ * @return string containing the URL for the texture
+ */
+ std::string AddExternalTexture(const EncodedImageBuffer& encodedImageBuffer);
+
+ /**
+ * Removes an external texture or external encoded image buffer from texture manager
* @param[in] url The string containing the texture to remove
* @return handle to the texture
*/
TextureSet RemoveExternalTexture(const std::string& url);
/**
- * @brief Notify that external textures are used.
+ * @brief Notify that external textures or external encoded image buffers are used.
* @param[in] url The URL of the texture to use.
*/
void UseExternalTexture(const VisualUrl& url);
int16_t referenceCount{1};
};
+ struct EncodedBufferTextureInfo
+ {
+ EncodedBufferTextureInfo(TextureId textureId,
+ const EncodedImageBuffer& encodedImageBuffer)
+ : textureId(textureId),
+ encodedImageBuffer(encodedImageBuffer),
+ referenceCount(1u)
+ {
+ }
+ TextureId textureId;
+ EncodedImageBuffer encodedImageBuffer;
+ int16_t referenceCount;
+ };
+
private:
/**
* Deleted copy constructor.
*/
void ObserverDestroyed(TextureUploadObserver* observer);
-private: // Member Variables:
- TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
- RoundRobinContainerView<AsyncLoadingHelper> mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads
- RoundRobinContainerView<AsyncLoadingHelper> mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
- std::vector<ExternalTextureInfo> mExternalTextures; ///< Externally provided textures
- Dali::Vector<LifecycleObserver*> mLifecycleObservers; ///< Lifecycle observers of texture manager
- Dali::Vector<LoadQueueElement> mLoadQueue; ///< Queue of textures to load after NotifyObservers
- TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
- bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued.
+private: // Member Variables:
+ TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
+ RoundRobinContainerView<AsyncLoadingHelper> mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads
+ RoundRobinContainerView<AsyncLoadingHelper> mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
+ std::vector<ExternalTextureInfo> mExternalTextures; ///< Externally provided textures
+ std::vector<EncodedBufferTextureInfo> mEncodedBufferTextures; ///< Externally encoded buffer textures
+ Dali::Vector<LifecycleObserver*> mLifecycleObservers; ///< Lifecycle observers of texture manager
+ Dali::Vector<LoadQueueElement> mLoadQueue; ///< Queue of textures to load after NotifyObservers
+ TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
+ bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued.
};
} // namespace Internal
const uint32_t length = url.size();
if((length > 7) && urlCStr[5] == ':' && urlCStr[6] == '/' && urlCStr[7] == '/')
{
- // https://
- if(('h' == tolower(urlCStr[0])) &&
- ('t' == tolower(urlCStr[1])) &&
- ('t' == tolower(urlCStr[2])) &&
- ('p' == tolower(urlCStr[3])) &&
- ('s' == tolower(urlCStr[4])))
+ // https:// or enbuf://
+ const char hOre = tolower(urlCStr[0]);
+ const char tOrn = tolower(urlCStr[1]);
+ const char tOrb = tolower(urlCStr[2]);
+ const char pOru = tolower(urlCStr[3]);
+ const char sOrf = tolower(urlCStr[4]);
+ if(('h' == hOre) &&
+ ('t' == tOrn) &&
+ ('t' == tOrb) &&
+ ('p' == pOru) &&
+ ('s' == sOrf))
{
return VisualUrl::REMOTE;
}
+ if(('e' == hOre) &&
+ ('n' == tOrn) &&
+ ('b' == tOrb) &&
+ ('u' == pOru) &&
+ ('f' == sOrf))
+ {
+ return VisualUrl::BUFFER;
+ }
}
else if((length > 6) && urlCStr[4] == ':' && urlCStr[5] == '/' && urlCStr[6] == '/')
{
else if((length > 5) && urlCStr[3] == ':' && urlCStr[4] == '/' && urlCStr[5] == '/')
{
// ftp:// or ssh://
- const char fOrS = tolower(urlCStr[0]);
- if(('f' == fOrS) || ('s' == fOrS))
+ const char fOrs = tolower(urlCStr[0]);
+ const char tOrs = tolower(urlCStr[1]);
+ const char pOrh = tolower(urlCStr[2]);
+ if(('f' == fOrs) &&
+ ('t' == tOrs) &&
+ ('p' == pOrh))
{
- const char tOrs = tolower(urlCStr[1]);
- if(('t' == tOrs) || ('s' == tOrs))
- {
- const char pOrh = tolower(urlCStr[2]);
- if(('p' == pOrh) || ('h' == pOrh))
- {
- return VisualUrl::REMOTE;
- }
- }
+ return VisualUrl::REMOTE;
+ }
+ if(('s' == fOrs) &&
+ ('s' == tOrs) &&
+ ('h' == pOrh))
+ {
+ return VisualUrl::REMOTE;
}
}
return VisualUrl::LOCAL;
if(!url.empty())
{
mLocation = ResolveLocation(url);
- if(VisualUrl::TEXTURE != mLocation)
+ if(VisualUrl::TEXTURE != mLocation && VisualUrl::BUFFER != mLocation)
{
- // TEXTURE location url doesn't need type resolving, REGULAR_IMAGE is fine
+ // TEXTURE and BUFFER location url doesn't need type resolving, REGULAR_IMAGE is fine
mType = ResolveType(url);
}
else
mType(url.mType),
mLocation(url.mLocation)
{
- if(VisualUrl::TEXTURE == mLocation)
+ if(VisualUrl::TEXTURE == mLocation || VisualUrl::BUFFER == mLocation)
{
Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
if(factory)
VisualUrl::~VisualUrl()
{
- if(VisualUrl::TEXTURE == mLocation)
+ if(VisualUrl::TEXTURE == mLocation || VisualUrl::BUFFER == mLocation)
{
Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
if(factory)
{
if(&url != this)
{
- if(VisualUrl::TEXTURE == mLocation)
+ if(VisualUrl::TEXTURE == mLocation || VisualUrl::BUFFER == mLocation)
{
Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
if(factory)
mType = url.mType;
mLocation = url.mLocation;
- if(VisualUrl::TEXTURE == mLocation)
+ if(VisualUrl::TEXTURE == mLocation || VisualUrl::BUFFER == mLocation)
{
Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
if(factory)
return mLocation == VisualUrl::LOCAL;
}
+bool VisualUrl::IsBufferResource() const
+{
+ return mLocation == VisualUrl::BUFFER;
+}
+
std::string VisualUrl::GetLocation() const
{
return GetLocation(mUrl);
return "dali://" + location;
}
+std::string VisualUrl::CreateBufferUrl(const std::string& location)
+{
+ return "enbuf://" + location;
+}
+
VisualUrl::ProtocolType VisualUrl::GetProtocolType(const std::string& url)
{
return ResolveLocation(url);
return url;
}
-
} // namespace Internal
} // namespace Toolkit
{
LOCAL, ///< file in local file system
TEXTURE, ///< texture uploaded to texture manager
- REMOTE ///< remote image
+ REMOTE, ///< remote image
+ BUFFER ///< encoded image buffer
};
/**
bool IsLocalResource() const;
/**
+ * @return true if the location is BUFFER, i.e. may contain EncodedImageBuffer
+ */
+ bool IsBufferResource() const;
+
+ /**
* @return the location part of the url
*/
std::string GetLocation() const;
static std::string CreateTextureUrl(const std::string& location);
/**
+ * Helper to create a URL of type BUFFER
+ * @param location the location of the texture
+ * @return the Url
+ */
+ static std::string CreateBufferUrl(const std::string& location);
+
+ /**
* Helper to get a ProtocolType from url
* @param url the url of the texture
* @return the protocol type
* @return the location
*/
static std::string GetLocation(const std::string& url);
+
private:
std::string mUrl;
Type mType;
return ImageUrl(internal.Get());
}
+ImageUrl ImageUrl::New(const EncodedImageBuffer& encodedImageBuffer)
+{
+ Toolkit::Internal::ImageUrlPtr internal = Toolkit::Internal::ImageUrl::New(encodedImageBuffer);
+ return ImageUrl(internal.Get());
+}
+
ImageUrl ImageUrl::DownCast(BaseHandle handle)
{
return ImageUrl(dynamic_cast<Toolkit::Internal::ImageUrl*>(handle.GetObjectPtr()));
// EXTERNAL INCLUDES
#include <string>
#include <dali/public-api/rendering/texture.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
// INTERNAL INCLUDES
#include <dali-toolkit/public-api/dali-toolkit-common.h>
static ImageUrl New(Texture& texture);
/**
+ * @brief Create an initialized ImageUrl.
+ *
+ * @param[in] encodedImageBuffer The encoded image buffer url is got from external buffer.
+ * @return A handle to a newly allocated Dali resource.
+ */
+ static ImageUrl New(const EncodedImageBuffer& encodedImageBuffer);
+
+ /**
* @brief Downcast an Object handle to ImageUrl handle.
*
* If handle points to a ImageUrl object the downcast produces valid
return imageUrl;
}
+Dali::Toolkit::ImageUrl GenerateUrl(const Dali::EncodedImageBuffer encodedImageBuffer)
+{
+ return Dali::Toolkit::ImageUrl::New(encodedImageBuffer);
+}
+
} // namespace Image
} // namespace Toolkit
// EXTERNAL INCLUDES
#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
#include <dali/public-api/images/pixel-data.h>
#include <dali/public-api/rendering/frame-buffer.h>
*/
DALI_TOOLKIT_API Dali::Toolkit::ImageUrl GenerateUrl(const Dali::NativeImageSourcePtr nativeImageSource);
+/**
+ * @brief Generate a Url from encoded image buffer.
+ * This Url can be used in visuals to render the image.
+ * @note This method does not check for duplicates, If same encoded image buffer is entered multiple times, a different URL is returned each time.
+ * @param[in] encodedImageBuffer the encoded image buffer to converted to Url
+ * @return the ImageUrl representing this encoded image buffer
+ */
+DALI_TOOLKIT_API Dali::Toolkit::ImageUrl GenerateUrl(const Dali::EncodedImageBuffer encodedImageBuffer);
+
} // namespace Image
} // namespace Toolkit