<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Sascha – IMG.LY Blog</title><description>Posts by Sascha on the IMG.LY blog.</description><link>https://img.ly/blog/author/sascha/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Sascha – IMG.LY Blog</title><link>https://img.ly/blog/author/sascha/</link></image><atom:link href="https://img.ly/blog/author/sascha/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Wed, 24 Jun 2026 09:29:32 GMT</lastBuildDate><ttl>60</ttl><item><title>How to Load Stripe Data into Google BigQuery</title><link>https://img.ly/blog/how-to-load-stripe-data-into-google-bigquery/</link><guid isPermaLink="true">https://img.ly/blog/how-to-load-stripe-data-into-google-bigquery/</guid><description>Discover how IMG.LY leverages Stripe&apos;s Data Pipeline to seamlessly transfer data into Google BigQuery using Google Cloud Functions.</description><pubDate>Thu, 18 Jul 2024 10:04:26 GMT</pubDate><content:encoded>&lt;p&gt;At IMG.LY, we recognize that leveraging data is essential for driving innovation and growth. To optimize our data for reporting, we consolidate multiple data sources, including Stripe billing and financial data, into Google BigQuery.&lt;/p&gt;
&lt;p&gt;IMG.LY is the leading provider of creative editing SDKs for &lt;a href=&quot;https://img.ly/products/video-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=stripebigquery&quot;&gt;video&lt;/a&gt;, &lt;a href=&quot;https://img.ly/products/photo-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=stripebigquery&quot;&gt;photo&lt;/a&gt;, and &lt;a href=&quot;https://img.ly/products/creative-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=stripebigquery&quot;&gt;design templates&lt;/a&gt;. While this article may not directly relate to media creation, we believe in empowering developers through knowledge sharing. Let’s dive in.&lt;/p&gt;
&lt;p&gt;Until now, we’ve relied on &lt;a href=&quot;https://www.fivetran.com&quot;&gt;Fivetran&lt;/a&gt; to fetch our data from Stripe and store it in Google BigQuery. Fivetran uses Stripe’s API, calling each endpoint, iterating over all resources, and storing the results in BigQuery (or any other supported data warehouse). While this generally works well, issues can arise. For instance, we sometimes create Stripe Subscriptions using inline pricing with &lt;a href=&quot;https://docs.stripe.com/api/subscription_items/create#create_subscription_item-price_data&quot;&gt;the &lt;code&gt;price_data&lt;/code&gt; parameter&lt;/a&gt;. This generates a new &lt;code&gt;Price&lt;/code&gt; object in Stripe on-the-fly and immediately sets it to &lt;code&gt;active: false&lt;/code&gt;. Consequently, the &lt;code&gt;Price&lt;/code&gt; object is not returned by Stripe API’s price endpoint, leading to missing data in our warehouse. Although Fivetran’s support was exceptional in resolving this issue within a day, it highlighted a potential flaw in relying solely on ETL services for data extraction.&lt;/p&gt;
&lt;p&gt;Recently, Stripe introduced &lt;a href=&quot;https://stripe.com/data-pipeline&quot;&gt;Data Pipeline&lt;/a&gt;, its own service for transferring Stripe data into a data warehouse. This ensures complete, reliable data without needing a third-party service to read Stripe’s API. Additionally, you can receive test environment data and access several tables not available via the API. For a comprehensive summary of the available data, &lt;a href=&quot;https://dashboard.stripe.com/stripe-schema&quot;&gt;refer to Stripe’s official data schema&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Currently, Stripe supports only Snowflake and Amazon Redshift as data warehouses. However, they’ve recently added the option to &lt;a href=&quot;https://docs.stripe.com/stripe-data/access-data-in-warehouse/cloud-storage/google-cloud-storage&quot;&gt;deliver data as Parquet files into Google Cloud Storage (GCS)&lt;/a&gt;. The next step for us was to import this data into Google BigQuery.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-stripe-data-pipeline-with-google-cloud-storage&quot;&gt;Setting Up Stripe Data Pipeline with Google Cloud Storage&lt;/h2&gt;
&lt;p&gt;Stripe is renowned for its excellent developer experience, and this beta feature is no exception. Enabling it within the Stripe Dashboard is quick, and the &lt;a href=&quot;https://docs.stripe.com/stripe-data/access-data-in-warehouse/cloud-storage/google-cloud-storage&quot;&gt;documentation&lt;/a&gt; is straightforward. After following the instructions and enabling the feature, it takes a while for data to appear in GCS. Once available, a complete data dump is provided every 6 hours, structured as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At the root level, Stripe creates a folder representing the date and time of the latest transfer, e.g., &lt;code&gt;2024071600&lt;/code&gt; (&lt;code&gt;YYYYMMDDHH&lt;/code&gt;), representing the 12 am push on July 16, 2024.&lt;/li&gt;
&lt;li&gt;One level deeper, there are two folders: &lt;code&gt;livemode&lt;/code&gt; and &lt;code&gt;testmode&lt;/code&gt;, representing live and test data, respectively.&lt;/li&gt;
&lt;li&gt;Each folder contains one folder per data table, e.g., &lt;code&gt;subscriptions&lt;/code&gt; or &lt;code&gt;invoices&lt;/code&gt;. Additionally, a &lt;code&gt;coreapi_SUCCESS&lt;/code&gt; file indicates successful data transfer to your GCS bucket and readiness for consumption.&lt;/li&gt;
&lt;li&gt;Within the table folders are several Parquet files containing the actual data for each table.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;loading-the-data-from-google-cloud-storage-into-google-bigquery&quot;&gt;Loading the Data from Google Cloud Storage into Google BigQuery&lt;/h2&gt;
&lt;p&gt;There are multiple ways to transfer data from GCS to BigQuery. We opted for the following approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using Google Cloud Scheduler to publish a message to Google Pub/Sub every 6 hours at 1 am, 7 am, 1 pm, and 7 pm.&lt;/li&gt;
&lt;li&gt;Creating a Google Cloud Function that listens for new messages on the above Pub/Sub topic. When a message is received, it triggers a Node.js script that loads the most recent data from GCS into BigQuery and deletes it from GCS.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let’s delve into the details.&lt;/p&gt;
&lt;h3 id=&quot;create-a-google-cloud-scheduler-job&quot;&gt;Create a Google Cloud Scheduler Job&lt;/h3&gt;
&lt;p&gt;First, create a new Cloud Scheduler job &lt;a href=&quot;https://console.cloud.google.com/cloudscheduler/jobs/new&quot;&gt;here&lt;/a&gt; with the following configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: Choose a name for this job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Region&lt;/strong&gt;: The region is not crucial for this task; we used &lt;code&gt;europe-west3&lt;/code&gt; since most of our services are in Germany.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frequency&lt;/strong&gt;: We want the job to run every 6 hours at 1 am, 7 am, 1 pm, and 7 pm. Stripe publishes data every 6 hours, but it takes time to transfer it to GCS. We chose 1 hour later than Stripe’s push time, so our value is &lt;code&gt;0 1,7,13,19 * * *&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timezone&lt;/strong&gt;: Choose ‘Coordinated Universal Time (UTC)’.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target type&lt;/strong&gt;: Choose ‘Pub/Sub’.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Select a Cloud Pub/Sub topic&lt;/strong&gt;: Select or create a new Pub/Sub topic using the default configuration. This is used to trigger the Cloud Function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message body&lt;/strong&gt;: For this task, we don’t look at the contents of the message, as such the content of this value doesn’t matter. We opted for a simple &lt;code&gt;load&lt;/code&gt; string.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 566px) 566px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;566&quot; height=&quot;1240&quot; src=&quot;https://img.ly/_astro/Screenshot-2024-07-16-at-11.46.22_1dcdSQ.webp&quot; srcset=&quot;/_astro/Screenshot-2024-07-16-at-11.46.22_1dcdSQ.webp 566w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finally, click ‘Create’ to set up the scheduler. Now, a message is published to the selected Pub/Sub topic every 6 hours. Next, we need to respond to this message.&lt;/p&gt;
&lt;h3 id=&quot;create-a-google-cloud-function&quot;&gt;Create a Google Cloud Function&lt;/h3&gt;
&lt;p&gt;Create a Google Cloud Function triggered by Pub/Sub &lt;a href=&quot;https://console.cloud.google.com/functions/add&quot;&gt;here&lt;/a&gt; with the following configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Environment&lt;/strong&gt;: Choose ‘2nd gen’.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Function name&lt;/strong&gt;: Choose a name for this Cloud function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Region&lt;/strong&gt;: Select the region for the function, typically europe-west3 for our services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trigger type&lt;/strong&gt;: Choose ‘Cloud Pub/Sub’.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud Pub/Sub topic&lt;/strong&gt;: Select the Pub/Sub topic created in the previous step.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adjust the ‘Runtime, build, connections and security settings’ based on your Cloud setup and the required processing power for Stripe data. Generally, the following settings work well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory allocated&lt;/strong&gt;: ‘512 MiB’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;: ‘1’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeout&lt;/strong&gt;: ‘540’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimum number of instances&lt;/strong&gt;: ‘0’ (to ensure the function shuts down when not in use)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maximum number of instances&lt;/strong&gt;: ‘1’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service account&lt;/strong&gt;: Use or create a service account with permissions to access the GCS bucket where Stripe data is stored and the BigQuery datasets to load the data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingress settings&lt;/strong&gt;: Choose ‘Allow internal traffic only’.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 554px) 554px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;554&quot; height=&quot;1286&quot; src=&quot;https://img.ly/_astro/Screenshot-2024-07-16-at-11.56.55_1Iq5S7.webp&quot; srcset=&quot;/_astro/Screenshot-2024-07-16-at-11.56.55_1Iq5S7.webp 554w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Click ‘Next’ to provide the function’s code. Select:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Runtime&lt;/strong&gt;: ‘Node.js 20’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source code&lt;/strong&gt;: ‘Inline Editor’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entry point&lt;/strong&gt;: &lt;code&gt;loadStripeData&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the &lt;code&gt;package.json&lt;/code&gt;, add the BigQuery and Cloud Storage Node.js packages:&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;index.js&lt;/code&gt;, add the following code:&lt;/p&gt;

&lt;p&gt;This script does the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For each environment (live and test), it searches for the latest folder containing a &lt;code&gt;coreapi_SUCCESS&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;For each table, it groups all related Parquet files and loads them into the BigQuery table using &lt;code&gt;WRITE_TRUNCATE&lt;/code&gt;, which overwrites existing data. Note that the location is specified as &lt;code&gt;EU&lt;/code&gt;, matching our BigQuery dataset and GCS bucket location. Adjust this parameter if your data is elsewhere.&lt;/li&gt;
&lt;li&gt;If all files for an environment are loaded without errors, the files are deleted from GCS. This step is optional; if you prefer to keep a backup, you can omit this part.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Click ‘Deploy’ to deploy your Cloud function.&lt;/p&gt;
&lt;h3 id=&quot;create-bigquery-datasets&quot;&gt;Create BigQuery Datasets&lt;/h3&gt;
&lt;p&gt;The final step is to create two datasets in Google BigQuery. Open &lt;a href=&quot;https://console.cloud.google.com/bigquery&quot;&gt;Google BigQuery&lt;/a&gt;, click on the three dots next to your project’s name, and select ‘Create dataset’. Enter a name and choose a location matching your GCS bucket’s location. Repeat this process for the test dataset.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Following these steps will ensure your Stripe data is imported into BigQuery and automatically updated every 6 hours. However, as Data Pipeline for GCS is still in beta, there are some limitations. For example, the schema of the Parquet files lacks type annotations for timestamps, so all timestamps in BigQuery are represented as &lt;code&gt;INTEGER&lt;/code&gt; instead of &lt;code&gt;TIMESTAMP&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, some tables, such as &lt;code&gt;subscription_item_change_events&lt;/code&gt;, are not currently transferred when syncing with Google Cloud Storage, although this issue is expected to be resolved soon. Meanwhile, we continue to use Fivetran in conjunction with the above method to sync Stripe data to Google BigQuery and plan to fully migrate to Data Pipeline once it exits the beta phase.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3,000+ creative professionals gain exclusive access and hear of our releases first—&lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;subscribe&lt;/a&gt; to our newsletter and never miss out.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Sascha</dc:creator><media:content url="https://blog.img.ly/2024/07/stripe-bigquery-how-to.jpg" medium="image"/><category>How-To</category><category>Business Intelligence</category><category>Data</category><category>Cloud</category><category>Insights</category></item><item><title>PE.SDK and VE.SDK 10 for Android and 11 for iOS Release</title><link>https://img.ly/blog/photo-editor-video-editor-sdk-v_10-11-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/photo-editor-video-editor-sdk-v_10-11-release-notes/</guid><description>This major update brings Background Removal and more to PhotoEditor SDK and VideoEditor SDK.</description><pubDate>Wed, 04 May 2022 12:46:21 GMT</pubDate><content:encoded>&lt;p&gt;We are thrilled to announce the release of PhotoEditor SDK and VideoEditor SDK 10 for Android and 11 for iOS. This new major version is packed with features and improvements.&lt;/p&gt;
&lt;p&gt;This release is adding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom Watermarks&lt;/li&gt;
&lt;li&gt;Background Removal for Photos&lt;/li&gt;
&lt;li&gt;Background Removal for Stickers&lt;/li&gt;
&lt;li&gt;Custom Sticker Libraries&lt;/li&gt;
&lt;li&gt;Giphy Integration&lt;/li&gt;
&lt;li&gt;And More Updates for Android and iOS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;custom-watermarks&quot;&gt;Custom Watermarks&lt;/h2&gt;
&lt;p&gt;With our new support for custom watermarks, you can add your company logo or any other image to photo and video exports. You can place your watermark in either corner or the center of your photo and video. Additionally, you can specify the size of the watermark and determine its distance from the outline if you choose to place it near a corner. Your users will not be able to remove nor modify the watermark.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Set your Custom Watermark for all exports.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/watermark-video-editor-custom-sdk_Z12Y3l4.webp&quot; srcset=&quot;/_astro/watermark-video-editor-custom-sdk_Z12Y3l4.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;For more details on Custom Watermarks, take a look at our documentation for &lt;a href=&quot;https://img.ly/docs/pesdk/android/customization/watermark/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Android&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/customization/watermark/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background-removal-for-photos&quot;&gt;Background Removal for Photos&lt;/h2&gt;
&lt;p&gt;You have unwaveringly requested this feature: we are excited to offer the automatic removal of backgrounds for static content! Background Removal is fully running &lt;strong&gt;on-device&lt;/strong&gt; and currently specializes in images containing a person only. PE.SDK enables this feature exclusively when it detects a person in the photo.&lt;/p&gt;
&lt;p&gt;The removed background will turn transparent if your selected output supports transparency, such as PNG. In other cases, such as JPG, your background removal will be tinted black.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Integrate Background Removal into your application.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-1_2jocg8.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-1_2jocg8.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on Android and iOS 15.0 and higher only. Easily enable Background Removal for Photos with our &lt;a href=&quot;https://img.ly/docs/pesdk/android/features/background_removal/&quot;&gt;Android guide&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/background_removal/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background-removal-for-stickers&quot;&gt;Background Removal for Stickers&lt;/h2&gt;
&lt;p&gt;A more common use case for automatic background removal is with stickers, so we’ve also added this functionality. Select a sticker including a person and tap the &lt;em&gt;Remove BG&lt;/em&gt; button. Simple!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Let your users create beautiful visuals with Sticker Background Removal.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-video_2nmAzB.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-video_2nmAzB.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on Android and iOS 15.0 and higher only. Easily enable Background Removal for Stickers with our &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;Android documentation&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;iOS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;custom-sticker-libraries&quot;&gt;Custom Sticker Libraries&lt;/h2&gt;
&lt;p&gt;We wanted to make it easier for you to provide your users with more sticker tool content. So far, you were able to create multiple sticker categories with different stickers that could either be part of your app or stored on a server. Additionally, you could &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#personal-stickers&quot;&gt;enable our personal stickers feature on iOS&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#personal-stickers&quot;&gt;Android&lt;/a&gt;), giving your users the option to select stickers from their camera roll.&lt;/p&gt;
&lt;p&gt;We have now added more ways to provide your users with stickers.&lt;/p&gt;
&lt;h3 id=&quot;android&quot;&gt;Android&lt;/h3&gt;
&lt;p&gt;You can now create sticker categories that do not present our sticker selection interface, but will instead load any arbitrary Fragment. That gives you complete control over the sticker selection screen, and you can use it to load and display any content. When the user selects any of your stickers, all you have to do is pass it back to the SDK with a callback. Get started with your &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#adding-custom-stickers&quot;&gt;Custom Sticker Library with our Android documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;ios&quot;&gt;iOS&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;You can now create sticker categories that do not present our sticker selection interface, but will instead load any arbitrary view controller that conforms to the &lt;code&gt;StickerCollection&lt;/code&gt; protocol. That gives you complete control over the sticker selection screen, and you can use it to load and display any content. When the user selects any of your stickers, simply pass it back to the SDK using a delegate method.&lt;/li&gt;
&lt;li&gt;Additionally, we’ve created a new &lt;code&gt;StickerProviderCategory&lt;/code&gt; that you can pass any object conforming to the &lt;code&gt;StickerProvider&lt;/code&gt; protocol. This category provides most of the features required to interact with sticker content providers, such as search and pagination. You can use this category to very quickly integrate any sticker service.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Find more information on &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#custom-sticker-view-controller&quot;&gt;Custom Sticker Libraries in the iOS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;giphy-integration&quot;&gt;GIPHY Integration&lt;/h2&gt;
&lt;p&gt;This online database and search engine for funny GIFs and beautiful animations is a staple in many social applications. Easily integrate GIPHY into your app:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/integrate-giphy-video-editor-photo-sdk_ZNfYn8.webp&quot; srcset=&quot;/_astro/integrate-giphy-video-editor-photo-sdk_ZNfYn8.webp 277w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;android-1&quot;&gt;Android&lt;/h3&gt;
&lt;p&gt;Using our new Custom Sticker Library, we’ve also created an integration for GIPHY on Android. All you have to do is head over to &lt;a href=&quot;https://developers.giphy.com&quot;&gt;GIPHY&lt;/a&gt;, create your API key, pass it to your &lt;code&gt;GiphySettings&lt;/code&gt; and create a &lt;code&gt;GiphyStickerCategoryItem&lt;/code&gt;. Your users will then immediately have access to all the content GIPHY has to offer.&lt;/p&gt;
&lt;p&gt;For more details, visit our &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#adding-giphy&quot;&gt;documentation on adding GIPHY&lt;/a&gt; for Android.&lt;/p&gt;
&lt;h3 id=&quot;ios-1&quot;&gt;iOS&lt;/h3&gt;
&lt;p&gt;Using the new &lt;code&gt;StickerProviderCategory&lt;/code&gt;, we added GIPHY support on iOS. All you have to do is head over to &lt;a href=&quot;https://developers.giphy.com&quot;&gt;GIPHY&lt;/a&gt;, create your API key, and pass this to the GIPHY sticker category. Your users will then immediately have access to all the content GIPHY has to offer.&lt;/p&gt;
&lt;p&gt;For more details, visit our documentation &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#giphy&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;more-updates-for-android&quot;&gt;More Updates for Android&lt;/h2&gt;
&lt;p&gt;Additionally, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increased the minimum API level for PhotoEditor SDK from 16 (Android 4) to 21 (Android 5), which ensures support for 98% of all phones in use.&lt;/li&gt;
&lt;li&gt;Added support for headless video exporting.&lt;/li&gt;
&lt;li&gt;Increased video playback stability.&lt;/li&gt;
&lt;li&gt;Fixed a number of issues with degraded audio quality in videos.&lt;/li&gt;
&lt;li&gt;And added the ability to choose a theme at runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;more-updates-for-ios&quot;&gt;More Updates for iOS&lt;/h2&gt;
&lt;p&gt;Additionally, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increased our deployment target from iOS 9 to iOS 13.&lt;/li&gt;
&lt;li&gt;Migrated all usage of OpenGL to Metal.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/ios/introduction/migration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Added a better result API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/ios/introduction/getting_started/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#swiftui&quot;&gt;Added support for SwiftUI&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enhanced our video export to display a progress indicator and the option to cancel the export.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;thanks-for-reading-let-us-know-what-you-think-on-twitter-or-stay-in-the-loop-with-our-newsletter&quot;&gt;Thanks for reading! Let us know what you think on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt;, or stay in the loop with our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/h3&gt;</content:encoded><dc:creator>Sascha</dc:creator><media:content url="https://blog.img.ly/2022/05/photo-editor-sdk-video-editor-sdk-background-removal.png" medium="image"/><category>Release Notes</category><category>Photo Editor</category><category>Video Editor</category><category>Android App Development</category><category>iOS App Development</category><category>App Development</category></item><item><title>Bringing Wide Color to PhotoEditor SDK</title><link>https://img.ly/blog/bringing-wide-color-to-photoeditor-sdk-a6ce8bb19ef7/</link><guid isPermaLink="true">https://img.ly/blog/bringing-wide-color-to-photoeditor-sdk-a6ce8bb19ef7/</guid><pubDate>Tue, 10 Jan 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Inspired by &lt;a href=&quot;https://medium.com/@mikekrieger&quot;&gt;Mike Krieger&lt;/a&gt;’s &lt;a href=&quot;https://instagram-engineering.com/bringing-wide-color-to-instagram-5a5481802d7d#.2gjnzpdeb&quot;&gt;great post&lt;/a&gt; on supporting wide color images in Instagram, I decided to challenge myself by introducing the same wide color support into our &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; within a day.&lt;/p&gt;
&lt;p&gt;Mike did an excellent job describing everything that is needed to support wide color images so I am not going to reiterate his explanation. Instead, here I’m going to share two findings I made in the process.&lt;/p&gt;
&lt;h2 id=&quot;image-export&quot;&gt;Image Export&lt;/h2&gt;
&lt;p&gt;Mike suggests that in order to preserve the color space while converting an &lt;code&gt;UIImage&lt;/code&gt; into a JPEG, the &lt;code&gt;UIImageJPEGRepresentation(_:_:)&lt;/code&gt; method has to be replaced with the new &lt;code&gt;UIGraphicsImageRenderer.jpegData(withCompressionQuality:actions:)&lt;/code&gt; method. Checking the color profile of the generated JPEG by &lt;code&gt;UIImageJPEGRepresentation(_:)&lt;/code&gt; I noticed that it seemed unnecessary and resulting in more work than needed. To verify this, I started &lt;a href=&quot;https://www.hopperapp.com&quot;&gt;Hopper&lt;/a&gt; and took a look at the internals of the new method. Here’s what it basically does:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It passes &lt;code&gt;actions&lt;/code&gt; to &lt;code&gt;UIGraphicsRenderer.runDrawingActions(_:completionActions:)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It obtains the resulting image using &lt;code&gt;UIGraphicsImageRendererContext.currentImage&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It passes that image to &lt;code&gt;UIImageJPEGRepresentation(_:_:)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can see, it makes use of &lt;code&gt;UIImageJPEGRepresentation(_:_:)&lt;/code&gt; internally too, so there really is no need to go the extra mile. If you are actually doing any drawing within the &lt;code&gt;actions&lt;/code&gt; block using wide color &lt;code&gt;UIColor&lt;/code&gt;s it absolutely makes sense to use Mike’s apoproach. But if you only want to convert an &lt;code&gt;UIImage&lt;/code&gt; into a JPEG image, using the old method is far easier.&lt;/p&gt;
&lt;h2 id=&quot;core-image&quot;&gt;Core Image&lt;/h2&gt;
&lt;p&gt;We are using &lt;code&gt;CIImage&lt;/code&gt;, &lt;code&gt;CIFilter&lt;/code&gt; and &lt;code&gt;CIContext&lt;/code&gt; for most of our processing. In our live preview we use a &lt;code&gt;CIContext&lt;/code&gt; to directly render a &lt;code&gt;CIImage&lt;/code&gt; into a &lt;code&gt;GLKView&lt;/code&gt; and I’ve run into exactly the same problem as Mike has — namely not being able to get that view to be color space-aware. Using the offscreen buffer workaround that he suggested was going to be too much work though and also I didn’t want to sacrifice any performance.&lt;/p&gt;
&lt;p&gt;After doing some research and digging further into the GLKit and Core Image assembly I found a nice solution. It looks like in order to render wide color images into OpenGL, OpenGLES 3 and a &lt;code&gt;GLKViewDrawableColorFormat&lt;/code&gt; (that is currently not defined as an &lt;code&gt;enum&lt;/code&gt; case) has to be used. The following code works like a charm for me:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let api: EAGLRenderingAPI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let colorFormat: GLKViewDrawableColorFormat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;if #available(iOS 10.0, *) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if UIScreen.main.traitCollection.displayGamut == .P3 {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    api = .openGLES3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    colorFormat = GLKViewDrawableColorFormat(rawValue: 10)!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } else {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    api = .openGLES2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    colorFormat = .RGBA8888&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;} else {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  api = .openGLES2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  colorFormat = .RGBA8888&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let context = EAGLContext(api: api)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let previewView = GLKView(frame: CGRect.zero, context: context!)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;previewView.delegate = self&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;previewView.drawableColorFormat = colorFormat&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code creates a &lt;code&gt;GLKView&lt;/code&gt; that is backed by a &lt;code&gt;CAEAGLLayer&lt;/code&gt; with the following &lt;code&gt;drawableProperties&lt;/code&gt; set:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; &quot;EAGLDrawablePropertyRetained&quot;: 0,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; &quot;EAGLDrawablePropertyColorFormat&quot;: EAGLColorFormatRGBA_XR10_64BPP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately &lt;code&gt;EAGLColorFormatRGBA_XR10_64BPP&lt;/code&gt; also doesn’t seem to be documented at this point, but my guess is that setting this color format on Instagram’s &lt;code&gt;EAGLView&lt;/code&gt; would also solve their problem of making the view color space-aware.&lt;/p&gt;
&lt;p&gt;Thanks to Core Image we can just switch to OpenGLES 3 without having to do any other modifications to our code. However, I am currently not sure if this is considered a private API use. I would greatly appreciate if anyone could shed some light on this.&lt;/p&gt;
&lt;p&gt;I have not yet been able to test this on any device other than the iPhone 7 Plus, but I will update this post if I run into any problems with future tests.&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Getting an app to support wide color images is definitely worth it and not as difficult as I had imagined. Unfortunately, it currently looks like iOS is still missing (public) support for wide color in some parts of its frameworks. I hope that Apple addresses these problems soon. Nevertheless we’re optimistic that we’ll be able to include wide color image support in the next release of our SDK. Feel free to check out our &lt;a href=&quot;https://apps.apple.com/de/app/img-ly-camera-pro-photo-sharing/id589839231&quot;&gt;demo app&lt;/a&gt; in the App Store which we will update as soon as possible.&lt;/p&gt;</content:encoded><dc:creator>Sascha</dc:creator><media:content url="https://blog.img.ly/2020/03/1-VF6BW_zDoIaklWdM3u98Tw.jpeg" medium="image"/><category>iOS</category><category>Swift</category><category>Instagram</category><category>Wide Color</category><category>Core Image</category><category>Tech</category><category>How-To</category><category>Insights</category></item></channel></rss>