Code Monkey home page Code Monkey logo

Comments (9)

tylerjbainbridge avatar tylerjbainbridge commented on September 21, 2024 1

I included replication instructions in the issue- very easy to reproduce it.

I believe it has to do with Safari/iOS having a max size for canvases and any larger image (basically anything taken on an iPhone) causes toBlob to quietly fail and return null.

I ended up having to move my image cropping to the server because this bug was effecting so many users.

from react-image-crop.

jwarykowski avatar jwarykowski commented on September 21, 2024 1

Hey All, just in case anyone else runs into this issue here is what I did, if you seen any flaws please respond to the comment 😅 .

import canvasSize from 'canvas-size'

export const processFile = async (
  crop: Crop,
  previewCanvasRef: HTMLCanvasElement,
  image: HTMLImageElement
) => {
  const ctx = previewCanvasRef.getContext('2d')

  if (!ctx || !crop) {
    return
  }

  const area = await canvasSize.maxArea()

  const constraints = area.success
    ? {
        height: area.height,
        width: area.width,
        pixels: area.height * area.width,
      }
    : { height: 4096, width: 4096, pixels: 4096 * 4096 }

  const pixelRatio = window.devicePixelRatio || 1

  const scaleX = image.naturalWidth / image.width
  const scaleY = image.naturalHeight / image.height

  const cropWidth = crop.width * scaleX * pixelRatio
  const cropHeight = crop.height * scaleY * pixelRatio

  const cropAspectRatio = cropWidth / cropHeight

  let resizedCropWidth = cropWidth
  let resizedCropHeight = cropHeight

  if (resizedCropWidth > constraints.width) {
    resizedCropWidth = constraints.width
    resizedCropHeight = resizedCropWidth / cropAspectRatio
  }
  if (resizedCropHeight > constraints.height) {
    resizedCropHeight = constraints.height
    resizedCropWidth = resizedCropHeight * cropAspectRatio
  }

  ctx.canvas.width = Math.floor(resizedCropWidth)
  ctx.canvas.height = Math.floor(resizedCropHeight)

  ctx.scale(pixelRatio, pixelRatio)
  ctx.imageSmoothingQuality = 'high'

  const cropX = crop.x * scaleX
  const cropY = crop.y * scaleY

  ctx.save()

  ctx.drawImage(
    image,
    cropX,
    cropY,
    cropWidth,
    cropHeight, // Source crop area in the image
    0,
    0,
    resizedCropWidth,
    resizedCropHeight // Destination on the canvas
  )

  ctx.restore()
}

from react-image-crop.

mnfwu avatar mnfwu commented on September 21, 2024

I've run into this same issue for mobile users on Safari with the preview canvas toBlob method failing to return a blob. It had been working well for months, but on January 10 we started receiving bug reports, all from users on mobile Safari browser and iOS version >17.0.

The behavior I've seen is like in @tylerjbainbridge's screenshot above, where the preview canvas does not populate with an image when the image is first selected. This seems to be happening more often with larger images.

Thanks for looking into this issue, we're also keen to know if anyone's found a work around or a source of the issue.

from react-image-crop.

sekoyo avatar sekoyo commented on September 21, 2024

Are you able to replicate the issue? There was a "Canvas lost" error regression in iOS 17 that was fixed in a patch, wondering if you are able to see what error is in the console

from react-image-crop.

Fasunle avatar Fasunle commented on September 21, 2024

Thanks for looking into this issue, we're also keen to know if anyone's found a work around or a source of the issue.

I just experienced a similar error now. I can create an issue for this if needed.

from react-image-crop.

Fasunle avatar Fasunle commented on September 21, 2024

I found a fix for this 💯

The solution is shown in the image below:

  • when we try to draw canvas on iOS, for downloadable canvas, the pixel ratio MUST be 1. if we use the default (the actual device pixelRatio which is 3 or more), the cropping is not going to work because the file will be too big to fit into a blob

  • the one in green works on both iOS and android. However, the one in red work for every versions of Android but some versions iOS on mobile are not working.

image

from react-image-crop.

sekoyo avatar sekoyo commented on September 21, 2024

The exact maximum size of a element depends on the browser and environment. While in most cases the maximum dimensions exceed 10,000 x 10,000 pixels, notably iOS devices limit the canvas size to only 4,096 x 4,096 pixels. See canvas size limits in different browsers and devices.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size

I'm not sure if devicePixelRatio affects that you could just make a larger canvas and see.

So the formula is either:
const MAX_SIZE = 4096
or
const MAX_SIZE = 4096 / devicePixelRatio

Then just ensure the crop preview doesn't exceed that (size it down to the max dimensions if exceeded). canvas.drawImage has params which allow you to resize the image:

dWidth
The width to draw the image in the destination canvas. This allows scaling of the drawn image. If not specified, the image is not scaled in width when drawn. Note that this argument is not included in the 3-argument syntax.

dHeight
The height to draw the image in the destination canvas. This allows scaling of the drawn image. If not specified, the image is not scaled in height when drawn. Note that this argument is not included in the 3-argument syntax.

You can also dynamically determine the max canvas size with that library: https://npmjs.com/package/canvas-size

from react-image-crop.

jwarykowski avatar jwarykowski commented on September 21, 2024

@sekoyo do you have example of this with the crop logic? I've tried to use the dWidth and dHeight params in your example but to no avail 😢

from react-image-crop.

jwarykowski avatar jwarykowski commented on September 21, 2024

Just to note on the above example, there is an issue if your user is zoomed in or out, we need to consider this otherwise the crop will be off. This is on my list for next week so I'll update the above if I find a fix 🙇

from react-image-crop.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.