Next.js Discord

Discord Forum

Image generation and download

Unanswered
Thiago Cabreira posted this in #help-forum
Open in Discord
Description "Allow the user to download the created story in format
image (JPG/PNG) with aspect ratio 9:16 (1080x1920)."

When I click on the button, I want to download this image that was generated, this project of mine is an image generator that is fed by the public list of cats, then the user chooses the breed that is the image, title and description, after it finishes to create when creating download I need to download

4 Replies

type StoryPreviewProps = {
  imageUrl: string;
  rating: number | null;
  titleStory: string;
  descriptionStory: string;
  storyRef: React.RefObject<HTMLDivElement> | null;
};

export function StoryPreview({
  imageUrl,
  rating,
  descriptionStory,
  titleStory,
  storyRef,
}: StoryPreviewProps) {
  return (
    <div className="flex items-center justify-center ">
      <div
        ref={storyRef}
        className="  w-80 h-[478px] rounded-3xl overflow-hidden shadow-lg bg-gray-50 space-y-5"
      >
        <div className="bg-gray-200 h-56 flex items-center justify-center">
          {imageUrl ? (
            <Image
              width={400}
              height={400}
              src={imageUrl}
              alt="Imagem da raça de gato"
              className="w-full h-full object-cover"
              crossOrigin="anonymous"
            />
          ) : (
            <ImagePlaceholder />
          )}
        </div>
        <div className="p-4 h-64 space-y-2">
          <div className="flex text-[var(--created-date-text)] text-sm mb-2 flex-col space-y-5">
            {rating && (
              <div className="flex items-center">
                <Star />
                <span className="ml-2 text-sm">{rating}</span>
              </div>
            )}
            <div>
              <p className="text-[var(--created-date-text)] font-secondary text-base font-normal">
                {normalizeDate(new Date())}
              </p>
            </div>
          </div>
          <h2 className="text-3xl text-[var(--font-story)] font-secondary font-medium">
            {titleStory || 'Titulo do story'}
          </h2>
          <p className="text-[var(--font-story)] font-normal mt-2 text-sm font-secondary">
            {descriptionStory || 'Descrição do story'}
          </p>
        </div>
      </div>
    </div>
  );
}
'use client';
import { toJpeg } from 'html-to-image';

export default function Home() {
  const [imageUrl, setImageUrl] = useState<string>('');
  const [rating, setRating] = useState<number | null>(null);
  const [titleStory, setTitleStory] = useState<string>('');
  const [descriptionStory, setDescriptionStory] = useState<string>('');
  const storyRef = useRef<HTMLDivElement>(
    null,
  ) as React.RefObject<HTMLDivElement>;
  const handleDownload = async () => {
    if (storyRef.current) {
      const dataUrl = await toJpeg(storyRef.current, {
        width: 1080,
        height: 1920,
        quality: 0.95,
      });

      const link = document.createElement('a');
      link.href = dataUrl;
      link.download = 'story.jpg';
      link.click();
    }
  };
  console.log(storyRef.current, 'storyRef');

  return (
    <div className="h-full w-full flex items-center justify-center font-sans py-10">
      <div className="flex flex-col md:flex-row items-center justify-center gap-8 w-11/12 max-w-6xl">
        <div className="flex flex-col items-start w-full md:w-3/5 space-y-8">
          <Header />
          <Form
            onClick={handleDownload}
            setImageUrl={setImageUrl}
            setRating={setRating}
            setTitleStory={setTitleStory}
            setDescriptionStory={setDescriptionStory}
          />
        </div>
        <div className="w-full md:w-2/5">
          <StoryPreview
            storyRef={storyRef}
            imageUrl={imageUrl}
            rating={rating}
            titleStory={titleStory}
            descriptionStory={descriptionStory}
          />
        </div>
      </div>
    </div>
  );
}
import { FormButton } from '../FormButton';
import { FormInput } from '../FormInput';
import { FormSelect } from '../FormSelect';
import { FormTextarea } from '../FormTextarea';

interface FormProps {
  setImageUrl: React.Dispatch<React.SetStateAction<string>>;
  setRating: React.Dispatch<React.SetStateAction<number | null>>;
  setTitleStory: React.Dispatch<React.SetStateAction<string>>;
  setDescriptionStory: React.Dispatch<React.SetStateAction<string>>;
  onClick: () => void;
}

export function Form({
  setImageUrl,
  setRating,
  setDescriptionStory,
  setTitleStory,
  onClick,
}: FormProps) {
  return (
    <form className="flex flex-col items-start space-y-6 w-full">
      <FormSelect setImageUrl={setImageUrl} setRating={setRating} />
      <FormInput
        setTitleStory={setTitleStory}
        label={'Titulo do Story'}
        placeholder={'Digite o titulo do story'}
      />
      <FormTextarea
        setDescriptionStory={setDescriptionStory}
        label={'Descrição do Story'}
        placeholder={'Digite a descrição do Story'}
      />
      <div className="w-full">
        <FormButton onClick={onClick} />
      </div>
    </form>
  );
}
I put my code so far as I did, at the moment it reloads but the save part is not appearing