Rotation now works

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2018-10-11 18:05:45 -07:00
parent 82e5875e52
commit 2f6f0ccfa5
4 changed files with 192 additions and 60 deletions

View File

@ -81,6 +81,10 @@
Polymer({
is: "photo-thumbnail",
properties: {
"unique": {
type: String,
value: ""
},
"disabled": {
reflectToAttribute: true
},
@ -89,7 +93,7 @@
},
"thumbpath": {
type: String,
computed: "safeItemThumbFilepath(item, base)"
computed: "safeItemThumbFilepath(item, base, unique)"
},
"width": {
type: Number
@ -130,11 +134,11 @@
this.style.height = width + "px";
},
safeItemThumbFilepath: function(item, base) {
safeItemThumbFilepath: function(item, base, unique) {
if (item === undefined|| base === undefined || item.path === undefined) {
return "";
}
return base + item.path + "thumbs/" + item.filename;
return base + item.path + "thumbs/" + item.filename + (this.unique ? ("?" + this.unique) : "");
},
date: function(item) {
@ -154,6 +158,10 @@
event.preventDefault();
},
reload: function() {
this.unique = parseInt(this.unique || 0) + 1;
},
attached: function() {
var base = document.querySelector("base");
if (base) {

View File

@ -10,6 +10,7 @@
<link rel="import" href="../../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/iron-icons/image-icons.html">
<link rel="import" href="../../bower_components/iron-iconset/iron-iconset.html">
<link rel="import" href="../../bower_components/iron-pages/iron-pages.html">
<link rel="import" href="../../bower_components/iron-resizable-behavior/iron-resizable-behavior.html">
@ -1221,9 +1222,11 @@
let actions = [ "delete" ];
if (this.mode == "duplicates") {
actions.unshift("text-format");
}
if (this.mode == "trash") {
} else if (this.mode == "trash") {
actions.unshift("undo");
} else {
actions.unshift("image:rotate-right");
actions.unshift("image:rotate-left");
}
thumbnail.actions = actions;
thumbnail.addEventListener("action", this._imageAction.bind(this));
@ -1293,49 +1296,65 @@
}.bind(this, thumbnail), 250);
},
_imageAction: function(event) {
switch (event.detail) {
case "undo": /* Undelete an image */
var thumbnail = event.currentTarget, params = {};
undoAction: function(thumbnail) {
var params = {};
thumbnail.disabled = true;
params.undelete = 1;
var query = "";
for (var key in params) {
if (!query) {
query = "?";
} else {
query += "&";
}
query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]);
}
window.fetch("api/v1/photos/" + thumbnail.item.id + query,
window.fetch("api/v1/photos/" + thumbnail.item.id + "?a=undelete",
this._removeImageAfterFetch.bind(this, thumbnail), {}, "PUT");
break;
},
case "delete": /* Delete image */
deleteAction: function(photo) {
var thumbnail = event.currentTarget, params = {};
thumbnail.disabled = true;
var query = "";
if (this.mode == "trash") {
console.log("TODO: Prompt user 'Are you sure?' ?");
params.permanent = 1;
}
var query = "";
for (var key in params) {
if (!query) {
query = "?";
} else {
query += "&";
}
query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]);
query += "?permanent=1";
}
window.fetch("api/v1/photos/" + thumbnail.item.id + query,
this._removeImageAfterFetch.bind(this, thumbnail), {}, "DELETE");
},
renameAction: function(thumbnail) {
return;
},
rotateAction: function(thumbnail, direction) {
thumbnail.disabled = true;
window.fetch("api/v1/photos/" + thumbnail.item.id + "?a=rotate&direction=" + direction,
function(thumbnail, error, xhr) {
thumbnail.disabled = false;
if (error) {
console.log("Unable to take action on photo: " + error);
return;
}
thumbnail.reload();
}.bind(this, thumbnail), {}, "PUT");
},
_imageAction: function(event) {
switch (event.detail) {
case "undo": /* Undelete an image */
this.undoAction(event.currentTarget);
break;
case "delete": /* Delete image */
this.deleteAction(event.currentTarget);
break;
case "image:rotate-left":
this.rotateAction(event.currentTarget, "left");
break;
case "image:rotate-right":
this.rotateAction(event.currentTarget, "right");
break;
case "text-format": /* Rename this image */
this.renameAction(event.currentTarget);
break;
}
},

View File

@ -32,39 +32,144 @@ const unlink = function (_path) {
});
}
const rename = function (_src, _dst) {
if (_src.indexOf(picturesPath.replace(/\/$/, "")) == 0) {
_src = _src.substring(picturesPath.length);
}
if (_dst.indexOf(picturesPath.replace(/\/$/, "")) == 0) {
_dst = _dst.substring(picturesPath.length);
}
let src = picturesPath + _src,
dst = picturesPath + _dst;
return new Promise(function (resolve, reject) {
fs.rename(src, dst, function (error, stats) {
if (error) {
return reject(error);
}
return resolve(stats);
});
});
}
const stat = function (_path) {
if (_path.indexOf(picturesPath.replace(/\/$/, "")) == 0) {
_path = _path.substring(picturesPath.length);
}
let path = picturesPath + _path;
return new Promise(function (resolve, reject) {
fs.stat(path, function (error, stats) {
if (error) {
return reject(error);
}
return resolve(stats);
});
});
}
const sharp = require("sharp"), exif = require("exif-reader");
router.put("/:id", function(req, res/*, next*/) {
if (!req.user.maintainer) {
return res.status(401).send("Unauthorized to delete photos.");
return res.status(401).send("Unauthorized to modify photos.");
}
const replacements = {
id: req.params.id
};
let query = "";
console.log("PUT /" + replacements.id, req.query);
for (let key in req.query) {
switch (key) {
switch (req.query.a) {
case "undelete":
console.log("Undeleting " + req.params.id);
query = "UPDATE photos SET deleted=0 WHERE id=:id";
break;
default:
continue;
}
}
if (!query) {
return res.status(400).send("Invalid request");
}
return photoDB.sequelize.query(query, {
return photoDB.sequelize.query("UPDATE photos SET deleted=0 WHERE id=:id", {
replacements: replacements
}).then(function() {
return res.status(200).send(req.params.id + " updated.");
});
case "rotate":
let direction = req.query.direction || "right";
if (direction == "right") {
direction = 90;
} else {
direction = -90;
}
return getPhoto(req.params.id).then(function(asset) {
if (!asset) {
return res.status(404).send(req.params.id + " not found.");
}
let original = picturesPath + asset.path + asset.filename,
target = picturesPath + asset.path + ".tmp." + asset.filename,
thumb = picturesPath + asset.path + "thumbs/" + asset.filename,
scaled = picturesPath + asset.path + "thumbs/scaled/" + asset.filename;
let tmp = asset.width;
asset.width = asset.height;
asset.height = tmp;
asset.image = sharp(original);
return asset.image.rotate(direction).withMetadata().toFile(target).then(function() {
/*...*/
}).then(function() {
return asset.image.rotate(direction).resize(256, 256).withMetadata().toFile(thumb);
}).then(function() {
return asset.image.resize(Math.min(1024, asset.width)).withMetadata().toFile(scaled);
}).then(function() {
return stat(target).then(function(stats) {
if (!stats) {
throw "Unable to find original file after attempting to rotate!";
}
asset.size = stats.size;
return photoDB.sequelize.query("UPDATE photos SET " +
"modified=CURRENT_TIMESTAMP,width=:width,height=:height,size=:size,scanned=CURRENT_TIMESTAMP " +
"WHERE id=:id", {
replacements: asset
}).then(function() {
return unlink(original).then(function() {
return rename(target, original);
});
});
});
}).then(function() {
sharp.cache(false);
sharp.cache(true);
return res.status(200).send(asset);
});
}).catch(function(error) {
console.log(error);
return res.status(500).send(error);
});
}
return res.status(400).send("Invalid request");
});
const getPhoto = function(id) {
return photoDB.sequelize.query("SELECT " +
"photos.*,albums.path AS path,photohashes.hash,(albums.path || photos.filename) AS filepath FROM photos " +
"LEFT JOIN albums ON albums.id=photos.albumId " +
"LEFT JOIN photohashes ON photohashes.photoId=photos.id " +
"WHERE photos.id=:id", {
replacements: {
id: id
},
type: photoDB.Sequelize.QueryTypes.SELECT,
raw: true
}).then(function(photos) {
if (photos.length == 0) {
return null;
}
return photos[0];
});
}
router.delete("/:id", function(req, res/*, next*/) {
if (!req.user.maintainer) {
return res.status(401).send("Unauthorized to delete photos.");

View File

@ -333,7 +333,7 @@ function processBlock(items) {
return;
}
return image.resize(256, 256).toFile(dst).catch(function(error) {
return image.resize(256, 256).withMetadata().toFile(dst).catch(function(error) {
setStatus("Error resizing image: " + dst + "\n" + error, "error");
throw error;
});
@ -344,7 +344,7 @@ function processBlock(items) {
return;
}
return image.resize(Math.min(1024, metadata.width)).toFile(dst).catch(function(error) {
return image.resize(Math.min(1024, metadata.width)).withMetadata().toFile(dst).catch(function(error) {
setStatus("Error resizing image: " + dst + "\n" + error, "error");
throw error;
});