Add scaling option and remove old image converter
This commit is contained in:
parent
3e86ea25be
commit
8cadbbdac1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -42,6 +42,8 @@ function downloadOutput() {
|
||||||
function readFile(
|
function readFile(
|
||||||
file,
|
file,
|
||||||
selectFile,
|
selectFile,
|
||||||
|
selectScaleWidth,
|
||||||
|
selectScaleHeight,
|
||||||
) {
|
) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
|
@ -50,6 +52,8 @@ function readFile(
|
||||||
fr.onload = () => {
|
fr.onload = () => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
|
selectScaleWidth(img.width);
|
||||||
|
selectScaleHeight(img.height);
|
||||||
selectFile(img);
|
selectFile(img);
|
||||||
};
|
};
|
||||||
img.src = fr.result;
|
img.src = fr.result;
|
||||||
|
@ -89,17 +93,37 @@ function addGrid(img, lightGrid, offsetX, offsetY) {
|
||||||
ctx.drawImage(img, 0, 0);
|
ctx.drawImage(img, 0, 0);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
ctx.fillStyle = (lightGrid) ? '#DDDDDD' : '#222222';
|
ctx.fillStyle = (lightGrid) ? '#DDDDDD' : '#222222';
|
||||||
|
|
||||||
for (let i = 0; i <= img.width; i += 1) {
|
for (let i = 0; i <= img.width; i += 1) {
|
||||||
const thick = ((i + (offsetX * 1)) % 10 === 0) ? 2 : 1;
|
const thick = ((i + (offsetX * 1)) % 10 === 0) ? 2 : 1;
|
||||||
ctx.fillRect(i * 5, 0, thick, can.height);
|
ctx.fillRect(i * 5, 0, thick, can.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = 0; j <= img.height; j += 1) {
|
for (let j = 0; j <= img.height; j += 1) {
|
||||||
const thick = ((j + (offsetY * 1)) % 10 === 0) ? 2 : 1;
|
const thick = ((j + (offsetY * 1)) % 10 === 0) ? 2 : 1;
|
||||||
ctx.fillRect(0, j * 5, can.width, thick);
|
ctx.fillRect(0, j * 5, can.width, thick);
|
||||||
}
|
}
|
||||||
|
return can;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scaleImage(img, width, height, doAA) {
|
||||||
|
const can = document.createElement('canvas');
|
||||||
|
const ctx = can.getContext('2d');
|
||||||
|
can.width = width;
|
||||||
|
can.height = height;
|
||||||
|
if (doAA) {
|
||||||
|
ctx.imageSmoothingEnabled = true;
|
||||||
|
ctx.mozImageSmoothingEnabled = true;
|
||||||
|
ctx.webkitImageSmoothingEnabled = true;
|
||||||
|
ctx.msImageSmoothingEnabled = true;
|
||||||
|
} else {
|
||||||
|
ctx.imageSmoothingEnabled = false;
|
||||||
|
ctx.mozImageSmoothingEnabled = false;
|
||||||
|
ctx.webkitImageSmoothingEnabled = false;
|
||||||
|
ctx.msImageSmoothingEnabled = false;
|
||||||
|
}
|
||||||
|
ctx.save();
|
||||||
|
ctx.scale(width / img.width, height / img.height);
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
ctx.restore();
|
||||||
return can;
|
return can;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,10 +138,23 @@ function renderOutputImage(
|
||||||
selectedLightGrid,
|
selectedLightGrid,
|
||||||
selectedGridOffsetX,
|
selectedGridOffsetX,
|
||||||
selectedGridOffsetY,
|
selectedGridOffsetY,
|
||||||
|
selectedDoScaling,
|
||||||
|
selectedScaleWidth,
|
||||||
|
selectedScaleHeight,
|
||||||
|
selectedScaleAA,
|
||||||
) {
|
) {
|
||||||
if (!selectedFile) {
|
if (!selectedFile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let image = selectedFile;
|
||||||
|
if (selectedDoScaling) {
|
||||||
|
image = scaleImage(
|
||||||
|
image,
|
||||||
|
selectedScaleWidth,
|
||||||
|
selectedScaleHeight,
|
||||||
|
selectedScaleAA,
|
||||||
|
);
|
||||||
|
}
|
||||||
const rgbQuant = new RgbQuant({
|
const rgbQuant = new RgbQuant({
|
||||||
colors: colors.length,
|
colors: colors.length,
|
||||||
dithKern: selectedStrategy,
|
dithKern: selectedStrategy,
|
||||||
|
@ -128,23 +165,23 @@ function renderOutputImage(
|
||||||
useCache: false,
|
useCache: false,
|
||||||
colorDist: selectedColorDist,
|
colorDist: selectedColorDist,
|
||||||
});
|
});
|
||||||
rgbQuant.sample(selectedFile);
|
rgbQuant.sample(image);
|
||||||
rgbQuant.palette();
|
rgbQuant.palette();
|
||||||
const pxls = rgbQuant.reduce(selectedFile);
|
const pxls = rgbQuant.reduce(image);
|
||||||
let can = drawPixels(pxls, selectedFile.width, selectedFile.height);
|
image = drawPixels(pxls, image.width, image.height);
|
||||||
const output = document.getElementById('imgoutput');
|
const output = document.getElementById('imgoutput');
|
||||||
if (selectedAddGrid) {
|
if (selectedAddGrid) {
|
||||||
can = addGrid(
|
image = addGrid(
|
||||||
can,
|
image,
|
||||||
selectedLightGrid,
|
selectedLightGrid,
|
||||||
selectedGridOffsetX,
|
selectedGridOffsetX,
|
||||||
selectedGridOffsetY,
|
selectedGridOffsetY,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
output.width = can.width;
|
output.width = image.width;
|
||||||
output.height = can.height;
|
output.height = image.height;
|
||||||
const ctx = output.getContext('2d');
|
const ctx = output.getContext('2d');
|
||||||
ctx.drawImage(can, 0, 0);
|
ctx.drawImage(image, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,6 +199,11 @@ function Converter({
|
||||||
const [selectedLightGrid, selectLightGrid] = useState(false);
|
const [selectedLightGrid, selectLightGrid] = useState(false);
|
||||||
const [selectedGridOffsetX, selectGridOffsetX] = useState(0);
|
const [selectedGridOffsetX, selectGridOffsetX] = useState(0);
|
||||||
const [selectedGridOffsetY, selectGridOffsetY] = useState(0);
|
const [selectedGridOffsetY, selectGridOffsetY] = useState(0);
|
||||||
|
const [selectedDoScaling, selectDoScaling] = useState(false);
|
||||||
|
const [selectedScaleWidth, selectScaleWidth] = useState(0);
|
||||||
|
const [selectedScaleHeight, selectScaleHeight] = useState(0);
|
||||||
|
const [selectedScaleKeepRatio, selectScaleKeepRatio] = useState(true);
|
||||||
|
const [selectedScaleAA, selectScaleAA] = useState(false);
|
||||||
const input = document.createElement('canvas');
|
const input = document.createElement('canvas');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -178,6 +220,10 @@ function Converter({
|
||||||
selectedLightGrid,
|
selectedLightGrid,
|
||||||
selectedGridOffsetX,
|
selectedGridOffsetX,
|
||||||
selectedGridOffsetY,
|
selectedGridOffsetY,
|
||||||
|
selectedDoScaling,
|
||||||
|
selectedScaleWidth,
|
||||||
|
selectedScaleHeight,
|
||||||
|
selectedScaleAA,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const output = document.getElementById('imgoutput');
|
const output = document.getElementById('imgoutput');
|
||||||
|
@ -245,7 +291,7 @@ function Converter({
|
||||||
const fileSel = evt.target;
|
const fileSel = evt.target;
|
||||||
const file = (!fileSel.files || !fileSel.files[0])
|
const file = (!fileSel.files || !fileSel.files[0])
|
||||||
? null : fileSel.files[0];
|
? null : fileSel.files[0];
|
||||||
readFile(file, selectFile);
|
readFile(file, selectFile, selectScaleWidth, selectScaleHeight);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<p style={textStyle}>Choose Strategy:
|
<p style={textStyle}>Choose Strategy:
|
||||||
|
@ -318,7 +364,7 @@ function Converter({
|
||||||
selectAddGrid(e.target.checked);
|
selectAddGrid(e.target.checked);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
Add Grid
|
Add Grid (uncheck if you need a 1:1 template)
|
||||||
</p>
|
</p>
|
||||||
{(selectedAddGrid)
|
{(selectedAddGrid)
|
||||||
? (
|
? (
|
||||||
|
@ -368,10 +414,103 @@ function Converter({
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
: null}
|
: null}
|
||||||
|
<p style={{ ...textStyle, fontHeight: 16 }}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={selectedDoScaling}
|
||||||
|
onChange={(e) => {
|
||||||
|
selectDoScaling(e.target.checked);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
Scale Image
|
||||||
|
</p>
|
||||||
|
{(selectedDoScaling)
|
||||||
|
? (
|
||||||
|
<div style={{
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderColor: '#D4D4D4',
|
||||||
|
borderWidth: 2,
|
||||||
|
padding: 5,
|
||||||
|
display: 'inline-block',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={textStyle}>Width:
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
step="1"
|
||||||
|
min="1"
|
||||||
|
max="16564"
|
||||||
|
style={{ width: '3em' }}
|
||||||
|
value={selectedScaleWidth}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newWidth = e.target.value;
|
||||||
|
if (!newWidth) return;
|
||||||
|
if (selectedScaleKeepRatio && selectedFile) {
|
||||||
|
const ratio = selectedFile.width / selectedFile.height;
|
||||||
|
const newHeight = Math.round(newWidth / ratio);
|
||||||
|
selectScaleHeight(newHeight);
|
||||||
|
}
|
||||||
|
selectScaleWidth(newWidth);
|
||||||
|
}}
|
||||||
|
/>%
|
||||||
|
</span>
|
||||||
|
<span style={textStyle}>Height:
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
step="1"
|
||||||
|
min="1"
|
||||||
|
max="16564"
|
||||||
|
style={{ width: '3em' }}
|
||||||
|
value={selectedScaleHeight}
|
||||||
|
onChange={(e) => {
|
||||||
|
const nuHeight = e.target.value;
|
||||||
|
if (!nuHeight) return;
|
||||||
|
if (selectedScaleKeepRatio && selectedFile) {
|
||||||
|
const ratio = selectedFile.width / selectedFile.height;
|
||||||
|
const nuWidth = Math.round(ratio * nuHeight);
|
||||||
|
selectScaleWidth(nuWidth);
|
||||||
|
}
|
||||||
|
selectScaleHeight(nuHeight);
|
||||||
|
}}
|
||||||
|
/>%
|
||||||
|
</span>
|
||||||
|
<p style={{ ...textStyle, fontHeight: 16 }}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={selectedScaleKeepRatio}
|
||||||
|
onChange={(e) => {
|
||||||
|
selectScaleKeepRatio(e.target.checked);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
Keep Ratio
|
||||||
|
</p>
|
||||||
|
<p style={{ ...textStyle, fontHeight: 16 }}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
onChange={(e) => {
|
||||||
|
selectScaleAA(e.target.checked);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
Anti Aliasing
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
if (selectedFile) {
|
||||||
|
selectScaleWidth(selectedFile.width);
|
||||||
|
selectScaleHeight(selectedFile.height);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
<p>
|
<p>
|
||||||
<canvas
|
<canvas
|
||||||
id="imgoutput"
|
id="imgoutput"
|
||||||
style={{ width: '80%' }}
|
style={{ width: '80%', imageRendering: 'crisp-edges' }}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -52,8 +52,6 @@ const HelpModal = () => (
|
||||||
<p>Discord: <a href="./discord" target="_blank">pixelplanet.fun/discord</a></p>
|
<p>Discord: <a href="./discord" target="_blank">pixelplanet.fun/discord</a></p>
|
||||||
<p>Source on <a href="https://github.com/pixelplanetdev/pixelplanet" target="_blank">github</a></p>
|
<p>Source on <a href="https://github.com/pixelplanetdev/pixelplanet" target="_blank">github</a></p>
|
||||||
<p>Reddit: <a href="https://www.reddit.com/r/PixelPlanetFun/" target="_blank">r/PixelPlanetFun</a></p>
|
<p>Reddit: <a href="https://www.reddit.com/r/PixelPlanetFun/" target="_blank">r/PixelPlanetFun</a></p>
|
||||||
<p>Image Converter: <a href="./convert" target="_blank">pixelplanet.fun/convert</a></p>
|
|
||||||
<p>Image Converter for 2nd Planet: <a href="./convert2" target="_blank">pixelplanet.fun/convert2</a></p>
|
|
||||||
<p style={titleStyle}>Map Data</p>
|
<p style={titleStyle}>Map Data</p>
|
||||||
<p style={textStyle}>The bare map data that we use, together with converted OpenStreetMap tiles for orientation,
|
<p style={textStyle}>The bare map data that we use, together with converted OpenStreetMap tiles for orientation,
|
||||||
can be downloaded from mega.nz here: <a href="https://mega.nz/#!JpkBwAbJ!EnSLlZmKv3kEBE0HDhakTgAZZycD3ELjduajJxPGaXo">pixelplanetmap.zip</a> (422MB)</p>
|
can be downloaded from mega.nz here: <a href="https://mega.nz/#!JpkBwAbJ!EnSLlZmKv3kEBE0HDhakTgAZZycD3ELjduajJxPGaXo">pixelplanetmap.zip</a> (422MB)</p>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user