Skip to content

Add image-diff-checker extension#17275

Merged
raycastbot merged 14 commits intoraycast:mainfrom
yasuhiro-yamamoto:ext/image-diff-checker
Mar 4, 2025
Merged

Add image-diff-checker extension#17275
raycastbot merged 14 commits intoraycast:mainfrom
yasuhiro-yamamoto:ext/image-diff-checker

Conversation

@yasuhiro-yamamoto
Copy link
Contributor

@yasuhiro-yamamoto yasuhiro-yamamoto commented Feb 24, 2025

Description

Screencast

Checklist

@raycastbot raycastbot added the new extension Label for PRs with new extensions label Feb 24, 2025
@raycastbot
Copy link
Collaborator

Congratulations on your new Raycast extension! 🚀

Due to our current reduced availability, the initial review may take up to 10-15 business days

Once the PR is approved and merged, the extension will be available on our Store.

@pernielsentikaer pernielsentikaer self-assigned this Mar 2, 2025
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

Added a new Image Diff Checker extension that compares two images and highlights differences, supporting JPEG, JPG, PNG, and GIF formats.

  • The extension uses pixelmatch and jimp libraries to process images and generate visual diffs with a clean form-based UI
  • The implementation includes proper file validation with test coverage in src/hooks/use-image-form/file-validation.spec.ts
  • The metadata folder with screenshots is missing but required since this is a view command (https://developers.raycast.com/basics/prepare-an-extension-for-store#how-to-use-it)
  • The compare function in src/utils/pixelmatch.ts should be wrapped in a try-catch block since image processing operations can fail
  • The fileValidation function in src/hooks/use-image-form/file-validation.ts doesn't explicitly return undefined when validation passes

💡 (1/5) You can manually trigger the bot by mentioning @greptileai in a comment!

12 file(s) reviewed, 8 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +8 to +13
export const fileValidation = (value?: string[]) => {
if (!value) return "The item is required.";
if (value?.length === 0) return "The item is required.";
const isValid = checkExtension(value[0]);
if (!isValid) return "Invalid file type.";
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The function doesn't return anything when validation passes. This will return undefined which might cause issues with form validation. Consider returning undefined explicitly or returning null to indicate successful validation.

Suggested change
export const fileValidation = (value?: string[]) => {
if (!value) return "The item is required.";
if (value?.length === 0) return "The item is required.";
const isValid = checkExtension(value[0]);
if (!isValid) return "Invalid file type.";
};
export const fileValidation = (value?: string[]) => {
if (!value) return "The item is required.";
if (value?.length === 0) return "The item is required.";
const isValid = checkExtension(value[0]);
if (!isValid) return "Invalid file type.";
return undefined; // Explicitly return undefined for valid files
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +33 to +36
describe("required", () => {
test("should return required error for empty array", () => {
expect(fileValidation([])).toBe(ERRORS.required);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Missing test for the undefined input case. The fileValidation function handles both empty arrays and undefined values, but only the empty array case is tested here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +25 to +26
"pixelmatch": "^7.1.0",
"pngjs": "^7.0.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: There's a version mismatch between pixelmatch v7.1.0 and the @types/pngjs v6.0.5. The pixelmatch library is using pngjs v7.0.0, but the type definitions are for v6.x

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +29 to +32
onSubmit(values) {
const diffImageSource = compare(values.actual[0], values.expected[0]);
createMarkdown(diffImageSource);
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Missing error handling for image comparison. If compare() or createMarkdown() fails, there's no error handling or feedback to the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +15 to +21
const createMarkdown = async (
diffImageSource: Promise<{
diffBuffer: Buffer;
width: number;
height: number;
}>,
) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Accepting a Promise as a parameter instead of awaiting it in the caller creates unnecessary complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +13 to +15
if (expectedImage.bitmap.width !== width || expectedImage.bitmap.height !== height) {
expectedImage.resize({ w: width, h: height });
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Resizing only the expected image might lead to distortion if aspect ratios differ significantly. Consider maintaining aspect ratio or providing an option for different scaling strategies.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const expectedBuffer = expectedImage.bitmap.data;
const diffBuffer = Buffer.alloc(actualBuffer.length);

pixelmatch(actualBuffer, expectedBuffer, diffBuffer, width, height, { threshold: 0.2 });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: The threshold value of 0.2 is hardcoded. Consider making this configurable via preferences to allow users to adjust sensitivity of the comparison.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +8 to +9
const actualImage = await Jimp.read(actual);
const expectedImage = await Jimp.read(expected);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Missing error handling for image loading failures. If either image can't be read, this will throw an unhandled exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pernielsentikaer
Copy link
Collaborator

Is this ready for another review?

@yasuhiro-yamamoto
Copy link
Contributor Author

@pernielsentikaer Yes, I have addressed the feedback and made the necessary changes. The pull request is now ready for another review.

Copy link
Collaborator

@pernielsentikaer pernielsentikaer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi 👋

Looks good to me, approved 🔥

@raycastbot raycastbot merged commit e7efbd1 into raycast:main Mar 4, 2025
2 checks passed
@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2025

Published to the Raycast Store:
https://raycast.com/yasuhiroyamamoto/image-diff-checker

@raycastbot
Copy link
Collaborator

🎉 🎉 🎉

Such a great contribution deserves a reward, but unfortunately we couldn't find your Raycast account based on your GitHub username (@yasuhiro-yamamoto).
Please link your GitHub account to your Raycast account to receive your credits and soon be able to exchange them for some swag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new extension Label for PRs with new extensions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants