diff --git a/src/components/map/MapTile.js b/src/components/map/MapTile.js index 640b8aa..6d59736 100644 --- a/src/components/map/MapTile.js +++ b/src/components/map/MapTile.js @@ -17,9 +17,15 @@ function MapTile({ onMapReset, onDone, }) { - const mapSource = useDataSource(map, defaultMapSources, unknownSource); const [isMapTileMenuOpen, setIsTileMenuOpen] = useState(false); const isDefault = map.type === "default"; + + const mapSource = useDataSource( + isDefault ? map : map.resolutions.length > 0 ? map.resolutions[0] : map, + defaultMapSources, + unknownSource + ); + const hasMapState = mapState && (Object.values(mapState.tokens).length > 0 || diff --git a/src/helpers/image.js b/src/helpers/image.js index 51379e5..7c5840f 100644 --- a/src/helpers/image.js +++ b/src/helpers/image.js @@ -1,17 +1,18 @@ const lightnessDetectionOffset = 0.1; /** + * @param {HTMLImageElement} image * @returns {boolean} True is the image is light */ export function getImageLightness(image) { - const imageWidth = image.width; - const imageHeight = image.height; + const width = image.width; + const height = image.height; let canvas = document.createElement("canvas"); - canvas.width = imageWidth; - canvas.height = imageHeight; + canvas.width = width; + canvas.height = height; let context = canvas.getContext("2d"); context.drawImage(image, 0, 0); - const imageData = context.getImageData(0, 0, imageWidth, imageHeight); + const imageData = context.getImageData(0, 0, width, height); const data = imageData.data; let lightPixels = 0; @@ -30,6 +31,38 @@ export function getImageLightness(image) { } } - const norm = (lightPixels - darkPixels) / (imageWidth * imageHeight); + const norm = (lightPixels - darkPixels) / (width * height); return norm + lightnessDetectionOffset >= 0; } + +/** + * @param {HTMLImageElement} image the image to resize + * @param {number} size the size of the longest edge of the new image + * @param {string} type the mime type of the image + * @param {number} quality if image is a jpeg or webp this is the quality setting + */ +export async function resizeImage(image, size, type, quality) { + const width = image.width; + const height = image.height; + const ratio = width / height; + let canvas = document.createElement("canvas"); + if (ratio > 1) { + canvas.width = size; + canvas.height = Math.round(size / ratio); + } else { + canvas.width = Math.round(size * ratio); + canvas.height = size; + } + let context = canvas.getContext("2d"); + context.drawImage(image, 0, 0, canvas.width, canvas.height); + + return new Promise((resolve) => { + canvas.toBlob( + (blob) => { + resolve({ blob, width: canvas.width, height: canvas.height }); + }, + type, + quality + ); + }); +} diff --git a/src/modals/SelectMapModal.js b/src/modals/SelectMapModal.js index ca8f9b2..276e6bb 100644 --- a/src/modals/SelectMapModal.js +++ b/src/modals/SelectMapModal.js @@ -13,6 +13,7 @@ import MapDataContext from "../contexts/MapDataContext"; import AuthContext from "../contexts/AuthContext"; import { isEmpty } from "../helpers/shared"; +import { resizeImage } from "../helpers/image"; const defaultMapSize = 22; const defaultMapProps = { @@ -22,6 +23,12 @@ const defaultMapProps = { showGrid: false, }; +const mapResolutions = [ + { size: 256, quality: 0.25 }, + { size: 512, quality: 0.5 }, + { size: 1024, quality: 0.75 }, +]; + function SelectMapModal({ isOpen, onDone, @@ -103,10 +110,31 @@ function SelectMapModal({ const url = URL.createObjectURL(blob); return new Promise((resolve, reject) => { - image.onload = function () { + image.onload = async function () { + // Create resolutions + const resolutions = []; + for (let resolution of mapResolutions) { + if (Math.max(image.width, image.height) > resolution.size) { + const resized = await resizeImage( + image, + resolution.size, + file.type, + resolution.quality + ); + const resizedBuffer = await blobToBuffer(resized.blob); + resolutions.push({ + file: resizedBuffer, + width: resized.width, + height: resized.height, + type: "file", + }); + } + } + handleMapAdd({ // Save as a buffer to send with msgpack file: buffer, + resolutions, name, type: "file", gridX: fileGridX,