Skip to content

Commit

Permalink
Generalized to combine RGB channels
Browse files Browse the repository at this point in the history
Somehow related to KhronosGroup/glTF#857
  • Loading branch information
javagl committed Feb 28, 2017
1 parent fd0c23e commit 93e44c6
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 90 deletions.
67 changes: 42 additions & 25 deletions MetallicRoughnessCreator/MetallicRoughnessCreator.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,30 @@
<p>
<table width="100%">
<tr>
<td width="50%">
<div id="metallicDropArea">
Drop metallic file here<br>
<img id="metallicImage" width="200px"></img><br>
<div id="metallicImageInfo"></div>
<td width="30%">
<div id="rDropArea">
Drop file for the RED channel here<br>
<img id="rImage" width="200px"></img><br>
<div id="rImageInfo"></div>
</div>
</td>
<td>
<div id="roughnessDropArea">
Drop roughness file here<br>
<img id="roughnessImage" width="200px"></img><br>
<div id="roughnessImageInfo"></div>
<td width="30%">
<div id="gDropArea">
Drop file for GREEN channel here<br>
<img id="gImage" width="200px"></img><br>
<div id="gImageInfo"></div>
</div>
</td>
<td width="30%">
<div id="bDropArea">
Drop file for BLUE channel here<br>
<img id="bImage" width="200px"></img><br>
<div id="bImageInfo"></div>
</div>
</td>
</tr>
<tr>
<td colspan="2">
<td colspan="3">
<div id="outputArea">
<b>Result</b><br>
<input type="checkbox" name="flipVerticallyCheckBox" id="flipVerticallyCheckBox">Flip vertically</input><br>
Expand All @@ -50,23 +57,33 @@
<script>
document.getElementById('flipVerticallyCheckBox').checked = false;

var metallicDropArea = document.getElementById('metallicDropArea');
metallicDropArea.addEventListener('dragover', handleDragOver, false);
var metallicHandler = function(e) {
var metallicImage = document.getElementById('metallicImage');
var metallicImageInfo = document.getElementById('metallicImageInfo');
handleFileSelect(e, 0, metallicImage, metallicImageInfo);
var rDropArea = document.getElementById('rDropArea');
rDropArea.addEventListener('dragover', handleDragOver, false);
var rHandler = function(e) {
var rImage = document.getElementById('rImage');
var rImageInfo = document.getElementById('rImageInfo');
handleFileSelect(e, 0, rImage, rImageInfo);
};
metallicDropArea.addEventListener('drop', metallicHandler, false);
rDropArea.addEventListener('drop', rHandler, false);

var roughnessDropArea = document.getElementById('roughnessDropArea');
roughnessDropArea.addEventListener('dragover', handleDragOver, false);
var roughnessHandler = function(e) {
var roughnessImage = document.getElementById('roughnessImage');
var roughnessImageInfo = document.getElementById('roughnessImageInfo');
handleFileSelect(e, 1, roughnessImage, roughnessImageInfo);
var gDropArea = document.getElementById('gDropArea');
gDropArea.addEventListener('dragover', handleDragOver, false);
var gHandler = function(e) {
var gImage = document.getElementById('gImage');
var gImageInfo = document.getElementById('gImageInfo');
handleFileSelect(e, 1, gImage, gImageInfo);
};
roughnessDropArea.addEventListener('drop', roughnessHandler, false);
gDropArea.addEventListener('drop', gHandler, false);

var bDropArea = document.getElementById('bDropArea');
bDropArea.addEventListener('dragover', handleDragOver, false);
var bHandler = function(e) {
var bImage = document.getElementById('bImage');
var bImageInfo = document.getElementById('bImageInfo');
handleFileSelect(e, 2, bImage, bImageInfo);
};
bDropArea.addEventListener('drop', bHandler, false);

</script>


Expand Down
160 changes: 97 additions & 63 deletions MetallicRoughnessCreator/scripts/MetallicRoughnessCreator.js
Original file line number Diff line number Diff line change
@@ -1,100 +1,134 @@

var inputImageDatas = [undefined, undefined];
var inputImageDatas = [undefined, undefined, undefined];
var outputImageData;

function isUndefined(object)
{
return (typeof object == "undefined");
}

function isDefined(object)
{
return !isUndefined(object);
}

function combine(metallicImageData, roughnessImageData, outputImageData, flip)
function combine(outputImageData, flip)
{
var metallicPixelData = metallicImageData.data;
var roughnessPixelData = roughnessImageData.data;
var outputPixelData = outputImageData.data;

var w = outputImageData.width;
var h = outputImageData.height;
for (var y = 0; y < h; y++)

for (var i = 0; i < 3; i++)
{
var metallicOffset = y * metallicImageData.width;
var roughnessOffset = y * roughnessImageData.width;
var outputOffset = y * outputImageData.width;
if (flip)
var inputImageData = inputImageDatas[i];
if (isUndefined(inputImageData))
{
outputOffset = (outputImageData.height - 1 - y) * outputImageData.width
continue;
}
for (var x = 0; x < w; x++)
var inputPixelData = inputImageData.data;
for (var y = 0; y < h; y++)
{
var metallicIndex = x + metallicOffset;
var red = metallicPixelData[metallicIndex << 2];

var roughnessIndex = x + roughnessOffset;
var green = roughnessPixelData[roughnessIndex << 2];

var outputIndex = x + outputOffset;

outputPixelData[(outputIndex << 2) + 0] = red;
outputPixelData[(outputIndex << 2) + 1] = green;
outputPixelData[(outputIndex << 2) + 2] = 0;
outputPixelData[(outputIndex << 2) + 3] = 255;
var inputOffset = y * inputImageData.width;
var outputOffset = y * outputImageData.width;
if (flip)
{
outputOffset = (outputImageData.height - 1 - y) * outputImageData.width
}
for (var x = 0; x < w; x++)
{
var inputIndex = x + inputOffset;
var value = inputPixelData[inputIndex << 2];
var outputIndex = x + outputOffset;
outputPixelData[(outputIndex << 2) + i] = value;
outputPixelData[(outputIndex << 2) + 3] = 255;
}
}
}
}


function updateOutput()
function haveEqualSize(imageDataA, imageDataB)
{
if (inputImageDatas[0] === undefined)
if (isUndefined(imageDataA))
{
return;
return true;
}
if (inputImageDatas[1] === undefined)
if (isUndefined(imageDataB))
{
return;
return true;
}

var infoElement = document.getElementById("outputImageInfo");
var metallicImageData = inputImageDatas[0];
var roughnessImageData = inputImageDatas[1];
if (metallicImageData.width != roughnessImageData.width)
return imageDataA.width == imageDataB.width && imageDataA.height == imageDataB.height;
}


function checkEqualWidths(nameA, imageDataA, nameB, imageDataB, infoElement)
{
if (!haveEqualSize(imageDataA, imageDataB))
{
infoElement.innerHTML +=
"Warning: Different widths: " + metallicImageData.width +
" and "+ roughnessImageData.width + "<br>";
infoElement.innerHTML +=
"Warning: Different size: " +
nameA + " is " + imageDataA.width + "x" + imageDataA.height + " and " +
nameB + " is " + imageDataB.width + "x" + imageDataB.height + "<br>";
}
if (metallicImageData.height != roughnessImageData.height)
}


function updateOutput()
{
var infoElement = document.getElementById("outputImageInfo");

infoElement.innerHTML = ""

var rImageData = inputImageDatas[0];
var gImageData = inputImageDatas[1];
var bImageData = inputImageDatas[2];

if (isUndefined(rImageData) &&
isUndefined(gImageData) &&
isUndefined(bImageData))
{
infoElement.innerHTML +=
"Warning: Different heights: " + metallicImageData.height +
" and "+ roughnessImageData.height + "<br>";
infoElement.innerHTML +=
"No input images" + "<br>";
return;
}

var width = Math.min(metallicImageData.width, roughnessImageData.width);
var height = Math.min(metallicImageData.height, roughnessImageData.height);


checkEqualWidths("r", rImageData, "g", gImageData, infoElement);
checkEqualWidths("g", gImageData, "b", bImageData, infoElement);
checkEqualWidths("r", rImageData, "b", bImageData, infoElement);


var width = (1<<16);
if (isDefined(rImageData)) width = Math.min(width, rImageData.width);
if (isDefined(gImageData)) width = Math.min(width, gImageData.width);
if (isDefined(bImageData)) width = Math.min(width, bImageData.width);

var height = (1<<16);
if (isDefined(rImageData)) height = Math.min(height, rImageData.height);
if (isDefined(gImageData)) height = Math.min(height, gImageData.height);
if (isDefined(bImageData)) height = Math.min(height, bImageData.height);

var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var context = canvas.getContext('2d');
outputImageData = context.createImageData(width, height);

var flip = document.getElementById("flipVerticallyCheckBox").checked;
combine(metallicImageData, roughnessImageData, outputImageData, flip);

context.putImageData(outputImageData, 0, 0);
combine(outputImageData, flip);

context.putImageData(outputImageData, 0, 0);

var typeForm = document.getElementById("typeForm");
if (typeForm.elements[0].checked)
if (typeForm.elements[0].checked)
{
var outputImage = document.getElementById("outputImage");
outputImage.src = canvas.toDataURL("image/png");
}
if (typeForm.elements[1].checked)
if (typeForm.elements[1].checked)
{
var outputImage = document.getElementById("outputImage");
outputImage.src = canvas.toDataURL("image/jpeg", 0.9);
}
if (typeForm.elements[2].checked)
if (typeForm.elements[2].checked)
{
var outputImage = document.getElementById("outputImage");
outputImage.src = canvas.toDataURL("image/jpeg", 0.7);
Expand All @@ -113,12 +147,12 @@ function imageFileLoaded(event, index, image, infoElement)
//updateOutput();
};
fullImage.src = event.target.result;

image.src = event.target.result;
}


function obtainImageData(image)
function obtainImageData(image)
{
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
Expand All @@ -131,7 +165,7 @@ function obtainImageData(image)
};


function handleFileSelect(event, index, image, infoElement)
function handleFileSelect(event, index, image, infoElement)
{
event.stopPropagation();
event.preventDefault();
Expand All @@ -142,24 +176,24 @@ function handleFileSelect(event, index, image, infoElement)
infoElement.innerHTML = "Only a single file is allowed. Dropped "+fileList.length+" files";
return;
}

var file = fileList[0];
if (!file.type.match('image.*'))
if (!file.type.match('image.*'))
{
infoElement.innerHTML = "Expected image file, but found "+file.type;
return;
}

var reader = new FileReader();
reader.onload = function(e)
reader.onload = function(e)
{
imageFileLoaded(e, index, image, infoElement);
};
reader.readAsDataURL(file);

}

function handleDragOver(event)
function handleDragOver(event)
{
event.stopPropagation();
event.preventDefault();
Expand Down
13 changes: 11 additions & 2 deletions MetallicRoughnessCreator/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ html {
background-color: white;
}

div#metallicDropArea {
div#rDropArea {
font-size: 1.5em;
width: 100%;
min-height: 300px;
Expand All @@ -12,7 +12,16 @@ div#metallicDropArea {
text-align: center;
}

div#roughnessDropArea {
div#gDropArea {
font-size: 1.5em;
width: 100%;
min-height: 300px;
border-style: solid;
border-width: 3px;
text-align: center;
}

div#bDropArea {
font-size: 1.5em;
width: 100%;
min-height: 300px;
Expand Down

0 comments on commit 93e44c6

Please sign in to comment.