ValentinH / react-easy-crop

A React component to crop images/videos with easy interactions
https://valentinh.github.io/react-easy-crop/
MIT License
2.32k stars 166 forks source link

Black border when cropping on the edge of images #156

Closed RichardHpa closed 4 years ago

RichardHpa commented 4 years ago

Like the title says, when I use any of the cropping examples, whenever you crop right against any sides of the image, you get a small black border around those sides. A lot of the images I will be passing through the cropper will have a white background so this now causes there to be a black line around the image.

Have a look at this fork and move the crop right to the top of the image to to to see what I mean. https://codesandbox.io/s/react-easy-crop-demo-with-cropped-output-194sk?file=/src/index.js

RichardHpa commented 4 years ago

Having a little play with it more and it actually only happens on the top and left side of the image.

ValentinH commented 4 years ago

The croppedAreaPixels values output by the cropper looks correct to me. It seems it's an issue with the cropImage.js file logic on this example.

czewail commented 4 years ago

cropImage.js replace

const createImage = (url: string): Promise<HTMLImageElement> =>
  new Promise((resolve, reject) => {
    const image = new Image()
    image.addEventListener('load', () => resolve(image))
    image.addEventListener('error', error => reject(error))
    image.setAttribute('crossOrigin', 'anonymous') // needed to avoid cross-origin issues on CodeSandbox
    image.src = url
  })
/**
 * @param image - Image File url
 * @param pixelCrop - pixelCrop Object provided by react-easy-crop
 * @param rotation - optional rotation parameter
 */
export async function getCroppedImg(imageSrc: string, crop: {
  width: number;
  height: number;
  x: number;
  y: number;
}): Promise<Blob> {
  const image = await createImage(imageSrc)
  const canvas = document.createElement('canvas');
  const scaleX = image.naturalWidth / image.width;
  const scaleY = image.naturalHeight / image.height;
  canvas.width = crop.width;
  canvas.height = crop.height;
  const ctx = canvas.getContext('2d')!;

  ctx.drawImage(
    image,
    crop.x * scaleX,
    crop.y * scaleY,
    crop.width * scaleX,
    crop.height * scaleY,
    0,
    0,
    crop.width,
    crop.height
  );

  // As a blob
  return new Promise(resolve => {
    canvas.toBlob(file => {
      // resolve(URL.createObjectURL(file))
      resolve(file!)
    }, 'image/jpeg')
  })
}
jmcdl commented 4 years ago

Hi, I was about to open another issue but I believe my question regards the same functionality that @RichardHpa is asking about.

The problem I'm having is if the crop area is larger than the image being cropped, the "whitespace" is black in the final cropped image. I've spent some time playing with the CSS to try to see what is causing this but haven't been able to figure it out. I tried the snippet posted by @czewail but I couldn't get it to work.

I would like to know how I can make the cropped image show a white background.

I have edited the code example so that the image can be made smaller than the crop area. When this is done show result shows the black background around the image that I'm referring to. https://codesandbox.io/s/showing-black-background-6hvln?file=/src/index.js

ValentinH commented 4 years ago

@jmcdl please see #148 and #158.

jmcdl commented 4 years ago

My apologies. I should have looked at the closed issues! Thank you.

skyylabz commented 4 years ago

hey so this worked for me until i tried to fix the mobile issue by making the safe area smaller this is what is did to fix that..

const safeArea = Math.max(image.width, image.height) * 1

but then now even with

ctx.fillStyle = 'white' ctx.fillRect(0, 0, canvas.width, canvas.height)

the black background border shows up again.. any ideas??

also, is there a reason the original background has to be black?? const safeArea = Math.max(image.width, image.height) * 1 would fix all the problems if we could come up with a better solution instead of

ctx.fillStyle = 'white' ctx.fillRect(0, 0, canvas.width, canvas.height) to make the background white...

ValentinH commented 4 years ago

The safe area being larger than the max of width and height is to avoid the image being cut when applying the rotation. If you don't use rotation, I guess you could only take the example from https://github.com/DominicTobias/react-image-crop#what-about-showing-the-crop-on-the-client (which we were using before).

Regarding the default background being black, this is just the standard behavior.

skyylabz commented 4 years ago

Is it possible to get a example version put together that has user be able to pick the image and have image rotate? I'm pretty new to coding and I've been beating myself up for days trying to put the code together from the examples. But it's hard because one is written in class component and the other uses hooks

Prettyyy pleeeeasee :)

ValentinH commented 4 years ago

I've updated the demo with the file picker: https://codesandbox.io/s/y09komm059 🙂

ValentinH commented 4 years ago

@RichardHpa I managed to remove the black borders by using Math.round() for the values passed to ctx.putImageData() 🙂

I've updated all the demo accordingly.

I'm closing this issue. Please reopen if it did not fix your example.

skyylabz commented 4 years ago

You are the man!

skyylabz commented 4 years ago

Is there anyway you could maybe demonstrate how I would apply pica to this??

ValentinH commented 4 years ago

I have never used it.

RichardHpa commented 4 years ago

@ValentinH Thanks for fixing that

skyylabz commented 4 years ago

Hey if I wanted the modal to close when I pressed show results how would I do that??

ValentinH commented 4 years ago

I'm not sure to understand: when the "show results" is shown, the modal is not open 🤔

skyylabz commented 4 years ago

So Normally when you finish cropping the image. You click show results. And another box opens to show you the cropped image. I've managed to disable the "results modal" but how can I make it so when I click show results the modal where the cropping takes place closes

I want it to finish and save what I've cropped and just close. And not show me a preview of the cropped image either

ValentinH commented 4 years ago

You need to reset the image state.

skyylabz commented 4 years ago

Could you possibly elaborate a little more please?

skyylabz commented 4 years ago

I just don't know in which component I need to do that? Or how? It would be suuuper cool if I could get a little bit more information. Please and thank you!!