xxxxxxxxxx
366
let capture = null;
let savedLinesArray = [];
let filter = null;
let screen = null;
let cWidth = 600;
let cHeight = 600;
// the threshold for the color
const threshold = 80;
// the aspect ratio of the camera
let aspectRatio = 1.333333;
// add a flag for iphone usage
let isMobile = false;
let facingModeOfCam = 'user';
let shouldSave = false;
let saveWithCapture = false;
let buttonSize = 80;
let UIMode = 'Intro';
let cameraInitTimer = false;
let exampleVideo = false;
let showVideo = false;
function setup() {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
isMobile = true;
}
if (isMobile) {
// aspectRatio = 0.5625;
cWidth = window.innerWidth;
cHeight = window.innerHeight;
facingModeOfCam = 'environment';
}
screen = createCanvas(cWidth, cHeight);
// capture = createCapture(VIDEO);
filter = createGraphics(width, height);
filter.pixelDensity(1);
for (let i = 0; i < width * height; i++) {
savedLinesArray.push(false);
}
textFont('Space Mono');
createConsentUI();
exampleVideo = createVideo(
['example.mp4'],
() => {
let vidW = width * 0.8;
let vidH = 720 / 436 * vidW;
exampleVideo.elt.muted=true;
exampleVideo.loop();
exampleVideo.volume(0);
exampleVideo.size(vidW, vidH);
exampleVideo.position(0,0);
exampleVideo.center();
exampleVideo.hide();
}
);
}
function startCamera() {
let constraints = {
video: {
facingMode: facingModeOfCam
},
audio: false
};
capture = createCapture(constraints);
capture.size(width * aspectRatio, height);
// set attr for iPhone
capture.elt.style.opacity = 0;
cameraInitTimer = true;
setTimeout(() => {
cameraInitTimer = false;
}, 1000);
// create the button
// createConsentUI();
}
function draw() {
switch (UIMode) {
case 'Intro':
displayConsentScreen();
break;
case 'camera':
if (capture) {
displayCamera();
}
break;
}
}
let consentButton = null;
let consentCheckBox = null;
function createConsentUI() {
consentButton = createButton('Turn On Camera');
consentButton.position(width / 2 - consentButton.elt.offsetWidth / 2, height - 80);
consentButton.mousePressed(toggleCamera);
consentButton.class('consentButton');
consentButton.attribute('disabled', '');
consentCheckBox = createCheckbox('I consent to use StampCam', false);
consentCheckBox.position(width - consentCheckBox.elt.offsetWidth / 2 - 120, height - 120);
consentCheckBox.changed(() => {
if (consentCheckBox.checked()) {
consentButton.removeAttribute('disabled');
} else {
consentButton.attribute('disabled', '');
}
});
}
function removeConsentUI() {
consentButton.remove();
consentCheckBox.remove();
}
function toggleCamera() {
console.log('press toggle')
switch (UIMode) {
case 'Intro':
UIMode = 'camera';
if (!capture) {
startCamera();
}
removeConsentUI();
clearLines();
break;
case 'camera':
UIMode = 'Intro';
createConsentUI();
break;
}
if (UIMode !== 'camera') {
// stop camera again
console.log('remove camera')
capture.remove();
capture = null;
}
}
function displayConsentScreen() {
if (showVideo) {
background(0);
exampleVideo.show();
exampleVideo.center();
consentButton.hide();
consentCheckBox.hide();
} else {
// classic p5
exampleVideo.hide();
consentButton.show();
consentCheckBox.show();
background(255, 213, 0); // post it yellow
textSize(14);
let displayText = `Welcome to StampCam!\n\n
This is a drawing tool. It uses your camera. Every time you press the 'capture button' it takes the darkest pixels and captures them on the screen. You can do this as often as you want to 'stamp' your perfect picture. Pressing the 'download ↓ button' saves the picture on your device. Pressing the 'close ✕ button' at the top left corner turns off the camera immediately again.\n\n
Everything is processed on your browser and device. Nothing is stored on any server or cloud.\n\n
Press and hold this text to see an example of how it works.`;
/*
push();
rectMode(CENTER);
fill(0);
rect(width/2,height/4*3-10,240,50);
fill(255)
textAlign(CENTER);
text('hold to see example',width/2,height/4*3-4);
pop();
*/
text(displayText, 20, 20, width - 40, height - 200);
}
}
function displayCamera() {
background(255);
if (!isMobile) {
translate(width, 0);
scale(-1, 1);
}
if (!saveWithCapture) {
copy(capture, int(width * ((aspectRatio - 1) / 2)), 0, width, capture.height, 0, 0, width, height);
}
// draw shapes again
filter.loadPixels();
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let indexFilter = (x + y * width) * 4;
let indexArr = indexFilter / 4;
if (savedLinesArray[indexArr]) {
filter.pixels[indexFilter] = 0;
filter.pixels[indexFilter + 1] = 0;
filter.pixels[indexFilter + 2] = 0;
filter.pixels[indexFilter + 3] = 255;
} else {
filter.pixels[indexFilter + 3] = 0;
}
}
}
filter.updatePixels();
image(filter, 0, 0, width, height);
// add mobile UI
if ( /*isMobile &&*/ !shouldSave) {
push();
if (!isMobile) {
translate(width, 0);
scale(-1, 1);
}
fill(255);
noStroke();
ellipse(width / 2, height - 60, buttonSize);
textSize(60);
text('↓', width - 60, height - 20);
textSize(30);
text('clear', 20, height - 30);
textSize(50);
text('✕', 10, 40);
pop();
}
if (shouldSave) {
saveCanvas(screen, 'stampCam', 'png');
shouldSave = false;
saveWithCapture = false;
}
}
function touchStarted() {
if (UIMode === 'camera' && !cameraInitTimer) {
// reset button
if (mouseX < 120 &&
mouseY < (height) &&
mouseY > (height - 60)) {
clearLines();
}
// close
if (mouseX < 50 &&
mouseY < 50) {
toggleCamera()
}
// main button
if (mouseX < (width / 2 + buttonSize / 2) &&
mouseX > (width / 2 - buttonSize / 2) &&
mouseY < (height - 20) &&
mouseY > (height - 20 - buttonSize)) {
captureLines();
}
// download
if (mouseX < (width) &&
mouseX > (width - 60) &&
mouseY < (height) &&
mouseY > (height - 60)) {
shouldSave = true;
}
} else if (UIMode === 'Intro') {
/*
if (mouseX < (width / 2 + 100 / 2) &&
mouseX > (width / 2 - 100 / 2) &&
mouseY < (height / 4 * 3 + 50) &&
mouseY > (height / 4 * 3)) {
*/
if (mouseX > 0 &&
mouseX < width &&
mouseY < height-200 &&
mouseY > 0 ){
showVideo = true;
}
}
}
function touchEnded() {
if (UIMode === 'Intro') {
if (mouseX > 0 &&
mouseX < width &&
mouseY < height-200 &&
mouseY > 0 ){
showVideo = false;
}
}
}
function keyPressed() {
if (UIMode === 'camera' && !cameraInitTimer) {
// delete drawing
if (keyCode === BACKSPACE || keyCode === DELETE) {
clearLines();
} else if (keyCode === 32) { // space
captureLines();
} else if (keyCode === DOWN_ARROW) {
shouldSave = true;
saveWithCapture = true;
} else if (key.toLowerCase() === "s") {
shouldSave = true;
}
}
}
function captureLines() {
capture.loadPixels();
let indexArr = 0;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width * aspectRatio; x++) {
let indexFilter = (x + y * int(width * aspectRatio)) * 4;
// only use the pixels in the center
if (x > width * (aspectRatio - 1) / 2 &&
x < (width + width * (aspectRatio - 1) / 2)) {
// only set to true if is dark
if (capture.pixels[indexFilter] < threshold &&
capture.pixels[indexFilter + 1] < threshold &&
capture.pixels[indexFilter + 2] < threshold &&
indexArr > 0) {
savedLinesArray[indexArr] = true;
}
indexArr++;
}
}
}
}
function clearLines() {
savedLinesArray = [];
for (let i = 0; i < width * height; i++) {
savedLinesArray.push(false);
}
}