Rotation now works
Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
parent
82e5875e52
commit
2f6f0ccfa5
@ -81,6 +81,10 @@
|
|||||||
Polymer({
|
Polymer({
|
||||||
is: "photo-thumbnail",
|
is: "photo-thumbnail",
|
||||||
properties: {
|
properties: {
|
||||||
|
"unique": {
|
||||||
|
type: String,
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
"disabled": {
|
"disabled": {
|
||||||
reflectToAttribute: true
|
reflectToAttribute: true
|
||||||
},
|
},
|
||||||
@ -89,7 +93,7 @@
|
|||||||
},
|
},
|
||||||
"thumbpath": {
|
"thumbpath": {
|
||||||
type: String,
|
type: String,
|
||||||
computed: "safeItemThumbFilepath(item, base)"
|
computed: "safeItemThumbFilepath(item, base, unique)"
|
||||||
},
|
},
|
||||||
"width": {
|
"width": {
|
||||||
type: Number
|
type: Number
|
||||||
@ -130,11 +134,11 @@
|
|||||||
this.style.height = width + "px";
|
this.style.height = width + "px";
|
||||||
},
|
},
|
||||||
|
|
||||||
safeItemThumbFilepath: function(item, base) {
|
safeItemThumbFilepath: function(item, base, unique) {
|
||||||
if (item === undefined|| base === undefined || item.path === undefined) {
|
if (item === undefined|| base === undefined || item.path === undefined) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return base + item.path + "thumbs/" + item.filename;
|
return base + item.path + "thumbs/" + item.filename + (this.unique ? ("?" + this.unique) : "");
|
||||||
},
|
},
|
||||||
|
|
||||||
date: function(item) {
|
date: function(item) {
|
||||||
@ -154,6 +158,10 @@
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
reload: function() {
|
||||||
|
this.unique = parseInt(this.unique || 0) + 1;
|
||||||
|
},
|
||||||
|
|
||||||
attached: function() {
|
attached: function() {
|
||||||
var base = document.querySelector("base");
|
var base = document.querySelector("base");
|
||||||
if (base) {
|
if (base) {
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
<link rel="import" href="../../bower_components/iron-icon/iron-icon.html">
|
<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/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-iconset/iron-iconset.html">
|
||||||
<link rel="import" href="../../bower_components/iron-pages/iron-pages.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">
|
<link rel="import" href="../../bower_components/iron-resizable-behavior/iron-resizable-behavior.html">
|
||||||
@ -1221,9 +1222,11 @@
|
|||||||
let actions = [ "delete" ];
|
let actions = [ "delete" ];
|
||||||
if (this.mode == "duplicates") {
|
if (this.mode == "duplicates") {
|
||||||
actions.unshift("text-format");
|
actions.unshift("text-format");
|
||||||
}
|
} else if (this.mode == "trash") {
|
||||||
if (this.mode == "trash") {
|
|
||||||
actions.unshift("undo");
|
actions.unshift("undo");
|
||||||
|
} else {
|
||||||
|
actions.unshift("image:rotate-right");
|
||||||
|
actions.unshift("image:rotate-left");
|
||||||
}
|
}
|
||||||
thumbnail.actions = actions;
|
thumbnail.actions = actions;
|
||||||
thumbnail.addEventListener("action", this._imageAction.bind(this));
|
thumbnail.addEventListener("action", this._imageAction.bind(this));
|
||||||
@ -1293,49 +1296,65 @@
|
|||||||
}.bind(this, thumbnail), 250);
|
}.bind(this, thumbnail), 250);
|
||||||
},
|
},
|
||||||
|
|
||||||
_imageAction: function(event) {
|
undoAction: function(thumbnail) {
|
||||||
switch (event.detail) {
|
var params = {};
|
||||||
case "undo": /* Undelete an image */
|
|
||||||
var thumbnail = event.currentTarget, params = {};
|
|
||||||
thumbnail.disabled = true;
|
thumbnail.disabled = true;
|
||||||
|
window.fetch("api/v1/photos/" + thumbnail.item.id + "?a=undelete",
|
||||||
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,
|
|
||||||
this._removeImageAfterFetch.bind(this, thumbnail), {}, "PUT");
|
this._removeImageAfterFetch.bind(this, thumbnail), {}, "PUT");
|
||||||
break;
|
},
|
||||||
|
|
||||||
case "delete": /* Delete image */
|
deleteAction: function(photo) {
|
||||||
var thumbnail = event.currentTarget, params = {};
|
var thumbnail = event.currentTarget, params = {};
|
||||||
thumbnail.disabled = true;
|
thumbnail.disabled = true;
|
||||||
|
var query = "";
|
||||||
if (this.mode == "trash") {
|
if (this.mode == "trash") {
|
||||||
console.log("TODO: Prompt user 'Are you sure?' ?");
|
console.log("TODO: Prompt user 'Are you sure?' ?");
|
||||||
params.permanent = 1;
|
query += "?permanent=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 + query,
|
||||||
this._removeImageAfterFetch.bind(this, thumbnail), {}, "DELETE");
|
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;
|
break;
|
||||||
|
|
||||||
case "text-format": /* Rename this image */
|
case "text-format": /* Rename this image */
|
||||||
|
this.renameAction(event.currentTarget);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -32,38 +32,143 @@ 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*/) {
|
router.put("/:id", function(req, res/*, next*/) {
|
||||||
if (!req.user.maintainer) {
|
if (!req.user.maintainer) {
|
||||||
return res.status(401).send("Unauthorized to delete photos.");
|
return res.status(401).send("Unauthorized to modify photos.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const replacements = {
|
const replacements = {
|
||||||
id: req.params.id
|
id: req.params.id
|
||||||
};
|
};
|
||||||
|
|
||||||
let query = "";
|
|
||||||
|
|
||||||
console.log("PUT /" + replacements.id, req.query);
|
console.log("PUT /" + replacements.id, req.query);
|
||||||
for (let key in req.query) {
|
switch (req.query.a) {
|
||||||
switch (key) {
|
|
||||||
case "undelete":
|
case "undelete":
|
||||||
console.log("Undeleting " + req.params.id);
|
console.log("Undeleting " + req.params.id);
|
||||||
query = "UPDATE photos SET deleted=0 WHERE id=:id";
|
return photoDB.sequelize.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, {
|
|
||||||
replacements: replacements
|
replacements: replacements
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
return res.status(200).send(req.params.id + " updated.");
|
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*/) {
|
router.delete("/:id", function(req, res/*, next*/) {
|
||||||
if (!req.user.maintainer) {
|
if (!req.user.maintainer) {
|
||||||
|
@ -333,7 +333,7 @@ function processBlock(items) {
|
|||||||
return;
|
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");
|
setStatus("Error resizing image: " + dst + "\n" + error, "error");
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
@ -344,7 +344,7 @@ function processBlock(items) {
|
|||||||
return;
|
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");
|
setStatus("Error resizing image: " + dst + "\n" + error, "error");
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user