Skip to content

Commit a54dcf2

Browse files
committed
fix: Previously, when batch processing images with "Keep original format" selected alongside compression or resizing, files would be incorrectly renamed to a .original extension (e.g., photo.png → photo.original), breaking links and file recognition. Files now retain their original extension while still being compressed/resized.
1 parent 595db3c commit a54dcf2

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

src/BatchImageProcessor.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,9 @@ export class BatchImageProcessor {
119119

120120
// Capture paths up-front so we can safely revert if needed
121121
const oldPath = linkedFile.path;
122-
const newFileName = `${linkedFile.basename}.${outputFormat.toLowerCase()}`;
123-
const newFilePath = linkedFile.path.replace(linkedFile.name, newFileName);
122+
// When outputFormat is ORIGINAL, keep the original filename (no rename)
123+
const newFileName = outputFormat === 'ORIGINAL' ? linkedFile.name : `${linkedFile.basename}.${outputFormat.toLowerCase()}`;
124+
const newFilePath = outputFormat === 'ORIGINAL' ? linkedFile.path : linkedFile.path.replace(linkedFile.name, newFileName);
124125

125126
let didRename = false;
126127
let didWrite = false;
@@ -298,8 +299,9 @@ export class BatchImageProcessor {
298299
imageCount++;
299300

300301
const oldPath = image.path;
301-
const newFileName = `${image.basename}.${outputFormat.toLowerCase()}`;
302-
const newFilePath = image.path.replace(image.name, newFileName);
302+
// When outputFormat is ORIGINAL, keep the original filename (no rename)
303+
const newFileName = outputFormat === 'ORIGINAL' ? image.name : `${image.basename}.${outputFormat.toLowerCase()}`;
304+
const newFilePath = outputFormat === 'ORIGINAL' ? image.path : image.path.replace(image.name, newFileName);
303305

304306
let didRename = false;
305307
let didWrite = false;
@@ -472,8 +474,9 @@ export class BatchImageProcessor {
472474
imageCount++;
473475

474476
const oldPath = image.path;
475-
const targetName = `${image.basename}.${outputFormat.toLowerCase()}`;
476-
let targetPath = image.path.replace(image.name, targetName);
477+
// When outputFormat is ORIGINAL, keep the original filename (no rename)
478+
const targetName = outputFormat === 'ORIGINAL' ? image.name : `${image.basename}.${outputFormat.toLowerCase()}`;
479+
let targetPath = outputFormat === 'ORIGINAL' ? image.path : image.path.replace(image.name, targetName);
477480

478481
let didRename = false;
479482
let didWrite = false;
@@ -698,8 +701,9 @@ export class BatchImageProcessor {
698701
);
699702

700703
// Construct the new file path based on conversion settings
701-
const newFileName = `${image.basename}.${outputFormat.toLowerCase()}`;
702-
let newFilePath = image.path.replace(image.name, newFileName);
704+
// When outputFormat is ORIGINAL, keep the original filename (no rename)
705+
const newFileName = outputFormat === 'ORIGINAL' ? image.name : `${image.basename}.${outputFormat.toLowerCase()}`;
706+
let newFilePath = outputFormat === 'ORIGINAL' ? image.path : image.path.replace(image.name, newFileName);
703707

704708
// Check for conflicts and generate unique name if necessary using FolderAndFilenameManagement
705709
if (

tests/integration/batch/ProcessAllVault.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,53 @@ describe('BatchImageProcessor — Vault-wide orchestration', () => {
120120
expect(folderAndFilenameManagement.handleNameConflicts).toHaveBeenCalled();
121121
});
122122

123+
it('4.12 Given convertTo=disabled (ORIGINAL), When processing, Then files are NOT renamed', async () => {
124+
// Fresh isolated environment with convertTo=disabled
125+
const noteFile = fakeTFile({ path: 'notes/test.md' });
126+
const pngImage = fakeTFile({ path: 'images/photo.png' });
127+
const jpgImage = fakeTFile({ path: 'images/picture.jpg' });
128+
const vaultIso = fakeVault({ files: [noteFile, pngImage, jpgImage] }) as any;
129+
const appIso = fakeApp({
130+
vault: vaultIso,
131+
metadataCache: { resolvedLinks: { [noteFile.path]: { [pngImage.path]: 1, [jpgImage.path]: 1 } } } as any
132+
}) as any;
133+
appIso.fileManager = { renameFile: vi.fn(async (file: any, newPath: string) => { await appIso.vault.rename(file, newPath); }) };
134+
135+
// convertTo=disabled means keep original format - set ALL required settings explicitly
136+
const pluginIso = makePluginStub({
137+
settings: {
138+
ProcessAllVaultconvertTo: 'disabled',
139+
ProcessAllVaultquality: 0.8, // compression applied (not 1, so processing should occur)
140+
ProcessAllVaultResizeModalresizeMode: 'None',
141+
ProcessAllVaultResizeModaldesiredWidth: 0,
142+
ProcessAllVaultResizeModaldesiredHeight: 0,
143+
ProcessAllVaultResizeModaldesiredLength: 0,
144+
ProcessAllVaultEnlargeOrReduce: 'Always',
145+
allowLargerFiles: true,
146+
ProcessAllVaultSkipFormats: '',
147+
ProcessAllVaultskipImagesInTargetFormat: false // Important: don't skip images in their own format
148+
}
149+
});
150+
const imgIso = { processImage: vi.fn(async (_blob: Blob) => new ArrayBuffer(4)) };
151+
const ffmIso = { handleNameConflicts: vi.fn(async (_dir: string, name: string) => name) };
152+
const bipIso = new BatchImageProcessor(appIso as any, pluginIso as any, imgIso as any, ffmIso as any);
153+
154+
await bipIso.processAllVaultImages();
155+
156+
// Images should be processed (compression applied)
157+
expect(imgIso.processImage).toHaveBeenCalled();
158+
159+
// But NO renames should have occurred - files keep their original extensions
160+
expect(appIso.fileManager.renameFile).not.toHaveBeenCalled();
161+
162+
// Verify the files still exist with original names
163+
expect(appIso.vault.getAbstractFileByPath('images/photo.png')).toBeTruthy();
164+
expect(appIso.vault.getAbstractFileByPath('images/picture.jpg')).toBeTruthy();
165+
// And NOT renamed to .original
166+
expect(appIso.vault.getAbstractFileByPath('images/photo.original')).toBeFalsy();
167+
expect(appIso.vault.getAbstractFileByPath('images/picture.original')).toBeFalsy();
168+
});
169+
123170
it('4.10 Skip target format (vault): when convertTo=webp and skipImagesInTargetFormat=true, webp files are skipped', async () => {
124171
// Fresh, isolated environment to avoid mutated TFile state across tests
125172
const noteFile = fakeTFile({ path: 'notes/m.md' });

0 commit comments

Comments
 (0)