Spaces:
Runtime error
Runtime error
insert pose meta data into png
Browse files- app.py +1 -1
- static/poseEditor.js +153 -0
app.py
CHANGED
|
@@ -129,7 +129,7 @@ Points to note for pseudo-3D rotation: When performing pseudo-3D rotation on the
|
|
| 129 |
- "shift + drag" to **rotate** (move right first, release shift, then up or down)
|
| 130 |
- "space + drag" to **range-move**
|
| 131 |
- "[", "]" or mouse "Alt + wheel" to shrink or expand **range**
|
| 132 |
-
- "ctrl +
|
| 133 |
- "ctrl + E" **add** new person
|
| 134 |
- "Q + click" to **delete** person
|
| 135 |
- "X + drag" to **x-axis** pseudo-3D rotation
|
|
|
|
| 129 |
- "shift + drag" to **rotate** (move right first, release shift, then up or down)
|
| 130 |
- "space + drag" to **range-move**
|
| 131 |
- "[", "]" or mouse "Alt + wheel" to shrink or expand **range**
|
| 132 |
+
- "ctrl + Z", "shift + ctrl + Z" to **undo**, **redo**
|
| 133 |
- "ctrl + E" **add** new person
|
| 134 |
- "Q + click" to **delete** person
|
| 135 |
- "X + drag" to **x-axis** pseudo-3D rotation
|
static/poseEditor.js
CHANGED
|
@@ -578,6 +578,7 @@ function importPose(jsonData) {
|
|
| 578 |
Redraw();
|
| 579 |
}
|
| 580 |
|
|
|
|
| 581 |
function savePose() {
|
| 582 |
const canvasUrl = canvas.toDataURL();
|
| 583 |
|
|
@@ -593,3 +594,155 @@ function savePose() {
|
|
| 593 |
var [candidate, subset] = poseDataToCandidateAndSubset(poseData);
|
| 594 |
return {candidate: candidate, subset: subset};
|
| 595 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 578 |
Redraw();
|
| 579 |
}
|
| 580 |
|
| 581 |
+
/*
|
| 582 |
function savePose() {
|
| 583 |
const canvasUrl = canvas.toDataURL();
|
| 584 |
|
|
|
|
| 594 |
var [candidate, subset] = poseDataToCandidateAndSubset(poseData);
|
| 595 |
return {candidate: candidate, subset: subset};
|
| 596 |
}
|
| 597 |
+
*/
|
| 598 |
+
|
| 599 |
+
// crc32
|
| 600 |
+
// CRC32を初期化
|
| 601 |
+
function initCrc32Table() {
|
| 602 |
+
const crcTable = new Uint32Array(256);
|
| 603 |
+
for (let i = 0; i < 256; i++) {
|
| 604 |
+
let c = i;
|
| 605 |
+
for (let j = 0; j < 8; j++) {
|
| 606 |
+
c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
|
| 607 |
+
}
|
| 608 |
+
crcTable[i] = c;
|
| 609 |
+
}
|
| 610 |
+
return crcTable;
|
| 611 |
+
}
|
| 612 |
+
|
| 613 |
+
// データのCRC32を計算
|
| 614 |
+
function getCrc32(data, crc=0) {
|
| 615 |
+
const crcTable = initCrc32Table();
|
| 616 |
+
crc = (crc ^ 0xFFFFFFFF) >>> 0;
|
| 617 |
+
for (let i = 0; i < data.length; i++) {
|
| 618 |
+
crc = crcTable[(crc ^ data[i]) & 0xFF] ^ (crc >>> 8);
|
| 619 |
+
}
|
| 620 |
+
return (crc ^ 0xFFFFFFFF) >>> 0;
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
function stringToUint8Array(str) {
|
| 624 |
+
var arr = new Uint8Array(str.length);
|
| 625 |
+
for (var i = 0; i < str.length; i++) {
|
| 626 |
+
arr[i] = str.charCodeAt(i);
|
| 627 |
+
}
|
| 628 |
+
return arr;
|
| 629 |
+
}
|
| 630 |
+
|
| 631 |
+
function base64ToUint8Array(base64Str) {
|
| 632 |
+
return stringToUint8Array(atob(base64Str));
|
| 633 |
+
}
|
| 634 |
+
|
| 635 |
+
function visitPng(png, type) {
|
| 636 |
+
var dataLength;
|
| 637 |
+
var chunkType;
|
| 638 |
+
var nextChunkPos;
|
| 639 |
+
var Signature = String.fromCharCode(137, 80, 78, 71, 13, 10, 26, 10);
|
| 640 |
+
var rpos = 0;
|
| 641 |
+
|
| 642 |
+
// シグネチャの確認
|
| 643 |
+
if (String.fromCharCode.apply(null, png.subarray(rpos, rpos += 8)) !== Signature) {
|
| 644 |
+
throw new Error('invalid signature');
|
| 645 |
+
}
|
| 646 |
+
|
| 647 |
+
// チャンクの探索
|
| 648 |
+
while (rpos < png.length) {
|
| 649 |
+
dataLength = (
|
| 650 |
+
(png[rpos++] << 24) |
|
| 651 |
+
(png[rpos++] << 16) |
|
| 652 |
+
(png[rpos++] << 8) |
|
| 653 |
+
(png[rpos++] )
|
| 654 |
+
) >>> 0;
|
| 655 |
+
|
| 656 |
+
nextChunkPos = rpos + dataLength + 8;
|
| 657 |
+
|
| 658 |
+
chunkType = String.fromCharCode.apply(null, png.subarray(rpos, rpos += 4));
|
| 659 |
+
|
| 660 |
+
if (chunkType === type) {
|
| 661 |
+
return [rpos - 8, dataLength, nextChunkPos];
|
| 662 |
+
}
|
| 663 |
+
|
| 664 |
+
rpos = nextChunkPos;
|
| 665 |
+
}
|
| 666 |
+
}
|
| 667 |
+
|
| 668 |
+
function createChunk(type, data) {
|
| 669 |
+
var dataLength = data.length;
|
| 670 |
+
var chunk = new Uint8Array(4 + 4 + dataLength + 4);
|
| 671 |
+
var type = stringToUint8Array(type);
|
| 672 |
+
var pos = 0;
|
| 673 |
+
|
| 674 |
+
// length
|
| 675 |
+
chunk[pos++] = (dataLength >> 24) & 0xff;
|
| 676 |
+
chunk[pos++] = (dataLength >> 16) & 0xff;
|
| 677 |
+
chunk[pos++] = (dataLength >> 8) & 0xff;
|
| 678 |
+
chunk[pos++] = (dataLength ) & 0xff;
|
| 679 |
+
|
| 680 |
+
// type
|
| 681 |
+
chunk[pos++] = type[0];
|
| 682 |
+
chunk[pos++] = type[1];
|
| 683 |
+
chunk[pos++] = type[2];
|
| 684 |
+
chunk[pos++] = type[3];
|
| 685 |
+
|
| 686 |
+
// data
|
| 687 |
+
for (let i = 0; i < dataLength; ++i) {
|
| 688 |
+
chunk[pos++] = data[i];
|
| 689 |
+
}
|
| 690 |
+
|
| 691 |
+
//crc
|
| 692 |
+
initCrc32Table();
|
| 693 |
+
let crc = getCrc32(type);
|
| 694 |
+
crc = getCrc32(data, crc);
|
| 695 |
+
chunk[pos++] = (crc >> 24) & 0xff;
|
| 696 |
+
chunk[pos++] = (crc >> 16) & 0xff;
|
| 697 |
+
chunk[pos++] = (crc >> 8) & 0xff;
|
| 698 |
+
chunk[pos++] = (crc ) & 0xff;
|
| 699 |
+
|
| 700 |
+
return chunk;
|
| 701 |
+
}
|
| 702 |
+
|
| 703 |
+
function insertChunk(destBuffer, sourceBuffer, rpos, chunk) {
|
| 704 |
+
var pos = 0;
|
| 705 |
+
|
| 706 |
+
// IDAT チャンクの前までコピー
|
| 707 |
+
destBuffer.set(sourceBuffer.subarray(0, rpos), pos);
|
| 708 |
+
pos += rpos;
|
| 709 |
+
|
| 710 |
+
// hoGe チャンクをコピー
|
| 711 |
+
destBuffer.set(chunk, pos);
|
| 712 |
+
pos += chunk.length;
|
| 713 |
+
|
| 714 |
+
// IDAT チャンク以降をコピー
|
| 715 |
+
destBuffer.set(sourceBuffer.subarray(rpos), pos);
|
| 716 |
+
}
|
| 717 |
+
|
| 718 |
+
function mergeCanvasWithPose(keyword, content) {
|
| 719 |
+
const canvasUrl = canvas.toDataURL();
|
| 720 |
+
|
| 721 |
+
var insertion = stringToUint8Array(`${keyword}\0${content}`);
|
| 722 |
+
var chunk = createChunk("tEXt", insertion);
|
| 723 |
+
var sourceBuffer = base64ToUint8Array(canvasUrl.split(',')[1]);
|
| 724 |
+
var destBuffer = new Uint8Array(sourceBuffer.length + insertion.length + 12);
|
| 725 |
+
|
| 726 |
+
var [rpos, dataLength, nextChunkPos] = visitPng(sourceBuffer, "IHDR");
|
| 727 |
+
insertChunk(destBuffer, sourceBuffer, nextChunkPos, chunk);
|
| 728 |
+
|
| 729 |
+
var blob = new Blob([destBuffer], {type: "image/png"});
|
| 730 |
+
var url = URL.createObjectURL(blob);
|
| 731 |
+
return url;
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
function savePose() {
|
| 735 |
+
var [candidate, subset] = poseDataToCandidateAndSubset(poseData);
|
| 736 |
+
let jsonData = {candidate: candidate, subset: subset};
|
| 737 |
+
|
| 738 |
+
var url = mergeCanvasWithPose("pose", JSON.stringify(jsonData));
|
| 739 |
+
|
| 740 |
+
const createEl = document.createElement('a');
|
| 741 |
+
createEl.href = url;
|
| 742 |
+
|
| 743 |
+
// This is the name of our downloaded file
|
| 744 |
+
createEl.download = "pose.png";
|
| 745 |
+
|
| 746 |
+
createEl.click();
|
| 747 |
+
createEl.remove();
|
| 748 |
+
}
|