{"id":39008,"date":"2025-10-30T07:00:00","date_gmt":"2025-10-30T14:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=39008"},"modified":"2025-11-01T06:12:48","modified_gmt":"2025-11-01T13:12:48","slug":"custom-wasm-functions-image-transformations","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations","title":{"rendered":"Using Cloudinary Custom WASM Functions for Image Transformations"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Cloudinary offers powerful image and <a href=\"https:\/\/cloudinary.com\/documentation\/video_manipulation_and_delivery\">video transformation<\/a> capabilities. When you need to apply a custom filter, execute pixel-level logic, or perform proprietary image manipulation not covered by the built-in effects, <a href=\"https:\/\/cloudinary.com\/documentation\/custom_functions\">Cloudinary Custom Functions<\/a> is available. This feature allows you to extend Cloudinary\u2019s core capabilities by injecting your custom logic into the image processing pipeline. Cloudinary has different types of custom functions to suit your creative needs.<\/p>\n<p>In this post, we\u2019ll focus on the implementation of Cloudinary Custom Functions with WebAssembly (WASM). This approach allows you to inject your own compiled code written in languages like Rust or C\/C++ directly into Cloudinary\u2019s image processing pipeline for high-performance, pixel-level control.<\/p>\n<p>We\u2019ll explore what these WASM-based custom functions are, how to write and export the required functions, how to compile and upload the WASM module, and how to use your custom function in a transformation URL.<\/p>\n<h2>What Are Cloudinary Custom WASM Functions?<\/h2>\n<p>A <a href=\"https:\/\/cloudinary.com\/documentation\/custom_functions#webassembly_functions\">custom WASM function<\/a> in Cloudinary is a user-defined transformation module that runs inside a secure, sandboxed environment. These functions operate directly on raw pixel data in RGBA format. This makes them ideal for implementing custom filters such as sepia or specialized color effects, creating proprietary branding overlays, executing artistic or AI-assisted transformations, or applying logic based on metadata or external variables.<\/p>\n<p>To be compatible with Cloudinary\u2019s execution engine, the WASM file must implement a specific contract using a fixed interface.<\/p>\n<h2>The Required WASM Interface<\/h2>\n<p>Every custom WASM module must export three functions that form the interface contract with Cloudinary:<\/p>\n<ul>\n<li>The <strong><code>alloc(size: i32) -&gt; i32<\/code><\/strong> function allocates a block of memory within the WASM instance. Cloudinary uses this to pass pixel and metadata buffers into your module.<\/li>\n<li>The <strong><code>dealloc(ptr: i32, size: i32)<\/code><\/strong> function releases previously allocated memory. WebAssembly doesn\u2019t have automatic memory management, so this manual step helps to prevent memory leaks.<\/li>\n<li>The <strong><code>transform(width: i32, height: i32, pixel_ptr: i32, meta_ptr: i32, meta_size: i32) -&gt; i32<\/code><\/strong> function is the core processing logic. Cloudinary calls it with the image dimensions, a pointer to the RGBA buffer, and an optional JSON metadata block. It must return a pointer to a new buffer that starts with the new width and height, followed by the transformed pixels.<\/li>\n<\/ul>\n<h2>Implementing a Grayscale Filter With Rust and WASM<\/h2>\n<p>Let\u2019s walk through a basic Rust implementation of a grayscale filter, compiling it to WebAssembly, and preparing it for Cloudinary.<\/p>\n<h3>Step 1: Create a New Rust Project<\/h3>\n<p>First, we\u2019ll set up a new Rust library project. Open your terminal or command prompt and run:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">cargo <span class=\"hljs-keyword\">new<\/span> grayscale_filter --lib\ncd grayscale_filter\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>These commands create a new directory named <code>grayscale_filter<\/code> with the basic Rust project structure inside and switch to this directory.<\/p>\n<h3>Step 2: Configure for WebAssembly Output<\/h3>\n<p>Next, we need to tell Rust to compile our code into a WebAssembly dynamic library. Open the <code>Cargo.toml<\/code> file within your <code>grayscale_filter<\/code> directory and add the following lines under the <code>[lib]<\/code> section:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">&#91;lib]\ncrate-type = &#91;<span class=\"hljs-string\">\"cdylib\"<\/span>]\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>crate-type = [&quot;cdylib&quot;]<\/code> setting is crucial for WebAssembly. It instructs Rust to compile your code as a C-compatible dynamic library. This ensures the output <code>.wasm<\/code> file is a standalone binary that directly exposes the functions marked <code>pub extern &quot;C&quot;<\/code>, making them accessible to external hosts like Cloudinary without any Rust-specific runtime dependencies or name mangling.<\/p>\n<h3>Step 3: Write the Grayscale Filter Code<\/h3>\n<p>Now, let\u2019s write the core logic for our grayscale filter. Open the <code>src\/lib.rs<\/code> file and replace its contents with the following Rust code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#&#91;unsafe(no_mangle)]<\/span>\npub extern <span class=\"hljs-string\">\"C\"<\/span> fn alloc(size: usize) -&gt; *mut u8 {\n    let mut buf = Vec::with_capacity(size);\n    let ptr = buf.as_mut_ptr();\n    std::mem::forget(buf);\n    ptr\n}\n\n<span class=\"hljs-comment\">#&#91;unsafe(no_mangle)]<\/span>\npub extern <span class=\"hljs-string\">\"C\"<\/span> fn dealloc(ptr: *mut u8, size: usize) {\n    unsafe { let _ = Vec::from_raw_parts(ptr, size, size); }\n}\n\n<span class=\"hljs-comment\">#&#91;unsafe(no_mangle)]<\/span>\npub extern <span class=\"hljs-string\">\"C\"<\/span> fn transform(width: i32, height: i32, ptr: *mut u8, _meta_ptr: *mut u8, _meta_size: i32) -&gt; *mut u8 {\n    <span class=\"hljs-comment\">\/\/ Calculate the total number of bytes in the RGBA pixel buffer<\/span>\n    let len = (width * height * <span class=\"hljs-number\">4<\/span>) <span class=\"hljs-keyword\">as<\/span> usize;\n    <span class=\"hljs-comment\">\/\/ Create a mutable slice from the raw pixel pointer<\/span>\n    let pixels = unsafe { std::slice::from_raw_parts_mut(ptr, len) };\n\n    <span class=\"hljs-comment\">\/\/ Iterate over chunks of 4 bytes (RGBA for each pixel)<\/span>\n    <span class=\"hljs-keyword\">for<\/span> chunk in pixels.chunks_mut(<span class=\"hljs-number\">4<\/span>) {\n        <span class=\"hljs-comment\">\/\/ Calculate the average of R, G, and B channels<\/span>\n        let avg = ((chunk&#91;<span class=\"hljs-number\">0<\/span>] <span class=\"hljs-keyword\">as<\/span> u16 + chunk&#91;<span class=\"hljs-number\">1<\/span>] <span class=\"hljs-keyword\">as<\/span> u16 + chunk&#91;<span class=\"hljs-number\">2<\/span>] <span class=\"hljs-keyword\">as<\/span> u16) \/ <span class=\"hljs-number\">3<\/span>) <span class=\"hljs-keyword\">as<\/span> u8;\n        <span class=\"hljs-comment\">\/\/ Set all R, G, B channels to the average value for grayscale effect<\/span>\n        chunk&#91;<span class=\"hljs-number\">0<\/span>] = avg; <span class=\"hljs-comment\">\/\/ Red<\/span>\n        chunk&#91;<span class=\"hljs-number\">1<\/span>] = avg; <span class=\"hljs-comment\">\/\/ Green<\/span>\n        chunk&#91;<span class=\"hljs-number\">2<\/span>] = avg; <span class=\"hljs-comment\">\/\/ Blue<\/span>\n        <span class=\"hljs-comment\">\/\/ Alpha (chunk&#91;3]) remains unchanged<\/span>\n    }\n\n    <span class=\"hljs-comment\">\/\/ Prepare the output buffer. It needs to start with new width\/height (4 bytes each)<\/span>\n    <span class=\"hljs-comment\">\/\/ followed by the transformed pixel data.<\/span>\n    let mut out = Vec::&lt;u8&gt;::with_capacity(<span class=\"hljs-number\">8<\/span> + len);\n    <span class=\"hljs-comment\">\/\/ Add the new width and height as big-endian 32-bit integers<\/span>\n    out.extend(&amp; (width  <span class=\"hljs-keyword\">as<\/span> u32).to_be_bytes());\n    out.extend(&amp; (height <span class=\"hljs-keyword\">as<\/span> u32).to_be_bytes());\n    <span class=\"hljs-comment\">\/\/ Add the transformed pixel data<\/span>\n    out.extend_from_slice(pixels);\n\n    <span class=\"hljs-comment\">\/\/ Get a raw pointer to the start of our output vector<\/span>\n    let out_ptr = out.as_mut_ptr();\n    <span class=\"hljs-comment\">\/\/ Prevent Rust from deallocating the Vec when it goes out of scope,<\/span>\n    <span class=\"hljs-comment\">\/\/ as Cloudinary will now manage this memory.<\/span>\n    std::mem::forget(out);\n    out_ptr\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This code implements the three required functions: <code>alloc<\/code>, <code>dealloc<\/code>, and <code>transform<\/code>. The <code>transform<\/code> function takes the RGBA pixel data, processes each pixel to convert it to grayscale, and then returns a pointer to a new buffer containing the modified image dimensions and pixels.\nEach function is marked with <code>#[unsafe(no_mangle)] pub extern &quot;C&quot;<\/code> to ensure it\u2019s publicly accessible, retains its original name, and uses a C-compatible calling convention, which is essential for Cloudinary\u2019s WASM runtime to invoke it.<\/p>\n<h3>Step 4: Compile Your Rust Project to WASM<\/h3>\n<p>Now, we\u2019ll compile our Rust code into a WebAssembly module. First, ensure you have the <code>wasm32-unknown-unknown<\/code> compilation target added to your Rust toolchain:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">rustup target add wasm32-unknown-unknown\n<\/code><\/span><\/pre>\n<p>This target tells Rust to compile your code to 32-bit WebAssembly without assuming any operating system or runtime interface. This is essential because Cloudinary executes your code in a very minimal environment.<\/p>\n<p>Next, compile your project in release mode for optimization:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">cargo build --release --target wasm32-unknown-unknown\n<\/code><\/span><\/pre>\n<p>The resulting <code>.wasm<\/code> file will be located in the <code>target\/wasm32-unknown-unknown\/release\/<\/code> directory. For this example, it will likely be named <code>grayscale_filter.wasm<\/code>.<\/p>\n<h3>Step 5: Upload Your WASM Module to Cloudinary<\/h3>\n<p>Once you\u2019ve compiled your module, you need to upload it to your Cloudinary account as a <a href=\"https:\/\/cloudinary.com\/documentation\/upload_parameters#uploading_non_media_files_as_raw_files\">raw<\/a> and <a href=\"https:\/\/cloudinary.com\/documentation\/upload_parameters#authenticated_assets\">authenticated<\/a> resource. Cloudinary rejects public uploads of custom functions due to security considerations.<\/p>\n<p>Here\u2019s an example <code>curl<\/code> command to upload your WASM module. Make sure to replace <code>&lt;cloud_name&gt;<\/code>, the <code>@target\/...\/grayscale_filter.wasm<\/code> file path, <code>&lt;ts&gt;<\/code> for timestamp, <code>&lt;your_api_key&gt;<\/code>, and <code>&lt;your_signature&gt;<\/code> with your actual Cloudinary information:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">curl -X POST https:\/\/api.cloudinary.com\/v1_1\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">cloud_name<\/span>&gt;<\/span>\/raw\/upload \\\n  -F file=@target\/wasm32-unknown-unknown\/release\/grayscale_filter.wasm \\\n  -F public_id=custom\/grayscale-filter \\\n  -F resource_type=raw \\\n  -F type=authenticated \\\n  -F api_key=<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">your_api_key<\/span>&gt;<\/span> \\\n  -F timestamp=<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ts<\/span>&gt;<\/span> \\\n  -F signature=<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">your_signature<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><strong>Important:<\/strong> Your <code>signature<\/code> must be properly generated using your Cloudinary API secret and the other upload parameters. For more details on how to manually generate a signature, see Cloudinary\u2019s <a href=\"https:\/\/cloudinary.com\/documentation\/authentication_signatures\">Generating authentication signatures documentation<\/a>.<\/p>\n<h2>Using the Custom Function in a URL<\/h2>\n<p>To invoke your custom transformation, use the <code>fn_wasm<\/code> action in a standard Cloudinary image URL. When referencing your WASM module\u2019s public_id, remember that any slashes in the <code>public_id<\/code> (e.g., <code>custom\/grayscale-filter<\/code>) must be replaced with colons in the URL (e.g., <code>custom:grayscale-filter<\/code>).<\/p>\n<p>Here\u2019s an example:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">https:\/\/res.cloudinary.com\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">cloud_name<\/span>&gt;<\/span>\/image\/upload\/fn_wasm:custom:grayscale-filter.wasm\/sample.jpg\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You can also combine it with other transformations like resizing or cropping:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">https:\/\/res.cloudinary.com\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">cloud_name<\/span>&gt;<\/span>\/image\/upload\/fn_wasm:custom:grayscale-filter.wasm\/w_500,c_fill\/sample.jpg\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This URL tells Cloudinary to apply your grayscale filter module as part of the image processing pipeline.<\/p>\n<h2>Best Practices<\/h2>\n<p>As you build and deploy your custom WASM functions, a few best practices will help make them stable and efficient.<\/p>\n<p>To manage updates and maintain old links, consider using versioned paths for your modules, such as <code>custom\/grayscale-v1<\/code>. Such versioning helps ensure that old links continue to work smoothly even when you update your functions.<\/p>\n<p>Also, when you\u2019re directly handling memory inside your WASM functions, be extremely careful with pointer safety. A small mistake can lead to transformation failures or corrupted output, so handle memory with care.<\/p>\n<p>For more flexibility, you can pass configuration data, such as filter strength or blending options, as JSON through the <code>meta_ptr<\/code>. Cloudinary automatically adds this data based on your transformation settings, giving you dynamic control over your custom functions.<\/p>\n<p>Lastly, for the best performance, try to keep your modules small and predictable. It\u2019s usually best to avoid outside dependencies, dynamic memory use, or randomness unless they are absolutely necessary for what your function needs to do.<\/p>\n<h2>Conclusion<\/h2>\n<p>Cloudinary Custom WASM Functions provide fine-grained control for developers who need precise, fast, and flexible image transformation. The combination of WebAssembly\u2019s speed and Cloudinary\u2019s powerful API enables you to create custom filters, unique improvements, or full visual pipelines that fit your app\u2019s exact needs. <a href=\"https:\/\/cloudinary.com\/users\/register_free\">Sign up<\/a> for a free Cloudinary account to get started.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":87,"featured_media":39009,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[370,165],"class_list":["post-39008","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-image","tag-image-transformation"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Using Cloudinary Custom WASM Functions for Image Transformations<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using Cloudinary Custom WASM Functions for Image Transformations\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-30T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-01T13:12:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Using Cloudinary Custom WASM Functions for Image Transformations\",\"datePublished\":\"2025-10-30T14:00:00+00:00\",\"dateModified\":\"2025-11-01T13:12:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA\",\"keywords\":[\"Image\",\"Image Transformation\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations\",\"url\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations\",\"name\":\"Using Cloudinary Custom WASM Functions for Image Transformations\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA\",\"datePublished\":\"2025-10-30T14:00:00+00:00\",\"dateModified\":\"2025-11-01T13:12:48+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using Cloudinary Custom WASM Functions for Image Transformations\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Using Cloudinary Custom WASM Functions for Image Transformations","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations","og_locale":"en_US","og_type":"article","og_title":"Using Cloudinary Custom WASM Functions for Image Transformations","og_url":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations","og_site_name":"Cloudinary Blog","article_published_time":"2025-10-30T14:00:00+00:00","article_modified_time":"2025-11-01T13:12:48+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Using Cloudinary Custom WASM Functions for Image Transformations","datePublished":"2025-10-30T14:00:00+00:00","dateModified":"2025-11-01T13:12:48+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA","keywords":["Image","Image Transformation"],"inLanguage":"en-US","copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations","url":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations","name":"Using Cloudinary Custom WASM Functions for Image Transformations","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA","datePublished":"2025-10-30T14:00:00+00:00","dateModified":"2025-11-01T13:12:48+00:00","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/custom-wasm-functions-image-transformations#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Using Cloudinary Custom WASM Functions for Image Transformations"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1761262122\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation\/Blog_Using_Cloudinary_custom_WASM_functions_for_Image_transformation.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/39008","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=39008"}],"version-history":[{"count":2,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/39008\/revisions"}],"predecessor-version":[{"id":39065,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/39008\/revisions\/39065"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/39009"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=39008"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=39008"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=39008"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}