From 1089f70d5ebe29d58ab28247d71b38f56ffa54c6 Mon Sep 17 00:00:00 2001 From: Zutatensuppe Date: Wed, 21 Apr 2021 19:22:58 +0200 Subject: [PATCH] image operations via Images.js, directory fun via Dirs.js --- scripts/install | 2 - scripts/resize_images.js | 45 ++---------------- scripts/rewrite_logs.js | 3 +- server/Dirs.js | 14 ++++++ server/Game.js | 3 +- server/GameLog.js | 3 +- server/Images.js | 81 +++++++++++++++++++++++++++++++++ server/Puzzle.js | 39 ++-------------- server/index.js | 98 +++++++--------------------------------- 9 files changed, 122 insertions(+), 166 deletions(-) create mode 100644 server/Dirs.js create mode 100644 server/Images.js diff --git a/scripts/install b/scripts/install index c2a2f09..1099ffb 100755 --- a/scripts/install +++ b/scripts/install @@ -1,7 +1,5 @@ #!/bin/sh -cd "$RUN_DIR/server" - npm install if [ ! -e "$RUN_DIR/server/config.js" ]; then diff --git a/scripts/resize_images.js b/scripts/resize_images.js index 1842cb8..27866f3 100755 --- a/scripts/resize_images.js +++ b/scripts/resize_images.js @@ -1,48 +1,9 @@ #!/bin/env node -import fs from 'fs' -import sharp from 'sharp' -import exif from 'exif' +import Images from './../server/Images.js' -async function getExifOrientation(imagePath) { - return new Promise((resolve, reject) => { - new exif.ExifImage({ image: imagePath }, function (error, exifData) { - if (error) { - resolve(0) - } else { - resolve(exifData.image.Orientation) - } - }) - }) -} - -const dir = `./../data/uploads` -const images = fs.readdirSync(dir) +const images = Images.allImages() images.forEach(async (image) => { - if (!image.toLowerCase().match(/\.(jpe?g|webp|png)$/)) { - return - } console.log(image) - - const imagePath = `${dir}/${image}` - const iamgeOutPath = `${dir}/r/${image}` - const orientation = await getExifOrientation(imagePath) - - let sharpImg = sharp(imagePath, { failOnError: false }) - // when image is rotated to the left or right, switch width/height - // https://jdhao.github.io/2019/07/31/image_rotation_exif_info/ - if (orientation === 6) { - sharpImg = sharpImg.rotate() - } else if (orientation === 3) { - sharpImg = sharpImg.rotate().rotate() - } else if (orientation === 8) { - sharpImg = sharpImg.rotate().rotate().rotate() - } - const sizes = [ - [150, 100], - [375, 210], - ] - sizes.forEach(([w, h]) => { - sharpImg.resize(w, h, {fit: 'contain'}).toFile(`${iamgeOutPath}-${w}x${h}.webp`) - }) + Images.resizeImage(image.filename) }) diff --git a/scripts/rewrite_logs.js b/scripts/rewrite_logs.js index 19ae2ea..ee8f1d5 100644 --- a/scripts/rewrite_logs.js +++ b/scripts/rewrite_logs.js @@ -1,11 +1,10 @@ import fs from 'fs' import Protocol from '../common/Protocol.js' import { logger } from '../common/Util.js' +import { DATA_DIR } from '../server/Dirs.js' const log = logger('rewrite_logs') -const DATA_DIR = '../data' - const filename = (gameId) => `${DATA_DIR}/log_${gameId}.log` const rewrite = (gameId) => { diff --git a/server/Dirs.js b/server/Dirs.js new file mode 100644 index 0000000..c7a0cd3 --- /dev/null +++ b/server/Dirs.js @@ -0,0 +1,14 @@ +import { fileURLToPath } from 'url' +import { dirname } from 'path' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +const BASE_DIR = `${__dirname}/..` + +export const DATA_DIR = `${BASE_DIR}/data` +export const UPLOAD_DIR = `${BASE_DIR}/data/uploads` +export const UPLOAD_URL = `/uploads` +export const COMMON_DIR = `${BASE_DIR}/common/` +export const GAME_DIR = `${BASE_DIR}/game/` +export const TEMPLATE_DIR = `${BASE_DIR}/game/templates` diff --git a/server/Game.js b/server/Game.js index 608d9ea..df09de3 100644 --- a/server/Game.js +++ b/server/Game.js @@ -5,11 +5,10 @@ import { Rng } from '../common/Rng.js' import GameLog from './GameLog.js' import { createPuzzle } from './Puzzle.js' import Protocol from '../common/Protocol.js' +import { DATA_DIR } from './Dirs.js' const log = logger('Game.js') -const DATA_DIR = './../data' - function loadAllGames() { const files = fs.readdirSync(DATA_DIR) for (const f of files) { diff --git a/server/GameLog.js b/server/GameLog.js index 5c75fdb..5f6e4f8 100644 --- a/server/GameLog.js +++ b/server/GameLog.js @@ -1,10 +1,9 @@ import fs from 'fs' import { logger } from '../common/Util.js' +import { DATA_DIR } from '../server/Dirs.js' const log = logger('GameLog.js') -const DATA_DIR = './../data' - const filename = (gameId) => `${DATA_DIR}/log_${gameId}.log` const create = (gameId) => { diff --git a/server/Images.js b/server/Images.js new file mode 100644 index 0000000..891a937 --- /dev/null +++ b/server/Images.js @@ -0,0 +1,81 @@ +import sizeOf from 'image-size' +import fs from 'fs' +import exif from 'exif' +import sharp from 'sharp' +import {UPLOAD_DIR, UPLOAD_URL} from './Dirs.js' + +const resizeImage = async (filename) => { + if (!filename.toLowerCase().match(/\.(jpe?g|webp|png)$/)) { + return + } + + const imagePath = `${UPLOAD_DIR}/${filename}` + const imageOutPath = `${UPLOAD_DIR}/r/${filename}` + const orientation = await getExifOrientation(imagePath) + + let sharpImg = sharp(imagePath, { failOnError: false }) + // when image is rotated to the left or right, switch width/height + // https://jdhao.github.io/2019/07/31/image_rotation_exif_info/ + if (orientation === 6) { + sharpImg = sharpImg.rotate() + } else if (orientation === 3) { + sharpImg = sharpImg.rotate().rotate() + } else if (orientation === 8) { + sharpImg = sharpImg.rotate().rotate().rotate() + } + const sizes = [ + [150, 100], + [375, 210], + ] + for (let [w,h] of sizes) { + console.log(w, h, imagePath) + await sharpImg.resize(w, h, { fit: 'contain' }).toFile(`${imageOutPath}-${w}x${h}.webp`) + } +} + +async function getExifOrientation(imagePath) { + return new Promise((resolve, reject) => { + new exif.ExifImage({ image: imagePath }, function (error, exifData) { + if (error) { + resolve(0) + } else { + resolve(exifData.image.Orientation) + } + }) + }) +} + +const allImages = () => { + const images = fs.readdirSync(UPLOAD_DIR) + .filter(f => f.toLowerCase().match(/\.(jpe?g|webp|png)$/)) + .map(f => ({ + filename: f, + file: `${UPLOAD_DIR}/${f}`, + url: `${UPLOAD_URL}/${f}`, + })) + .sort((a, b) => { + return fs.statSync(b.file).mtime.getTime() - + fs.statSync(a.file).mtime.getTime() + }) + return images +} + +async function getDimensions(imagePath) { + let dimensions = sizeOf(imagePath) + const orientation = await getExifOrientation(imagePath) + // when image is rotated to the left or right, switch width/height + // https://jdhao.github.io/2019/07/31/image_rotation_exif_info/ + if (orientation === 6 || orientation === 8) { + return { + width: dimensions.height, + height: dimensions.width, + } + } + return dimensions +} + +export default { + allImages, + resizeImage, + getDimensions, +} diff --git a/server/Puzzle.js b/server/Puzzle.js index 8d454d1..804ff2d 100644 --- a/server/Puzzle.js +++ b/server/Puzzle.js @@ -1,40 +1,11 @@ -import sizeOf from 'image-size' import Util from '../common/Util.js' -import exif from 'exif' import { Rng } from '../common/Rng.js' +import Images from './Images.js' // cut size of each puzzle tile in the // final resized version of the puzzle image const TILE_SIZE = 64 -async function getDimensions(imagePath) { - let dimensions = sizeOf(imagePath) - try { - const orientation = await getExifOrientation(imagePath) - // when image is rotated to the left or right, switch width/height - // https://jdhao.github.io/2019/07/31/image_rotation_exif_info/ - if (orientation === 6 || orientation === 8) { - return { - width: dimensions.height, - height: dimensions.width, - } - } - } catch {} - return dimensions -} - -async function getExifOrientation(imagePath) { - return new Promise((resolve, reject) => { - new exif.ExifImage({ image: imagePath }, function (error, exifData) { - if (error) { - reject(error) - } else { - resolve(exifData.image.Orientation) - } - }) - }) -} - async function createPuzzle( /** @type Rng */ rng, targetTiles, @@ -44,10 +15,8 @@ async function createPuzzle( const imagePath = image.file const imageUrl = image.url - // load bitmap, to determine the original size of the image - const dim = await getDimensions(imagePath) - - // determine puzzle information from the bitmap + // determine puzzle information from the image dimensions + const dim = await Images.getDimensions(imagePath) const info = determinePuzzleInfo(dim.width, dim.height, targetTiles) let tiles = new Array(info.tiles) @@ -58,7 +27,7 @@ async function createPuzzle( let positions = new Array(info.tiles) for (let tile of tiles) { - let coord = Util.coordByTileIdx(info, tile.idx) + const coord = Util.coordByTileIdx(info, tile.idx) positions[tile.idx] ={ // instead of info.tileSize, we use info.tileDrawSize // to spread the tiles a bit diff --git a/server/index.js b/server/index.js index 24a5df6..2cb4ba3 100644 --- a/server/index.js +++ b/server/index.js @@ -1,6 +1,5 @@ import WebSocketServer from './WebSocketServer.js' -import fs from 'fs' import express from 'express' import multer from 'multer' import config from './../config.js' @@ -13,96 +12,33 @@ import v8 from 'v8' import GameLog from './GameLog.js' import GameSockets from './GameSockets.js' import Time from '../common/Time.js' -import exif from 'exif' -import sharp from 'sharp' +import Images from './Images.js' +import { + UPLOAD_DIR, + UPLOAD_URL, + COMMON_DIR, + GAME_DIR, + TEMPLATE_DIR, +} from './Dirs.js' const log = logger('index.js') -async function getExifOrientation(imagePath) { - return new Promise((resolve, reject) => { - new exif.ExifImage({ image: imagePath }, function (error, exifData) { - if (error) { - resolve(0) - -async function getExifOrientation(imagePath) { - return new Promise((resolve, reject) => { - new exif.ExifImage({ image: imagePath }, function (error, exifData) { - if (error) { - resolve(0) - } else { - resolve(exifData.image.Orientation) - } - }) - }) -} - } else { - resolve(exifData.image.Orientation) - } - }) - }) -} - -const resizeImage = async (filename) => { - const dir = `./../data/uploads/` - if (!filename.toLowerCase().match(/\.(jpe?g|webp|png)$/)) { - return - } - console.log(filename) - - const imagePath = `${dir}/${filename}` - const iamgeOutPath = `${dir}/r/${filename}` - const orientation = await getExifOrientation(imagePath) - - let sharpImg = sharp(imagePath, { failOnError: false }) - // when image is rotated to the left or right, switch width/height - // https://jdhao.github.io/2019/07/31/image_rotation_exif_info/ - if (orientation === 6) { - sharpImg = sharpImg.rotate() - } else if (orientation === 3) { - sharpImg = sharpImg.rotate().rotate() - } else if (orientation === 8) { - sharpImg = sharpImg.rotate().rotate().rotate() - } - const sizes = [ - [150, 100], - [375, 210], - ] - sizes.forEach(([w, h]) => { - sharpImg.resize(w, h, {fit: 'contain'}).toFile(`${iamgeOutPath}-${w}x${h}.webp`) - }) -} - -const allImages = () => { - const images = fs.readdirSync('./../data/uploads/') - .filter(f => f.toLowerCase().match(/\.(jpe?g|webp|png)$/)) - .map(f => ({ - file: `./../data/uploads/${f}`, - url: `/uploads/${f}`, - })) - .sort((a, b) => { - return fs.statSync(b.file).mtime.getTime() - - fs.statSync(a.file).mtime.getTime() - }) - return images -} - const port = config.http.port const hostname = config.http.hostname const app = express() -const uploadDir = './../data/uploads' const storage = multer.diskStorage({ - destination: uploadDir, + destination: UPLOAD_DIR, filename: function (req, file, cb) { cb(null , file.originalname); } }) const upload = multer({storage}).single('file'); -const statics = express.static('./../game/') +const statics = express.static(GAME_DIR) const render = async (template, data) => { - const loader = new twing.TwingLoaderFilesystem('./../game/templates') + const loader = new twing.TwingLoaderFilesystem(TEMPLATE_DIR) const env = new twing.TwingEnvironment(loader) return env.render(template, data) } @@ -129,7 +65,7 @@ app.post('/upload', (req, res) => { } try { - await resizeImage(req.file.filename) + await Images.resizeImage(req.file.filename) } catch (err) { log.log(err) res.status(400).send("Something went wrong!"); @@ -137,8 +73,8 @@ app.post('/upload', (req, res) => { res.send({ image: { - file: './../data/uploads/' + req.file.filename, - url: '/uploads/' + req.file.filename, + file: `${UPLOAD_DIR}/${req.file.filename}`, + url: `${UPLOAD_URL}/${req.file.filename}`, }, }) }) @@ -154,8 +90,8 @@ app.post('/newgame', bodyParser.json(), async (req, res) => { res.send({ url: `/g/${gameId}` }) }) -app.use('/common/', express.static('./../common/')) -app.use('/uploads/', express.static('./../data/uploads/')) +app.use('/common/', express.static(COMMON_DIR)) +app.use('/uploads/', express.static(UPLOAD_DIR)) app.use('/', async (req, res, next) => { if (req.path === '/') { const ts = Time.timestamp() @@ -175,7 +111,7 @@ app.use('/', async (req, res, next) => { res.send(await render('index.html.twig', { gamesRunning: games.filter(g => !g.finished), gamesFinished: games.filter(g => !!g.finished), - images: allImages(), + images: Images.allImages(), })) } else { statics(req, res, next)