diff --git a/dd-sdk-android-internal/api/apiSurface b/dd-sdk-android-internal/api/apiSurface
index f80629999a..597d40934f 100644
--- a/dd-sdk-android-internal/api/apiSurface
+++ b/dd-sdk-android-internal/api/apiSurface
@@ -29,6 +29,12 @@ sealed class com.datadog.android.internal.telemetry.InternalTelemetryEvent
       constructor(Boolean, Boolean, Boolean, MutableMap<String, Any?> = mutableMapOf())
   object InterceptorInstantiated : InternalTelemetryEvent
 fun ByteArray.toHexString(): String
+object com.datadog.android.internal.utils.ImageViewUtils
+  fun resolveParentRectAbsPosition(android.view.View): android.graphics.Rect
+  fun calculateClipping(android.graphics.Rect, android.graphics.Rect, Float): android.graphics.Rect
+  fun resolveContentRectWithScaling(android.widget.ImageView, android.graphics.drawable.Drawable): android.graphics.Rect
+fun Int.densityNormalized(Float): Int
+fun Long.densityNormalized(Float): Long
 fun Throwable.loggableStackTrace(): String
 annotation com.datadog.tools.annotation.NoOpImplementation
   constructor(Boolean = false)
diff --git a/dd-sdk-android-internal/api/dd-sdk-android-internal.api b/dd-sdk-android-internal/api/dd-sdk-android-internal.api
index a6ae5b9963..f15b234506 100644
--- a/dd-sdk-android-internal/api/dd-sdk-android-internal.api
+++ b/dd-sdk-android-internal/api/dd-sdk-android-internal.api
@@ -108,6 +108,21 @@ public final class com/datadog/android/internal/utils/ByteArrayExtKt {
 	public static final fun toHexString ([B)Ljava/lang/String;
 }
 
+public final class com/datadog/android/internal/utils/ImageViewUtils {
+	public static final field INSTANCE Lcom/datadog/android/internal/utils/ImageViewUtils;
+	public final fun calculateClipping (Landroid/graphics/Rect;Landroid/graphics/Rect;F)Landroid/graphics/Rect;
+	public final fun resolveContentRectWithScaling (Landroid/widget/ImageView;Landroid/graphics/drawable/Drawable;)Landroid/graphics/Rect;
+	public final fun resolveParentRectAbsPosition (Landroid/view/View;)Landroid/graphics/Rect;
+}
+
+public final class com/datadog/android/internal/utils/IntExtKt {
+	public static final fun densityNormalized (IF)I
+}
+
+public final class com/datadog/android/internal/utils/LongExtKt {
+	public static final fun densityNormalized (JF)J
+}
+
 public final class com/datadog/android/internal/utils/ThrowableExtKt {
 	public static final fun loggableStackTrace (Ljava/lang/Throwable;)Ljava/lang/String;
 }
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/ImageViewUtils.kt b/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/utils/ImageViewUtils.kt
similarity index 84%
rename from features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/ImageViewUtils.kt
rename to dd-sdk-android-internal/src/main/java/com/datadog/android/internal/utils/ImageViewUtils.kt
index d5ca9d6b26..b8a35b3496 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/ImageViewUtils.kt
+++ b/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/utils/ImageViewUtils.kt
@@ -4,17 +4,25 @@
  * Copyright 2016-Present Datadog, Inc.
  */
 
-package com.datadog.android.sessionreplay.internal.utils
+package com.datadog.android.internal.utils
 
 import android.graphics.Rect
 import android.graphics.drawable.Drawable
 import android.view.View
 import android.widget.ImageView
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
-import com.datadog.android.sessionreplay.model.MobileSegment
 
-internal object ImageViewUtils {
-    internal fun resolveParentRectAbsPosition(view: View): Rect {
+/**
+ * A collection of view utility functions for resolving absolute
+ * positions, clipping bounds, and other useful data for
+ * image views operations.
+ */
+object ImageViewUtils {
+    /**
+     * Resolves the absolute position on the screen of the given [View].
+     * @param view: the [View].
+     * @return the [Rect] representing the absolute position of the view.
+     */
+    fun resolveParentRectAbsPosition(view: View): Rect {
         val coords = IntArray(2)
         // this will always have size >= 2
         @Suppress("UnsafeThirdPartyFunctionCall")
@@ -31,7 +39,15 @@ internal object ImageViewUtils {
         )
     }
 
-    internal fun calculateClipping(parentRect: Rect, childRect: Rect, density: Float): MobileSegment.WireframeClip {
+    /**
+     * Calculates the clipping [Rect] of the given child [Rect] using its parent [Rect] and
+     * the screen density.
+     * @param parentRect: the parent [Rect].
+     * @param childRect: the child [Rect].
+     * @param density: the screen density.
+     * @return the clipping [Rect].
+     */
+    fun calculateClipping(parentRect: Rect, childRect: Rect, density: Float): Rect {
         val left = if (childRect.left < parentRect.left) {
             parentRect.left - childRect.left
         } else {
@@ -52,16 +68,21 @@ internal object ImageViewUtils {
         } else {
             0
         }
-
-        return MobileSegment.WireframeClip(
-            left = left.densityNormalized(density).toLong(),
-            top = top.densityNormalized(density).toLong(),
-            right = right.densityNormalized(density).toLong(),
-            bottom = bottom.densityNormalized(density).toLong()
+        return Rect(
+            left.densityNormalized(density),
+            top.densityNormalized(density),
+            right.densityNormalized(density),
+            bottom.densityNormalized(density)
         )
     }
 
-    internal fun resolveContentRectWithScaling(
+    /**
+     * Resolves the [Drawable] content [Rect] using the given [ImageView] scale type.
+     * @param imageView: the [ImageView].
+     * @param drawable: the [Drawable].
+     * @return the resolved content [Rect].
+     */
+    fun resolveContentRectWithScaling(
         imageView: ImageView,
         drawable: Drawable
     ): Rect {
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/IntExt.kt b/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/utils/IntExt.kt
similarity index 83%
rename from features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/IntExt.kt
rename to dd-sdk-android-internal/src/main/java/com/datadog/android/internal/utils/IntExt.kt
index 59d515a40e..04d5528f34 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/IntExt.kt
+++ b/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/utils/IntExt.kt
@@ -4,7 +4,7 @@
  * Copyright 2016-Present Datadog, Inc.
  */
 
-package com.datadog.android.sessionreplay.internal.recorder
+package com.datadog.android.internal.utils
 
 /**
  * Normalizes an Int value (font size, view dimension, view position, etc.) according with the
@@ -13,7 +13,7 @@ package com.datadog.android.sessionreplay.internal.recorder
  * view.height/2.
  * @param density
  */
-internal fun Int.densityNormalized(density: Float): Int {
+fun Int.densityNormalized(density: Float): Int {
     if (density == 0f) {
         return this
     }
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/LongExt.kt b/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/utils/LongExt.kt
similarity index 83%
rename from features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/LongExt.kt
rename to dd-sdk-android-internal/src/main/java/com/datadog/android/internal/utils/LongExt.kt
index 53e04d322e..b057e92220 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/LongExt.kt
+++ b/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/utils/LongExt.kt
@@ -4,7 +4,7 @@
  * Copyright 2016-Present Datadog, Inc.
  */
 
-package com.datadog.android.sessionreplay.internal.recorder
+package com.datadog.android.internal.utils
 
 /**
  * Normalizes a Long value (font size, view dimension, view position, etc.) according with the
@@ -13,7 +13,7 @@ package com.datadog.android.sessionreplay.internal.recorder
  * view.height/2.
  * @param density
  */
-internal fun Long.densityNormalized(density: Float): Long {
+fun Long.densityNormalized(density: Float): Long {
     if (density == 0f) {
         return this
     }
diff --git a/features/dd-sdk-android-session-replay/api/apiSurface b/features/dd-sdk-android-session-replay/api/apiSurface
index ef2ead17ba..ad23691fd8 100644
--- a/features/dd-sdk-android-session-replay/api/apiSurface
+++ b/features/dd-sdk-android-session-replay/api/apiSurface
@@ -59,10 +59,6 @@ interface com.datadog.android.sessionreplay.internal.recorder.obfuscator.StringO
   fun obfuscate(String): String
   companion object 
     fun getStringObfuscator(): StringObfuscator
-class com.datadog.android.sessionreplay.internal.recorder.resources.DefaultDrawableCopier : DrawableCopier
-  override fun copy(android.graphics.drawable.Drawable, android.content.res.Resources): android.graphics.drawable.Drawable?
-interface com.datadog.android.sessionreplay.internal.recorder.resources.DrawableCopier
-  fun copy(android.graphics.drawable.Drawable, android.content.res.Resources): android.graphics.drawable.Drawable?
 data class com.datadog.android.sessionreplay.recorder.MappingContext
   constructor(SystemInformation, com.datadog.android.sessionreplay.utils.ImageWireframeHelper, com.datadog.android.sessionreplay.TextAndInputPrivacy, com.datadog.android.sessionreplay.ImagePrivacy, Boolean = false)
 interface com.datadog.android.sessionreplay.recorder.OptionSelectorDetector
@@ -70,7 +66,11 @@ interface com.datadog.android.sessionreplay.recorder.OptionSelectorDetector
 data class com.datadog.android.sessionreplay.recorder.SystemInformation
   constructor(com.datadog.android.sessionreplay.utils.GlobalBounds, Int = Configuration.ORIENTATION_UNDEFINED, Float, String? = null)
 abstract class com.datadog.android.sessionreplay.recorder.mapper.BaseAsyncBackgroundWireframeMapper<T: android.view.View> : BaseWireframeMapper<T>
+  constructor(com.datadog.android.sessionreplay.utils.ViewIdentifierResolver, com.datadog.android.sessionreplay.utils.ColorStringFormatter, com.datadog.android.sessionreplay.utils.ViewBoundsResolver, com.datadog.android.sessionreplay.utils.DrawableToColorMapper)
   override fun map(T, com.datadog.android.sessionreplay.recorder.MappingContext, com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback, com.datadog.android.api.InternalLogger): List<com.datadog.android.sessionreplay.model.MobileSegment.Wireframe>
+  protected open fun resolveViewBackground(android.view.View, com.datadog.android.sessionreplay.recorder.MappingContext, com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback, com.datadog.android.api.InternalLogger): com.datadog.android.sessionreplay.model.MobileSegment.Wireframe?
+  protected open fun resolveBackgroundAsShapeWireframe(android.view.View, com.datadog.android.sessionreplay.utils.GlobalBounds, Int, Int, com.datadog.android.sessionreplay.model.MobileSegment.ShapeStyle?): com.datadog.android.sessionreplay.model.MobileSegment.Wireframe.ShapeWireframe?
+  protected open fun resolveBackgroundAsImageWireframe(android.view.View, com.datadog.android.sessionreplay.utils.GlobalBounds, Int, Int, com.datadog.android.sessionreplay.recorder.MappingContext, com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback): com.datadog.android.sessionreplay.model.MobileSegment.Wireframe?
   companion object 
 open class com.datadog.android.sessionreplay.recorder.mapper.BaseViewGroupMapper<T: android.view.ViewGroup> : BaseAsyncBackgroundWireframeMapper<T>, TraverseAllChildrenMapper<T>
   constructor(com.datadog.android.sessionreplay.utils.ViewIdentifierResolver, com.datadog.android.sessionreplay.utils.ColorStringFormatter, com.datadog.android.sessionreplay.utils.ViewBoundsResolver, com.datadog.android.sessionreplay.utils.DrawableToColorMapper)
@@ -83,7 +83,7 @@ class com.datadog.android.sessionreplay.recorder.mapper.EditTextMapper : TextVie
   override fun resolveCapturedText(android.widget.EditText, com.datadog.android.sessionreplay.TextAndInputPrivacy, Boolean): String
   companion object 
 open class com.datadog.android.sessionreplay.recorder.mapper.ImageViewMapper : BaseAsyncBackgroundWireframeMapper<android.widget.ImageView>
-  constructor(com.datadog.android.sessionreplay.utils.ViewIdentifierResolver, com.datadog.android.sessionreplay.utils.ColorStringFormatter, com.datadog.android.sessionreplay.utils.ViewBoundsResolver, com.datadog.android.sessionreplay.utils.DrawableToColorMapper)
+  constructor(com.datadog.android.sessionreplay.utils.ViewIdentifierResolver, com.datadog.android.sessionreplay.utils.ColorStringFormatter, com.datadog.android.sessionreplay.utils.ViewBoundsResolver, com.datadog.android.sessionreplay.utils.DrawableToColorMapper, com.datadog.android.sessionreplay.recorder.resources.DrawableCopier)
   override fun map(android.widget.ImageView, com.datadog.android.sessionreplay.recorder.MappingContext, com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback, com.datadog.android.api.InternalLogger): List<com.datadog.android.sessionreplay.model.MobileSegment.Wireframe>
 open class com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper<T: android.widget.TextView> : BaseAsyncBackgroundWireframeMapper<T>
   constructor(com.datadog.android.sessionreplay.utils.ViewIdentifierResolver, com.datadog.android.sessionreplay.utils.ColorStringFormatter, com.datadog.android.sessionreplay.utils.ViewBoundsResolver, com.datadog.android.sessionreplay.utils.DrawableToColorMapper)
@@ -93,6 +93,10 @@ open class com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper<T: a
 interface com.datadog.android.sessionreplay.recorder.mapper.TraverseAllChildrenMapper<T: android.view.ViewGroup> : WireframeMapper<T>
 interface com.datadog.android.sessionreplay.recorder.mapper.WireframeMapper<T: android.view.View>
   fun map(T, com.datadog.android.sessionreplay.recorder.MappingContext, com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback, com.datadog.android.api.InternalLogger): List<com.datadog.android.sessionreplay.model.MobileSegment.Wireframe>
+class com.datadog.android.sessionreplay.recorder.resources.DefaultDrawableCopier : DrawableCopier
+  override fun copy(android.graphics.drawable.Drawable, android.content.res.Resources): android.graphics.drawable.Drawable?
+interface com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
+  fun copy(android.graphics.drawable.Drawable, android.content.res.Resources): android.graphics.drawable.Drawable?
 open class com.datadog.android.sessionreplay.utils.AndroidMDrawableToColorMapper : LegacyDrawableToColorMapper
   constructor(List<DrawableToColorMapper> = emptyList())
   override fun resolveRippleDrawable(android.graphics.drawable.RippleDrawable, com.datadog.android.api.InternalLogger): Int?
@@ -126,7 +130,7 @@ data class com.datadog.android.sessionreplay.utils.GlobalBounds
   constructor(Long, Long, Long, Long)
 interface com.datadog.android.sessionreplay.utils.ImageWireframeHelper
   fun createImageWireframeByBitmap(Long, GlobalBounds, android.graphics.Bitmap, Float, Boolean, com.datadog.android.sessionreplay.ImagePrivacy, AsyncJobStatusCallback, com.datadog.android.sessionreplay.model.MobileSegment.WireframeClip? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeStyle? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeBorder? = null): com.datadog.android.sessionreplay.model.MobileSegment.Wireframe?
-  fun createImageWireframeByDrawable(android.view.View, com.datadog.android.sessionreplay.ImagePrivacy, Int, Long, Long, Int, Int, Boolean, android.graphics.drawable.Drawable, com.datadog.android.sessionreplay.internal.recorder.resources.DrawableCopier = DefaultDrawableCopier(), AsyncJobStatusCallback, com.datadog.android.sessionreplay.model.MobileSegment.WireframeClip? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeStyle? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeBorder? = null, String? = DRAWABLE_CHILD_NAME, String?): com.datadog.android.sessionreplay.model.MobileSegment.Wireframe?
+  fun createImageWireframeByDrawable(android.view.View, com.datadog.android.sessionreplay.ImagePrivacy, Int, Long, Long, Int, Int, Boolean, android.graphics.drawable.Drawable, com.datadog.android.sessionreplay.recorder.resources.DrawableCopier = DefaultDrawableCopier(), AsyncJobStatusCallback, com.datadog.android.sessionreplay.model.MobileSegment.WireframeClip? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeStyle? = null, com.datadog.android.sessionreplay.model.MobileSegment.ShapeBorder? = null, String? = DRAWABLE_CHILD_NAME, String?): com.datadog.android.sessionreplay.model.MobileSegment.Wireframe?
   fun createCompoundDrawableWireframes(android.widget.TextView, com.datadog.android.sessionreplay.recorder.MappingContext, Int, String?, AsyncJobStatusCallback): MutableList<com.datadog.android.sessionreplay.model.MobileSegment.Wireframe>
   companion object 
 open class com.datadog.android.sessionreplay.utils.LegacyDrawableToColorMapper : DrawableToColorMapper
diff --git a/features/dd-sdk-android-session-replay/api/dd-sdk-android-session-replay.api b/features/dd-sdk-android-session-replay/api/dd-sdk-android-session-replay.api
index 08d8e85f4b..cd5b8ca7e0 100644
--- a/features/dd-sdk-android-session-replay/api/dd-sdk-android-session-replay.api
+++ b/features/dd-sdk-android-session-replay/api/dd-sdk-android-session-replay.api
@@ -117,15 +117,6 @@ public final class com/datadog/android/sessionreplay/internal/recorder/obfuscato
 	public final fun getStringObfuscator ()Lcom/datadog/android/sessionreplay/internal/recorder/obfuscator/StringObfuscator;
 }
 
-public final class com/datadog/android/sessionreplay/internal/recorder/resources/DefaultDrawableCopier : com/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier {
-	public fun <init> ()V
-	public fun copy (Landroid/graphics/drawable/Drawable;Landroid/content/res/Resources;)Landroid/graphics/drawable/Drawable;
-}
-
-public abstract interface class com/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier {
-	public abstract fun copy (Landroid/graphics/drawable/Drawable;Landroid/content/res/Resources;)Landroid/graphics/drawable/Drawable;
-}
-
 public final class com/datadog/android/sessionreplay/model/MobileSegment {
 	public static final field Companion Lcom/datadog/android/sessionreplay/model/MobileSegment$Companion;
 	public fun <init> (Lcom/datadog/android/sessionreplay/model/MobileSegment$Application;Lcom/datadog/android/sessionreplay/model/MobileSegment$Session;Lcom/datadog/android/sessionreplay/model/MobileSegment$View;JJJLjava/lang/Long;Ljava/lang/Boolean;Lcom/datadog/android/sessionreplay/model/MobileSegment$Source;Ljava/util/List;)V
@@ -1453,7 +1444,11 @@ public final class com/datadog/android/sessionreplay/recorder/SystemInformation
 
 public abstract class com/datadog/android/sessionreplay/recorder/mapper/BaseAsyncBackgroundWireframeMapper : com/datadog/android/sessionreplay/recorder/mapper/BaseWireframeMapper {
 	public static final field Companion Lcom/datadog/android/sessionreplay/recorder/mapper/BaseAsyncBackgroundWireframeMapper$Companion;
+	public fun <init> (Lcom/datadog/android/sessionreplay/utils/ViewIdentifierResolver;Lcom/datadog/android/sessionreplay/utils/ColorStringFormatter;Lcom/datadog/android/sessionreplay/utils/ViewBoundsResolver;Lcom/datadog/android/sessionreplay/utils/DrawableToColorMapper;)V
 	public fun map (Landroid/view/View;Lcom/datadog/android/sessionreplay/recorder/MappingContext;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/api/InternalLogger;)Ljava/util/List;
+	protected fun resolveBackgroundAsImageWireframe (Landroid/view/View;Lcom/datadog/android/sessionreplay/utils/GlobalBounds;IILcom/datadog/android/sessionreplay/recorder/MappingContext;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
+	protected fun resolveBackgroundAsShapeWireframe (Landroid/view/View;Lcom/datadog/android/sessionreplay/utils/GlobalBounds;IILcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe$ShapeWireframe;
+	protected fun resolveViewBackground (Landroid/view/View;Lcom/datadog/android/sessionreplay/recorder/MappingContext;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/api/InternalLogger;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
 }
 
 public final class com/datadog/android/sessionreplay/recorder/mapper/BaseAsyncBackgroundWireframeMapper$Companion {
@@ -1483,7 +1478,7 @@ public final class com/datadog/android/sessionreplay/recorder/mapper/EditTextMap
 }
 
 public class com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapper : com/datadog/android/sessionreplay/recorder/mapper/BaseAsyncBackgroundWireframeMapper {
-	public fun <init> (Lcom/datadog/android/sessionreplay/utils/ViewIdentifierResolver;Lcom/datadog/android/sessionreplay/utils/ColorStringFormatter;Lcom/datadog/android/sessionreplay/utils/ViewBoundsResolver;Lcom/datadog/android/sessionreplay/utils/DrawableToColorMapper;)V
+	public fun <init> (Lcom/datadog/android/sessionreplay/utils/ViewIdentifierResolver;Lcom/datadog/android/sessionreplay/utils/ColorStringFormatter;Lcom/datadog/android/sessionreplay/utils/ViewBoundsResolver;Lcom/datadog/android/sessionreplay/utils/DrawableToColorMapper;Lcom/datadog/android/sessionreplay/recorder/resources/DrawableCopier;)V
 	public synthetic fun map (Landroid/view/View;Lcom/datadog/android/sessionreplay/recorder/MappingContext;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/api/InternalLogger;)Ljava/util/List;
 	public fun map (Landroid/widget/ImageView;Lcom/datadog/android/sessionreplay/recorder/MappingContext;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/api/InternalLogger;)Ljava/util/List;
 }
@@ -1503,6 +1498,15 @@ public abstract interface class com/datadog/android/sessionreplay/recorder/mappe
 	public abstract fun map (Landroid/view/View;Lcom/datadog/android/sessionreplay/recorder/MappingContext;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/api/InternalLogger;)Ljava/util/List;
 }
 
+public final class com/datadog/android/sessionreplay/recorder/resources/DefaultDrawableCopier : com/datadog/android/sessionreplay/recorder/resources/DrawableCopier {
+	public fun <init> ()V
+	public fun copy (Landroid/graphics/drawable/Drawable;Landroid/content/res/Resources;)Landroid/graphics/drawable/Drawable;
+}
+
+public abstract interface class com/datadog/android/sessionreplay/recorder/resources/DrawableCopier {
+	public abstract fun copy (Landroid/graphics/drawable/Drawable;Landroid/content/res/Resources;)Landroid/graphics/drawable/Drawable;
+}
+
 public class com/datadog/android/sessionreplay/utils/AndroidMDrawableToColorMapper : com/datadog/android/sessionreplay/utils/LegacyDrawableToColorMapper {
 	public fun <init> ()V
 	public fun <init> (Ljava/util/List;)V
@@ -1586,7 +1590,7 @@ public abstract interface class com/datadog/android/sessionreplay/utils/ImageWir
 	public static final field Companion Lcom/datadog/android/sessionreplay/utils/ImageWireframeHelper$Companion;
 	public abstract fun createCompoundDrawableWireframes (Landroid/widget/TextView;Lcom/datadog/android/sessionreplay/recorder/MappingContext;ILjava/lang/String;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;)Ljava/util/List;
 	public abstract fun createImageWireframeByBitmap (JLcom/datadog/android/sessionreplay/utils/GlobalBounds;Landroid/graphics/Bitmap;FZLcom/datadog/android/sessionreplay/ImagePrivacy;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
-	public abstract fun createImageWireframeByDrawable (Landroid/view/View;Lcom/datadog/android/sessionreplay/ImagePrivacy;IJJIIZLandroid/graphics/drawable/Drawable;Lcom/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
+	public abstract fun createImageWireframeByDrawable (Landroid/view/View;Lcom/datadog/android/sessionreplay/ImagePrivacy;IJJIIZLandroid/graphics/drawable/Drawable;Lcom/datadog/android/sessionreplay/recorder/resources/DrawableCopier;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
 }
 
 public final class com/datadog/android/sessionreplay/utils/ImageWireframeHelper$Companion {
@@ -1594,7 +1598,7 @@ public final class com/datadog/android/sessionreplay/utils/ImageWireframeHelper$
 
 public final class com/datadog/android/sessionreplay/utils/ImageWireframeHelper$DefaultImpls {
 	public static synthetic fun createImageWireframeByBitmap$default (Lcom/datadog/android/sessionreplay/utils/ImageWireframeHelper;JLcom/datadog/android/sessionreplay/utils/GlobalBounds;Landroid/graphics/Bitmap;FZLcom/datadog/android/sessionreplay/ImagePrivacy;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
-	public static synthetic fun createImageWireframeByDrawable$default (Lcom/datadog/android/sessionreplay/utils/ImageWireframeHelper;Landroid/view/View;Lcom/datadog/android/sessionreplay/ImagePrivacy;IJJIIZLandroid/graphics/drawable/Drawable;Lcom/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
+	public static synthetic fun createImageWireframeByDrawable$default (Lcom/datadog/android/sessionreplay/utils/ImageWireframeHelper;Landroid/view/View;Lcom/datadog/android/sessionreplay/ImagePrivacy;IJJIIZLandroid/graphics/drawable/Drawable;Lcom/datadog/android/sessionreplay/recorder/resources/DrawableCopier;Lcom/datadog/android/sessionreplay/utils/AsyncJobStatusCallback;Lcom/datadog/android/sessionreplay/model/MobileSegment$WireframeClip;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeStyle;Lcom/datadog/android/sessionreplay/model/MobileSegment$ShapeBorder;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/model/MobileSegment$Wireframe;
 }
 
 public class com/datadog/android/sessionreplay/utils/LegacyDrawableToColorMapper : com/datadog/android/sessionreplay/utils/DrawableToColorMapper {
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/DefaultRecorderProvider.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/DefaultRecorderProvider.kt
index bbe80d462c..d73d4e15b3 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/DefaultRecorderProvider.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/DefaultRecorderProvider.kt
@@ -22,6 +22,7 @@ import android.widget.TextView
 import androidx.appcompat.widget.ActionBarContainer
 import androidx.appcompat.widget.SwitchCompat
 import com.datadog.android.api.feature.FeatureSdkCore
+import com.datadog.android.internal.utils.ImageViewUtils
 import com.datadog.android.sessionreplay.ImagePrivacy
 import com.datadog.android.sessionreplay.MapperTypeWrapper
 import com.datadog.android.sessionreplay.TextAndInputPrivacy
@@ -41,12 +42,12 @@ import com.datadog.android.sessionreplay.internal.resources.ResourceDataStoreMan
 import com.datadog.android.sessionreplay.internal.storage.RecordWriter
 import com.datadog.android.sessionreplay.internal.storage.ResourcesWriter
 import com.datadog.android.sessionreplay.internal.time.SessionReplayTimeProvider
-import com.datadog.android.sessionreplay.internal.utils.ImageViewUtils
 import com.datadog.android.sessionreplay.recorder.OptionSelectorDetector
 import com.datadog.android.sessionreplay.recorder.mapper.EditTextMapper
 import com.datadog.android.sessionreplay.recorder.mapper.ImageViewMapper
 import com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper
 import com.datadog.android.sessionreplay.recorder.mapper.WireframeMapper
+import com.datadog.android.sessionreplay.recorder.resources.DefaultDrawableCopier
 import com.datadog.android.sessionreplay.utils.ColorStringFormatter
 import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter
 import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver
@@ -101,7 +102,8 @@ internal class DefaultRecorderProvider(
             colorStringFormatter = colorStringFormatter,
             viewBoundsResolver = viewBoundsResolver,
             drawableToColorMapper = drawableToColorMapper,
-            imageViewUtils = ImageViewUtils
+            imageViewUtils = ImageViewUtils,
+            drawableCopier = DefaultDrawableCopier()
         )
         val textViewMapper = TextViewMapper<TextView>(
             viewIdentifierResolver,
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/ViewUtilsInternal.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/ViewUtilsInternal.kt
index 41bca26faa..dd9f119ab0 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/ViewUtilsInternal.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/ViewUtilsInternal.kt
@@ -12,6 +12,7 @@ import android.view.View
 import android.view.ViewStub
 import androidx.appcompat.widget.ActionBarContextView
 import androidx.appcompat.widget.Toolbar
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.internal.recorder.resources.DefaultImageWireframeHelper
 import com.datadog.android.sessionreplay.utils.GlobalBounds
 
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/callback/RecorderWindowCallback.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/callback/RecorderWindowCallback.kt
index 40293a5ae4..0c60391473 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/callback/RecorderWindowCallback.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/callback/RecorderWindowCallback.kt
@@ -12,13 +12,13 @@ import android.view.MotionEvent
 import android.view.Window
 import androidx.annotation.MainThread
 import com.datadog.android.api.InternalLogger
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.ImagePrivacy
 import com.datadog.android.sessionreplay.TextAndInputPrivacy
 import com.datadog.android.sessionreplay.internal.TouchPrivacyManager
 import com.datadog.android.sessionreplay.internal.async.RecordedDataQueueHandler
 import com.datadog.android.sessionreplay.internal.recorder.ViewOnDrawInterceptor
 import com.datadog.android.sessionreplay.internal.recorder.WindowInspector
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.internal.utils.TimeProvider
 import com.datadog.android.sessionreplay.model.MobileSegment
 import java.util.LinkedList
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BasePickerMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BasePickerMapper.kt
index 712a2b6dfd..7031d33ea7 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BasePickerMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BasePickerMapper.kt
@@ -9,7 +9,7 @@ package com.datadog.android.sessionreplay.internal.recorder.mapper
 import android.os.Build
 import android.widget.NumberPicker
 import androidx.annotation.RequiresApi
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.mapper.BaseWireframeMapper
 import com.datadog.android.sessionreplay.utils.ColorStringFormatter
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckableCompoundButtonMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckableCompoundButtonMapper.kt
index 1d057ff9a9..8cc7d1f449 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckableCompoundButtonMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckableCompoundButtonMapper.kt
@@ -12,7 +12,7 @@ import android.os.Build
 import android.widget.CompoundButton
 import androidx.annotation.UiThread
 import com.datadog.android.api.InternalLogger
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper
 import com.datadog.android.sessionreplay.utils.ColorStringFormatter
 import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckableTextViewMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckableTextViewMapper.kt
index ab75a3f988..c4fb1f894b 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckableTextViewMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckableTextViewMapper.kt
@@ -11,10 +11,10 @@ import android.widget.Checkable
 import android.widget.TextView
 import androidx.annotation.UiThread
 import com.datadog.android.api.InternalLogger
-import com.datadog.android.sessionreplay.internal.recorder.resources.DrawableCopier
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
 import com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper
+import com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
 import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
 import com.datadog.android.sessionreplay.utils.ColorStringFormatter
 import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckedTextViewMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckedTextViewMapper.kt
index 05222776c7..9b788120bc 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckedTextViewMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/CheckedTextViewMapper.kt
@@ -10,7 +10,7 @@ import android.graphics.drawable.Drawable
 import android.graphics.drawable.DrawableContainer
 import android.widget.CheckedTextView
 import androidx.annotation.UiThread
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper
 import com.datadog.android.sessionreplay.utils.ColorStringFormatter
 import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/ProgressBarWireframeMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/ProgressBarWireframeMapper.kt
index 621cc5e6fb..f5ba0fdfc8 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/ProgressBarWireframeMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/ProgressBarWireframeMapper.kt
@@ -14,8 +14,8 @@ import android.widget.ProgressBar
 import androidx.annotation.RequiresApi
 import androidx.annotation.UiThread
 import com.datadog.android.api.InternalLogger
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.TextAndInputPrivacy
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
 import com.datadog.android.sessionreplay.recorder.mapper.BaseAsyncBackgroundWireframeMapper
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SeekBarWireframeMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SeekBarWireframeMapper.kt
index c2cd516288..e3cce77f8e 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SeekBarWireframeMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SeekBarWireframeMapper.kt
@@ -8,8 +8,8 @@ package com.datadog.android.sessionreplay.internal.recorder.mapper
 
 import android.widget.SeekBar
 import com.datadog.android.api.InternalLogger
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.TextAndInputPrivacy
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
 import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SwitchCompatMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SwitchCompatMapper.kt
index 603ff000c1..c25c7ce16d 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SwitchCompatMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SwitchCompatMapper.kt
@@ -9,11 +9,11 @@ package com.datadog.android.sessionreplay.internal.recorder.mapper
 import androidx.annotation.UiThread
 import androidx.appcompat.widget.SwitchCompat
 import com.datadog.android.api.InternalLogger
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
-import com.datadog.android.sessionreplay.internal.recorder.resources.DrawableCopier
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
 import com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper
+import com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
 import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
 import com.datadog.android.sessionreplay.utils.ColorStringFormatter
 import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultImageWireframeHelper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultImageWireframeHelper.kt
index e915659362..d9bae6304e 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultImageWireframeHelper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultImageWireframeHelper.kt
@@ -15,11 +15,12 @@ import android.widget.TextView
 import androidx.annotation.UiThread
 import androidx.annotation.VisibleForTesting
 import com.datadog.android.api.InternalLogger
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.ImagePrivacy
 import com.datadog.android.sessionreplay.internal.recorder.ViewUtilsInternal
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
+import com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
 import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
 import com.datadog.android.sessionreplay.utils.GlobalBounds
 import com.datadog.android.sessionreplay.utils.ImageWireframeHelper
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ImageTypeResolver.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ImageTypeResolver.kt
index a414a0849b..4417eb3927 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ImageTypeResolver.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ImageTypeResolver.kt
@@ -9,7 +9,7 @@ package com.datadog.android.sessionreplay.internal.recorder.resources
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.GradientDrawable
 import androidx.annotation.VisibleForTesting
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
+import com.datadog.android.internal.utils.densityNormalized
 
 internal class ImageTypeResolver {
     fun isDrawablePII(drawable: Drawable, density: Float): Boolean {
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ResourceResolver.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ResourceResolver.kt
index de04810994..0ff79eaeb5 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ResourceResolver.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ResourceResolver.kt
@@ -18,6 +18,7 @@ import com.datadog.android.api.InternalLogger
 import com.datadog.android.core.internal.utils.executeSafe
 import com.datadog.android.sessionreplay.internal.async.DataQueueHandler
 import com.datadog.android.sessionreplay.internal.utils.DrawableUtils
+import com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
 import java.util.concurrent.ExecutorService
 import java.util.concurrent.LinkedBlockingDeque
 import java.util.concurrent.ThreadPoolExecutor
@@ -110,8 +111,8 @@ internal class ResourceResolver(
         // do in the background
         threadPoolExecutor.executeSafe("resolveResourceId", logger) {
             createBitmap(
-                resources = resources,
                 drawable = originalDrawable,
+                copiedDrawable = copiedDrawable,
                 drawableWidth = drawableWidth,
                 drawableHeight = drawableHeight,
                 displayMetrics = displayMetrics,
@@ -137,8 +138,8 @@ internal class ResourceResolver(
 
     @WorkerThread
     private fun createBitmap(
-        resources: Resources,
         drawable: Drawable,
+        copiedDrawable: Drawable,
         drawableWidth: Int,
         drawableHeight: Int,
         displayMetrics: DisplayMetrics,
@@ -148,7 +149,7 @@ internal class ResourceResolver(
     ) {
         val handledBitmap = if (bitmapFromDrawable != null) {
             tryToGetBitmapFromBitmapDrawable(
-                drawable = drawable as BitmapDrawable,
+                drawable = drawable,
                 bitmapFromDrawable = bitmapFromDrawable,
                 customResourceIdCacheKey = customResourceIdCacheKey,
                 resolveResourceCallback = resolveResourceCallback
@@ -159,8 +160,7 @@ internal class ResourceResolver(
 
         if (handledBitmap == null) {
             tryToDrawNewBitmap(
-                resources = resources,
-                drawable = drawable,
+                drawable = copiedDrawable,
                 drawableWidth = drawableWidth,
                 drawableHeight = drawableHeight,
                 displayMetrics = displayMetrics,
@@ -249,7 +249,6 @@ internal class ResourceResolver(
 
     @WorkerThread
     private fun tryToDrawNewBitmap(
-        resources: Resources,
         drawable: Drawable,
         drawableWidth: Int,
         drawableHeight: Int,
@@ -258,7 +257,6 @@ internal class ResourceResolver(
         resolveResourceCallback: ResolveResourceCallback
     ) {
         drawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = resources,
             drawable = drawable,
             drawableWidth = drawableWidth,
             drawableHeight = drawableHeight,
@@ -295,7 +293,7 @@ internal class ResourceResolver(
     @WorkerThread
     @Suppress("ReturnCount")
     private fun tryToGetBitmapFromBitmapDrawable(
-        drawable: BitmapDrawable,
+        drawable: Drawable,
         bitmapFromDrawable: Bitmap,
         customResourceIdCacheKey: String?,
         resolveResourceCallback: ResolveResourceCallback
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/DrawableUtils.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/DrawableUtils.kt
index 49eebf59ea..1e6dadf165 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/DrawableUtils.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/DrawableUtils.kt
@@ -6,7 +6,6 @@
 
 package com.datadog.android.sessionreplay.internal.utils
 
-import android.content.res.Resources
 import android.graphics.Bitmap
 import android.graphics.Bitmap.Config
 import android.graphics.Color
@@ -39,7 +38,6 @@ internal class DrawableUtils(
      */
     @WorkerThread
     internal fun createBitmapOfApproxSizeFromDrawable(
-        resources: Resources,
         drawable: Drawable,
         drawableWidth: Int,
         drawableHeight: Int,
@@ -59,7 +57,6 @@ internal class DrawableUtils(
                 override fun onSuccess(bitmap: Bitmap) {
                     executorService.submitSafe("drawOnCanvas", internalLogger) {
                         drawOnCanvas(
-                            resources,
                             bitmap,
                             drawable,
                             bitmapCreationCallback
@@ -103,27 +100,21 @@ internal class DrawableUtils(
 
     @WorkerThread
     private fun drawOnCanvas(
-        resources: Resources,
         bitmap: Bitmap,
         drawable: Drawable,
         bitmapCreationCallback: ResourceResolver.BitmapCreationCallback
     ) {
-        // don't use the original drawable - it will affect the view hierarchy
-        val newDrawable = drawable.constantState?.newDrawable(resources)?.apply {
-            // `constantState` contains only immutable properties of drawable,the state needs to be set manually
-            setState(drawable.current.state)
-        }
         val canvas = canvasWrapper.createCanvas(bitmap)
 
-        if (canvas == null || newDrawable == null) {
+        if (canvas == null) {
             bitmapCreationCallback.onFailure()
         } else {
             // erase the canvas
             // needed because overdrawing an already used bitmap causes unusual visual artifacts
             canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.MULTIPLY)
 
-            newDrawable.setBounds(0, 0, canvas.width, canvas.height)
-            newDrawable.draw(canvas)
+            drawable.setBounds(0, 0, canvas.width, canvas.height)
+            drawable.draw(canvas)
             bitmapCreationCallback.onReady(bitmap)
         }
     }
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/MiscUtils.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/MiscUtils.kt
index 96a7859abb..324d7db542 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/MiscUtils.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/MiscUtils.kt
@@ -13,7 +13,7 @@ import android.os.Build
 import android.util.TypedValue
 import android.view.WindowManager
 import com.datadog.android.api.InternalLogger
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.recorder.SystemInformation
 import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter
 import com.datadog.android.sessionreplay.utils.GlobalBounds
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/RectExt.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/RectExt.kt
new file mode 100644
index 0000000000..d60e440d7f
--- /dev/null
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/RectExt.kt
@@ -0,0 +1,19 @@
+/*
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
+ * Copyright 2016-Present Datadog, Inc.
+ */
+
+package com.datadog.android.sessionreplay.internal.utils
+
+import android.graphics.Rect
+import com.datadog.android.sessionreplay.model.MobileSegment
+
+internal fun Rect.toWireframeClip(): MobileSegment.WireframeClip {
+    return MobileSegment.WireframeClip(
+        this.top.toLong(),
+        this.bottom.toLong(),
+        this.left.toLong(),
+        this.right.toLong()
+    )
+}
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/BaseAsyncBackgroundWireframeMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/BaseAsyncBackgroundWireframeMapper.kt
index e3f4cad38a..7d64174f59 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/BaseAsyncBackgroundWireframeMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/BaseAsyncBackgroundWireframeMapper.kt
@@ -9,7 +9,7 @@ package com.datadog.android.sessionreplay.recorder.mapper
 import android.view.View
 import androidx.annotation.UiThread
 import com.datadog.android.api.InternalLogger
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
 import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
@@ -31,7 +31,7 @@ import com.datadog.android.sessionreplay.utils.ViewIdentifierResolver
  *  @param viewBoundsResolver the [ViewBoundsResolver] to get a view boundaries in density independent units
  *  @param drawableToColorMapper the [DrawableToColorMapper] to convert a background drawable into a solid color
  */
-abstract class BaseAsyncBackgroundWireframeMapper<in T : View> internal constructor(
+abstract class BaseAsyncBackgroundWireframeMapper<in T : View> (
     viewIdentifierResolver: ViewIdentifierResolver,
     colorStringFormatter: ColorStringFormatter,
     viewBoundsResolver: ViewBoundsResolver,
@@ -57,8 +57,16 @@ abstract class BaseAsyncBackgroundWireframeMapper<in T : View> internal construc
         return backgroundWireframe?.let { listOf(it) } ?: emptyList()
     }
 
+    /**
+     *  Function used to resolve the Wireframe to represent the view background, based on its type.
+     *
+     *  @param view the [View] to map
+     *  @param mappingContext the [MappingContext] which contains contextual data, useful for mapping.
+     *  @param asyncJobStatusCallback the [AsyncJobStatusCallback] callback used for internal async operations.
+     *  @param internalLogger the [InternalLogger], used for internal logging.
+     */
     @UiThread
-    private fun resolveViewBackground(
+    protected open fun resolveViewBackground(
         view: View,
         mappingContext: MappingContext,
         asyncJobStatusCallback: AsyncJobStatusCallback,
@@ -90,7 +98,16 @@ abstract class BaseAsyncBackgroundWireframeMapper<in T : View> internal construc
         }
     }
 
-    private fun resolveBackgroundAsShapeWireframe(
+    /**
+     *  Function used to resolve the view background as a Shape wireframe.
+     *
+     *  @param view the [View] to map
+     *  @param bounds the [GlobalBounds] of the view.
+     *  @param width the view width.
+     *  @param height the view height.
+     *  @param shapeStyle the optional [MobileSegment.ShapeStyle] to use.
+     */
+    protected open fun resolveBackgroundAsShapeWireframe(
         view: View,
         bounds: GlobalBounds,
         width: Int,
@@ -115,8 +132,18 @@ abstract class BaseAsyncBackgroundWireframeMapper<in T : View> internal construc
         )
     }
 
+    /**
+     *  Function used to resolve the view background as a Image wireframe.
+     *
+     *  @param view the [View] to map
+     *  @param bounds the [GlobalBounds] of the view.
+     *  @param width the view width.
+     *  @param height the view height.
+     *  @param mappingContext the [MappingContext] which contains contextual data, useful for mapping.
+     *  @param asyncJobStatusCallback the [AsyncJobStatusCallback] callback used for internal async operations.
+     */
     @UiThread
-    private fun resolveBackgroundAsImageWireframe(
+    protected open fun resolveBackgroundAsImageWireframe(
         view: View,
         bounds: GlobalBounds,
         width: Int,
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapper.kt
index 4d5b9a16c1..b080a898df 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapper.kt
@@ -9,10 +9,12 @@ package com.datadog.android.sessionreplay.recorder.mapper
 import android.widget.ImageView
 import androidx.annotation.UiThread
 import com.datadog.android.api.InternalLogger
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
-import com.datadog.android.sessionreplay.internal.utils.ImageViewUtils
+import com.datadog.android.internal.utils.ImageViewUtils
+import com.datadog.android.internal.utils.densityNormalized
+import com.datadog.android.sessionreplay.internal.utils.toWireframeClip
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
+import com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
 import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
 import com.datadog.android.sessionreplay.utils.ColorStringFormatter
 import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
@@ -25,19 +27,22 @@ import com.datadog.android.sessionreplay.utils.ViewIdentifierResolver
  */
 open class ImageViewMapper : BaseAsyncBackgroundWireframeMapper<ImageView> {
     private val imageViewUtils: ImageViewUtils
+    private val drawableCopier: DrawableCopier
 
     @Suppress("Unused") // used by external mappers
     constructor(
         viewIdentifierResolver: ViewIdentifierResolver,
         colorStringFormatter: ColorStringFormatter,
         viewBoundsResolver: ViewBoundsResolver,
-        drawableToColorMapper: DrawableToColorMapper
+        drawableToColorMapper: DrawableToColorMapper,
+        drawableCopier: DrawableCopier
     ) : this(
         viewIdentifierResolver,
         colorStringFormatter,
         viewBoundsResolver,
         drawableToColorMapper,
-        ImageViewUtils
+        ImageViewUtils,
+        drawableCopier
     )
 
     internal constructor(
@@ -45,7 +50,8 @@ open class ImageViewMapper : BaseAsyncBackgroundWireframeMapper<ImageView> {
         colorStringFormatter: ColorStringFormatter,
         viewBoundsResolver: ViewBoundsResolver,
         drawableToColorMapper: DrawableToColorMapper,
-        imageViewUtils: ImageViewUtils
+        imageViewUtils: ImageViewUtils,
+        drawableCopier: DrawableCopier
     ) : super(
         viewIdentifierResolver,
         colorStringFormatter,
@@ -53,6 +59,7 @@ open class ImageViewMapper : BaseAsyncBackgroundWireframeMapper<ImageView> {
         drawableToColorMapper
     ) {
         this.imageViewUtils = imageViewUtils
+        this.drawableCopier = drawableCopier
     }
 
     @UiThread
@@ -76,7 +83,7 @@ open class ImageViewMapper : BaseAsyncBackgroundWireframeMapper<ImageView> {
         val density = resources.displayMetrics.density
 
         val clipping = if (view.cropToPadding) {
-            imageViewUtils.calculateClipping(parentRect, contentRect, density)
+            imageViewUtils.calculateClipping(parentRect, contentRect, density).toWireframeClip()
         } else {
             null
         }
@@ -97,6 +104,7 @@ open class ImageViewMapper : BaseAsyncBackgroundWireframeMapper<ImageView> {
             height = contentHeightPx,
             usePIIPlaceholder = true,
             drawable = drawable,
+            drawableCopier = drawableCopier,
             asyncJobStatusCallback = asyncJobStatusCallback,
             clipping = clipping,
             shapeStyle = null,
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/TextViewMapper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/TextViewMapper.kt
index 85ba1b627b..289e66e44d 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/TextViewMapper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/mapper/TextViewMapper.kt
@@ -11,8 +11,8 @@ import android.view.Gravity
 import android.widget.TextView
 import androidx.annotation.UiThread
 import com.datadog.android.api.InternalLogger
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.TextAndInputPrivacy
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.internal.recorder.obfuscator.StringObfuscator
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultDrawableCopier.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/resources/DefaultDrawableCopier.kt
similarity index 83%
rename from features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultDrawableCopier.kt
rename to features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/resources/DefaultDrawableCopier.kt
index 8bd17fdba1..92f527d404 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultDrawableCopier.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/resources/DefaultDrawableCopier.kt
@@ -4,16 +4,14 @@
  * Copyright 2016-Present Datadog, Inc.
  */
 
-package com.datadog.android.sessionreplay.internal.recorder.resources
+package com.datadog.android.sessionreplay.recorder.resources
 
 import android.content.res.Resources
 import android.graphics.drawable.Drawable
-import com.datadog.android.lint.InternalApi
 
 /**
  * Default implementation of [DrawableCopier] interface, it copies the drawable from constant state.
  */
-@InternalApi
 class DefaultDrawableCopier : DrawableCopier {
     override fun copy(originalDrawable: Drawable, resources: Resources): Drawable? {
         return originalDrawable.constantState?.newDrawable(resources)
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/resources/DrawableCopier.kt
similarity index 84%
rename from features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier.kt
rename to features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/resources/DrawableCopier.kt
index f732b1b5a4..a01e0bc09f 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DrawableCopier.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/recorder/resources/DrawableCopier.kt
@@ -4,16 +4,14 @@
  * Copyright 2016-Present Datadog, Inc.
  */
 
-package com.datadog.android.sessionreplay.internal.recorder.resources
+package com.datadog.android.sessionreplay.recorder.resources
 
 import android.content.res.Resources
 import android.graphics.drawable.Drawable
-import com.datadog.android.lint.InternalApi
 
 /**
  * Interface of copying drawable to a new one.
  */
-@InternalApi
 fun interface DrawableCopier {
 
     /**
diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/utils/ImageWireframeHelper.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/utils/ImageWireframeHelper.kt
index b147caf4ce..d627d49fe0 100644
--- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/utils/ImageWireframeHelper.kt
+++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/utils/ImageWireframeHelper.kt
@@ -12,10 +12,10 @@ import android.view.View
 import android.widget.TextView
 import androidx.annotation.UiThread
 import com.datadog.android.sessionreplay.ImagePrivacy
-import com.datadog.android.sessionreplay.internal.recorder.resources.DefaultDrawableCopier
-import com.datadog.android.sessionreplay.internal.recorder.resources.DrawableCopier
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
+import com.datadog.android.sessionreplay.recorder.resources.DefaultDrawableCopier
+import com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
 
 /**
  * A Helper to handle capturing images in Session replay wireframes.
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/IntExtTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/IntExtTest.kt
index 68a9b90fc4..cc4da5de0e 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/IntExtTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/IntExtTest.kt
@@ -6,6 +6,7 @@
 
 package com.datadog.android.sessionreplay.internal.recorder
 
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
 import fr.xgouchet.elmyr.annotation.FloatForgery
 import fr.xgouchet.elmyr.annotation.IntForgery
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/LongExtTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/LongExtTest.kt
index 0715d2f8b1..be1842864d 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/LongExtTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/LongExtTest.kt
@@ -6,6 +6,7 @@
 
 package com.datadog.android.sessionreplay.internal.recorder
 
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
 import fr.xgouchet.elmyr.annotation.FloatForgery
 import fr.xgouchet.elmyr.annotation.LongForgery
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseCheckableTextViewMapperTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseCheckableTextViewMapperTest.kt
index 930c1a030f..15558911ff 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseCheckableTextViewMapperTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseCheckableTextViewMapperTest.kt
@@ -17,9 +17,9 @@ import com.datadog.android.sessionreplay.TextAndInputPrivacy
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
 import com.datadog.android.sessionreplay.internal.recorder.mapper.CheckableTextViewMapper.Companion.CHECK_BOX_CHECKED_DRAWABLE_INDEX
 import com.datadog.android.sessionreplay.internal.recorder.mapper.CheckableTextViewMapper.Companion.CHECK_BOX_NOT_CHECKED_DRAWABLE_INDEX
-import com.datadog.android.sessionreplay.internal.recorder.resources.DrawableCopier
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper
+import com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
 import com.datadog.android.sessionreplay.utils.GlobalBounds
 import com.datadog.android.sessionreplay.utils.OPAQUE_ALPHA_VALUE
 import com.datadog.tools.unit.annotations.TestTargetApi
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseNumberPickerMapperTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseNumberPickerMapperTest.kt
index 67b0596bb0..e74dcfbd27 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseNumberPickerMapperTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseNumberPickerMapperTest.kt
@@ -7,7 +7,7 @@
 package com.datadog.android.sessionreplay.internal.recorder.mapper
 
 import android.widget.NumberPicker
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.utils.GlobalBounds
 import com.datadog.android.sessionreplay.utils.OPAQUE_ALPHA_VALUE
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseSwitchCompatMapperTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseSwitchCompatMapperTest.kt
index c48948df15..e3a7e09327 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseSwitchCompatMapperTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/BaseSwitchCompatMapperTest.kt
@@ -11,9 +11,9 @@ import android.graphics.Rect
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.Drawable.ConstantState
 import androidx.appcompat.widget.SwitchCompat
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.TextAndInputPrivacy
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper
 import com.datadog.android.sessionreplay.utils.GlobalBounds
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/ProgressBarWireframeMapperTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/ProgressBarWireframeMapperTest.kt
index ed4e4dfcb4..31da2a5dad 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/ProgressBarWireframeMapperTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/ProgressBarWireframeMapperTest.kt
@@ -4,9 +4,9 @@ import android.content.res.ColorStateList
 import android.graphics.Rect
 import android.os.Build
 import android.widget.ProgressBar
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.TextAndInputPrivacy
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.internal.recorder.mapper.SeekBarWireframeMapper.Companion.TRACK_HEIGHT_IN_PX
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.mapper.AbstractWireframeMapperTest
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SeekBarWireframeMapperTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SeekBarWireframeMapperTest.kt
index a282d78e9f..638ba063a8 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SeekBarWireframeMapperTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SeekBarWireframeMapperTest.kt
@@ -5,9 +5,9 @@ import android.graphics.Rect
 import android.graphics.drawable.Drawable
 import android.os.Build
 import android.widget.SeekBar
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.TextAndInputPrivacy
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.internal.recorder.mapper.SeekBarWireframeMapper.Companion.TRACK_HEIGHT_IN_PX
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.mapper.AbstractWireframeMapperTest
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SwitchCompatMapperTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SwitchCompatMapperTest.kt
index ccb3181a0d..b93ef068a9 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SwitchCompatMapperTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/SwitchCompatMapperTest.kt
@@ -7,10 +7,10 @@
 package com.datadog.android.sessionreplay.internal.recorder.mapper
 
 import android.graphics.drawable.Drawable
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.ImagePrivacy
 import com.datadog.android.sessionreplay.TextAndInputPrivacy
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.model.MobileSegment
 import fr.xgouchet.elmyr.Forge
 import fr.xgouchet.elmyr.junit5.ForgeConfiguration
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultImageWireframeHelperTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultImageWireframeHelperTest.kt
index 196ff22dc7..2b8416a3d5 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultImageWireframeHelperTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/DefaultImageWireframeHelperTest.kt
@@ -173,15 +173,6 @@ internal class DefaultImageWireframeHelperTest {
             )
         ).thenReturn(fakeGeneratedIdentifier)
 
-        whenever(
-            mockViewUtilsInternal.resolveCompoundDrawableBounds(
-                view = any(),
-                drawable = any(),
-                pixelsDensity = any(),
-                position = any()
-            )
-        ).thenReturn(fakeBounds)
-
         testedHelper = DefaultImageWireframeHelper(
             logger = mockLogger,
             resourceResolver = mockResourceResolver,
@@ -503,7 +494,26 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M not return image wireframe W createImageWireframeByDrawable { usePIIPlaceholder and MASK_NONE }`() {
+    fun `M return content placeholder W createImageWireframeByBitmap() { ImagePrivacy MASK_ALL }`() {
+        // When
+        val wireframe = testedHelper.createImageWireframeByBitmap(
+            id = fakeViewId,
+            bitmap = mockBitmap,
+            density = fakeDensity,
+            imagePrivacy = ImagePrivacy.MASK_ALL,
+            isContextualImage = false,
+            globalBounds = fakeBounds,
+            shapeStyle = null,
+            border = null,
+            asyncJobStatusCallback = mockAsyncJobStatusCallback
+        )
+
+        // Then
+        assertThat(wireframe).isInstanceOf(MobileSegment.Wireframe.PlaceholderWireframe::class.java)
+    }
+
+    @Test
+    fun `M not return image wireframe W createImageWireframeByDrawable(usePIIPlaceholder = true) { MASK_NONE }`() {
         // When
         val wireframe = testedHelper.createImageWireframeByDrawable(
             view = mockView,
@@ -526,7 +536,26 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M return null W createImageWireframeByDrawable { application context is null }`() {
+    fun `M not return image wireframe W createImageWireframeByBitmap { MASK_LARGE_ONLY & isContextual image}`() {
+        // When
+        val wireframe = testedHelper.createImageWireframeByBitmap(
+            id = fakeViewId,
+            bitmap = mockBitmap,
+            density = fakeDensity,
+            imagePrivacy = ImagePrivacy.MASK_LARGE_ONLY,
+            isContextualImage = true,
+            globalBounds = fakeBounds,
+            shapeStyle = null,
+            border = null,
+            asyncJobStatusCallback = mockAsyncJobStatusCallback
+        )
+
+        // Then
+        assertThat(wireframe).isInstanceOf(MobileSegment.Wireframe.PlaceholderWireframe::class.java)
+    }
+
+    @Test
+    fun `M return null W createImageWireframeByDrawable() { application context is null }`() {
         // Given
         whenever(mockView.context.applicationContext).thenReturn(null)
 
@@ -552,7 +581,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M send telemetry W createImageWireframeByDrawable { application context is null }`() {
+    fun `M send telemetry W createImageWireframeByDrawable() { application context is null }`() {
         // Given
         whenever(mockView.context.applicationContext).thenReturn(null)
 
@@ -582,7 +611,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M log error W createImageWireframeByDrawable { resources is null }`() {
+    fun `M log error W createImageWireframeByDrawable() { resources is null }`() {
         // Given
         whenever(mockView.resources).thenReturn(null)
 
@@ -612,7 +641,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M return null W createImageWireframeByDrawable { id is null }`() {
+    fun `M return null W createImageWireframeByDrawable() { id is null }`() {
         // Given
         whenever(mockViewIdentifierResolver.resolveChildUniqueIdentifier(any(), any()))
             .thenReturn(null)
@@ -640,7 +669,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M return null W createImageWireframeByDrawable { drawable has no width }`() {
+    fun `M return null W createImageWireframeByDrawable() { drawable has no width }`() {
         // When
         val wireframe = testedHelper.createImageWireframeByDrawable(
             view = mockView,
@@ -663,7 +692,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M return null W createImageWireframeByDrawable { drawable has no height }`() {
+    fun `M return null W createImageWireframeByDrawable() { drawable has no height }`() {
         // When
         val wireframe = testedHelper.createImageWireframeByDrawable(
             view = mockView,
@@ -686,7 +715,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M return wireframe W createImageWireframeByDrawable`(
+    fun `M return wireframe W createImageWireframeByDrawable()`(
         @Mock mockShapeStyle: MobileSegment.ShapeStyle,
         @Mock mockBorder: MobileSegment.ShapeBorder,
         @Mock stubWireframeClip: MobileSegment.WireframeClip
@@ -761,7 +790,202 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M resolve view width and height W createImageWireframeByDrawable { RippleDrawable }`(
+    fun `M return wireframe W createImageWireframeByBitmap()`(
+        @Mock mockShapeStyle: MobileSegment.ShapeStyle,
+        @Mock mockBorder: MobileSegment.ShapeBorder,
+        @Mock stubWireframeClip: MobileSegment.WireframeClip
+    ) {
+        // Given
+        whenever(
+            mockResourceResolver.resolveResourceId(
+                bitmap = any(),
+                resourceResolverCallback = any()
+            )
+        ).thenAnswer {
+            val callback = it.arguments[1] as ResourceResolverCallback
+            callback.onSuccess(fakeResourceId)
+        }
+
+        val expectedWireframe = MobileSegment.Wireframe.ImageWireframe(
+            id = fakeGeneratedIdentifier,
+            x = fakeBounds.x,
+            y = fakeBounds.y,
+            width = fakeBounds.width,
+            height = fakeBounds.height,
+            shapeStyle = mockShapeStyle,
+            border = mockBorder,
+            resourceId = fakeResourceId,
+            clip = stubWireframeClip,
+            isEmpty = false
+        )
+
+        // When
+        val wireframe = testedHelper.createImageWireframeByBitmap(
+            id = fakeGeneratedIdentifier,
+            imagePrivacy = ImagePrivacy.MASK_LARGE_ONLY,
+            density = fakeDensity,
+            globalBounds = fakeBounds,
+            bitmap = mockBitmap,
+            shapeStyle = mockShapeStyle,
+            border = mockBorder,
+            asyncJobStatusCallback = mockAsyncJobStatusCallback,
+            isContextualImage = false,
+            clipping = stubWireframeClip
+        )
+
+        // Then
+        verify(mockResourceResolver).resolveResourceId(
+            bitmap = any(),
+            resourceResolverCallback = any()
+        )
+        verify(mockAsyncJobStatusCallback).jobStarted()
+        verify(mockAsyncJobStatusCallback).jobFinished()
+        verifyNoMoreInteractions(mockAsyncJobStatusCallback)
+        assertThat(wireframe).isEqualTo(expectedWireframe)
+    }
+
+    // endregion
+
+    // region createCompoundDrawableWireframes
+
+    @Test
+    fun `M return empty list W createCompoundDrawableWireframes() { no compound drawables }`() {
+        // Given
+        whenever(mockTextView.compoundDrawables)
+            .thenReturn(arrayOf(null, null, null, null))
+
+        // When
+        val wireframes = testedHelper.createCompoundDrawableWireframes(
+            textView = mockTextView,
+            mappingContext = mockMappingContext,
+            prevWireframeIndex = 0,
+            customResourceIdCacheKey = null,
+            asyncJobStatusCallback = mockAsyncJobStatusCallback
+        )
+
+        // Then
+        verifyNoInteractions(mockAsyncJobStatusCallback)
+        assertThat(wireframes).isEmpty()
+    }
+
+    @Test
+    fun `M return wireframe W createCompoundDrawableWireframes()`() {
+        // Given
+        whenever(
+            mockViewUtilsInternal.resolveCompoundDrawableBounds(
+                view = any(),
+                drawable = any(),
+                pixelsDensity = any(),
+                position = any()
+            )
+        ).thenReturn(fakeBounds)
+        val fakeDrawables = arrayOf(null, mockDrawable, null, null)
+        whenever(mockTextView.compoundDrawables)
+            .thenReturn(fakeDrawables)
+
+        // When
+        val wireframes = testedHelper.createCompoundDrawableWireframes(
+            textView = mockTextView,
+            mappingContext = mockMappingContext,
+            prevWireframeIndex = 0,
+            customResourceIdCacheKey = null,
+            asyncJobStatusCallback = mockAsyncJobStatusCallback
+        )
+
+        assertThat(wireframes[0]).isInstanceOf(MobileSegment.Wireframe.ImageWireframe::class.java)
+
+        // Then
+        val argumentCaptor = argumentCaptor<ResourceResolverCallback>()
+
+        verify(mockResourceResolver).resolveResourceId(
+            resources = any(),
+            applicationContext = any(),
+            displayMetrics = any(),
+            originalDrawable = any(),
+            drawableCopier = any(),
+            drawableWidth = any(),
+            drawableHeight = any(),
+            customResourceIdCacheKey = anyOrNull(),
+            resourceResolverCallback = argumentCaptor.capture()
+        )
+        argumentCaptor.allValues.forEach {
+            it.onSuccess(fakeResourceId)
+        }
+        verify(mockAsyncJobStatusCallback).jobStarted()
+        verify(mockAsyncJobStatusCallback).jobFinished()
+        assertThat(wireframes.size).isEqualTo(1)
+    }
+
+    @Test
+    fun `M return multiple wireframes W createCompoundDrawableWireframes() { multiple drawables }`() {
+        // Given
+        whenever(
+            mockViewUtilsInternal.resolveCompoundDrawableBounds(
+                view = any(),
+                drawable = any(),
+                pixelsDensity = any(),
+                position = any()
+            )
+        )
+            .thenReturn(fakeBounds)
+        val fakeDrawables = arrayOf(null, mockDrawable, null, mockDrawable)
+        whenever(mockTextView.compoundDrawables)
+            .thenReturn(fakeDrawables)
+
+        // When
+        val wireframes = testedHelper.createCompoundDrawableWireframes(
+            textView = mockTextView,
+            mappingContext = mockMappingContext,
+            prevWireframeIndex = 0,
+            customResourceIdCacheKey = null,
+            asyncJobStatusCallback = mockAsyncJobStatusCallback
+        )
+
+        assertThat(wireframes[0]).isInstanceOf(MobileSegment.Wireframe.ImageWireframe::class.java)
+
+        // Then
+        val argumentCaptor = argumentCaptor<ResourceResolverCallback>()
+        verify(mockResourceResolver, times(2)).resolveResourceId(
+            resources = any(),
+            applicationContext = any(),
+            displayMetrics = any(),
+            originalDrawable = any(),
+            drawableCopier = any(),
+            drawableWidth = any(),
+            drawableHeight = any(),
+            customResourceIdCacheKey = anyOrNull(),
+            resourceResolverCallback = argumentCaptor.capture()
+        )
+        argumentCaptor.allValues.forEach {
+            it.onSuccess(fakeResourceId)
+        }
+        verify(mockAsyncJobStatusCallback, times(2)).jobStarted()
+        verify(mockAsyncJobStatusCallback, times(2)).jobFinished()
+        assertThat(wireframes).hasSize(2)
+    }
+
+    @Test
+    fun `M skip invalid elements W createCompoundDrawableWireframes() { invalid indices }`() {
+        // Given
+        whenever(mockTextView.compoundDrawables)
+            .thenReturn(arrayOf(null, null, null, null, null, null))
+
+        // When
+        val wireframes = testedHelper.createCompoundDrawableWireframes(
+            textView = mockTextView,
+            mappingContext = mockMappingContext,
+            prevWireframeIndex = 0,
+            customResourceIdCacheKey = null,
+            asyncJobStatusCallback = mockAsyncJobStatusCallback
+        )
+
+        // Then
+        verifyNoInteractions(mockAsyncJobStatusCallback)
+        assertThat(wireframes).isEmpty()
+    }
+
+    @Test
+    fun `M resolve view width and height W createImageWireframe() { RippleDrawable }`(
         @Mock mockDrawable: RippleDrawable,
         @Mock mockInsetDrawable: InsetDrawable,
         @Mock mockGradientDrawable: GradientDrawable,
@@ -809,7 +1033,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M resolve drawable width and height W createImageWireframeByDrawable { TextView }`() {
+    fun `M resolve drawable width and height W createImageWireframe() { TextView }`() {
         // When
         testedHelper.createImageWireframeByDrawable(
             view = mockView,
@@ -845,7 +1069,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M not try to resolve bitmap W createImageWireframeByDrawable { PII image }`(
+    fun `M not try to resolve bitmap W createImageWireframeByDrawable() { PII image }`(
         forge: Forge,
         @Mock mockResources: Resources,
         @Mock mockDisplayMetrics: DisplayMetrics,
@@ -893,7 +1117,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M try to resolve bitmap W createImageWireframeByDrawable { non-PII image }`() {
+    fun `M try to resolve bitmap W createImageWireframeByDrawable() { non-PII image }`() {
         // Given
         whenever(mockImageTypeResolver.isDrawablePII(any(), any())).thenReturn(false)
 
@@ -929,7 +1153,7 @@ internal class DefaultImageWireframeHelperTest {
     }
 
     @Test
-    fun `M return content placeholder W createImageWireframeByDrawable { PII image }`() {
+    fun `M return content placeholder W createImageWireframeByDrawable() { PII image }`() {
         // Given
         whenever(mockImageTypeResolver.isDrawablePII(any(), any())).thenReturn(true)
 
@@ -968,6 +1192,15 @@ internal class DefaultImageWireframeHelperTest {
         whenever(mockTextView.compoundDrawables)
             .thenReturn(arrayOf(mockDrawable, mockDrawable, mockDrawable, mockDrawable))
 
+        whenever(
+            mockViewUtilsInternal.resolveCompoundDrawableBounds(
+                view = any(),
+                drawable = any(),
+                pixelsDensity = any(),
+                position = any()
+            )
+        ).thenReturn(fakeBounds)
+
         // When
         testedHelper.createCompoundDrawableWireframes(
             textView = mockTextView,
@@ -1022,6 +1255,15 @@ internal class DefaultImageWireframeHelperTest {
         whenever(mockTextView.compoundDrawables)
             .thenReturn(fakeDrawables)
 
+        whenever(
+            mockViewUtilsInternal.resolveCompoundDrawableBounds(
+                view = any(),
+                drawable = any(),
+                pixelsDensity = any(),
+                position = any()
+            )
+        ).thenReturn(fakeBounds)
+
         // When
         val wireframes = testedHelper.createCompoundDrawableWireframes(
             textView = mockTextView,
@@ -1030,7 +1272,8 @@ internal class DefaultImageWireframeHelperTest {
             customResourceIdCacheKey = null,
             asyncJobStatusCallback = mockAsyncJobStatusCallback
         )
-        wireframes[0] as MobileSegment.Wireframe.ImageWireframe
+
+        assertThat(wireframes[0]).isInstanceOf(MobileSegment.Wireframe.ImageWireframe::class.java)
 
         // Then
         val argumentCaptor = argumentCaptor<ResourceResolverCallback>()
@@ -1078,7 +1321,8 @@ internal class DefaultImageWireframeHelperTest {
             customResourceIdCacheKey = null,
             asyncJobStatusCallback = mockAsyncJobStatusCallback
         )
-        wireframes[0] as MobileSegment.Wireframe.ImageWireframe
+
+        assertThat(wireframes[0]).isInstanceOf(MobileSegment.Wireframe.ImageWireframe::class.java)
 
         // Then
         val argumentCaptor = argumentCaptor<ResourceResolverCallback>()
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ResourceResolverTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ResourceResolverTest.kt
index 7f8b40bec7..8d640190d3 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ResourceResolverTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/resources/ResourceResolverTest.kt
@@ -18,6 +18,7 @@ import com.datadog.android.api.InternalLogger
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
 import com.datadog.android.sessionreplay.internal.async.RecordedDataQueueHandler
 import com.datadog.android.sessionreplay.internal.utils.DrawableUtils
+import com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
 import fr.xgouchet.elmyr.Forge
 import fr.xgouchet.elmyr.annotation.Forgery
 import fr.xgouchet.elmyr.annotation.StringForgery
@@ -141,7 +142,6 @@ internal class ResourceResolverTest {
 
         whenever(
             mockDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-                resources = any(),
                 drawable = any(),
                 drawableWidth = any(),
                 drawableHeight = any(),
@@ -151,7 +151,7 @@ internal class ResourceResolverTest {
                 bitmapCreationCallback = any()
             )
         ).then {
-            (it.arguments[7] as ResourceResolver.BitmapCreationCallback).onReady(mockBitmap)
+            (it.arguments[6] as ResourceResolver.BitmapCreationCallback).onReady(mockBitmap)
         }
 
         // executeSafe is an extension so we have to mock the internal execute function
@@ -233,7 +233,6 @@ internal class ResourceResolverTest {
 
         // Then
         verify(mockDrawableUtils).createBitmapOfApproxSizeFromDrawable(
-            resources = any(),
             drawable = any(),
             drawableWidth = any(),
             drawableHeight = any(),
@@ -342,7 +341,6 @@ internal class ResourceResolverTest {
 
         // Then
         verify(mockDrawableUtils).createBitmapOfApproxSizeFromDrawable(
-            resources = any(),
             drawable = any(),
             drawableWidth = any(),
             drawableHeight = any(),
@@ -359,7 +357,6 @@ internal class ResourceResolverTest {
         whenever(mockResourcesLRUCache.get(fakeResourceKey)).thenReturn(null)
         whenever(
             mockDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-                resources = any(),
                 drawable = any(),
                 drawableWidth = any(),
                 drawableHeight = any(),
@@ -369,7 +366,7 @@ internal class ResourceResolverTest {
                 bitmapCreationCallback = any()
             )
         ).then {
-            (it.arguments[7] as ResourceResolver.BitmapCreationCallback).onFailure()
+            (it.arguments[6] as ResourceResolver.BitmapCreationCallback).onFailure()
         }
 
         // When
@@ -459,7 +456,6 @@ internal class ResourceResolverTest {
 
         // Then
         verify(mockDrawableUtils, times(1)).createBitmapOfApproxSizeFromDrawable(
-            resources = any(),
             drawable = any(),
             drawableWidth = any(),
             drawableHeight = any(),
@@ -490,7 +486,6 @@ internal class ResourceResolverTest {
 
         // Then
         verify(mockDrawableUtils, times(1)).createBitmapOfApproxSizeFromDrawable(
-            resources = any(),
             drawable = any(),
             drawableWidth = any(),
             drawableHeight = any(),
@@ -547,7 +542,6 @@ internal class ResourceResolverTest {
             anyOrNull()
         )
         verify(mockDrawableUtils, times(1)).createBitmapOfApproxSizeFromDrawable(
-            resources = any(),
             drawable = any(),
             drawableWidth = any(),
             drawableHeight = any(),
@@ -582,7 +576,6 @@ internal class ResourceResolverTest {
             anyOrNull()
         )
         verify(mockDrawableUtils, times(1)).createBitmapOfApproxSizeFromDrawable(
-            resources = any(),
             drawable = any(),
             drawableWidth = any(),
             drawableHeight = any(),
@@ -873,7 +866,6 @@ internal class ResourceResolverTest {
 
         // Then
         verify(mockDrawableUtils).createBitmapOfApproxSizeFromDrawable(
-            resources = any(),
             drawable = any(),
             drawableWidth = any(),
             drawableHeight = any(),
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/DrawableUtilsTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/DrawableUtilsTest.kt
index e46f22922d..60b419f7da 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/DrawableUtilsTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/DrawableUtilsTest.kt
@@ -33,7 +33,6 @@ import org.mockito.kotlin.any
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.doAnswer
 import org.mockito.kotlin.mock
-import org.mockito.kotlin.never
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 import org.mockito.quality.Strictness
@@ -141,7 +140,6 @@ internal class DrawableUtilsTest {
 
         // When
         testedDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = mockResources,
             drawable = mockDrawable,
             drawableWidth = mockDrawable.intrinsicWidth,
             drawableHeight = mockDrawable.intrinsicHeight,
@@ -179,7 +177,6 @@ internal class DrawableUtilsTest {
 
         // When
         testedDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = mockResources,
             drawable = mockDrawable,
             drawableWidth = mockDrawable.intrinsicWidth,
             drawableHeight = mockDrawable.intrinsicHeight,
@@ -214,7 +211,6 @@ internal class DrawableUtilsTest {
 
         // When
         testedDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = mockResources,
             drawable = mockDrawable,
             drawableWidth = mockDrawable.intrinsicWidth,
             drawableHeight = mockDrawable.intrinsicHeight,
@@ -254,7 +250,6 @@ internal class DrawableUtilsTest {
 
         // When
         testedDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = mockResources,
             drawable = mockDrawable,
             drawableWidth = mockDrawable.intrinsicWidth,
             drawableHeight = mockDrawable.intrinsicHeight,
@@ -279,7 +274,6 @@ internal class DrawableUtilsTest {
 
         // When
         testedDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = mockResources,
             drawable = mockDrawable,
             drawableWidth = mockDrawable.intrinsicWidth,
             drawableHeight = mockDrawable.intrinsicHeight,
@@ -297,12 +291,13 @@ internal class DrawableUtilsTest {
         // Given
         whenever(mockDrawable.intrinsicWidth).thenReturn(1)
         whenever(mockDrawable.intrinsicHeight).thenReturn(1)
-        whenever(mockConstantState.newDrawable(mockResources))
-            .thenReturn(null)
+        whenever(mockBitmap.isRecycled).thenReturn(true)
+        whenever(mockBitmapWrapper.createBitmap(any(), any(), any(), any())).thenReturn(
+            null
+        )
 
         // When
         testedDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = mockResources,
             drawable = mockDrawable,
             drawableWidth = mockDrawable.intrinsicWidth,
             drawableHeight = mockDrawable.intrinsicHeight,
@@ -325,7 +320,6 @@ internal class DrawableUtilsTest {
 
         // When
         testedDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = mockResources,
             drawable = mockDrawable,
             drawableWidth = mockDrawable.intrinsicWidth,
             drawableHeight = mockDrawable.intrinsicHeight,
@@ -353,7 +347,6 @@ internal class DrawableUtilsTest {
 
         // When
         testedDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = mockResources,
             drawable = mockDrawable,
             drawableWidth = mockDrawable.intrinsicWidth,
             drawableHeight = mockDrawable.intrinsicHeight,
@@ -378,30 +371,6 @@ internal class DrawableUtilsTest {
         assertThat(displayMetricsCaptor.firstValue).isEqualTo(mockDisplayMetrics)
     }
 
-    @Test
-    fun `M not use original drawable W createBitmapOfApproxSizeFromDrawable`() {
-        // Given
-        whenever(mockDrawable.intrinsicWidth).thenReturn(1)
-        whenever(mockDrawable.intrinsicHeight).thenReturn(1)
-
-        // When
-        testedDrawableUtils.createBitmapOfApproxSizeFromDrawable(
-            resources = mockResources,
-            drawable = mockDrawable,
-            drawableWidth = mockDrawable.intrinsicWidth,
-            drawableHeight = mockDrawable.intrinsicHeight,
-            displayMetrics = mockDisplayMetrics,
-            config = mockConfig,
-            bitmapCreationCallback = mockBitmapCreationCallback
-        )
-
-        // Then
-        verify(mockDrawable, never()).setBounds(any(), any(), any(), any())
-        verify(mockDrawable, never()).draw(any())
-        verify(mockSecondDrawable).setBounds(any(), any(), any(), any())
-        verify(mockSecondDrawable).draw(any())
-    }
-
     @Test
     fun `M return scaled bitmap W createScaledBitmap()`(
         @Mock mockScaledBitmap: Bitmap
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/ImageViewUtilsTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/ImageViewUtilsTest.kt
index 45bf0adcdd..b3ad5c0df4 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/ImageViewUtilsTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/ImageViewUtilsTest.kt
@@ -10,6 +10,7 @@ import android.graphics.Rect
 import android.graphics.drawable.Drawable
 import android.view.View
 import android.widget.ImageView
+import com.datadog.android.internal.utils.ImageViewUtils
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.utils.isCloseToOrGreaterThan
@@ -72,7 +73,7 @@ internal class ImageViewUtilsTest {
         )
 
         // Then
-        assertThat(result).isEqualTo(expectedClipping)
+        assertThat(result.toWireframeClip()).isEqualTo(expectedClipping)
     }
 
     @Test
@@ -104,7 +105,7 @@ internal class ImageViewUtilsTest {
         )
 
         // Then
-        assertThat(result).isEqualTo(expectedClipping)
+        assertThat(result.toWireframeClip()).isEqualTo(expectedClipping)
     }
 
     @Test
@@ -136,7 +137,7 @@ internal class ImageViewUtilsTest {
         )
 
         // Then
-        assertThat(result).isEqualTo(expectedClipping)
+        assertThat(result.toWireframeClip()).isEqualTo(expectedClipping)
     }
 
     @Test
@@ -168,7 +169,7 @@ internal class ImageViewUtilsTest {
         )
 
         // Then
-        assertThat(result).isEqualTo(expectedClipping)
+        assertThat(result.toWireframeClip()).isEqualTo(expectedClipping)
     }
 
     @Test
@@ -200,7 +201,7 @@ internal class ImageViewUtilsTest {
         )
 
         // Then
-        assertThat(result).isEqualTo(expectedClipping)
+        assertThat(result.toWireframeClip()).isEqualTo(expectedClipping)
     }
 
     // endregion
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/MiscUtilsTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/MiscUtilsTest.kt
index 12187927b2..1d2c73c720 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/MiscUtilsTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/MiscUtilsTest.kt
@@ -19,8 +19,8 @@ import android.view.Display
 import android.view.WindowManager
 import android.view.WindowMetrics
 import com.datadog.android.api.InternalLogger
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import com.datadog.android.sessionreplay.internal.utils.MiscUtils.DESERIALIZE_JSON_ERROR
 import com.datadog.android.sessionreplay.recorder.SystemInformation
 import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapperTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapperTest.kt
index 9bf84246ba..ae4891ec68 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapperTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/recorder/mapper/ImageViewMapperTest.kt
@@ -16,12 +16,13 @@ import android.util.DisplayMetrics
 import android.view.View
 import android.widget.ImageView
 import com.datadog.android.api.InternalLogger
+import com.datadog.android.internal.utils.ImageViewUtils
 import com.datadog.android.sessionreplay.ImagePrivacy
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
-import com.datadog.android.sessionreplay.internal.utils.ImageViewUtils
 import com.datadog.android.sessionreplay.model.MobileSegment
 import com.datadog.android.sessionreplay.recorder.MappingContext
 import com.datadog.android.sessionreplay.recorder.SystemInformation
+import com.datadog.android.sessionreplay.recorder.resources.DrawableCopier
 import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
 import com.datadog.android.sessionreplay.utils.ColorStringFormatter
 import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
@@ -100,6 +101,9 @@ internal class ImageViewMapperTest {
     @Mock
     lateinit var mockDrawableToColorMapper: DrawableToColorMapper
 
+    @Mock
+    lateinit var mockDrawableCopier: DrawableCopier
+
     @Mock
     lateinit var mockGlobalBounds: GlobalBounds
 
@@ -113,7 +117,7 @@ internal class ImageViewMapperTest {
     lateinit var mockBackgroundConstantState: ConstantState
 
     @Mock
-    lateinit var stubClipping: MobileSegment.WireframeClip
+    lateinit var stubClipping: Rect
 
     @Mock
     lateinit var stubParentRect: Rect
@@ -197,7 +201,8 @@ internal class ImageViewMapperTest {
             colorStringFormatter = mockColorStringFormatter,
             viewBoundsResolver = mockViewBoundsResolver,
             drawableToColorMapper = mockDrawableToColorMapper,
-            imageViewUtils = stubImageViewUtils
+            imageViewUtils = stubImageViewUtils,
+            drawableCopier = mockDrawableCopier
         )
     }
 
diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/utils/DefaultViewBoundsResolverTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/utils/DefaultViewBoundsResolverTest.kt
index 4242325e1b..69eab2fcaf 100644
--- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/utils/DefaultViewBoundsResolverTest.kt
+++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/utils/DefaultViewBoundsResolverTest.kt
@@ -7,8 +7,8 @@
 package com.datadog.android.sessionreplay.utils
 
 import android.view.View
+import com.datadog.android.internal.utils.densityNormalized
 import com.datadog.android.sessionreplay.forge.ForgeConfigurator
-import com.datadog.android.sessionreplay.internal.recorder.densityNormalized
 import fr.xgouchet.elmyr.Forge
 import fr.xgouchet.elmyr.junit5.ForgeConfiguration
 import fr.xgouchet.elmyr.junit5.ForgeExtension