diff --git a/dlls/d2d1/brush.c b/dlls/d2d1/brush.c
index b9a673fe54c..45614630ef6 100644
--- a/dlls/d2d1/brush.c
+++ b/dlls/d2d1/brush.c
@@ -1450,7 +1450,22 @@ BOOL d2d_brush_fill_cb(const struct d2d_brush *brush, struct d2d_brush_cb *cb)
             return TRUE;
 
         case D2D_BRUSH_TYPE_BITMAP:
-            bitmap = brush->u.bitmap.bitmap;
+        case D2D_BRUSH_TYPE_IMAGE:
+        {
+            ID2D1Bitmap *src_bitmap;
+
+            if (brush->type == D2D_BRUSH_TYPE_BITMAP)
+                bitmap = brush->u.bitmap.bitmap;
+            else
+            {
+                if (FAILED(ID2D1Image_QueryInterface(brush->u.image.image, &IID_ID2D1Bitmap, (void **)&src_bitmap)))
+                {
+                    FIXME("ID2D1Image doesn't support ID2D1Bitmap interface.\n");
+                    return FALSE;
+                }
+
+                bitmap = unsafe_impl_from_ID2D1Bitmap(src_bitmap);
+            }
 
             /* Scale for bitmap size and dpi. */
             b = brush->transform;
@@ -1477,7 +1492,11 @@ BOOL d2d_brush_fill_cb(const struct d2d_brush *brush, struct d2d_brush_cb *cb)
 
             cb->u.bitmap.ignore_alpha = bitmap->format.alphaMode == D2D1_ALPHA_MODE_IGNORE;
 
+            if (brush->type == D2D_BRUSH_TYPE_IMAGE)
+                ID2D1Bitmap_Release(src_bitmap);
+
             return TRUE;
+        }
 
         default:
             FIXME("Unhandled brush type %#x.\n", brush->type);
@@ -1529,6 +1548,61 @@ static void d2d_brush_bind_bitmap(struct d2d_brush *brush, struct d2d_device_con
     ID3D11DeviceContext_Release(d3d_context);
 }
 
+static void d2d_brush_bind_image(struct d2d_brush *brush, struct d2d_device_context *context,
+        unsigned int brush_idx)
+{
+    ID3D11SamplerState **sampler_state;
+    ID3D11DeviceContext *d3d_context;
+    ID2D1Bitmap *src_bitmap;
+    struct d2d_bitmap *bitmap;
+    HRESULT hr;
+
+    if (FAILED(hr = ID2D1Image_QueryInterface(brush->u.image.image, &IID_ID2D1Bitmap, (void **)&src_bitmap)))
+    {
+        FIXME("ID2D1Image doesn't support ID2D1Bitmap interface.\n");
+        return;
+    }
+
+    bitmap = unsafe_impl_from_ID2D1Bitmap(src_bitmap);
+
+    ID3D11Device1_GetImmediateContext(context->d3d_device, &d3d_context);
+    ID3D11DeviceContext_PSSetShaderResources(d3d_context, brush_idx, 1, &bitmap->srv);
+
+    sampler_state = &context->sampler_states
+            [brush->u.image.interpolation_mode % D2D_SAMPLER_INTERPOLATION_MODE_COUNT]
+            [brush->u.image.extend_mode_x % D2D_SAMPLER_EXTEND_MODE_COUNT]
+            [brush->u.image.extend_mode_y % D2D_SAMPLER_EXTEND_MODE_COUNT];
+
+    if (!*sampler_state)
+    {
+        D3D11_SAMPLER_DESC sampler_desc;
+
+        if (brush->u.image.interpolation_mode == D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR)
+            sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+        else
+            sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+        sampler_desc.AddressU = texture_address_mode_from_extend_mode(brush->u.image.extend_mode_x);
+        sampler_desc.AddressV = texture_address_mode_from_extend_mode(brush->u.image.extend_mode_y);
+        sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+        sampler_desc.MipLODBias = 0.0f;
+        sampler_desc.MaxAnisotropy = 0;
+        sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+        sampler_desc.BorderColor[0] = 0.0f;
+        sampler_desc.BorderColor[1] = 0.0f;
+        sampler_desc.BorderColor[2] = 0.0f;
+        sampler_desc.BorderColor[3] = 0.0f;
+        sampler_desc.MinLOD = 0.0f;
+        sampler_desc.MaxLOD = 0.0f;
+
+        if (FAILED(hr = ID3D11Device1_CreateSamplerState(context->d3d_device, &sampler_desc, sampler_state)))
+            ERR("Failed to create sampler state, hr %#lx.\n", hr);
+    }
+
+    ID3D11DeviceContext_PSSetSamplers(d3d_context, brush_idx, 1, sampler_state);
+    ID3D11DeviceContext_Release(d3d_context);
+    ID2D1Bitmap_Release(src_bitmap);
+}
+
 void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_device_context *context, unsigned int brush_idx)
 {
     switch (brush->type)
@@ -1548,6 +1622,10 @@ void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_device_context
             d2d_brush_bind_bitmap(brush, context, brush_idx);
             break;
 
+        case D2D_BRUSH_TYPE_IMAGE:
+            d2d_brush_bind_image(brush, context, brush_idx);
+            break;
+
         default:
             FIXME("Unhandled brush type %#x.\n", brush->type);
             break;
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c
index eb0c1935ebb..e8e25a7b3e3 100644
--- a/dlls/d2d1/device.c
+++ b/dlls/d2d1/device.c
@@ -1040,7 +1040,7 @@ static void STDMETHODCALLTYPE d2d_device_context_FillGeometry(ID2D1DeviceContext
     if (FAILED(context->error.code))
         return;
 
-    if (opacity_brush && brush_impl->type != D2D_BRUSH_TYPE_BITMAP)
+    if (opacity_brush && !(brush_impl->type == D2D_BRUSH_TYPE_BITMAP || brush_impl->type == D2D_BRUSH_TYPE_IMAGE))
     {
         d2d_device_context_set_error(context, D2DERR_INCOMPATIBLE_BRUSH_TYPES);
         return;
