Parcourir la source

Add "min", "max", "median" in getImage and getImageExtracts + tests

rigwild il y a 5 ans
Parent
commit
411afd5df9

+ 8 - 4
server/functions.js

@@ -104,6 +104,8 @@ export const getSceneFiles = sceneName => {
 
 /** Image data type definition (do no remove)
  * @typedef {object} ImageData
+ * @property {string} fileName file name of image
+ * @property {string} sceneName scene name of image
  * @property {string} prefix prefix of image
  * @property {number} quality quality of image
  * @property {string} ext extension of image
@@ -112,7 +114,7 @@ export const getSceneFiles = sceneName => {
  * Get image data from every files in a scene (exclude blacklisted ones)
  * @typedef {string} filename path to the image
  * @param {string} sceneName the scene name
- * @returns {Promise<Map<filename, ImageData>>} the data for all images in a scene (Map key = file name)
+ * @returns {Promise<ImageData[]>} the data for all images in a scene
  * @throws some file names could not be parsed
  */
 export const getSceneFilesData = async sceneName => {
@@ -146,20 +148,22 @@ export const getSceneFilesData = async sceneName => {
       const fileData = {
         prefix: regexRes[1],
         quality: parseInt(regexRes[2], 10),
-        ext: regexRes[3]
+        ext: regexRes[3],
+        fileName: regexRes[0],
+        sceneName
       }
 
       // Check valid quality
       if (isNaN(fileData.quality)) return acc
 
       // Data is valid, set it
-      acc.set(regexRes[0], fileData)
+      acc.push(fileData)
     }
     catch (err) {
       failList.push(`Failed to parse file name : "${image}".`)
     }
     return acc
-  }, new Map())
+  }, [])
 
   // Check if the parse fail list is empty
   if (failList.length > 0)

+ 36 - 17
server/routes/getImage.js

@@ -18,7 +18,7 @@ const router = express.Router()
  * @apiDescription Get an image from a scene with the required quality
  *
  * @apiParam {String} sceneName The selected scene
- * @apiParam {Number} imageQuality The required quality of the image
+ * @apiParam {Number|"min"|"max"|"median"} imageQuality The required quality of the image
  *
  * @apiExample Usage example
  * curl -i -L -X GET "http://diran.univ-littoral.fr/api/getImage?sceneName=bathroom&imageQuality=200"
@@ -88,26 +88,39 @@ const router = express.Router()
 /**
  * Get the link and path to an image
  * @param {string} sceneName the scene to get the image from
- * @param {number} qualityInt the requested quality
+ * @param {number|"min"|"max"|"median"} quality the requested quality
  * @returns {Promise<Image>} the link and path to the image
  */
-export const getImage = async (sceneName, qualityInt) => {
+export const getImage = async (sceneName, quality) => {
   const sceneData = await getSceneFilesData(sceneName)
 
+  let imageData = null
   // Search an image with the requested quality in the scene
-  for (const [imageName, imageData] of sceneData.entries())
-    if (qualityInt === imageData.quality)
-      return {
-        link: `${imageServedUrl}/${sceneName}/${imageName}`,
-        path: path.resolve(imagesPath, sceneName, imageName),
-        fileName: imageName,
-        sceneName,
-        quality: imageData.quality,
-        ext: imageData.ext
-      }
+  if (quality === 'min') {
+    const toFind = Math.min(...sceneData.map(x => x.quality))
+    imageData = sceneData.find(x => x.quality === toFind)
+  }
+  else if (quality === 'max') {
+    const toFind = Math.max(...sceneData.map(x => x.quality))
+    imageData = sceneData.find(x => x.quality === toFind)
+  }
+  else if (quality === 'median')
+    imageData = sceneData.length > 0 ? sceneData[Math.ceil(sceneData.length / 2) - 1] : null
+  else
+    imageData = sceneData.find(x => quality === x.quality)
+
+  if (imageData)
+    return {
+      link: `${imageServedUrl}/${sceneName}/${imageData.fileName}`,
+      path: path.resolve(imagesPath, sceneName, imageData.fileName),
+      fileName: imageData.fileName,
+      sceneName: imageData.sceneName,
+      quality: imageData.quality,
+      ext: imageData.ext
+    }
 
   // Image not found
-  throw boom.notFound(`The requested quality (${qualityInt}) was not found for the requested scene (${sceneName}).`)
+  throw boom.notFound(`The requested quality "${quality}" was not found for the requested scene "${sceneName}".`)
 }
 
 router.get('/', asyncMiddleware(async (req, res) => {
@@ -126,15 +139,21 @@ router.get('/', asyncMiddleware(async (req, res) => {
     errorList.push(err.message)
   }
 
-  // Check `imageQuality` is an integer
+  // Check `imageQuality` is an integer or `min`, `max` or `median`
   const qualityInt = parseInt(imageQuality, 10)
-  if (isNaN(qualityInt)) errorList.push('The specified quality is not an integer.')
+  let quality = null
+  if (['min', 'median', 'max'].some(x => x === imageQuality))
+    quality = imageQuality
+  else if (!isNaN(qualityInt))
+    quality = qualityInt
+  else
+    errorList.push('The specified quality is not an integer or "min", "max" or "median".')
 
   // Check there is no errors with parameters
   if (errorList.length > 0)
     throw boom.badRequest('Invalid query parameter(s).', errorList)
 
-  const { link } = await getImage(sceneName, qualityInt)
+  const { link } = await getImage(sceneName, quality)
   res.json({ data: link })
 }))
 

+ 11 - 5
server/routes/getImageExtracts.js

@@ -21,7 +21,7 @@ const router = express.Router()
  * @apiDescription Get an image from a scene with the required quality and cut it with the requested configuration
  *
  * @apiParam {String} sceneName The selected scene
- * @apiParam {Number} imageQuality The required quality of the image
+ * @apiParam {Number|"min"|"max"|"median"} imageQuality The required quality of the image
  * @apiParam {Number} horizontalExtractCount The amount of extracts for the horizontal axis
  * @apiParam {Number} verticalExtractCount The amount of extracts for the vertical axis
  *
@@ -216,15 +216,21 @@ router.get('/', asyncMiddleware(async (req, res) => {
     errorList.push(err.message)
   }
 
-  // Check `imageQuality` is an integer
+  // Check `imageQuality` is an integer or `min`, `max` or `median`
   const qualityInt = parseInt(imageQuality, 10)
-  if (isNaN(qualityInt)) errorList.push('The specified quality is not an integer.')
+  let quality = null
+  if (['min', 'median', 'max'].some(x => x === imageQuality))
+    quality = imageQuality
+  else if (!isNaN(qualityInt))
+    quality = qualityInt
+  else
+    errorList.push('The specified quality is not an integer or "min", "max" or "median".')
 
   // Check `horizontalExtractCount` is an integer
   const horizontalExtractCountInt = parseInt(horizontalExtractCount, 10)
   if (isNaN(horizontalExtractCountInt)) errorList.push('The specified number of extract for the horizontal axis is not an integer.')
 
-  // Check `imageQuality` is an integer
+  // Check `verticalExtractCountInt` is an integer
   const verticalExtractCountInt = parseInt(verticalExtractCount, 10)
   if (isNaN(verticalExtractCountInt)) errorList.push('The specified number of extract for the vertical axis is not an integer.')
 
@@ -234,7 +240,7 @@ router.get('/', asyncMiddleware(async (req, res) => {
     throw boom.badRequest('Invalid query parameter(s).', errorList)
 
   // Get the image path and link
-  const image = await getImage(sceneName, qualityInt)
+  const image = await getImage(sceneName, quality)
 
   // Cut the image
   const extracts = await cutImage(image, horizontalExtractCountInt, verticalExtractCountInt)

+ 1 - 1
server/routes/listSceneQualities.js

@@ -69,7 +69,7 @@ router.get('/', asyncMiddleware(async (req, res) => {
 
   const { sceneName } = req.query
   const sceneData = await getSceneFilesData(sceneName)
-  const data = Array.from(sceneData.values()).map(x => x.quality)
+  const data = sceneData.map(x => x.quality)
   res.json({ data })
 }))
 

+ 26 - 0
test/api/getImage.js

@@ -46,6 +46,30 @@ test('GET /getImage?sceneName=bathroom&imageQuality=999999', async t => {
   t.truthy(res.body.message.match(/requested quality.*not found for.*scene/), json(res.body))
 })
 
+test('GET /getImage?sceneName=bathroom&imageQuality=min', async t => {
+  const res = await request(t.context.server)
+    .get(`${apiPrefix}/getImage?sceneName=bathroom&imageQuality=min`)
+
+  t.is(res.status, 200, json(res))
+  t.is(res.body.data, `${imageServedUrl}/bathroom/bathroom_00010.png`, json(res.body))
+})
+
+test('GET /getImage?sceneName=bathroom&imageQuality=median', async t => {
+  const res = await request(t.context.server)
+    .get(`${apiPrefix}/getImage?sceneName=bathroom&imageQuality=median`)
+
+  t.is(res.status, 200, json(res))
+  t.is(res.body.data, `${imageServedUrl}/bathroom/bathroom_00010.png`, json(res.body))
+})
+
+test('GET /getImage?sceneName=bathroom&imageQuality=max', async t => {
+  const res = await request(t.context.server)
+    .get(`${apiPrefix}/getImage?sceneName=bathroom&imageQuality=max`)
+
+  t.is(res.status, 200, json(res))
+  t.is(res.body.data, `${imageServedUrl}/bathroom/bathroom_00010.png`, json(res.body))
+})
+
 test('GET /getImage?sceneName=bathroom&imageQuality=10', async t => {
   const res = await request(t.context.server)
     .get(`${apiPrefix}/getImage?sceneName=bathroom&imageQuality=10`)
@@ -60,3 +84,5 @@ test('GET /getImage?sceneName=bathroom&imageQuality=10', async t => {
   t.is(res2.status, 200, json(res2))
   t.is(res2.header['content-type'], 'image/png', json(res2))
 })
+
+

+ 27 - 0
test/api/getImageExtracts.js

@@ -63,6 +63,33 @@ test('GET /getImageExtracts?sceneName=bathroom&imageQuality=10&horizontalExtract
   t.truthy(res.body.data.find(x => x.includes('Incompatible number of vertical extracts')), json(res.body))
 })
 
+test('GET /getImageExtracts?sceneName=bathroom&imageQuality=min&horizontalExtractCount=5&verticalExtractCount=2', async t => {
+  const res = await request(t.context.server)
+    .get(`${apiPrefix}/getImageExtracts?sceneName=bathroom&imageQuality=min&horizontalExtractCount=5&verticalExtractCount=2`)
+
+  t.is(res.status, 200, json(res))
+  t.true(Array.isArray(res.body.data), json(res.body))
+  t.is(res.body.data[0], `${imageServedUrl}/bathroom/extracts/x5_y2/zone00001/bathroom_zone00001_10.png`, json(res.body))
+})
+
+test('GET /getImageExtracts?sceneName=bathroom&imageQuality=median&horizontalExtractCount=5&verticalExtractCount=2', async t => {
+  const res = await request(t.context.server)
+    .get(`${apiPrefix}/getImageExtracts?sceneName=bathroom&imageQuality=median&horizontalExtractCount=5&verticalExtractCount=2`)
+
+  t.is(res.status, 200, json(res))
+  t.true(Array.isArray(res.body.data), json(res.body))
+  t.is(res.body.data[0], `${imageServedUrl}/bathroom/extracts/x5_y2/zone00001/bathroom_zone00001_10.png`, json(res.body))
+})
+
+test('GET /getImageExtracts?sceneName=bathroom&imageQuality=max&horizontalExtractCount=5&verticalExtractCount=2', async t => {
+  const res = await request(t.context.server)
+    .get(`${apiPrefix}/getImageExtracts?sceneName=bathroom&imageQuality=max&horizontalExtractCount=5&verticalExtractCount=2`)
+
+  t.is(res.status, 200, json(res))
+  t.true(Array.isArray(res.body.data), json(res.body))
+  t.is(res.body.data[0], `${imageServedUrl}/bathroom/extracts/x5_y2/zone00001/bathroom_zone00001_10.png`, json(res.body))
+})
+
 test.serial('GET /getImageExtracts?sceneName=bathroom&imageQuality=10&horizontalExtractCount=5&verticalExtractCount=2', async t => {
   const res = await request(t.context.server)
     .get(`${apiPrefix}/getImageExtracts?sceneName=bathroom&imageQuality=10&horizontalExtractCount=5&verticalExtractCount=2`)