Skip to content

Commit

Permalink
Merge pull request #1187 from prezly/fix/care-5657-innogames-blurry-c…
Browse files Browse the repository at this point in the history
…over-images-in-home-site-for-stories

[CARE-5657] Fix - Crop to aspect ratio before passing to the renderer
  • Loading branch information
e1himself authored Sep 13, 2024
2 parents a06e035 + 765a799 commit 03c77c7
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 12 deletions.
3 changes: 3 additions & 0 deletions components/StoryCards/StoryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import styles from './StoryCard.module.scss';

type Props = {
className?: string;
forceAspectRatio?: boolean;
layout: 'horizontal' | 'vertical';
publishedAt: string | null;
showDate: boolean;
Expand All @@ -30,6 +31,7 @@ type Props = {

export function StoryCard({
className,
forceAspectRatio,
layout,
publishedAt,
showDate,
Expand Down Expand Up @@ -65,6 +67,7 @@ export function StoryCard({
>
<StoryImage
className={styles.image}
forceAspectRatio={forceAspectRatio ? 4 / 3 : undefined}
isStatic={withStaticImage}
placeholderClassName={styles.placeholder}
size={size}
Expand Down
52 changes: 48 additions & 4 deletions components/StoryImage/StoryImage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import UploadcareImage from '@uploadcare/nextjs-loader';
import type { UploadcareImage } from '@prezly/uploadcare';
import UploadcareImageLoader from '@uploadcare/nextjs-loader';
import classNames from 'classnames';

import type { ListStory } from 'types';
Expand All @@ -13,6 +14,7 @@ import styles from './StoryImage.module.scss';

type Props = {
className?: string;
forceAspectRatio?: number;
isStatic?: boolean;
placeholderClassName?: string;
size: ImageSize;
Expand All @@ -22,6 +24,7 @@ type Props = {

export function StoryImage({
className,
forceAspectRatio,
isStatic = false,
placeholderClassName,
size,
Expand All @@ -30,12 +33,12 @@ export function StoryImage({
}: Props) {
const fallback = useFallback();
const image = getStoryThumbnail(thumbnailImage);
const uploadcareImage = getUploadcareImage(image);
const uploadcareImage = applyAspectRatio(getUploadcareImage(image), forceAspectRatio);

if (uploadcareImage) {
return (
<div className={classNames(styles.imageContainer, className)}>
<UploadcareImage
<UploadcareImageLoader
fill
alt={title}
className={classNames(styles.image, {
Expand All @@ -57,7 +60,7 @@ export function StoryImage({
})}
>
{fallbackImage ? (
<UploadcareImage
<UploadcareImageLoader
alt="No image"
src={fallbackImage.cdnUrl}
className={classNames(styles.imageContainer, styles.placeholderLogo, className)}
Expand All @@ -70,3 +73,44 @@ export function StoryImage({
</span>
);
}

function applyAspectRatio(
image: UploadcareImage | null,
aspectRatio: number | undefined,
): UploadcareImage | null {
if (!image || !aspectRatio) {
return image;
}

const actualAspectRatio = image.width / image.height;

if (actualAspectRatio > aspectRatio) {
const [width, height] = constrain(Math.round(image.height * aspectRatio), image.height);
// The image is wider than it should
return image.scaleCrop(width, height, true);
}

if (actualAspectRatio < aspectRatio) {
// The image is taller than it should
const [width, height] = constrain(image.width, Math.round(image.width / aspectRatio));
return image.scaleCrop(width, height, true);
}

return image;
}

const MAX_SCALED_SIZE = 3000;

/**
* Scale down vectors, which has at least one of dimensions > 3000px.
* This is necessary because Uploadcare scale_crop transformation fails if one of the dimensions is larger than 3000px.
*/
function constrain(width: number, height: number): [number, number] {
if (width < MAX_SCALED_SIZE && height < MAX_SCALED_SIZE) {
return [width, height];
}
return [
Math.min(MAX_SCALED_SIZE, Math.round((width / height) * MAX_SCALED_SIZE)),
Math.min(MAX_SCALED_SIZE, Math.round((height / width) * MAX_SCALED_SIZE)),
];
}
1 change: 1 addition & 0 deletions modules/InfiniteStories/StoriesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export function StoriesList({
{restStories.map((story, index) => (
<StoryCard
key={story.uuid}
forceAspectRatio
layout="vertical"
publishedAt={story.published_at}
showDate={showDate}
Expand Down
56 changes: 49 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@prezly/sdk": "21.12.0",
"@prezly/story-content-format": "0.65.1",
"@prezly/theme-kit-nextjs": "9.7.0",
"@prezly/uploadcare": "2.4.4",
"@prezly/uploadcare": "2.5.0",
"@prezly/uploadcare-image": "0.3.2",
"@react-hookz/web": "14.7.1",
"@sentry/nextjs": "7.98.0",
Expand Down

0 comments on commit 03c77c7

Please sign in to comment.