+        
           {{ category }}
         
         
diff --git a/src/tools/image-color-inverter/image-color-inverter.e2e.spec.ts b/src/tools/image-color-inverter/image-color-inverter.e2e.spec.ts
new file mode 100644
index 00000000..a27375e2
--- /dev/null
+++ b/src/tools/image-color-inverter/image-color-inverter.e2e.spec.ts
@@ -0,0 +1,123 @@
+import { promises as fs } from 'node:fs';
+import path from 'node:path';
+import process from 'node:process';
+import { expect, test } from '@playwright/test';
+
+test.describe('Tool - Image color inverter', () => {
+  test.beforeEach(async ({ page }) => {
+    await page.goto('/image-color-inverter');
+  });
+
+  test('Has correct title', async ({ page }) => {
+    await expect(page).toHaveTitle('Image color inverter - IT Tools');
+  });
+
+  test('Displays file upload area', async ({ page }) => {
+    // Check if the file upload component is visible
+    const uploadArea = page.locator('text=Drag and drop an image here, or click to select');
+    await expect(uploadArea).toBeVisible();
+  });
+
+  test('Shows error for invalid file type', async ({ page }) => {
+    // Create a temporary non-image file
+    const testFilePath = path.join(process.cwd(), 'test-file.txt');
+    await fs.writeFile(testFilePath, 'This is not an image');
+
+    try {
+      // Upload the text file
+      const fileInput = page.locator('input[type="file"]');
+      await fileInput.setInputFiles(testFilePath);
+
+      // Should show error message
+      const errorAlert = page.locator('.n-alert--error');
+      await expect(errorAlert).toBeVisible();
+      await expect(errorAlert).toContainText('File must be an image');
+    }
+    finally {
+      // Clean up
+      await fs.unlink(testFilePath).catch(() => {});
+    }
+  });
+
+  test('Processes image upload successfully', async ({ page }) => {
+    // Create a simple test image (1x1 pixel PNG in base64)
+    const testImageDataUrl
+      = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
+
+    // Create a blob from the data URL
+    const response = await fetch(testImageDataUrl);
+    const blob = await response.blob();
+
+    // Create a temporary file
+    const buffer = await blob.arrayBuffer();
+    const testFilePath = path.join(process.cwd(), 'test-image.png');
+    await fs.writeFile(testFilePath, new Uint8Array(buffer));
+
+    try {
+      // Upload the image
+      const fileInput = page.locator('input[type="file"]');
+      await fileInput.setInputFiles(testFilePath);
+
+      // Wait for processing to complete
+      await page.waitForSelector('text=Original Image', { timeout: 5000 });
+      await page.waitForSelector('text=Inverted Image', { timeout: 5000 });
+
+      // Check that both images are displayed
+      const originalImage = page.locator('text=Original Image');
+      const invertedImage = page.locator('text=Inverted Image');
+
+      await expect(originalImage).toBeVisible();
+      await expect(invertedImage).toBeVisible();
+
+      // Check that download button is available
+      const downloadButton = page.locator('text=Download PNG');
+      await expect(downloadButton).toBeVisible();
+
+      // Check that copy button is available
+      const copyButton = page.locator('text=Copy Base64');
+      await expect(copyButton).toBeVisible();
+    }
+    finally {
+      // Clean up
+      await fs.unlink(testFilePath).catch(() => {});
+    }
+  });
+
+  test('Clear button resets the tool', async ({ page }) => {
+    // Create a simple test image
+    const testImageDataUrl
+      = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
+
+    const response = await fetch(testImageDataUrl);
+    const blob = await response.blob();
+    const buffer = await blob.arrayBuffer();
+    const testFilePath = path.join(process.cwd(), 'test-image.png');
+    await fs.writeFile(testFilePath, new Uint8Array(buffer));
+
+    try {
+      // Upload and process image
+      const fileInput = page.locator('input[type="file"]');
+      await fileInput.setInputFiles(testFilePath);
+
+      await page.waitForSelector('text=Inverted Image', { timeout: 5000 });
+
+      // Click clear button
+      const clearButton = page.locator('text=Clear & Upload New');
+      await clearButton.click();
+
+      // Check that images are cleared
+      const originalImage = page.locator('text=Original Image');
+      const invertedImage = page.locator('text=Inverted Image');
+
+      await expect(originalImage).not.toBeVisible();
+      await expect(invertedImage).not.toBeVisible();
+
+      // Check that upload area is visible again
+      const uploadArea = page.locator('text=Drag and drop an image here, or click to select');
+      await expect(uploadArea).toBeVisible();
+    }
+    finally {
+      await fs.unlink(testFilePath).catch(() => {});
+    }
+  });
+});
diff --git a/src/tools/image-color-inverter/image-color-inverter.service.test.ts b/src/tools/image-color-inverter/image-color-inverter.service.test.ts
new file mode 100644
index 00000000..ac8c9269
--- /dev/null
+++ b/src/tools/image-color-inverter/image-color-inverter.service.test.ts
@@ -0,0 +1,133 @@
+import { describe, expect, it } from 'vitest';
+import { invertImageColors } from './image-color-inverter.service';
+
+// Mock ImageData for Node.js environment
+Object.defineProperty(globalThis, 'ImageData', {
+  value: class ImageData {
+    data: Uint8ClampedArray;
+    width: number;
+    height: number;
+
+    constructor(data: Uint8ClampedArray | number, width: number, height?: number) {
+      if (typeof data === 'number') {
+        // ImageData(width, height)
+        this.width = data;
+        this.height = width;
+        this.data = new Uint8ClampedArray(data * width * 4);
+      }
+      else {
+        // ImageData(data, width, height)
+        this.data = data;
+        this.width = width;
+        this.height = height || data.length / (width * 4);
+      }
+    }
+  },
+});
+
+// Mock other browser APIs for completeness
+Object.defineProperty(globalThis, 'HTMLCanvasElement', {
+  value: class {
+    width = 0;
+    height = 0;
+
+    getContext() {
+      return {
+        drawImage: () => {},
+        getImageData: () => new (globalThis as any).ImageData(new Uint8ClampedArray([255, 0, 128, 255]), 1, 1),
+        putImageData: () => {},
+      };
+    }
+
+    toDataURL() {
+      return 'data:image/png;base64,mock';
+    }
+  },
+});
+
+Object.defineProperty(globalThis, 'Image', {
+  value: class {
+    onload: () => void = () => {};
+    onerror: () => void = () => {};
+    width = 100;
+    height = 100;
+
+    set src(value: string) {
+      setTimeout(() => this.onload(), 0);
+    }
+
+    get src(): string {
+      return '';
+    }
+  },
+});
+
+describe('image-color-inverter service', () => {
+  describe('invertImageColors', () => {
+    it('should invert RGB colors while preserving alpha', () => {
+      // Create test image data with known values
+      const originalData = new Uint8ClampedArray([
+        255,
+        0,
+        128,
+        255, // Red=255, Green=0, Blue=128, Alpha=255
+        0,
+        255,
+        64,
+        128, // Red=0, Green=255, Blue=64, Alpha=128
+      ]);
+      const imageData = new (globalThis as any).ImageData(originalData, 2, 1);
+
+      const inverted = invertImageColors(imageData);
+
+      // Check that colors are inverted correctly
+      expect(inverted.data[0]).toBe(0); // 255 - 255 = 0
+      expect(inverted.data[1]).toBe(255); // 255 - 0 = 255
+      expect(inverted.data[2]).toBe(127); // 255 - 128 = 127
+      expect(inverted.data[3]).toBe(255); // Alpha unchanged
+
+      expect(inverted.data[4]).toBe(255); // 255 - 0 = 255
+      expect(inverted.data[5]).toBe(0); // 255 - 255 = 0
+      expect(inverted.data[6]).toBe(191); // 255 - 64 = 191
+      expect(inverted.data[7]).toBe(128); // Alpha unchanged
+    });
+
+    it('should preserve image dimensions', () => {
+      const originalData = new Uint8ClampedArray([255, 0, 128, 255]);
+      const imageData = new (globalThis as any).ImageData(originalData, 1, 1);
+
+      const inverted = invertImageColors(imageData);
+
+      expect(inverted.width).toBe(1);
+      expect(inverted.height).toBe(1);
+    });
+
+    it('should handle pure black and white pixels', () => {
+      const originalData = new Uint8ClampedArray([
+        0,
+        0,
+        0,
+        255, // Pure black
+        255,
+        255,
+        255,
+        255, // Pure white
+      ]);
+      const imageData = new (globalThis as any).ImageData(originalData, 2, 1);
+
+      const inverted = invertImageColors(imageData);
+
+      // Black should become white
+      expect(inverted.data[0]).toBe(255);
+      expect(inverted.data[1]).toBe(255);
+      expect(inverted.data[2]).toBe(255);
+      expect(inverted.data[3]).toBe(255);
+
+      // White should become black
+      expect(inverted.data[4]).toBe(0);
+      expect(inverted.data[5]).toBe(0);
+      expect(inverted.data[6]).toBe(0);
+      expect(inverted.data[7]).toBe(255);
+    });
+  });
+});
diff --git a/src/tools/image-color-inverter/image-color-inverter.service.ts b/src/tools/image-color-inverter/image-color-inverter.service.ts
new file mode 100644
index 00000000..04fb71dc
--- /dev/null
+++ b/src/tools/image-color-inverter/image-color-inverter.service.ts
@@ -0,0 +1,87 @@
+export function invertImageFile(file: File): Promise
 {
+  return new Promise((resolve, reject) => {
+    // Validate file type
+    if (!file.type.startsWith('image/')) {
+      reject(new Error('File must be an image'));
+      return;
+    }
+
+    // Check file size (limit to 10MB)
+    const maxSize = 10 * 1024 * 1024; // 10MB
+    if (file.size > maxSize) {
+      reject(new Error('Image file size must be less than 10MB'));
+      return;
+    }
+
+    const reader = new FileReader();
+
+    reader.onload = () => {
+      const img = new Image();
+      img.src = reader.result as string;
+
+      img.onload = () => {
+        try {
+          const canvas = document.createElement('canvas');
+          const ctx = canvas.getContext('2d');
+
+          if (!ctx) {
+            reject(new Error('Failed to get canvas context'));
+            return;
+          }
+
+          canvas.width = img.width;
+          canvas.height = img.height;
+
+          // Draw the original image
+          ctx.drawImage(img, 0, 0);
+
+          // Get image data
+          const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+          const data = imageData.data;
+
+          // Invert colors (RGB channels only, preserve alpha)
+          for (let i = 0; i < data.length; i += 4) {
+            data[i] = 255 - data[i]; // Red
+            data[i + 1] = 255 - data[i + 1]; // Green
+            data[i + 2] = 255 - data[i + 2]; // Blue
+            // data[i + 3] is alpha - keep unchanged
+          }
+
+          // Put the modified image data back
+          ctx.putImageData(imageData, 0, 0);
+
+          // Convert to base64 PNG
+          const invertedDataUrl = canvas.toDataURL('image/png');
+          resolve(invertedDataUrl);
+        }
+        catch (err) {
+          reject(new Error(`Failed to process image: ${err}`));
+        }
+      };
+
+      img.onerror = () => {
+        reject(new Error('Failed to load image'));
+      };
+    };
+
+    reader.onerror = () => {
+      reject(new Error('Failed to read file'));
+    };
+
+    reader.readAsDataURL(file);
+  });
+}
+
+export function invertImageColors(imageData: ImageData): ImageData {
+  const data = new Uint8ClampedArray(imageData.data);
+
+  // Invert RGB values while preserving alpha
+  for (let i = 0; i < data.length; i += 4) {
+    data[i] = 255 - data[i]; // Red
+    data[i + 1] = 255 - data[i + 1]; // Green
+    data[i + 2] = 255 - data[i + 2]; // Blue
+    // data[i + 3] is alpha - keep unchanged
+  }
+
+  return new ImageData(data, imageData.width, imageData.height);
+}
diff --git a/src/tools/image-color-inverter/image-color-inverter.vue b/src/tools/image-color-inverter/image-color-inverter.vue
new file mode 100644
index 00000000..d6a783cc
--- /dev/null
+++ b/src/tools/image-color-inverter/image-color-inverter.vue
@@ -0,0 +1,129 @@
+
+
+
+  
+    
+
+    
+      
+        {{ error }}
+      
+
+      
+
+      
+        
+          
+            
Original Image
+            
+              
![Original]()
+            
+          
+            
Inverted Image
+            
+              
![Inverted]()
+            
+            
+              
+                Download PNG
+              
+              
+                Copy Base64
+              
+            
+          
+        
+          Clear & Upload New
+        
+      
+    
+  
+
+
+
diff --git a/src/tools/image-color-inverter/index.ts b/src/tools/image-color-inverter/index.ts
new file mode 100644
index 00000000..c407d2a5
--- /dev/null
+++ b/src/tools/image-color-inverter/index.ts
@@ -0,0 +1,13 @@
+import { Palette } from '@vicons/tabler';
+import { defineTool } from '../tool';
+import { translate } from '@/plugins/i18n.plugin';
+
+export const tool = defineTool({
+  name: translate('tools.image-color-inverter.title'),
+  path: '/image-color-inverter',
+  description: translate('tools.image-color-inverter.description'),
+  keywords: ['image', 'color', 'invert', 'negative', 'photo', 'filter', 'effect', 'png', 'jpg', 'jpeg'],
+  component: () => import('./image-color-inverter.vue'),
+  icon: Palette,
+  createdAt: new Date('2025-08-25'),
+});
diff --git a/src/tools/index.ts b/src/tools/index.ts
index 388cfaf4..caddda37 100644
--- a/src/tools/index.ts
+++ b/src/tools/index.ts
@@ -1,6 +1,7 @@
 import { tool as base64FileConverter } from './base64-file-converter';
 import { tool as base64StringConverter } from './base64-string-converter';
 import { tool as basicAuthGenerator } from './basic-auth-generator';
+import { tool as imageColorInverter } from './image-color-inverter';
 import { tool as emailNormalizer } from './email-normalizer';
 
 import { tool as asciiTextDrawer } from './ascii-text-drawer';
@@ -91,7 +92,19 @@ import { tool as yamlViewer } from './yaml-viewer';
 export const toolsByCategory: ToolCategory[] = [
   {
     name: 'Crypto',
-    components: [tokenGenerator, hashText, bcrypt, uuidGenerator, ulidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser, pdfSignatureChecker],
+    components: [
+      tokenGenerator,
+      hashText,
+      bcrypt,
+      uuidGenerator,
+      ulidGenerator,
+      cypher,
+      bip39,
+      hmacGenerator,
+      rsaKeyPairGenerator,
+      passwordStrengthAnalyser,
+      pdfSignatureChecker,
+    ],
   },
   {
     name: 'Converter',
@@ -141,7 +154,7 @@ export const toolsByCategory: ToolCategory[] = [
   },
   {
     name: 'Images and videos',
-    components: [qrCodeGenerator, wifiQrCodeGenerator, svgPlaceholderGenerator, cameraRecorder],
+    components: [qrCodeGenerator, wifiQrCodeGenerator, svgPlaceholderGenerator, cameraRecorder, imageColorInverter],
   },
   {
     name: 'Development',
@@ -164,7 +177,14 @@ export const toolsByCategory: ToolCategory[] = [
   },
   {
     name: 'Network',
-    components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator],
+    components: [
+      ipv4SubnetCalculator,
+      ipv4AddressConverter,
+      ipv4RangeExpander,
+      macAddressLookup,
+      macAddressGenerator,
+      ipv6UlaGenerator,
+    ],
   },
   {
     name: 'Math',
diff --git a/src/ui/c-select/c-select.vue b/src/ui/c-select/c-select.vue
index 7b3607c9..38e2eb8f 100644
--- a/src/ui/c-select/c-select.vue
+++ b/src/ui/c-select/c-select.vue
@@ -151,7 +151,7 @@ function onSearchInput() {
       >