From f2a6e95fcfd50755b0e060f57ddddb4b5e667755 Mon Sep 17 00:00:00 2001
From: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com>
Date: Fri, 26 Sep 2025 12:46:02 +0100
Subject: [PATCH] Feature/remove images (#4503)
---
.../public/locales/en-US/translation.json | 14 ++++--
.../src/data/useTranslatedToolRegistry.tsx | 10 +++--
.../removeImage/useRemoveImageOperation.ts | 30 +++++++++++++
.../removeImage/useRemoveImageParameters.ts | 17 +++++++
frontend/src/tools/RemoveImage.tsx | 45 +++++++++++++++++++
5 files changed, 109 insertions(+), 7 deletions(-)
create mode 100644 frontend/src/hooks/tools/removeImage/useRemoveImageOperation.ts
create mode 100644 frontend/src/hooks/tools/removeImage/useRemoveImageParameters.ts
create mode 100644 frontend/src/tools/RemoveImage.tsx
diff --git a/frontend/public/locales/en-US/translation.json b/frontend/public/locales/en-US/translation.json
index 5bdde8cb2..331a76511 100644
--- a/frontend/public/locales/en-US/translation.json
+++ b/frontend/public/locales/en-US/translation.json
@@ -1810,10 +1810,16 @@
}
},
"removeImage": {
- "title": "Remove image",
- "header": "Remove image",
- "removeImage": "Remove image",
- "submit": "Remove image"
+ "title": "Remove Images",
+ "header": "Remove Images",
+ "removeImage": "Remove Images",
+ "submit": "Remove Images",
+ "results": {
+ "title": "Remove Images Results"
+ },
+ "error": {
+ "failed": "Failed to remove images from the PDF."
+ }
},
"splitByChapters": {
"title": "Split PDF by Chapters",
diff --git a/frontend/src/data/useTranslatedToolRegistry.tsx b/frontend/src/data/useTranslatedToolRegistry.tsx
index 97aa9725c..c23fe3628 100644
--- a/frontend/src/data/useTranslatedToolRegistry.tsx
+++ b/frontend/src/data/useTranslatedToolRegistry.tsx
@@ -22,6 +22,7 @@ import AutoRename from "../tools/AutoRename";
import SingleLargePage from "../tools/SingleLargePage";
import UnlockPdfForms from "../tools/UnlockPdfForms";
import RemoveCertificateSign from "../tools/RemoveCertificateSign";
+import RemoveImage from "../tools/RemoveImage";
import CertSign from "../tools/CertSign";
import BookletImposition from "../tools/BookletImposition";
import Flatten from "../tools/Flatten";
@@ -533,11 +534,14 @@ export function useFlatToolRegistry(): ToolRegistry {
},
removeImage: {
icon: ,
- name: t("home.removeImage.title", "Remove Image"),
- component: null,
- description: t("home.removeImage.desc", "Remove images from PDF documents"),
+ name: t("home.removeImage.title", "Remove Images"),
+ component: RemoveImage,
+ description: t("home.removeImage.desc", "Remove all images from a PDF document"),
categoryId: ToolCategoryId.STANDARD_TOOLS,
subcategoryId: SubcategoryId.REMOVAL,
+ maxFiles: -1,
+ endpoints: ["remove-image-pdf"],
+ operationConfig: undefined,
synonyms: getSynonyms(t, "removeImage"),
},
removePassword: {
diff --git a/frontend/src/hooks/tools/removeImage/useRemoveImageOperation.ts b/frontend/src/hooks/tools/removeImage/useRemoveImageOperation.ts
new file mode 100644
index 000000000..0f6649598
--- /dev/null
+++ b/frontend/src/hooks/tools/removeImage/useRemoveImageOperation.ts
@@ -0,0 +1,30 @@
+import { useTranslation } from 'react-i18next';
+import { useToolOperation, ToolOperationConfig, ToolType } from '../shared/useToolOperation';
+import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
+import type { RemoveImageParameters } from './useRemoveImageParameters';
+
+export const buildRemoveImageFormData = (_params: RemoveImageParameters, file: File): FormData => {
+ const formData = new FormData();
+ formData.append('fileInput', file);
+ return formData;
+};
+
+export const removeImageOperationConfig: ToolOperationConfig = {
+ toolType: ToolType.singleFile,
+ buildFormData: buildRemoveImageFormData,
+ operationType: 'removeImage',
+ endpoint: '/api/v1/general/remove-image-pdf',
+};
+
+export const useRemoveImageOperation = () => {
+ const { t } = useTranslation();
+
+ return useToolOperation({
+ ...removeImageOperationConfig,
+ getErrorMessage: createStandardErrorHandler(
+ t('removeImage.error.failed', 'Failed to remove images from the PDF.')
+ ),
+ });
+};
+
+
diff --git a/frontend/src/hooks/tools/removeImage/useRemoveImageParameters.ts b/frontend/src/hooks/tools/removeImage/useRemoveImageParameters.ts
new file mode 100644
index 000000000..f57a9e93e
--- /dev/null
+++ b/frontend/src/hooks/tools/removeImage/useRemoveImageParameters.ts
@@ -0,0 +1,17 @@
+import { useBaseParameters } from '../shared/useBaseParameters';
+import type { BaseParametersHook } from '../shared/useBaseParameters';
+
+export type RemoveImageParameters = Record;
+
+export const defaultParameters: RemoveImageParameters = {};
+
+export type RemoveImageParametersHook = BaseParametersHook;
+
+export const useRemoveImageParameters = (): RemoveImageParametersHook => {
+ return useBaseParameters({
+ defaultParameters,
+ endpointName: 'remove-image-pdf',
+ });
+};
+
+
diff --git a/frontend/src/tools/RemoveImage.tsx b/frontend/src/tools/RemoveImage.tsx
new file mode 100644
index 000000000..f636f9f65
--- /dev/null
+++ b/frontend/src/tools/RemoveImage.tsx
@@ -0,0 +1,45 @@
+import { useTranslation } from "react-i18next";
+import { createToolFlow } from "../components/tools/shared/createToolFlow";
+import { useRemoveImageParameters } from "../hooks/tools/removeImage/useRemoveImageParameters";
+import { useRemoveImageOperation } from "../hooks/tools/removeImage/useRemoveImageOperation";
+import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
+import { BaseToolProps, ToolComponent } from "../types/tool";
+
+const RemoveImage = (props: BaseToolProps) => {
+ const { t } = useTranslation();
+
+ const base = useBaseTool(
+ 'removeImage',
+ useRemoveImageParameters,
+ useRemoveImageOperation,
+ props
+ );
+
+ return createToolFlow({
+ files: {
+ selectedFiles: base.selectedFiles,
+ isCollapsed: base.hasResults,
+ },
+ steps: [],
+ executeButton: {
+ text: t("removeImage.submit", "Remove Images"),
+ isVisible: !base.hasResults,
+ loadingText: t("loading"),
+ onClick: base.handleExecute,
+ disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
+ },
+ review: {
+ isVisible: base.hasResults,
+ operation: base.operation,
+ title: t("removeImage.results.title", "Remove Images Results"),
+ onFileClick: base.handleThumbnailClick,
+ onUndo: base.handleUndo,
+ },
+ });
+};
+
+RemoveImage.tool = () => useRemoveImageOperation;
+
+export default RemoveImage as ToolComponent;
+
+