arcade-img-import/main.js

244 lines
7 KiB
JavaScript
Raw Permalink Normal View History

2020-05-03 13:09:35 +02:00
let mode = "full-width"
2020-04-25 21:46:08 +02:00
// https://makecode.com/_EvPP98M4pYEC
2020-04-25 18:19:36 +02:00
2020-04-26 15:48:40 +02:00
/**
* To do:
*
* 1. Implement "fit", "fill", "custom"
* 2. Black and white mode
* 3. Other cool effects
* 4. Shuffle colors
*/
2020-04-25 20:31:05 +02:00
const canvas = document.querySelector("canvas")
2020-05-02 10:32:33 +02:00
const copyButton = document.querySelector("button#copy")
const customSizes = document.querySelectorAll("input[type='number'].custom")
const fileInput = document.querySelector("input#myFile")
2020-04-26 15:48:40 +02:00
const form = document.querySelector("form")
const numberInputs = document.querySelectorAll("input[type='number']")
2020-05-02 10:32:33 +02:00
const radioButtons = document.querySelectorAll("input[type='radio']")
const scaleFactor = document.querySelector("input[type='number']#factor")
2020-04-25 22:49:46 +02:00
const textarea = document.querySelector("textarea")
let originalImageSize = {
width: 0,
height: 0
}
fileInput.addEventListener("change", function whenImageIsUploaded() {
2020-04-25 20:31:05 +02:00
const img = document.createElement("img")
img.src = window.URL.createObjectURL(this.files[0])
2020-05-03 13:09:35 +02:00
const node = document.querySelector("img")
2020-05-05 05:46:49 +02:00
2020-05-03 13:09:35 +02:00
if (node !== null) {
node.parentNode.removeChild(node)
}
2020-05-05 05:46:49 +02:00
2020-05-03 13:09:35 +02:00
document.body.appendChild(img)
2020-05-05 05:46:49 +02:00
2020-05-03 13:09:35 +02:00
img.addEventListener("load", () => {
originalImageSize.width = img.width
originalImageSize.height = img.height
mode = "full-width"
convert(img)
})
2020-04-25 20:31:05 +02:00
})
2020-05-02 10:32:33 +02:00
radioButtons.forEach(radioButton => {
radioButton.addEventListener("change", function sizeOption() {
mode = this.id
const numberInput = this.parentElement.querySelector("input[type='number']")
2020-05-02 10:32:33 +02:00
customSizes.forEach(field => field.disabled = (mode !== "custom"))
scaleFactor.disabled = (mode !== "scale")
2020-05-05 05:46:49 +02:00
scaleFactor.value = 0.1
img = document.querySelector("img")
convert(img)
2020-05-02 10:32:33 +02:00
})
})
form.addEventListener("submit", function convertImage(event) {
event.preventDefault()
const imageDOM = document.querySelector("img")
if (originalImageSize.width === 0 && originalImageSize.height === 0) {
2020-05-03 13:09:35 +02:00
originalImageSize.width = imageDOM.width
originalImageSize.height = imageDOM.height
}
img = document.querySelector("img")
convert(img)
resetImageSize(img)
2020-05-02 10:32:33 +02:00
})
2020-04-25 22:49:46 +02:00
function convert(img) {
// originalImageSize
2020-05-02 10:32:33 +02:00
copyButton.innerText = "Copy code" // Reset text if another image is uploaded
2020-04-26 15:48:40 +02:00
const arcadeColors = [
2020-04-25 22:49:46 +02:00
"#00000000", // Transparent
2020-04-25 18:19:36 +02:00
"#ffffff",
2020-04-25 20:31:05 +02:00
"#ff2121",
2020-04-25 18:19:36 +02:00
"#ff93c4",
"#ff8135",
"#fff609",
"#249ca3",
"#78dc52",
"#003fad",
"#87f2ff",
"#8e2ec4",
"#a4839f",
"#5c406c",
"#e5cdc4",
"#91463d",
"#000000",
2020-04-25 22:49:46 +02:00
].map(function convertFromHexToRGB(color, index) {
2020-05-02 10:32:33 +02:00
const r = parseInt(color[1] + color[2], 16) // parseInt("a", 16) === 10
2020-04-25 20:31:05 +02:00
const g = parseInt(color[3] + color[4], 16)
const b = parseInt(color[5] + color[6], 16)
2020-04-26 15:48:40 +02:00
2020-04-25 18:19:36 +02:00
return {
2020-04-25 20:31:05 +02:00
color: { r, g, b },
2020-04-26 15:48:40 +02:00
index: (index).toString(16) // (10).toString(16) === "a"
2020-04-25 18:19:36 +02:00
}
})
2020-05-02 10:32:33 +02:00
/**
* MakeCode Arcade is 160x120
*
* Full width:
* factor = 160 / img.width
* Full height:
* factor = 120 / img.height
* Custom width:
* factor = n / img.width
* Custom height:
* factor = n / img.height
*
* w *= factor
* h *= factor
*/
function setSpriteDimensions(type) {
let imageWidth = originalImageSize.width
let imageHeight = originalImageSize.height
2020-05-03 13:09:35 +02:00
let factor = 1
2020-05-02 10:32:33 +02:00
if (type === "custom") {
let customWidth = document.querySelector(".custom#width").value
let customHeight = document.querySelector(".custom#height").value
if (customWidth && !customHeight) {
const factor = customWidth / originalImageSize.width
imageWidth = customWidth
imageHeight *= factor
} else if (!customWidth && customHeight) {
const factor = customHeight / originalImageSize.height
imageWidth *= factor
imageHeight = customHeight
} else {
imageWidth = customWidth
imageHeight = customHeight
2020-05-02 10:32:33 +02:00
}
} else if (type === "scale") {
const factor = document.querySelector("input#factor").value
imageWidth *= factor
imageHeight *= factor
} else if (type === "full-width") {
const factor = 160 / imageWidth
imageWidth *= factor
imageHeight *= factor
} else if (type === "full-height") {
const factor = 120 / imageHeight
imageWidth *= factor
imageHeight *= factor
2020-05-02 10:32:33 +02:00
}
img.width = imageWidth
img.height = imageHeight
2020-05-05 05:46:49 +02:00
copyButton.innerText += ` (${img.width} x ${img.height})`
2020-05-02 10:32:33 +02:00
}
setSpriteDimensions(mode) // Mode is set when radio buttons are clicked. Default is full-width.
2020-04-25 18:19:36 +02:00
2020-04-25 22:49:46 +02:00
// Get the image's pixels and draw them onto a canvas element
// This way, we can loop through the pixels
2020-04-25 18:19:36 +02:00
canvas.width = img.width
canvas.height = img.height
const c = canvas.getContext("2d")
c.drawImage(img, 0, 0, canvas.width, canvas.height)
2020-04-25 22:49:46 +02:00
2020-04-25 18:19:36 +02:00
let pixelIndex = 0
2020-04-26 15:48:40 +02:00
let makeCodeString = {}
2020-04-25 22:49:46 +02:00
const data = c.getImageData(0, 0, canvas.width, canvas.height).data
2020-04-25 18:19:36 +02:00
2020-04-26 15:48:40 +02:00
// Canvas pixel values are stored as rgba: [r, g, b, a, r, g, b, a, ...]
2020-04-25 18:19:36 +02:00
for (let i = 0; i < data.length; i += 4) {
2020-04-25 22:49:46 +02:00
// This is how you get x and y coordinates from one variable
2020-04-26 15:48:40 +02:00
const x = pixelIndex % canvas.width
const y = Math.floor(pixelIndex / canvas.width)
2020-04-25 18:19:36 +02:00
const r = data[i + 0]
const g = data[i + 1]
const b = data[i + 2]
const a = data[i + 3]
2020-04-25 22:49:46 +02:00
/*
Now we have the rgba values for one pixel from the original image.
2020-05-02 10:32:33 +02:00
MakeCode colors are represented as index values from 0-15 (or really, 0-f).
2020-04-25 22:49:46 +02:00
We loop through the 16 color palette and pick the one that has
the closest r, g, and b values to the pixel we're checking.
*/
2020-04-26 15:48:40 +02:00
const nearest = arcadeColors.sort((prev, curr) => {
2020-04-25 20:31:05 +02:00
const rDifference = Math.abs(prev.color.r - r) - Math.abs(curr.color.r - r)
const gDifference = Math.abs(prev.color.g - g) - Math.abs(curr.color.g - g)
const bDifference = Math.abs(prev.color.b - b) - Math.abs(curr.color.b - b)
2020-04-26 15:48:40 +02:00
2020-04-25 20:31:05 +02:00
return rDifference + gDifference + bDifference
2020-04-25 18:19:36 +02:00
})[0]
2020-04-25 22:49:46 +02:00
// Draw a preview
2020-04-25 20:31:05 +02:00
c.fillStyle = `rgb(${nearest.color.r}, ${nearest.color.g}, ${nearest.color.b})`
2020-04-25 18:19:36 +02:00
c.fillRect(x, y, 1, 1)
2020-04-25 22:49:46 +02:00
/*
makeCodeString is a piece of working code that can be directly
pasted into MakeCode's JavaScript window.
*/
2020-04-25 18:19:36 +02:00
if (makeCodeString[`row-${y}`] === undefined) {
makeCodeString[`row-${y}`] = ""
} else {
2020-04-25 22:49:46 +02:00
if (nearest.index == 0) {
2020-05-02 10:32:33 +02:00
// 0 is transparent, f is black.
makeCodeString[`row-${y}`] += "f"
2020-04-25 22:49:46 +02:00
} else {
makeCodeString[`row-${y}`] += nearest.index
2020-04-25 22:49:46 +02:00
}
2020-04-25 18:19:36 +02:00
}
pixelIndex++
}
2020-04-25 22:49:46 +02:00
// Loop through the makeCodeString object to create the output
let dateString = new Date()
.toISOString()
.replaceAll("-", "")
.replaceAll(":", "")
.replaceAll(".", "")
let spriteJavaScript = `let mySprite${dateString} = sprites.create(img\``
2020-04-25 18:19:36 +02:00
for (const row in makeCodeString) {
2020-05-02 10:32:33 +02:00
spriteJavaScript += makeCodeString[row] + "\n"
2020-04-25 18:19:36 +02:00
}
2020-05-02 10:32:33 +02:00
spriteJavaScript += "`, SpriteKind.Player)"
2020-04-25 18:19:36 +02:00
2020-04-25 22:49:46 +02:00
// Copy text when user clicks button
// Sure, they can copy it themselves, but it's good to do nice things sometimes.
2020-05-02 10:32:33 +02:00
textarea.textContent = spriteJavaScript
2020-04-25 20:31:05 +02:00
copyButton.removeAttribute("disabled")
2020-05-02 10:32:33 +02:00
copyButton.addEventListener("click", function addCodeToClipboard() {
2020-04-25 22:49:46 +02:00
textarea.select()
2020-04-25 20:31:05 +02:00
document.execCommand("copy")
2020-05-05 05:46:49 +02:00
console.log("copy!");
2020-04-25 20:31:05 +02:00
copyButton.innerText = "Code copied to clipboard!"
resetImageSize(img)
2020-04-25 20:31:05 +02:00
})
}
function resetImageSize(img) {
img.width = originalImageSize.width
img.height = originalImageSize.height
2020-04-24 09:44:24 +02:00
}