diff --git a/README.md b/README.md
index f3d520a..6b7efee 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,7 @@ Your tool will combine multiple tools listed below to achieve your goal.
 | `draw_lines` | Draws lines on an image using OpenCV | "Draw a red line from (50,50) to (150,100) on my image 'photo.jpg'" |
 | `draw_rectangles` | Draws rectangles on an image using OpenCV | "Draw a red rectangle from (50,50) to (150,100) and a filled blue rectangle from (200,150) to (300,250) on my image 'photo.jpg'" |
 | `draw_texts` | Draws text on an image using OpenCV | "Add text 'Hello World' at position (50,50) and 'Copyright 2023' at the bottom right corner of my image 'photo.jpg'" |
-| `fill` | Fills specified rectangular or polygonal areas of an image with a color and opacity, or makes them transparent | "Fill the area from (150, 100) to (250, 200) with semi-transparent red in my image 'test_image.png'" |
+| `fill` | Fills specified rectangular or polygonal areas of an image with a color and opacity, or makes them transparent. Can also invert the provided areas f.e. to remove background. | "Fill the area from (150, 100) to (250, 200) with semi-transparent red in my image 'test_image.png'" |
 | `find` | Finds objects in an image based on a text description. Can return segmentation masks/polygons. | "Find all dogs in my image 'photo.jpg' with a confidence threshold of 0.4" |
 | `get_metainfo` | Gets metadata information about an image file | "Get metadata information about my image 'photo.jpg'" |
 | `ocr` | Performs Optical Character Recognition (OCR) on an image using EasyOCR | "Extract text from my image 'document.jpg' using OCR with English language" |
diff --git a/src/imagesorcery_mcp/tools/README.md b/src/imagesorcery_mcp/tools/README.md
index afafe55..eb4e766 100644
--- a/src/imagesorcery_mcp/tools/README.md
+++ b/src/imagesorcery_mcp/tools/README.md
@@ -539,13 +539,14 @@ Fills specified rectangular or polygonal areas of an image with a color and opac
     - A polygon: `polygon` (a list of points, e.g., `[[x1, y1], [x2, y2], ...]`).
     - Optionally, each dictionary can also contain `color` (list of 3 ints [B,G,R] or `null`, default [0,0,0]) and `opacity` (float 0.0-1.0, default 0.5).
 - **Optional arguments:**
+  - `invert_areas` (boolean): If True, fills everything EXCEPT the specified areas. Useful for background removal. Default is False.
   - `output_path` (string): Full path to save the output image. If not provided, will use input filename with '_filled' suffix.
 - **Returns:** string (path to the image with filled areas)
 
 **Example Claude Request:**
 
 ```
-Fill the rectangular area from (150, 100) to (250, 200) with semi-transparent red in my image 'test_image.png' and save it as 'output.png'
+Fill the rectangular area from (150, 100) to (250, 200) with semi-transparent red and erase the area [[10, 10], [50, 10], [50, 50], [10, 50]] in my image 'test_image.png' and save it as 'output.png'
 ```
 
 **Example Tool Call (JSON):**
@@ -582,6 +583,34 @@ Fill the rectangular area from (150, 100) to (250, 200) with semi-transparent re
 }
 ```
 
+**Example Claude Request (Background Removal):**
+
+```
+Remove the background from 'my_image.png' by making everything outside the rectangle (100, 100) to (300, 300) transparent, and save it as 'object_only.png'
+```
+
+**Example Tool Call (JSON):**
+
+```json
+{
+  "name": "fill",
+  "arguments": {
+    "input_path": "/home/user/images/my_image.png",
+    "areas": [
+      {
+        "x1": 100,
+        "y1": 100,
+        "x2": 300,
+        "y2": 300,
+        "color": null
+      }
+    ],
+    "invert_areas": true,
+    "output_path": "/home/user/images/object_only.png"
+  }
+}
+```
+
 ### `find`
 
 Finds objects in an image based on a text description. This tool uses open-vocabulary detection models to find objects matching a text description. It requires pre-downloaded YOLOE models that support text prompts (e.g. yoloe-11l-seg.pt). This tool can optionally return segmentation masks or polygons.
diff --git a/src/imagesorcery_mcp/tools/fill.py b/src/imagesorcery_mcp/tools/fill.py
index 76af8a9..8e8e3ff 100644
--- a/src/imagesorcery_mcp/tools/fill.py
+++ b/src/imagesorcery_mcp/tools/fill.py
@@ -25,6 +25,12 @@ def register_tool(mcp: FastMCP):
                 )
             ),
         ],
+        invert_areas: Annotated[
+            bool,
+            Field(
+                description="If True, fills everything EXCEPT the specified areas. Useful for background removal."
+            ),
+        ] = False,
         output_path: Annotated[
             Optional[str],
             Field(
@@ -50,10 +56,12 @@ def register_tool(mcp: FastMCP):
         If the `color` is set to `None`, the specified area will be made fully transparent,
         effectively deleting it (similar to ImageMagick). In this case, the `opacity`
         parameter is ignored.
+        
+        If `invert_areas` is True, the tool will fill everything EXCEPT the specified areas.
         Returns:
             Path to the image with filled areas
         """
-        logger.info(f"Fill tool requested for image: {input_path} with {len(areas)} areas")
+        logger.info(f"Fill tool requested for image: {input_path} with {len(areas)} areas, invert_areas={invert_areas}")
 
         # Check if input file exists
         if not os.path.exists(input_path):
@@ -74,70 +82,113 @@ def register_tool(mcp: FastMCP):
             raise ValueError(f"Failed to read image: {input_path}")
         logger.info(f"Image read successfully. Shape: {img.shape}")
 
-        # If any area requests transparency, ensure we have an alpha channel
-        if any(area.get("color") is None for area in areas):
+        # If any area requests transparency OR invert_areas is used with transparency, ensure we have an alpha channel
+        if any(area.get("color") is None for area in areas) or (invert_areas and areas and areas[0].get("color") is None):
             if len(img.shape) < 3 or img.shape[2] == 3:
                 logger.info("Converting image to BGRA to support transparency")
                 img = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA if len(img.shape) > 2 and img.shape[2] == 3 else cv2.COLOR_GRAY2BGRA)
 
-        # Process each area to fill
-        for i, area in enumerate(areas):
-            color = area.get("color")
-
-            if color is None:
-                # Make area transparent
-                logger.debug(f"Making area {i+1} transparent")
-                if img.shape[2] != 4:
-                    raise ValueError("Image must have an alpha channel for transparency operations.")
-                
-                transparent_color = (0, 0, 0, 0)
+        # Create mask for invert mode if needed
+        if invert_areas:
+            # Create a mask where specified areas are 0 (don't fill) and everything else is 255 (fill)
+            mask = np.ones(img.shape[:2], dtype=np.uint8) * 255
+            
+            # Mark each area as 0 (don't fill)
+            for area in areas:
                 if "polygon" in area:
                     polygon_points = np.array(area["polygon"], dtype=np.int32)
-                    cv2.fillPoly(img, [polygon_points], transparent_color)
-                    logger.debug(f"Polygon area {i+1} made transparent")
+                    cv2.fillPoly(mask, [polygon_points], 0)
                 elif "x1" in area and "y1" in area and "x2" in area and "y2" in area:
                     x1, y1, x2, y2 = area["x1"], area["y1"], area["x2"], area["y2"]
-                    img[y1:y2, x1:x2] = transparent_color
-                    logger.debug(f"Rectangle area {i+1} made transparent")
-                else:
-                    logger.warning(f"Skipping area {i+1} due to missing 'polygon' or 'x1,y1,x2,y2' keys.")
+                    mask[y1:y2, x1:x2] = 0
+            
+            # Get fill parameters from the first area
+            color = areas[0].get("color") if areas else None
+            opacity = areas[0].get("opacity", 0.5) if areas else 0.5
+            
+            logger.info("Inverted areas: applying fill to masked regions")
+            
+            # Apply the fill using the mask
+            if color is None:
+                # Make masked areas transparent
+                if img.shape[2] != 4:
+                    raise ValueError("Image must have an alpha channel for transparency operations.")
+                # Set alpha to 0 where mask is 255
+                img[:, :, 3] = np.where(mask == 255, 0, img[:, :, 3])
             else:
-                # Fill with color
+                # Fill with color where mask is 255
                 color_tuple = tuple(color)
-                opacity = area.get("opacity", 0.5)
-
                 if not (0.0 <= opacity <= 1.0):
                     logger.warning(f"Opacity {opacity} is outside the valid range [0.0, 1.0]. Clamping it.")
                     opacity = max(0.0, min(1.0, opacity))
-
-                if "polygon" in area:
-                    logger.debug(f"Filling polygon area {i+1} with color={color_tuple}, opacity={opacity}")
-                    polygon_points = np.array(area["polygon"], dtype=np.int32)
-                    mask = np.zeros(img.shape[:2], dtype=np.uint8)
-                    cv2.fillPoly(mask, [polygon_points], (255))
-                    x, y, w, h = cv2.boundingRect(polygon_points)
-                    roi = img[y : y + h, x : x + w]
-                    
-                    overlay_roi = roi.copy()
-                    cv2.fillPoly(overlay_roi, [polygon_points - [x, y]], color_tuple)
-                    blended_roi = cv2.addWeighted(overlay_roi, opacity, roi, 1 - opacity, 0)
-                    
-                    roi_mask = mask[y : y + h, x : x + w]
-                    img[y : y + h, x : x + w] = np.where(roi_mask[:, :, None] == 255, blended_roi, roi)
-                    logger.debug(f"Polygon area {i+1} filled")
-
-                elif "x1" in area and "y1" in area and "x2" in area and "y2" in area:
-                    x1, y1, x2, y2 = area["x1"], area["y1"], area["x2"], area["y2"]
-                    logger.debug(f"Filling rectangle area {i+1}: ({x1}, {y1}) to ({x2}, {y2}) with color={color_tuple}, opacity={opacity}")
+                
+                # Create an overlay image
+                overlay = img.copy()
+                overlay[mask == 255] = color_tuple + (255,) if img.shape[2] == 4 else color_tuple
+                
+                # Blend the overlay with the original image
+                img = np.where(mask[:, :, None] == 255, 
+                              cv2.addWeighted(overlay, opacity, img, 1 - opacity, 0),
+                              img)
+        else:
+            # Normal mode - process each area to fill
+            for i, area in enumerate(areas):
+                color = area.get("color")
+
+                if color is None:
+                    # Make area transparent
+                    logger.debug(f"Making area {i+1} transparent")
+                    if img.shape[2] != 4:
+                        raise ValueError("Image must have an alpha channel for transparency operations.")
                     
-                    roi = img[y1:y2, x1:x2]
-                    overlay_roi = roi.copy()
-                    cv2.rectangle(overlay_roi, (0, 0), (roi.shape[1], roi.shape[0]), color_tuple, -1)
-                    blended_roi = cv2.addWeighted(overlay_roi, opacity, roi, 1 - opacity, 0)
-                    img[y1:y2, x1:x2] = blended_roi
-                    logger.debug(f"Rectangle area {i+1} filled")
+                    transparent_color = (0, 0, 0, 0)
+                    if "polygon" in area:
+                        polygon_points = np.array(area["polygon"], dtype=np.int32)
+                        cv2.fillPoly(img, [polygon_points], transparent_color)
+                        logger.debug(f"Polygon area {i+1} made transparent")
+                    elif "x1" in area and "y1" in area and "x2" in area and "y2" in area:
+                        x1, y1, x2, y2 = area["x1"], area["y1"], area["x2"], area["y2"]
+                        img[y1:y2, x1:x2] = transparent_color
+                        logger.debug(f"Rectangle area {i+1} made transparent")
+                    else:
+                        logger.warning(f"Skipping area {i+1} due to missing 'polygon' or 'x1,y1,x2,y2' keys.")
                 else:
-                    logger.warning(f"Skipping area {i+1} due to missing 'polygon' or 'x1,y1,x2,y2' keys.")
+                    # Fill with color
+                    color_tuple = tuple(color)
+                    opacity = area.get("opacity", 0.5)
+
+                    if not (0.0 <= opacity <= 1.0):
+                        logger.warning(f"Opacity {opacity} is outside the valid range [0.0, 1.0]. Clamping it.")
+                        opacity = max(0.0, min(1.0, opacity))
+
+                    if "polygon" in area:
+                        logger.debug(f"Filling polygon area {i+1} with color={color_tuple}, opacity={opacity}")
+                        polygon_points = np.array(area["polygon"], dtype=np.int32)
+                        mask = np.zeros(img.shape[:2], dtype=np.uint8)
+                        cv2.fillPoly(mask, [polygon_points], (255))
+                        x, y, w, h = cv2.boundingRect(polygon_points)
+                        roi = img[y : y + h, x : x + w]
+                        
+                        overlay_roi = roi.copy()
+                        cv2.fillPoly(overlay_roi, [polygon_points - [x, y]], color_tuple)
+                        blended_roi = cv2.addWeighted(overlay_roi, opacity, roi, 1 - opacity, 0)
+                        
+                        roi_mask = mask[y : y + h, x : x + w]
+                        img[y : y + h, x : x + w] = np.where(roi_mask[:, :, None] == 255, blended_roi, roi)
+                        logger.debug(f"Polygon area {i+1} filled")
+
+                    elif "x1" in area and "y1" in area and "x2" in area and "y2" in area:
+                        x1, y1, x2, y2 = area["x1"], area["y1"], area["x2"], area["y2"]
+                        logger.debug(f"Filling rectangle area {i+1}: ({x1}, {y1}) to ({x2}, {y2}) with color={color_tuple}, opacity={opacity}")
+                        
+                        roi = img[y1:y2, x1:x2]
+                        overlay_roi = roi.copy()
+                        cv2.rectangle(overlay_roi, (0, 0), (roi.shape[1], roi.shape[0]), color_tuple, -1)
+                        blended_roi = cv2.addWeighted(overlay_roi, opacity, roi, 1 - opacity, 0)
+                        img[y1:y2, x1:x2] = blended_roi
+                        logger.debug(f"Rectangle area {i+1} filled")
+                    else:
+                        logger.warning(f"Skipping area {i+1} due to missing 'polygon' or 'x1,y1,x2,y2' keys.")
 
         output_dir = os.path.dirname(output_path)
         if output_dir and not os.path.exists(output_dir):
diff --git a/tests/tools/test_fill.py b/tests/tools/test_fill.py
index fbf39f9..bae7ece 100644
--- a/tests/tools/test_fill.py
+++ b/tests/tools/test_fill.py
@@ -28,6 +28,24 @@ def test_image_path(tmp_path):
     cv2.imwrite(str(img_path), img)
     return str(img_path)
 
+@pytest.fixture
+def test_jpeg_image_path(tmp_path):
+    """Create a test JPEG image (no alpha channel) for testing transparency operations."""
+    img_path = tmp_path / "test_image.jpg"
+    
+    # Create a white image
+    img = np.ones((300, 400, 3), dtype=np.uint8) * 255
+    
+    # Draw a black rectangle to check blending against
+    cv2.rectangle(img, (100, 75), (300, 225), (0, 0, 0), -1)
+    
+    # Draw a red circle
+    cv2.circle(img, (200, 150), 50, (0, 0, 255), -1)
+    
+    cv2.imwrite(str(img_path), img)
+    return str(img_path)
+
+
 class TestFillToolDefinition:
     """Tests for the fill tool definition and metadata."""
 
@@ -190,3 +208,365 @@ class TestFillToolExecution:
             # Check a pixel outside the transparent area
             pixel_outside = img[50, 50]
             assert pixel_outside[3] == 255  # Alpha should be 255
+    
+    @pytest.mark.asyncio
+    async def test_fill_invert_rectangle(self, mcp_server: FastMCP, test_image_path, tmp_path):
+        """Tests the fill tool with invert_areas for a rectangle."""
+        output_path = str(tmp_path / "output_inverted.png")
+        
+        # Define a rectangle in the center (where the black rectangle is)
+        fill_area = {"x1": 150, "y1": 100, "x2": 250, "y2": 200, "color": [0, 255, 0], "opacity": 1.0}
+        
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill", 
+                {
+                    "input_path": test_image_path, 
+                    "areas": [fill_area], 
+                    "invert_areas": True,
+                    "output_path": output_path
+                }
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path)
+            
+            # Center pixel (inside the specified area) should NOT be filled - remains original
+            center_pixel = img[150, 200]
+            assert np.array_equal(center_pixel, [0, 0, 0])  # Should remain black (original)
+            
+            # Pixels outside the area should be filled with green
+            outside_pixel = img[50, 50]
+            assert np.allclose(outside_pixel, [0, 255, 0], atol=2)  # Should be green - allow tolerance for JPEG
+            
+            # Another outside pixel
+            edge_pixel = img[250, 350]
+            assert np.array_equal(edge_pixel, [0, 255, 0])  # Should be green
+
+    @pytest.mark.asyncio
+    async def test_fill_invert_polygon(self, mcp_server: FastMCP, test_image_path, tmp_path):
+        """Tests the fill tool with invert_areas for a polygon."""
+        output_path = str(tmp_path / "output_inverted_poly.png")
+        
+        # Define a triangle polygon
+        polygon_area = {"polygon": [[160, 110], [240, 110], [200, 190]], "color": [255, 0, 0], "opacity": 0.8}
+        
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill",
+                {
+                    "input_path": test_image_path,
+                    "areas": [polygon_area],
+                    "invert_areas": True,
+                    "output_path": output_path
+                }
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path)
+            
+            # Center of polygon (inside the specified area) should NOT be filled
+            poly_center = img[150, 200]
+            assert np.array_equal(poly_center, [0, 0, 0])  # Should remain black
+            
+            # Outside pixels should be filled with blue at 80% opacity
+            # Since original is white [255,255,255], and we're applying blue [255,0,0] at 80% opacity:
+            # Result = 0.8 * [255,0,0] + 0.2 * [255,255,255] = [255, 51, 51] (approximately)
+            outside_pixel = img[50, 50]
+            assert np.allclose(outside_pixel, [255, 51, 51], atol=2)  # 80% blue over white
+
+    @pytest.mark.asyncio
+    async def test_fill_invert_transparent(self, mcp_server: FastMCP, test_image_path, tmp_path):
+        """Tests making everything except a rectangle transparent (background removal)."""
+        output_path = str(tmp_path / "output_bg_removed.png")
+        
+        # Keep only the center rectangle, make everything else transparent
+        keep_area = {"x1": 150, "y1": 100, "x2": 250, "y2": 200, "color": None}
+        
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill",
+                {
+                    "input_path": test_image_path,
+                    "areas": [keep_area],
+                    "invert_areas": True,
+                    "output_path": output_path
+                }
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path, cv2.IMREAD_UNCHANGED)
+            assert img.shape[2] == 4  # Should have alpha channel
+            
+            # Inside the kept area - should be opaque (not modified)
+            inside_pixel = img[150, 200]
+            assert inside_pixel[3] == 255  # Alpha should be 255 (opaque)
+            assert np.array_equal(inside_pixel[:3], [0, 0, 0])  # Color preserved
+            
+            # Outside the kept area - should be transparent
+            outside_pixel = img[50, 50]
+            assert outside_pixel[3] == 0  # Alpha should be 0 (transparent)
+
+    @pytest.mark.asyncio
+    async def test_fill_invert_multiple_areas(self, mcp_server: FastMCP, test_image_path, tmp_path):
+        """Tests invert_areas with multiple areas to keep."""
+        output_path = str(tmp_path / "output_multi_keep.png")
+        
+        # Keep two areas, fill everything else
+        areas = [
+            {"x1": 50, "y1": 50, "x2": 100, "y2": 100, "color": [0, 0, 255], "opacity": 1.0},
+            {"x1": 200, "y1": 150, "x2": 250, "y2": 200}  # Will use first area's color
+        ]
+        
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill",
+                {
+                    "input_path": test_image_path,
+                    "areas": areas,
+                    "invert_areas": True,
+                    "output_path": output_path
+                }
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path)
+            
+            # First kept area should NOT be filled (remains original)
+            kept_pixel1 = img[75, 75]
+            assert np.array_equal(kept_pixel1, [255, 255, 255])  # Should remain white
+            
+            # Second kept area should NOT be filled (remains original)
+            kept_pixel2 = img[175, 225]
+            assert np.array_equal(kept_pixel2, [0, 0, 0])  # Should remain black
+            
+            # Area between them should be filled with blue
+            between_pixel = img[125, 150]
+            assert np.array_equal(between_pixel, [0, 0, 255])  # Should be blue (BGR format)
+
+    @pytest.mark.asyncio
+    async def test_fill_invert_complex_polygon(self, mcp_server: FastMCP, test_image_path, tmp_path):
+        """Tests invert_areas with a complex polygon shape to keep."""
+        output_path = str(tmp_path / "output_complex_keep.png")
+        
+        # Create a star-like polygon
+        star_polygon = {
+            "polygon": [
+                [200, 50], [220, 100], [270, 100], [230, 130],
+                [250, 180], [200, 150], [150, 180], [170, 130],
+                [130, 100], [180, 100]
+            ],
+            "color": None  # Make background transparent
+        }
+        
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill",
+                {
+                    "input_path": test_image_path,
+                    "areas": [star_polygon],
+                    "invert_areas": True,
+                    "output_path": output_path
+                }
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path, cv2.IMREAD_UNCHANGED)
+            assert img.shape[2] == 4  # Should have alpha channel
+            
+            # Center of star should be opaque (not modified)
+            star_center = img[115, 200]
+            assert star_center[3] == 255  # Should be opaque
+            
+            # Outside corners should be transparent
+            corner_pixel = img[10, 10]
+            assert corner_pixel[3] == 0  # Should be transparent
+
+    @pytest.mark.asyncio
+    async def test_fill_invert_single_area_transparent(self, mcp_server: FastMCP, test_image_path, tmp_path):
+        """Tests a simple background removal use case - keep single object, remove background."""
+        output_path = str(tmp_path / "object_only.png")
+        
+        # Define object boundaries
+        object_area = {"x1": 100, "y1": 80, "x2": 300, "y2": 220, "color": None}
+        
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill",
+                {
+                    "input_path": test_image_path,
+                    "areas": [object_area],
+                    "invert_areas": True,
+                    "output_path": output_path
+                }
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path, cv2.IMREAD_UNCHANGED)
+            
+            # Check that image has alpha channel
+            assert img.shape[2] == 4
+            
+            # Inside object area should be opaque
+            object_pixel = img[150, 200]
+            assert object_pixel[3] == 255
+            
+            # Outside object area should be transparent  
+            bg_pixel = img[10, 10]
+            assert bg_pixel[3] == 0
+            
+            # Edge case - just outside the object
+            edge_pixel = img[79, 150]  # Just above the object
+            assert edge_pixel[3] == 0
+
+class TestFillToolWithJPEG:
+    """Tests for the fill tool with JPEG images (no alpha channel)."""
+
+    @pytest.mark.asyncio
+    async def test_fill_jpeg_to_transparent_rectangle(self, mcp_server: FastMCP, test_jpeg_image_path, tmp_path):
+        """Tests making a rectangular area transparent in a JPEG image."""
+        output_path = str(tmp_path / "output_transparent.png")  # Output as PNG to support transparency
+        fill_area = {"x1": 150, "y1": 100, "x2": 250, "y2": 200, "color": None}
+
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill",
+                {
+                    "input_path": test_jpeg_image_path,
+                    "areas": [fill_area],
+                    "output_path": output_path,
+                },
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path, cv2.IMREAD_UNCHANGED)
+            assert img.shape[2] == 4  # Should have alpha channel added
+
+            # Check a pixel inside the transparent area
+            pixel_inside = img[150, 200]
+            assert pixel_inside[3] == 0  # Alpha should be 0
+
+            # Check a pixel outside the transparent area
+            pixel_outside = img[50, 50]
+            assert pixel_outside[3] == 255  # Alpha should be 255
+
+    @pytest.mark.asyncio
+    async def test_fill_jpeg_invert_transparent(self, mcp_server: FastMCP, test_jpeg_image_path, tmp_path):
+        """Tests making everything except a rectangle transparent in a JPEG image (background removal)."""
+        output_path = str(tmp_path / "output_bg_removed.png")
+        
+        # Keep only the center rectangle, make everything else transparent
+        keep_area = {"x1": 150, "y1": 100, "x2": 250, "y2": 200, "color": None}
+        
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill",
+                {
+                    "input_path": test_jpeg_image_path,
+                    "areas": [keep_area],
+                    "invert_areas": True,
+                    "output_path": output_path
+                }
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path, cv2.IMREAD_UNCHANGED)
+            assert img.shape[2] == 4  # Should have alpha channel
+            
+            # Inside the kept area - should be opaque (not modified)
+            inside_pixel = img[150, 200]
+            assert inside_pixel[3] == 255  # Alpha should be 255 (opaque)
+            # Check the red circle is preserved (use allclose due to JPEG compression)
+            circle_center = img[150, 200]
+            assert circle_center[3] == 255  # Should be opaque
+            assert np.allclose(circle_center[:3], [0, 0, 255], atol=2)  # Should be red (BGR) - allow tolerance for JPEG
+            
+            # Outside the kept area - should be transparent
+            outside_pixel = img[50, 50]
+            assert outside_pixel[3] == 0  # Alpha should be 0 (transparent)
+
+    @pytest.mark.asyncio
+    async def test_fill_jpeg_invert_with_color(self, mcp_server: FastMCP, test_jpeg_image_path, tmp_path):
+        """Tests invert_areas with color fill on a JPEG image."""
+        output_path = str(tmp_path / "output_inverted_color.jpg")  # Keep as JPEG
+        
+        # Define a rectangle in the center
+        fill_area = {"x1": 150, "y1": 100, "x2": 250, "y2": 200, "color": [0, 255, 0], "opacity": 1.0}
+        
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill", 
+                {
+                    "input_path": test_jpeg_image_path, 
+                    "areas": [fill_area], 
+                    "invert_areas": True,
+                    "output_path": output_path
+                }
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path)
+            
+            # Center pixel (inside the specified area) should NOT be filled
+            center_pixel = img[150, 200]
+            assert np.allclose(center_pixel, [0, 0, 255], atol=2)  # Should remain red - allow tolerance for JPEG
+            
+            # Pixels outside the area should be filled with green
+            outside_pixel = img[50, 50]
+            assert np.allclose(outside_pixel, [0, 255, 0], atol=2)  # Should be green - allow tolerance for JPEG
+
+    @pytest.mark.asyncio 
+    async def test_fill_jpeg_multiple_transparent_areas(self, mcp_server: FastMCP, test_jpeg_image_path, tmp_path):
+        """Tests multiple transparent areas on a JPEG image."""
+        output_path = str(tmp_path / "output_multi_transparent.png")
+        
+        areas = [
+            {"x1": 50, "y1": 50, "x2": 100, "y2": 100, "color": None},
+            {"polygon": [[250, 150], [350, 150], [300, 250]], "color": None}
+        ]
+        
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "fill",
+                {
+                    "input_path": test_jpeg_image_path,
+                    "areas": areas,
+                    "output_path": output_path
+                }
+            )
+            assert len(result) == 1
+            assert result[0].text == output_path
+            assert os.path.exists(output_path)
+
+            img = cv2.imread(output_path, cv2.IMREAD_UNCHANGED)
+            assert img.shape[2] == 4  # Should have alpha channel
+            
+            # First transparent area
+            pixel_area1 = img[75, 75]
+            assert pixel_area1[3] == 0  # Should be transparent
+            
+            # Second transparent area (inside polygon)
+            pixel_area2 = img[180, 300]
+            assert pixel_area2[3] == 0  # Should be transparent
+            
+            # Non-transparent area
+            pixel_normal = img[150, 200]
+            assert pixel_normal[3] == 255  # Should be opaque
