Open Bug 1931692 Opened 18 days ago Updated 2 days ago

Core::Graphics: Canvas2D: Canvas API to read pixel data doesn't work

Categories

(Core :: Graphics: Canvas2D, defect, P3)

Firefox 134
Desktop
Windows 10
defect

Tracking

()

UNCONFIRMED

People

(Reporter: reza.bakhshi1381r, Unassigned, NeedInfo)

References

()

Details

(Keywords: webcompat:needs-diagnosis, webcompat:site-report)

User Story

platform:windows,mac,linux,android
impact:feature-broken
configuration:general
affects:all
branch:release
diagnosis-team:dom

Attachments

(2 files)

Attached image Bug-Image-Report.png

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36

Steps to reproduce:

https://fazayesh.spaceomid.com
This is the website that I develope myself, I'm using React-leaflet to display png images of NDVI value in a tooltip by mousemove event handler from ImageOverlay. I use Canvas API for getting pixel RGB data and a Map to give the color and return related NDVI value, the feature works correct in Chrome and Edge as I checked.
you can see an example code in stack overflow: https://stackoverflow.com/questions/77631436/how-to-read-pixel-values-of-an-imageoverlay-in-react-leaflet-by-mousemove-event

Actual results:

When I move the mouse over the image, it should open a tooltip and show a different value for each RGB pixel, but it only shows the default Map object string value.

Expected results:

It should read each pixel value and extract RGB and then give it to the Map object of predefined colors and return value to be displayed in a tooltip. please check the stack overflow link which I put in first text area.

React.js component:

import { useRef, useState } from "react"
import { ImageOverlay, SVGOverlay, Tooltip } from "react-leaflet"
import { useSelector } from "react-redux"

import { ndmiMap, ndviMap } from "./utils/statics"

export default function ImageEvents() {
  const activeField = useSelector(store => store.userFarms.activeField)
  const socketData = useSelector(store => store.socketCluster)
  const selectedDay = useSelector(store => store.userFarms.selectedDay)
  const imageRef = useRef()
  const [tooltip, setTooltip] = useState(1)
  function rgbToHex(rgb) {
    const hex = rgb.replace(/[^\d,]/g, "").split(",")
    const r = parseInt(hex[0], 10).toString(16).padStart(2, "0")
    const g = parseInt(hex[1], 10).toString(16).padStart(2, "0")
    const b = parseInt(hex[2], 10).toString(16).padStart(2, "0")
    return `#${r}${g}${b}`
  }

  const onHover = event => {
    const canvas = document.createElement("canvas")
    canvas.style.display = "none"
    const ctx = canvas.getContext("2d")
    const image = imageRef.current._image
    const width = image.width
    const height = image.height
    const x = event.originalEvent.offsetX
    const y = event.originalEvent.offsetY
    image.crossOrigin = "Anonymous" // Set the crossOrigin attribute of the image
    canvas.width = width
    canvas.height = height
    ctx.drawImage(image, 0, 0, width, height)
    const pixelData = ctx.getImageData(x, y, 1, 1).data
    const hexColor = rgbToHex(`rgb(${pixelData[0]}, ${pixelData[1]}, ${pixelData[2]})`)
    socketData.imageIndicator === "ndvi"
      ? setTooltip(ndviValue => ndviMap.get(hexColor) ?? ndviValue)
      : setTooltip(ndmiValue => ndmiMap.get(hexColor) ?? ndmiValue)
  }

  const debounce = (func, delay) => {
    let timeoutId
    return (...args) => {
      clearTimeout(timeoutId)
      timeoutId = setTimeout(() => {
        func(...args)
      }, delay)
    }
  }

  const debouncedOnHover = debounce(onHover, 10) // Adjust the debounce delay as needed

  return (
    <>
      {socketData.data &&
      activeField &&
      activeField.farm_id &&
      selectedDay &&
      socketData.data[activeField.farm_id] &&
      socketData.data[activeField.farm_id][selectedDay] &&
      socketData.data[activeField.farm_id][selectedDay].base64_encode ? (
        <ImageOverlay
          url={socketData.data[activeField.farm_id][selectedDay].base64_encode}
          crossOrigin={"anonymous"}
          bounds={activeField.bbox}
          key={activeField.bbox[0][0]}
          ref={imageRef}
          id={"image-ndvi"}
          opacity={socketData.imageIndicator === "nolayer" ? 0 : 1}
          interactive={true}
          eventHandlers={{
            mousemove: debouncedOnHover,
            click: onHover,
          }}
        >
          {(tooltip !== undefined || tooltip !== 0) && <Tooltip sticky>{tooltip}</Tooltip>}
        </ImageOverlay>
      ) : activeField.bbox && socketData.imageIndicator !== "nolayer" ? (
        <SVGOverlay
          attributes={{
            width: "40",
            height: "40",
            viewBox: "-30 -30 100 100",
          }}
          bounds={activeField.bbox}
        >
          <defs>
            <linearGradient x1="8.042%" y1="0%" x2="65.682%" y2="23.865%" id="a">
              <stop stopColor="#D6AD60" stopOpacity="0" offset="0%" />
              <stop stopColor="#D6AD60" stopOpacity=".631" offset="63.146%" />
              <stop stopColor="#D6AD60" offset="100%" />
            </linearGradient>
          </defs>
          <g fill="none" fillRule="evenodd">
            <g transform="translate(1 1)">
              <path d="M36 18c0-9.94-8.06-18-18-18" id="Oval-2" stroke="url(#a)" strokeWidth="2">
                <animateTransform
                  attributeName="transform"
                  type="rotate"
                  from="0 18 18"
                  to="360 18 18"
                  dur="0.9s"
                  repeatCount="indefinite"
                />
              </path>
              <circle fill="#D6AD60" cx="36" cy="18" r="1">
                <animateTransform
                  attributeName="transform"
                  type="rotate"
                  from="0 18 18"
                  to="360 18 18"
                  dur="0.9s"
                  repeatCount="indefinite"
                />
              </circle>
            </g>
          </g>
        </SVGOverlay>
      ) : null}
    </>
  )
}

Map variable values:

export const ndviMap = new Map([
  ["#ffffff", "ابر"],
  ["#000000", "وارد محدوده رنگی شوید"],
  ["#ff0303", "0.01, بدون پوشش"],
  ["#ff0b05", "0.02, بدون پوشش"],
  ["#ff1308", "0.03, بدون پوشش"],
  ["#ff1b0b", "0.04, بدون پوشش"],
  ["#ff230d", "0.05, بدون پوشش"],
  ["#ff2b10", "0.06, بدون پوشش"],
  ["#ff3313", "0.07, بدون پوشش"],
  ["#ff3413", "0.07, بدون پوشش"],
  ["#ff3a15", "0.08, بدون پوشش"],
  ["#fe4a1a", "0.08, بدون پوشش"],
  ["#ff3212", "0.08, بدون پوشش"],
  ["#ff4318", "0.09, بدون پوشش"],
  ["#ff4b1b", "0.1, بدون پوشش"], // 0.1
  ["#ff531e", "0.11, بدون پوشش"],
  ["#fd5c20", "0.12, بدون پوشش"],
  ["#fc6722", "0.11, بدون پوشش"],
  ["#fc6522", "0.13, بدون پوشش"],
  ["#fb6e24", "0.14, بدون پوشش"],
  ["#f97726", "0.15, بدون پوشش"],
  ["#f88128", "0.16, بدون پوشش"],
  ["#f78a2a", "0.17, بدون پوشش"],
  ["#f5932c", "0.18, بدون پوشش"],
  ["#f49c2e", "0.19, بدون پوشش"],
  ["#f3a530", "0.2, تراکم پایین"], // 0.2
  ["#f0aa2f", "0.21, تراکم پایین"],
  ["#f2af33", "0.21, تراکم پایین"],
  ["#efb331", "0.21, تراکم پایین"],
  ["#eeb530", "0.22, تراکم پایین"],
  ["#eabc2e", "0.23, تراکم پایین"],
  ["#ebb92f", "0.23, تراکم پایین"],
  ["#e6c32b", "0.24, تراکم پایین"],
  ["#e9bd2d", "0.24, تراکم پایین"],
  ["#e2c929", "0.25, تراکم پایین"],
  ["#e2c829", "0.25, تراکم پایین"],
  ["#ded027", "0.26, تراکم پایین"],
  ["#e1ca29", "0.26, تراکم پایین"],
  ["#dfce28", "0.27, تراکم پایین"],
  ["#dad724", "0.27, تراکم پایین"],
  ["#d6dd22", "0.28, تراکم پایین"],
  ["#d2e41f", "0.29, تراکم پایین"],
  ["#ceeb1d", "0.3, تراکم متوسط"], // 0.3
  ["#cbf21b", "0.31, تراکم متوسط"],
  ["#c3ef1a", "0.32, تراکم متوسط"],
  ["#bced1a", "0.33, تراکم متوسط"],
  ["#b5eb19", "0.34, تراکم متوسط"],
  ["#ade819", "0.35, تراکم متوسط"],
  ["#a6e618", "0.36, تراکم متوسط"],
  ["#9fe418", "0.37, تراکم متوسط"],
  ["#97e117", "0.38, تراکم متوسط"],
  ["#90df17", "0.39, تراکم متوسط"],
  ["#89dd16", "0.4, تراکم متوسط"], // 0.4
  ["#82db16", "0.41, تراکم متوسط"],
  ["#7ad715", "0.42, تراکم متوسط"],
  ["#72d415", "0.43, تراکم متوسط"],
  ["#6ad114", "0.44, تراکم متوسط"],
  ["#63cd14", "0.45, تراکم متوسط"],
  ["#5bca13", "0.46, تراکم متوسط"],
  ["#53c713", "0.47, تراکم متوسط"],
  ["#4cc312", "0.48, تراکم متوسط"],
  ["#44c012", "0.49, تراکم متوسط"],
  ["#3cbd11", "0.5, تراکم بالا"], // 0.5
  ["#35ba11", "0.51, تراکم بالا"],
  ["#32b310", "0.52, تراکم بالا"],
  ["#2fad0f", "0.53, تراکم بالا"],
  ["#2ca70d", "0.54, تراکم بالا"],
  ["#29a10d", "0.55, تراکم بالا"],
  ["#279b0c", "0.56, تراکم بالا"],
  ["#24950b", "0.57, تراکم بالا"],
  ["#218f0a", "0.58, تراکم بالا"],
  ["#1e8909", "0.59, تراکم بالا"],
  ["#1b8308", "0.6, تراکم بالا"], // 0.6
  ["#45a10b", "0.61, تراکم بالا"],
  ["#409d0a", "0.62, تراکم بالا"],
  ["#3c990a", "0.63, تراکم بالا"],
  ["#379609", "0.64, تراکم بالا"],
  ["#339209", "0.65, تراکم بالا"],
  ["#2f8f09", "0.66, تراکم بالا"],
  ["#2a8b08", "0.67, تراکم بالا"],
  ["#268708", "0.68, تراکم بالا"],
  ["#218407", "0.69, تراکم بالا"],
  ["#1d8007", "0.7, تراکم بالا"], // 0.7
  ["#197d07", "0.71, تراکم بالا"],
  ["#177806", "0.72, تراکم بالا"],
  ["#157305", "0.73, تراکم بالا"],
  ["#136e04", "0.74, تراکم بالا"],
  ["#116904", "0.75, تراکم بالا"],
  ["#0f6503", "0.76, تراکم بالا"],
  ["#0d6002", "0.77, تراکم بالا"],
  ["#0b5b02", "0.78, تراکم بالا"],
  ["#095601", "0.79, تراکم بالا"],
  ["#075100", "0.8, تراکم بالا"], // 0.8
  ["#064d00", "0.81, تراکم بالا"],
  ["#054b00", "0.82, تراکم بالا"],
  ["#054a00", "0.83, تراکم بالا"],
  ["#054800", "0.84, تراکم بالا"],
  ["#054700", "0.85, تراکم بالا"],
  ["#054600", "0.86, تراکم بالا"],
  ["#054400", "0.87, تراکم بالا"],
  ["#054300", "0.88, تراکم بالا"],
  ["#054100", "0.89, تراکم بالا"],
  ["#054000", "0.9, تراکم بالا"], // 0.9
  ["#053f00", "0.91, تراکم بالا"],
  ["#053d00", "0.92, تراکم بالا"],
  ["#053c00", "0.93, تراکم بالا"],
  ["#053a00", "0.94, تراکم بالا"],
  ["#053900", "0.95, تراکم بالا"],
  ["#053800", "0.96, تراکم بالا"],
  ["#053600", "0.97, تراکم بالا"],
  ["#053500", "0.98, تراکم بالا"],
  ["#053300", "0.99, تراکم بالا"],
  ["#053200", "1.0, تراکم بالا"], // 1.0
])

export const ndmiMap = new Map([
  ["#ffffff", "ابر"],
  ["#b29f99", "0.00"],
  ["#b3a09b", "0.01"],
  ["#b4a19d", "0.02"],
  ["#b5a29f", "0.03"],
  ["#b6a4a1", "0.04"],
  ["#b8a5a3", "0.05"],
  ["#b9a6a5", "0.06"],
  ["#baa8a7", "0.07"],
  ["#bba9a9", "0.08"],
  ["#bcaaab", "0.09"],
  ["#beacad", "0.10"],
  ["#bfadae", "0.11"],
  ["#c1aeb0", "0.12"],
  ["#c2afb1", "0.13"],
  ["#c4b0b3", "0.14"],
  ["#c5b2b4", "0.15"],
  ["#c7b3b6", "0.16"],
  ["#c8b4b7", "0.17"],
  ["#cab5b9", "0.18"],
  ["#cbb6ba", "0.19"],
  ["#cdb8bc", "0.20"],
  ["#ceb8bd", "0.21"],
  ["#cfb9bf", "0.22"],
  ["#d0bac1", "0.23"],
  ["#d1bbc3", "0.24"],
  ["#d3bcc5", "0.25"],
  ["#d4bdc6", "0.26"],
  ["#d5bec8", "0.27"],
  ["#d6bfca", "0.28"],
  ["#d7c0cc", "0.29"],
  ["#d9c1ce", "0.30"],
  ["#d6bfcf", "0.31"],
  ["#d3bdd0", "0.32"],
  ["#d0bbd1", "0.33"],
  ["#cdb9d2", "0.34"],
  ["#cab7d3", "0.35"],
  ["#c7b5d4", "0.36"],
  ["#c4b3d5", "0.37"],
  ["#c1b1d6", "0.38"],
  ["#beafd7", "0.39"],
  ["#bcaed9", "0.40"],
  ["#b8abd9", "0.41"],
  ["#b4a9d9", "0.42"],
  ["#b1a7d9", "0.43"],
  ["#ada5d9", "0.44"],
  ["#aaa3d9", "0.45"],
  ["#a6a0d9", "0.46"],
  ["#a29ed9", "0.47"],
  ["#9f9cd9", "0.48"],
  ["#9b9ad9", "0.49"],
  ["#9898d9", "0.51"],
  ["#9495d9", "0.52"],
  ["#9192d9", "0.53"],
  ["#8d8fd9", "0.54"],
  ["#8a8cd9", "0.55"],
  ["#8789d9", "0.56"],
  ["#8386d9", "0.57"],
  ["#8083d9", "0.58"],
  ["#7c80d9", "0.59"],
  ["#797dd9", "0.60"],
  ["#767ada", "0.61"],
  ["#7277da", "0.62"],
  ["#6f75da", "0.63"],
  ["#6c72da", "0.64"],
  ["#6870db", "0.65"],
  ["#656edb", "0.66"],
  ["#626bdb", "0.67"],
  ["#5e69dc", "0.68"],
  ["#5b66dc", "0.69"],
  ["#5864dc", "0.70"],
  ["#5562dd", "0.71"],
  ["#515fdd", "0.72"],
  ["#4e5cdd", "0.73"],
  ["#4a5ade", "0.74"],
  ["#4757de", "0.75"],
  ["#4455df", "0.76"],
  ["#4052df", "0.77"],
  ["#3d4fdf", "0.78"],
  ["#394de0", "0.79"],
  ["#364ae0", "0.80"],
  ["#3348e1", "0.81"],
  ["#2f45e0", "0.82"],
  ["#2c42e0", "0.83"],
  ["#293fe0", "0.84"],
  ["#263de0", "0.85"],
  ["#233ae0", "0.86"],
  ["#2037e0", "0.87"],
  ["#1d35e0", "0.88"],
  ["#1a32e0", "0.89"],
  ["#172fe0", "0.90"],
  ["#142de0", "0.91"],
  ["#142be0", "0.92"],
  ["#142ae0", "0.93"],
  ["#1429e0", "0.94"],
  ["#1428e0", "0.95"],
  ["#1427e0", "0.96"],
  ["#1426e0", "0.97"],
  ["#1425e0", "0.98"],
  ["#1424e0", "0.99"],
  ["#1423e0", "1"],
])
Attachment #9438144 - Attachment description: The image that I used to for taking screen shot → The image that I used to take screen shot

The Bugbug bot thinks this bug should belong to the 'Core::Graphics: Canvas2D' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → Graphics: Canvas2D
Product: Firefox → Core
OS: Unspecified → Windows 10
Hardware: Unspecified → Desktop
Summary: mousemove event from react-leaflet ImageOverlay attached to a function to use Canvas API to read pixel data of an png image but it doesn't work → Core::Graphics: Canvas2D: Canvas API to read pixel data doesn't work

How do I get the image into the map?

Flags: needinfo?(reza.bakhshi1381r)

Is it possible to get a standalone test case that shows the problem?

(In reply to Jeff Muizelaar [:jrmuizel] from comment #5)

Is it possible to get a standalone test case that shows the problem?

Here is a standalone test case to view the error on FireFox, You can fork the repo and run it on your desktop.
Github rep: Link

Flags: needinfo?(reza.bakhshi1381r)

I can reproduce it with that test case. It looks like problem might be that offsetX and offsetY are always 0

There are two warnings in the console, which indicate:

  1. MouseEvent.mozPressure is deprecated. Use PointerEvent.pressure instead. (Util.js:15:3)
  2. MouseEvent.mozInputSource is deprecated. Use PointerEvent.pointerType instead. (Util.js:15:3)

Tom, is this related to the TikTok captcha thing?

Flags: needinfo?(twisniewski)
Severity: -- → S2
User Story: (updated)
Priority: -- → P3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: