From ae0c67aa721fdf23cd46a6f09d07ac331a09d876 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Mon, 30 Nov 2020 10:15:01 +0000 Subject: [PATCH 01/36] Detect file type inside tiff, do not assume jpg or png --- .../gu/mediaservice/lib/imaging/ImageOperations.scala | 9 +++++---- image-loader/app/model/ImageUpload.scala | 8 ++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala index bdbf64741e..83adeec193 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala @@ -131,14 +131,14 @@ class ImageOperations(playPath: String) extends GridLogging { } yield outputFile } - def transformImage(sourceFile: File, sourceMimeType: Option[MimeType], tempDir: File): Future[File] = { + def transformImage(sourceFile: File, sourceMimeType: Option[MimeType], tempDir: File): Future[(File, String)] = { for { outputFile <- createTempFile(s"transformed-", ".png", tempDir) transformSource = addImage(sourceFile) addOutput = addDestImage(transformSource)(outputFile) _ <- runConvertCmd(addOutput, useImageMagick = sourceMimeType.contains(Tiff)) - _ <- checkForOutputFileChange(outputFile) - } yield outputFile + extension <- checkForOutputFileChange(outputFile) + } yield (outputFile, extension) } // When a layered tiff is unpacked, the temp file (blah.something) is moved @@ -147,7 +147,7 @@ class ImageOperations(playPath: String) extends GridLogging { // As the file has been renamed, the file object still exists, but has the wrong name // We will need to put it back where it is expected to be found, and clean up the other // files. - private def checkForOutputFileChange(f: File): Future[Unit] = Future { + private def checkForOutputFileChange(f: File): Future[String] = Future { val fileBits = f.getAbsolutePath.split("\\.").toList val mainPart = fileBits.dropRight(1).mkString(".") val extension = fileBits.last @@ -160,6 +160,7 @@ class ImageOperations(playPath: String) extends GridLogging { // Tidy up any other files (blah-1,2,3 etc will be created for each subsequent layer) cleanUpLayerFiles(mainPart, extension, 1) } + fileBits.last } @scala.annotation.tailrec diff --git a/image-loader/app/model/ImageUpload.scala b/image-loader/app/model/ImageUpload.scala index cf4d0ccb8b..702b795087 100644 --- a/image-loader/app/model/ImageUpload.scala +++ b/image-loader/app/model/ImageUpload.scala @@ -279,6 +279,10 @@ object Uploader extends GridLogging { val sourceDimensionsFuture = FileMetadataReader.dimensions(uploadedFile, uploadRequest.mimeType) // if the file needs pre-processing into a supported type of file, do it now and create the new upload request. + + // we don't create a new upload request, we just override the old one. This is the bug! + + createOptimisedFileFuture(uploadRequest, deps).flatMap(uploadRequest => { val sourceStoreFuture = storeOrProjectOriginalFile(uploadRequest) val toOptimiseFile = uploadRequest.tempFile @@ -406,8 +410,8 @@ object Uploader extends GridLogging { transformedImage <- imageOps.transformImage(uploadRequest.tempFile, uploadRequest.mimeType, config.tempDir) } yield uploadRequest // This file has been converted. - .copy(mimeType = Some(Jpeg)) - .copy(tempFile = transformedImage) + .copy(mimeType = Some(MimeType(transformedImage._2))) + .copy(tempFile = transformedImage._1) case _ => Future.successful(uploadRequest) } From e8a7bd4da24a1e32388c826ef1d933aaa9f7bee4 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Mon, 30 Nov 2020 14:38:02 +0000 Subject: [PATCH 02/36] First draft at testable image handling --- image-loader/app/model/ImageUpload.scala | 128 ++++++++---------- .../test/scala/model/ImageUploadTest.scala | 26 ++++ 2 files changed, 83 insertions(+), 71 deletions(-) create mode 100644 image-loader/test/scala/model/ImageUploadTest.scala diff --git a/image-loader/app/model/ImageUpload.scala b/image-loader/app/model/ImageUpload.scala index 702b795087..d054dbd890 100644 --- a/image-loader/app/model/ImageUpload.scala +++ b/image-loader/app/model/ImageUpload.scala @@ -26,10 +26,28 @@ import play.api.libs.json.{JsObject, Json} import scala.concurrent.{ExecutionContext, Future} import scala.sys.process._ -case class OptimisedPng(optimisedFileStoreFuture: Future[Option[S3Object]], isPng24: Boolean, - optimisedTempFile: Option[File]) +case class OptimisedPng(optimisedFileStoreFuture: Future[S3Object], + optimisedTempFile: File) + +trait OptimisedPngOps { + def toOptimisedFile(file: File, uploadRequest: UploadRequest, config: ImageUploadOpsCfg) + (implicit logMarker: LogMarker): File + def isTransformedFilePath(filePath: String): Boolean + def shouldOptimise(mimeType: Option[MimeType], fileMetadata: FileMetadata): Boolean +} -case object OptimisedPng { +object OptimisedPngQuantOps extends OptimisedPngOps { + + def toOptimisedFile(file: File, uploadRequest: UploadRequest, config: ImageUploadOpsCfg) + (implicit logMarker: LogMarker): File = { + val optimisedFilePath = config.tempDir.getAbsolutePath + "/optimisedpng - " + uploadRequest.imageId + ".png" + Stopwatch("pngquant") { + Seq("pngquant", "--quality", "1-85", file.getAbsolutePath, "--output", optimisedFilePath).! + } + new File(optimisedFilePath) + } + + def isTransformedFilePath(filePath: String): Boolean = filePath.contains("transformed-") def shouldOptimise(mimeType: Option[MimeType], fileMetadata: FileMetadata): Boolean = mimeType match { @@ -44,42 +62,6 @@ case object OptimisedPng { } } -object OptimisedPngOps { - - def build(file: File, - uploadRequest: UploadRequest, - fileMetadata: FileMetadata, - config: ImageUploadOpsCfg, - storeOrProject: (UploadRequest, File) => Future[S3Object]) - (implicit ec: ExecutionContext, logMarker: LogMarker): OptimisedPng = { - - val result = if (!OptimisedPng.shouldOptimise(uploadRequest.mimeType, fileMetadata)) { - OptimisedPng(Future(None), isPng24 = false, None) - } else { - val optimisedFile: File = toOptimisedFile(file, uploadRequest, config) - val pngStoreFuture: Future[Option[S3Object]] = Some(storeOrProject(uploadRequest, optimisedFile)) - .map(result => result.map(Option(_))) - .getOrElse(Future.successful(None)) - if (isTransformedFilePath(file.getAbsolutePath)) - file.delete - OptimisedPng(pngStoreFuture, isPng24 = true, Some(optimisedFile)) - } - result - } - - private def toOptimisedFile(file: File, uploadRequest: UploadRequest, config: ImageUploadOpsCfg) - (implicit logMarker: LogMarker): File = { - val optimisedFilePath = config.tempDir.getAbsolutePath + "/optimisedpng - " + uploadRequest.imageId + ".png" - Stopwatch("pngquant") { - Seq("pngquant", "--quality", "1-85", file.getAbsolutePath, "--output", optimisedFilePath).! - } - new File(optimisedFilePath) - } - - private def isTransformedFilePath(filePath: String): Boolean = filePath.contains("transformed-") - -} - case class ImageUpload(uploadRequest: UploadRequest, image: Image) case object ImageUpload { @@ -254,6 +236,7 @@ object Uploader extends GridLogging { storeOrProjectOriginalFile, storeOrProjectThumbFile, storeOrProjectOptimisedPNG, + OptimisedPngQuantOps, uploadRequest, deps, uploadedFile, @@ -262,44 +245,51 @@ object Uploader extends GridLogging { }) } - private def uploadAndStoreImage(config: ImageUploadOpsCfg, - storeOrProjectOriginalFile: UploadRequest => Future[S3Object], - storeOrProjectThumbFile: (UploadRequest, File) => Future[S3Object], - storeOrProjectOptimisedPNG: (UploadRequest, File) => Future[S3Object], - uploadRequest: UploadRequest, - deps: ImageUploadOpsDependencies, - uploadedFile: File, - fileMetadataFuture: Future[FileMetadata], - fileMetadata: FileMetadata) + private[model] def uploadAndStoreImage(config: ImageUploadOpsCfg, + storeOrProjectOriginalFile: UploadRequest => Future[S3Object], + storeOrProjectThumbFile: (UploadRequest, File) => Future[S3Object], + storeOrProjectOptimisedPNG: (UploadRequest, File) => Future[S3Object], + pngOptimiser: OptimisedPngOps, + originalUploadRequest: UploadRequest, + deps: ImageUploadOpsDependencies, + uploadedFile: File, + fileMetadataFuture: Future[FileMetadata], + fileMetadata: FileMetadata) (implicit ec: ExecutionContext, logMarker: LogMarker) = { logger.info("Have read file metadata") logger.info("stored source file") // FIXME: pass mimeType val colourModelFuture = ImageOperations.identifyColourModel(uploadedFile, Jpeg) - val sourceDimensionsFuture = FileMetadataReader.dimensions(uploadedFile, uploadRequest.mimeType) + val sourceDimensionsFuture = FileMetadataReader.dimensions(uploadedFile, originalUploadRequest.mimeType) // if the file needs pre-processing into a supported type of file, do it now and create the new upload request. // we don't create a new upload request, we just override the old one. This is the bug! +// We have three actions to take. +// 1) storeOrProjectOriginalFile - takes original upload request +// 2) storeOrProjectThumbFile - takes a new upload request +// 3) storeOrProjectOptimisedPNG - takes a new upload request, possibly for the extracted tiff file + + val sourceStoreFuture = storeOrProjectOriginalFile(originalUploadRequest) - createOptimisedFileFuture(uploadRequest, deps).flatMap(uploadRequest => { - val sourceStoreFuture = storeOrProjectOriginalFile(uploadRequest) - val toOptimiseFile = uploadRequest.tempFile - val thumbFuture = createThumbFuture(fileMetadataFuture, colourModelFuture, uploadRequest, deps) + createOptimisedFileFuture(originalUploadRequest, deps).flatMap(optimisedUploadRequest => { + val thumbFuture = createThumbFuture(fileMetadataFuture, colourModelFuture, optimisedUploadRequest, deps) logger.info("thumbnail created") - val optimisedPng = OptimisedPngOps.build( - toOptimiseFile, - uploadRequest, - fileMetadata, - config, - storeOrProjectOptimisedPNG)(ec, logMarker) - logger.info(s"optimised image ($toOptimiseFile) created") + val optimisedPng: Option[OptimisedPng] = if (pngOptimiser.shouldOptimise(optimisedUploadRequest.mimeType, fileMetadata)) { + val optimisedFile: File = pngOptimiser.toOptimisedFile(optimisedUploadRequest.tempFile, optimisedUploadRequest, config) + val pngStoreFuture: Future[S3Object] = + storeOrProjectOptimisedPNG(optimisedUploadRequest, optimisedFile) + .andThen{case _ => optimisedFile.delete()} + Some(OptimisedPng(pngStoreFuture, optimisedFile)) + } else { + None + } bracket(thumbFuture)(_.delete) { thumb => // Run the operations in parallel - val thumbStoreFuture = storeOrProjectThumbFile(uploadRequest, thumb) + val thumbStoreFuture = storeOrProjectThumbFile(optimisedUploadRequest, thumb) val thumbDimensionsFuture = FileMetadataReader.dimensions(thumb, Some(Jpeg)) val finalImage = toFinalImage( @@ -310,11 +300,11 @@ object Uploader extends GridLogging { fileMetadataFuture, colourModelFuture, optimisedPng, - uploadRequest + optimisedUploadRequest ) logger.info(s"Deleting temp file ${uploadedFile.getAbsolutePath}") uploadedFile.delete() - toOptimiseFile.delete() + optimisedUploadRequest.tempFile.delete() finalImage } @@ -339,14 +329,14 @@ object Uploader extends GridLogging { thumbDimensionsFuture: Future[Option[Dimensions]], fileMetadataFuture: Future[FileMetadata], colourModelFuture: Future[Option[String]], - optimisedPng: OptimisedPng, + optimisedPng: Option[OptimisedPng], uploadRequest: UploadRequest) (implicit ec: ExecutionContext, logMarker: LogMarker): Future[Image] = { logger.info("Starting image ops") for { s3Source <- sourceStoreFuture s3Thumb <- thumbStoreFuture - s3PngOption <- optimisedPng.optimisedFileStoreFuture + s3PngOption <- optimisedPng.map(_.optimisedFileStoreFuture.map(a => Some(a))).getOrElse(Future.successful(None)) sourceDimensions <- sourceDimensionsFuture thumbDimensions <- thumbDimensionsFuture fileMetadata <- fileMetadataFuture @@ -358,11 +348,7 @@ object Uploader extends GridLogging { sourceAsset = Asset.fromS3Object(s3Source, sourceDimensions) thumbAsset = Asset.fromS3Object(s3Thumb, thumbDimensions) - pngAsset = if (optimisedPng.isPng24) - Some(Asset.fromS3Object(s3PngOption.get, sourceDimensions)) - else - None - + pngAsset = s3PngOption.map (Asset.fromS3Object(_, sourceDimensions)) baseImage = ImageUpload.createImage(uploadRequest, sourceAsset, thumbAsset, pngAsset, fullFileMetadata, cleanMetadata) processedImage = SupplierProcessors.process(baseImage) @@ -373,7 +359,7 @@ object Uploader extends GridLogging { originalUsageRights = processedImage.usageRights ) } yield { - if (optimisedPng.isPng24) optimisedPng.optimisedTempFile.get.delete + optimisedPng.foreach(_.optimisedTempFile.delete) logger.info("Ending image ops") finalImage } diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala new file mode 100644 index 0000000000..6a27c6cd4a --- /dev/null +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -0,0 +1,26 @@ +package scala.model + +import java.io.File +import java.net.URI +import java.util.UUID + +import com.amazonaws.services.s3.AmazonS3 +import com.gu.mediaservice.lib.imaging.ImageOperations +import com.gu.mediaservice.lib.logging.RequestLoggingContext +import com.gu.mediaservice.model._ +import com.gu.mediaservice.model.leases.LeasesByMedia +import lib.DigestedFile +import org.joda.time.{DateTime, DateTimeZone} +import org.scalatest.concurrent.ScalaFutures +import org.scalatest.mockito.MockitoSugar +import org.scalatest.time.{Millis, Span} +import org.scalatest.{FunSuite, Matchers} +import play.api.libs.json.{JsArray, JsString} +import test.lib.ResourceHelpers + +class ImageUploadTest extends FunSuite with Matchers with ScalaFutures with MockitoSugar { + test("do something") { + fail("failure you are, says Yoda") + } +} + From 601ab49a089e5737363616b48f9ec3713e5c7f3d Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Mon, 30 Nov 2020 15:02:49 +0000 Subject: [PATCH 03/36] First draft at testable image handling --- image-loader/app/model/ImageUpload.scala | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/image-loader/app/model/ImageUpload.scala b/image-loader/app/model/ImageUpload.scala index d054dbd890..499dfb0805 100644 --- a/image-loader/app/model/ImageUpload.scala +++ b/image-loader/app/model/ImageUpload.scala @@ -225,9 +225,8 @@ object Uploader extends GridLogging { import deps._ logger.info("Starting image ops") - val uploadedFile = uploadRequest.tempFile - val fileMetadataFuture = toFileMetadata(uploadedFile, uploadRequest.imageId, uploadRequest.mimeType) + val fileMetadataFuture = toFileMetadata(uploadRequest.tempFile, uploadRequest.imageId, uploadRequest.mimeType) logger.info("Have read file headers") @@ -239,7 +238,6 @@ object Uploader extends GridLogging { OptimisedPngQuantOps, uploadRequest, deps, - uploadedFile, fileMetadataFuture, fileMetadata)(ec, addLogMarkers(fileMetadata.toLogMarker)) }) @@ -252,15 +250,14 @@ object Uploader extends GridLogging { pngOptimiser: OptimisedPngOps, originalUploadRequest: UploadRequest, deps: ImageUploadOpsDependencies, - uploadedFile: File, fileMetadataFuture: Future[FileMetadata], fileMetadata: FileMetadata) (implicit ec: ExecutionContext, logMarker: LogMarker) = { logger.info("Have read file metadata") logger.info("stored source file") // FIXME: pass mimeType - val colourModelFuture = ImageOperations.identifyColourModel(uploadedFile, Jpeg) - val sourceDimensionsFuture = FileMetadataReader.dimensions(uploadedFile, originalUploadRequest.mimeType) + val colourModelFuture = ImageOperations.identifyColourModel(originalUploadRequest.tempFile, Jpeg) + val sourceDimensionsFuture = FileMetadataReader.dimensions(originalUploadRequest.tempFile, originalUploadRequest.mimeType) // if the file needs pre-processing into a supported type of file, do it now and create the new upload request. @@ -302,8 +299,8 @@ object Uploader extends GridLogging { optimisedPng, optimisedUploadRequest ) - logger.info(s"Deleting temp file ${uploadedFile.getAbsolutePath}") - uploadedFile.delete() + logger.info(s"Deleting temp file ${originalUploadRequest.tempFile.getAbsolutePath}") + originalUploadRequest.tempFile.delete() optimisedUploadRequest.tempFile.delete() finalImage From 9969b7dd21af4b74c3480d38faff3fb1ed60b6b1 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Mon, 30 Nov 2020 15:06:44 +0000 Subject: [PATCH 04/36] First draft at testable image handling --- image-loader/app/model/ImageUpload.scala | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/image-loader/app/model/ImageUpload.scala b/image-loader/app/model/ImageUpload.scala index 499dfb0805..1cc29e5de7 100644 --- a/image-loader/app/model/ImageUpload.scala +++ b/image-loader/app/model/ImageUpload.scala @@ -238,7 +238,6 @@ object Uploader extends GridLogging { OptimisedPngQuantOps, uploadRequest, deps, - fileMetadataFuture, fileMetadata)(ec, addLogMarkers(fileMetadata.toLogMarker)) }) } @@ -250,7 +249,6 @@ object Uploader extends GridLogging { pngOptimiser: OptimisedPngOps, originalUploadRequest: UploadRequest, deps: ImageUploadOpsDependencies, - fileMetadataFuture: Future[FileMetadata], fileMetadata: FileMetadata) (implicit ec: ExecutionContext, logMarker: LogMarker) = { logger.info("Have read file metadata") @@ -271,7 +269,7 @@ object Uploader extends GridLogging { val sourceStoreFuture = storeOrProjectOriginalFile(originalUploadRequest) createOptimisedFileFuture(originalUploadRequest, deps).flatMap(optimisedUploadRequest => { - val thumbFuture = createThumbFuture(fileMetadataFuture, colourModelFuture, optimisedUploadRequest, deps) + val thumbFuture = createThumbFuture(fileMetadata, colourModelFuture, optimisedUploadRequest, deps) logger.info("thumbnail created") val optimisedPng: Option[OptimisedPng] = if (pngOptimiser.shouldOptimise(optimisedUploadRequest.mimeType, fileMetadata)) { @@ -369,13 +367,12 @@ object Uploader extends GridLogging { } } - private def createThumbFuture(fileMetadataFuture: Future[FileMetadata], + private def createThumbFuture(fileMetadata: FileMetadata, colourModelFuture: Future[Option[String]], uploadRequest: UploadRequest, deps: ImageUploadOpsDependencies)(implicit ec: ExecutionContext) = { import deps._ for { - fileMetadata <- fileMetadataFuture colourModel <- colourModelFuture iccColourSpace = FileMetadataHelper.normalisedIccColourSpace(fileMetadata) thumb <- imageOps From 27e7c2fb062a0575e4ad336468419c3ab0833612 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Mon, 30 Nov 2020 15:07:50 +0000 Subject: [PATCH 05/36] First draft at testable image handling --- image-loader/app/model/ImageUpload.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/image-loader/app/model/ImageUpload.scala b/image-loader/app/model/ImageUpload.scala index 1cc29e5de7..38a123086d 100644 --- a/image-loader/app/model/ImageUpload.scala +++ b/image-loader/app/model/ImageUpload.scala @@ -292,7 +292,7 @@ object Uploader extends GridLogging { thumbStoreFuture, sourceDimensionsFuture, thumbDimensionsFuture, - fileMetadataFuture, + fileMetadata, colourModelFuture, optimisedPng, optimisedUploadRequest @@ -322,7 +322,7 @@ object Uploader extends GridLogging { thumbStoreFuture: Future[S3Object], sourceDimensionsFuture: Future[Option[Dimensions]], thumbDimensionsFuture: Future[Option[Dimensions]], - fileMetadataFuture: Future[FileMetadata], + fileMetadata: FileMetadata, colourModelFuture: Future[Option[String]], optimisedPng: Option[OptimisedPng], uploadRequest: UploadRequest) @@ -334,7 +334,6 @@ object Uploader extends GridLogging { s3PngOption <- optimisedPng.map(_.optimisedFileStoreFuture.map(a => Some(a))).getOrElse(Future.successful(None)) sourceDimensions <- sourceDimensionsFuture thumbDimensions <- thumbDimensionsFuture - fileMetadata <- fileMetadataFuture colourModel <- colourModelFuture fullFileMetadata = fileMetadata.copy(colourModel = colourModel) metadata = ImageMetadataConverter.fromFileMetadata(fullFileMetadata) From ba28cec0fffd761884bdac7d9b3024248fc1736c Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Mon, 30 Nov 2020 16:20:09 +0000 Subject: [PATCH 06/36] First attempt at a mocked test --- image-loader/app/model/ImageUpload.scala | 7 +- .../test/scala/model/ImageUploadTest.scala | 83 +++++++++++++++---- 2 files changed, 73 insertions(+), 17 deletions(-) diff --git a/image-loader/app/model/ImageUpload.scala b/image-loader/app/model/ImageUpload.scala index 38a123086d..8dde3a8edc 100644 --- a/image-loader/app/model/ImageUpload.scala +++ b/image-loader/app/model/ImageUpload.scala @@ -263,12 +263,13 @@ object Uploader extends GridLogging { // We have three actions to take. // 1) storeOrProjectOriginalFile - takes original upload request -// 2) storeOrProjectThumbFile - takes a new upload request -// 3) storeOrProjectOptimisedPNG - takes a new upload request, possibly for the extracted tiff file +// 2) storeOrProjectOptimisedPNG - takes a new upload request, possibly for the extracted tiff file +// 3) storeOrProjectThumbFile - takes a new upload request val sourceStoreFuture = storeOrProjectOriginalFile(originalUploadRequest) - createOptimisedFileFuture(originalUploadRequest, deps).flatMap(optimisedUploadRequest => { + createOptimisedFileFuture(originalUploadRequest, deps) + .flatMap(optimisedUploadRequest => { val thumbFuture = createThumbFuture(fileMetadata, colourModelFuture, optimisedUploadRequest, deps) logger.info("thumbnail created") diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index 6a27c6cd4a..03e4de2489 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -1,26 +1,81 @@ -package scala.model +package model import java.io.File -import java.net.URI import java.util.UUID -import com.amazonaws.services.s3.AmazonS3 +import com.gu.mediaservice.lib.aws.S3Object import com.gu.mediaservice.lib.imaging.ImageOperations -import com.gu.mediaservice.lib.logging.RequestLoggingContext -import com.gu.mediaservice.model._ -import com.gu.mediaservice.model.leases.LeasesByMedia -import lib.DigestedFile -import org.joda.time.{DateTime, DateTimeZone} +import com.gu.mediaservice.lib.logging.LogMarker +import com.gu.mediaservice.model.{FileMetadata, UploadInfo} +import org.joda.time.DateTime +import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito.when import org.scalatest.concurrent.ScalaFutures import org.scalatest.mockito.MockitoSugar -import org.scalatest.time.{Millis, Span} -import org.scalatest.{FunSuite, Matchers} -import play.api.libs.json.{JsArray, JsString} -import test.lib.ResourceHelpers +import org.scalatest.{AsyncFlatSpec, AsyncFunSuite, FunSuite, FunSuiteLike, Matchers} -class ImageUploadTest extends FunSuite with Matchers with ScalaFutures with MockitoSugar { +import scala.concurrent.{ExecutionContext, Future} +import ExecutionContext.Implicits.global + +class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { test("do something") { - fail("failure you are, says Yoda") + class MockLogMarker extends LogMarker { + override def markerContents: Map[String, Any] = ??? + } + implicit val logMarker = new MockLogMarker(); + + val mockConfig = mock[ImageUploadOpsCfg] + + val mockStoreOrProjectOriginalFileResult = mock[S3Object] + + val mockS3Object = mock[S3Object] + def storeOrProjectOriginalFile: UploadRequest => Future[S3Object] = { + _ => Future.successful(mockS3Object) + } + def storeOrProjectThumbFile: (UploadRequest, File) => Future[S3Object] = { + (_, _) => Future.successful(mockS3Object) + } + def storeOrProjectOptimisedPNG: (UploadRequest, File) => Future[S3Object] = { + (_, _) => Future.successful(mockS3Object) + } + val imageOps: ImageOperations = new ImageOperations("") + + val mockDependencies = ImageUploadOpsDependencies( + mockConfig, + imageOps, + storeOrProjectOriginalFile, + storeOrProjectThumbFile, + storeOrProjectOptimisedPNG) + + val mockOptimisedPngOps = mock[OptimisedPngOps] + + val uuid = UUID.randomUUID() + val tempFile = java.io.File.createTempFile("aaaa", "b") + val ul = UploadInfo(None) + val uploadRequest = new UploadRequest( + uuid, + "imageId": String, + tempFile, //: File, + None, //mimeType: Option[MimeType], + DateTime.now(), //uploadTime: DateTime, + "uploadedBy", //: String, + Map(), // identifiers: Map[String, String], + ul //uploadInfo: UploadInfo + ) + + val fileMetadata = FileMetadata() + + val futureImage = Uploader.uploadAndStoreImage(mockConfig, + mockDependencies.storeOrProjectOriginalFile, + mockDependencies.storeOrProjectThumbFile, + mockDependencies.storeOrProjectOptimisedPNG, + mockOptimisedPngOps, + uploadRequest, //originalUploadRequest: UploadRequest, + mockDependencies, //deps: ImageUploadOpsDependencies, + fileMetadata)(global, logMarker) //fileMetadata: FileMetadata) + + futureImage.map({_ => fail()})(global) + } } From 54b2d9b2418a62b05f78eb45c6b63a6f2130c3b1 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Tue, 1 Dec 2020 09:24:12 +0000 Subject: [PATCH 07/36] Add basic README on TIFFs --- docs/06-objects-of-interest/06.01-tiffs.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 docs/06-objects-of-interest/06.01-tiffs.md diff --git a/docs/06-objects-of-interest/06.01-tiffs.md b/docs/06-objects-of-interest/06.01-tiffs.md new file mode 100644 index 0000000000..ffdfda3108 --- /dev/null +++ b/docs/06-objects-of-interest/06.01-tiffs.md @@ -0,0 +1,18 @@ +# TIFF files + +Tiff files have special handling for importing. + +Like all files, we upload the original, but create an optimised and thumbnail +png version. + +For TIFF files, these pngs derive from the first image file found inside the +container format, which, in a file named `xxx.tif` will explode out as +`xxx.png` or `xxx.jpg`. + +However, there is additional complexity with tiff files which contain layered +images. Specifically, the layer files will explode as `xxx-n.jpg` or +`xxx-n.png` where `n` is a numeric index. + +Our code looks for this special case (see `ImageOperations.checkForOutputFileChange`) +and simply moves the layer file to the expected location. + From 43864896f71470b3151957144898c6254f10ea99 Mon Sep 17 00:00:00 2001 From: Jonathon Herbert Date: Tue, 1 Dec 2020 09:25:59 +0000 Subject: [PATCH 08/36] Failing test --- image-loader/app/model/ImageUpload.scala | 3 +- image-loader/test/resources/rubbish.jpg | Bin 0 -> 134789 bytes image-loader/test/resources/srgb.icc | Bin 0 -> 3144 bytes .../test/scala/model/ImageUploadTest.scala | 65 ++++++++++-------- 4 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 image-loader/test/resources/rubbish.jpg create mode 100644 image-loader/test/resources/srgb.icc diff --git a/image-loader/app/model/ImageUpload.scala b/image-loader/app/model/ImageUpload.scala index 8dde3a8edc..fc48f23742 100644 --- a/image-loader/app/model/ImageUpload.scala +++ b/image-loader/app/model/ImageUpload.scala @@ -268,8 +268,7 @@ object Uploader extends GridLogging { val sourceStoreFuture = storeOrProjectOriginalFile(originalUploadRequest) - createOptimisedFileFuture(originalUploadRequest, deps) - .flatMap(optimisedUploadRequest => { + createOptimisedFileFuture(originalUploadRequest, deps).flatMap(optimisedUploadRequest => { val thumbFuture = createThumbFuture(fileMetadata, colourModelFuture, optimisedUploadRequest, deps) logger.info("thumbnail created") diff --git a/image-loader/test/resources/rubbish.jpg b/image-loader/test/resources/rubbish.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3bfa4367b11fe44ed368180bf227c61c5485a9c8 GIT binary patch literal 134789 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�Fts~_!R})A*g&uYCg%J68}B`g)zg76<^BYJ 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 BDfR#W literal 0 HcmV?d00001 diff --git a/image-loader/test/resources/srgb.icc b/image-loader/test/resources/srgb.icc new file mode 100644 index 0000000000000000000000000000000000000000..7f9d18d097d1bcccb32e6d5743ac4af593170b6f GIT binary patch literal 3144 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 L{PK7vZD!`*_k{EN literal 0 HcmV?d00001 diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index 03e4de2489..5cda863edb 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -1,34 +1,34 @@ package model import java.io.File +import java.net.URI import java.util.UUID -import com.gu.mediaservice.lib.aws.S3Object +import com.gu.mediaservice.lib.aws.{S3Metadata, S3Object, S3ObjectMetadata} import com.gu.mediaservice.lib.imaging.ImageOperations import com.gu.mediaservice.lib.logging.LogMarker import com.gu.mediaservice.model.{FileMetadata, UploadInfo} import org.joda.time.DateTime -import org.mockito.ArgumentMatchers.any -import org.mockito.Mockito.when -import org.scalatest.concurrent.ScalaFutures import org.scalatest.mockito.MockitoSugar -import org.scalatest.{AsyncFlatSpec, AsyncFunSuite, FunSuite, FunSuiteLike, Matchers} +import org.scalatest.{AsyncFunSuite, Matchers} +import test.lib.ResourceHelpers import scala.concurrent.{ExecutionContext, Future} -import ExecutionContext.Implicits.global +import scala.util.{Failure, Success} class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { + implicit val ec = ExecutionContext.Implicits.global + test("do something") { class MockLogMarker extends LogMarker { override def markerContents: Map[String, Any] = ??? } implicit val logMarker = new MockLogMarker(); - val mockConfig = mock[ImageUploadOpsCfg] - - val mockStoreOrProjectOriginalFileResult = mock[S3Object] + val mockConfig = ImageUploadOpsCfg(new File("/tmp"), 256, 85d, Nil, "img-bucket", "thumb-bucket") - val mockS3Object = mock[S3Object] + val mockS3Meta = S3Metadata(Map.empty, S3ObjectMetadata(None, None, None)) + val mockS3Object = S3Object(new URI("innernets.com"), 12345, mockS3Meta) def storeOrProjectOriginalFile: UploadRequest => Future[S3Object] = { _ => Future.successful(mockS3Object) } @@ -38,44 +38,55 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { def storeOrProjectOptimisedPNG: (UploadRequest, File) => Future[S3Object] = { (_, _) => Future.successful(mockS3Object) } - val imageOps: ImageOperations = new ImageOperations("") + + /** + * @todo: I flailed about until I found a path that worked, but + * what arcane magic System.getProperty relies upon, and exactly + * _how_ it will break in CI, I do not know + */ + val imageOps: ImageOperations = new ImageOperations(System.getProperty("user.dir")) val mockDependencies = ImageUploadOpsDependencies( mockConfig, imageOps, storeOrProjectOriginalFile, storeOrProjectThumbFile, - storeOrProjectOptimisedPNG) + storeOrProjectOptimisedPNG + ) val mockOptimisedPngOps = mock[OptimisedPngOps] val uuid = UUID.randomUUID() - val tempFile = java.io.File.createTempFile("aaaa", "b") + val tempFile = ResourceHelpers.fileAt("rubbish.jpg") val ul = UploadInfo(None) - val uploadRequest = new UploadRequest( - uuid, - "imageId": String, - tempFile, //: File, - None, //mimeType: Option[MimeType], - DateTime.now(), //uploadTime: DateTime, - "uploadedBy", //: String, - Map(), // identifiers: Map[String, String], - ul //uploadInfo: UploadInfo - ) + val uploadRequest = UploadRequest( + uuid, + "imageId": String, + tempFile, + None, + DateTime.now(), + "uploadedBy", + Map(), + ul + ) val fileMetadata = FileMetadata() - val futureImage = Uploader.uploadAndStoreImage(mockConfig, + val futureImage = Uploader.uploadAndStoreImage( + mockConfig, mockDependencies.storeOrProjectOriginalFile, mockDependencies.storeOrProjectThumbFile, mockDependencies.storeOrProjectOptimisedPNG, mockOptimisedPngOps, uploadRequest, //originalUploadRequest: UploadRequest, mockDependencies, //deps: ImageUploadOpsDependencies, - fileMetadata)(global, logMarker) //fileMetadata: FileMetadata) - - futureImage.map({_ => fail()})(global) + fileMetadata + ) + futureImage transformWith { + case Success(_) => fail("Do summat 'ere") + case Failure(e) => e.getMessage shouldBe "gnar" + } } } From c6190691e7df04edfd2236c7cf392d098c97bc35 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Tue, 1 Dec 2020 09:49:53 +0000 Subject: [PATCH 09/36] Remove all information which does not change from test to specific test --- .../test/scala/model/ImageUploadTest.scala | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index 5cda863edb..11358e9bc4 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -18,17 +18,28 @@ import scala.util.{Failure, Success} class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { implicit val ec = ExecutionContext.Implicits.global + class MockLogMarker extends LogMarker { + override def markerContents: Map[String, Any] = ??? + } + implicit val logMarker = new MockLogMarker(); + val mockConfig = ImageUploadOpsCfg(new File("/tmp"), 256, 85d, Nil, "img-bucket", "thumb-bucket") - test("do something") { - class MockLogMarker extends LogMarker { - override def markerContents: Map[String, Any] = ??? - } - implicit val logMarker = new MockLogMarker(); + /** + * @todo: I flailed about until I found a path that worked, but + * what arcane magic System.getProperty relies upon, and exactly + * _how_ it will break in CI, I do not know + */ + val imageOps: ImageOperations = new ImageOperations(System.getProperty("user.dir")) - val mockConfig = ImageUploadOpsCfg(new File("/tmp"), 256, 85d, Nil, "img-bucket", "thumb-bucket") + val mockOptimisedPngOps = mock[OptimisedPngOps] + + test("do something") { + val imageFileName = "rubbish.jpg" + val uuid = UUID.randomUUID() val mockS3Meta = S3Metadata(Map.empty, S3ObjectMetadata(None, None, None)) val mockS3Object = S3Object(new URI("innernets.com"), 12345, mockS3Meta) + def storeOrProjectOriginalFile: UploadRequest => Future[S3Object] = { _ => Future.successful(mockS3Object) } @@ -39,13 +50,6 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { (_, _) => Future.successful(mockS3Object) } - /** - * @todo: I flailed about until I found a path that worked, but - * what arcane magic System.getProperty relies upon, and exactly - * _how_ it will break in CI, I do not know - */ - val imageOps: ImageOperations = new ImageOperations(System.getProperty("user.dir")) - val mockDependencies = ImageUploadOpsDependencies( mockConfig, imageOps, @@ -54,14 +58,11 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { storeOrProjectOptimisedPNG ) - val mockOptimisedPngOps = mock[OptimisedPngOps] - - val uuid = UUID.randomUUID() - val tempFile = ResourceHelpers.fileAt("rubbish.jpg") + val tempFile = ResourceHelpers.fileAt(imageFileName) val ul = UploadInfo(None) val uploadRequest = UploadRequest( uuid, - "imageId": String, + "imageId", tempFile, None, DateTime.now(), @@ -70,22 +71,24 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { ul ) - val fileMetadata = FileMetadata() - val futureImage = Uploader.uploadAndStoreImage( mockConfig, mockDependencies.storeOrProjectOriginalFile, mockDependencies.storeOrProjectThumbFile, mockDependencies.storeOrProjectOptimisedPNG, mockOptimisedPngOps, - uploadRequest, //originalUploadRequest: UploadRequest, - mockDependencies, //deps: ImageUploadOpsDependencies, - fileMetadata + uploadRequest, + mockDependencies, + FileMetadata() ) futureImage transformWith { - case Success(_) => fail("Do summat 'ere") - case Failure(e) => e.getMessage shouldBe "gnar" + case Success(_) => + // Assertions or fails + fail("Do summat 'ere") + case Failure(e) => + // Assertions or fail + e.getMessage shouldBe "gnar" } } } From d62b4f57bcb6bdb965bb72f4cefad825a6df9210 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Wed, 2 Dec 2020 08:27:40 +0000 Subject: [PATCH 10/36] Add test resources - various png images with or without true colour --- image-loader/test/resources/IndexedColor.png | Bin 0 -> 1120 bytes .../resources/basn2c16_TrueColor_16bit.png | Bin 0 -> 302 bytes .../bgan6a16_TrueColorWithAlpha_16bit.png | Bin 0 -> 3435 bytes image-loader/test/resources/tiff_8bpc_flat.tif | Bin 0 -> 102004 bytes .../tiff_8bpc_layered_withTransparency.tif | Bin 0 -> 183416 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 image-loader/test/resources/IndexedColor.png create mode 100644 image-loader/test/resources/basn2c16_TrueColor_16bit.png create mode 100644 image-loader/test/resources/bgan6a16_TrueColorWithAlpha_16bit.png create mode 100644 image-loader/test/resources/tiff_8bpc_flat.tif create mode 100644 image-loader/test/resources/tiff_8bpc_layered_withTransparency.tif diff --git a/image-loader/test/resources/IndexedColor.png b/image-loader/test/resources/IndexedColor.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6cf9e44c2eab2ce78201d1ee1d1486a8cb5299 GIT binary patch literal 1120 zcmWku4^Y!}6#oo1Y``!2Sxj%puK^cT1U{Wq4vTxr%@7=xkx%b}Zz3+W1x20{O z0)>G9sFcl$w}=+~f1mOvQqfv9NEBC_q)Yy7|l5KCMClh-|M~BU3qk+gs zuq+xH8dMY%3e?q+Q|ET0rl!VXvE)*ytgO^%V7H@20E5B6QUuTHbh@@S6ciL_wb}t8 zoK9dKn8PRowOXy!0xqajDhxxZRJs`?Bmi~@C<-=YP~h`{I-mxyKq{3=$P!D$VxSnM zr4aHUjsaMRiAjfE0b*ie^c13^qM#-L;bZ_Jg`fZ#A37Z%K>{5^(=(P&igNu8y==xsxr6;_7N%gxPgLQ^9e=OdAwolVkW7MYouE*Go< z!qP$_3V4JF%rx|RU;ujPS+F|j6r}HMa4?X|BmErUQHV8BoUN+KcE0t|+SNk3=`l-+LUgU za&`2~;!m>F&Z~K~YHF$2&|0FKa5cDod|c}OWxdaLf}L$(C9UaE1Jfe4J-Pgee_@4j z>z1Ius?(JA!%y~FIo&1RMsdWNp$p#TknhVUelJ>~AL;888JPabGxs(PR@ocYYE{|Y z34Bqa3X88wFU&RvM%+-v%h$-i40HO;J=#}0^1%F37YcRv$#UAj2C|87`T97j0af7+%F z>pO=B_jR5PkX(E1`FpL{ztkAMcc-V!X&ygPd8@zY<{vMma&L3f?|i*F;Nq>zgTt)B z<9P=6L$Y4+#lHAY-LleC)lcVjCOoKLTD*&1z2U`9a5y07Z) zD<8dgbC37HV4wWPa^~P<-1*?ES&Ifj_u$qxlV^ZJh}F< zqtp5Dc>A=uHwxpi3eBAgm(>=HmMc-q_stJUPk8ru{xlZ%?CRmlvjV*pL9N}!+GmS) je|wH6>P+8$>V8jzBlrubsxJLUfYB}}2w literal 0 HcmV?d00001 diff --git a/image-loader/test/resources/basn2c16_TrueColor_16bit.png b/image-loader/test/resources/basn2c16_TrueColor_16bit.png new file mode 100644 index 0000000000000000000000000000000000000000..50c1cb91a0171e9f34991b079fe932f5f0bb16d6 GIT binary patch literal 302 zcmV+}0nz@6P)NTxus~-YE?|ew94KIo9tHTv?hhRR zwrA%J^h9UxCeRmyPjW#d?oxNFL9(uFDZ1gBle+D$rIj`J+5;}Xa zfF63WfGT3xy1iYa$zve>zUI)9x>;M1&07*qoM6N<$g8PGj A5dZ)H literal 0 HcmV?d00001 diff --git a/image-loader/test/resources/bgan6a16_TrueColorWithAlpha_16bit.png b/image-loader/test/resources/bgan6a16_TrueColorWithAlpha_16bit.png new file mode 100644 index 0000000000000000000000000000000000000000..984a99525f5246cbc5d7083dd79006c7efa0ab0b GIT binary patch literal 3435 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 AY5)KL literal 0 HcmV?d00001 diff --git a/image-loader/test/resources/tiff_8bpc_flat.tif b/image-loader/test/resources/tiff_8bpc_flat.tif new file mode 100644 index 0000000000000000000000000000000000000000..e4e176485e1be25ef88aa4b3eb6a3809bae0b2ac GIT binary patch literal 102004 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 literal 0 HcmV?d00001 diff --git a/image-loader/test/resources/tiff_8bpc_layered_withTransparency.tif b/image-loader/test/resources/tiff_8bpc_layered_withTransparency.tif new file mode 100644 index 0000000000000000000000000000000000000000..1580e32154779db5aa5db49ea00219142d0f1fc1 GIT binary patch literal 183416 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 literal 0 HcmV?d00001 From 4e0077f83ea36ebfb4758d599a341249635a4dd1 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Wed, 2 Dec 2020 08:28:11 +0000 Subject: [PATCH 11/36] Expand and clean up tests --- .../test/scala/model/ImageUploadTest.scala | 107 ++++++++++++++---- 1 file changed, 84 insertions(+), 23 deletions(-) diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index 11358e9bc4..c02621cef8 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -7,7 +7,8 @@ import java.util.UUID import com.gu.mediaservice.lib.aws.{S3Metadata, S3Object, S3ObjectMetadata} import com.gu.mediaservice.lib.imaging.ImageOperations import com.gu.mediaservice.lib.logging.LogMarker -import com.gu.mediaservice.model.{FileMetadata, UploadInfo} +import com.gu.mediaservice.model.{FileMetadata, Image, Jpeg, MimeType, Png, Tiff, UploadInfo} +import lib.imaging.MimeTypeDetection import org.joda.time.DateTime import org.scalatest.mockito.MockitoSugar import org.scalatest.{AsyncFunSuite, Matchers} @@ -18,36 +19,69 @@ import scala.util.{Failure, Success} class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { implicit val ec = ExecutionContext.Implicits.global + class MockLogMarker extends LogMarker { - override def markerContents: Map[String, Any] = ??? + override def markerContents: Map[String, Any] = Map() } + implicit val logMarker = new MockLogMarker(); - val mockConfig = ImageUploadOpsCfg(new File("/tmp"), 256, 85d, Nil, "img-bucket", "thumb-bucket") + // For mime type info, see https://github.com/guardian/grid/pull/2568 + val mockConfig = ImageUploadOpsCfg(new File("/tmp"), 256, 85d, List(Tiff), "img-bucket", "thumb-bucket") /** * @todo: I flailed about until I found a path that worked, but - * what arcane magic System.getProperty relies upon, and exactly - * _how_ it will break in CI, I do not know + * what arcane magic System.getProperty relies upon, and exactly + * _how_ it will break in CI, I do not know */ val imageOps: ImageOperations = new ImageOperations(System.getProperty("user.dir")) - val mockOptimisedPngOps = mock[OptimisedPngOps] + def imageUpload( + fileName: String, + expectedOriginalMimeType: MimeType, + expectedThumbMimeType: MimeType, + expectedOptimisedMimeType: Option[MimeType] = None) = { + val willCreateOptimisedPNG = expectedOptimisedMimeType.isDefined - test("do something") { - val imageFileName = "rubbish.jpg" val uuid = UUID.randomUUID() + val randomId = UUID.randomUUID().toString + fileName val mockS3Meta = S3Metadata(Map.empty, S3ObjectMetadata(None, None, None)) val mockS3Object = S3Object(new URI("innernets.com"), 12345, mockS3Meta) def storeOrProjectOriginalFile: UploadRequest => Future[S3Object] = { - _ => Future.successful(mockS3Object) + a => { + Future.successful( + mockS3Object + .copy(size = a.tempFile.length()) + .copy(metadata = mockS3Object.metadata + .copy(objectMetadata = mockS3Object.metadata.objectMetadata + .copy(contentType = a.mimeType)))) + } } + def storeOrProjectThumbFile: (UploadRequest, File) => Future[S3Object] = { - (_, _) => Future.successful(mockS3Object) + (a, b) => { + Future.successful( + mockS3Object + .copy(size = b.length()) + .copy(metadata = mockS3Object.metadata + .copy(objectMetadata = mockS3Object.metadata.objectMetadata + .copy(contentType = a.mimeType))) + ) + } } + def storeOrProjectOptimisedPNG: (UploadRequest, File) => Future[S3Object] = { - (_, _) => Future.successful(mockS3Object) + (a, b) => { + if (a.mimeType.contains(Jpeg)) fail("We should not create optimised jpg") + Future.successful( + mockS3Object + .copy(size = b.length()) + .copy(metadata = mockS3Object.metadata + .copy(objectMetadata = mockS3Object.metadata.objectMetadata + .copy(contentType = a.mimeType))) + ) + } } val mockDependencies = ImageUploadOpsDependencies( @@ -58,13 +92,14 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { storeOrProjectOptimisedPNG ) - val tempFile = ResourceHelpers.fileAt(imageFileName) + val tempFile = ResourceHelpers.fileAt(fileName) val ul = UploadInfo(None) + val uploadRequest = UploadRequest( uuid, - "imageId", + randomId, tempFile, - None, + MimeTypeDetection.guessMimeType(tempFile).right.toOption, DateTime.now(), "uploadedBy", Map(), @@ -76,20 +111,46 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { mockDependencies.storeOrProjectOriginalFile, mockDependencies.storeOrProjectThumbFile, mockDependencies.storeOrProjectOptimisedPNG, - mockOptimisedPngOps, + OptimisedPngQuantOps, uploadRequest, mockDependencies, FileMetadata() ) - futureImage transformWith { - case Success(_) => - // Assertions or fails - fail("Do summat 'ere") - case Failure(e) => - // Assertions or fail - e.getMessage shouldBe "gnar" - } + // Assertions; Failure will auto-fail + futureImage.map(i => { + assert(i.id == randomId, "Correct id comes back") + assert(i.source.mimeType.contains(expectedOriginalMimeType), "Should have the correct mime type") + assert(i.thumbnail.isDefined, "Should always create a thumbnail") + assert(i.optimisedPng.isDefined == willCreateOptimisedPNG, "Should or should not create an optimised png") + assert(i.thumbnail.get.mimeType.get == expectedThumbMimeType, "Should have correct thumb mime type") + assert(i.optimisedPng.flatMap(p => p.mimeType) == expectedOptimisedMimeType, "Should have correct optimised mime type") + }) + } + + // TODO check somehow that the temp files have all been cleared up. + + test("rubbish") { + imageUpload("rubbish.jpg", Jpeg, Jpeg) + } + test("lighthouse") { + imageUpload("lighthouse.tif", Tiff, Png, Some(Png)) + } + test("tiff_8bpc_layered_withTransparency") { + imageUpload("tiff_8bpc_layered_withTransparency.tif", Tiff, Png, Some(Png)) + } + test("tiff_8bpc_flat") { + imageUpload("tiff_8bpc_flat.tif", Tiff, Png, Some(Png)) + } + test("IndexedColor") { + imageUpload("IndexedColor.png", Png, Png) + } + test("bgan6a16_TrueColorWithAlpha_16bit") { + imageUpload("bgan6a16_TrueColorWithAlpha_16bit.png", Png, Png, Some(Png)) + } + test("basn2c16_TrueColor_16bit") { + imageUpload("basn2c16_TrueColor_16bit.png", Png, Png, Some(Png)) } } +// todo add to tests - tiff with layers, but not true colour so does not need optimising. MK to provide From 87db2967997d8461b3a3bd87316e423924d62859 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Wed, 2 Dec 2020 08:29:32 +0000 Subject: [PATCH 12/36] Fix actual bug - upload original, thumb, and optional optimised file --- .../app/lib/imaging/FileMetadataReader.scala | 10 ++- image-loader/app/model/ImageUpload.scala | 88 +++++++++---------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/image-loader/app/lib/imaging/FileMetadataReader.scala b/image-loader/app/lib/imaging/FileMetadataReader.scala index 59978fd4a0..43ab1dadcc 100644 --- a/image-loader/app/lib/imaging/FileMetadataReader.scala +++ b/image-loader/app/lib/imaging/FileMetadataReader.scala @@ -15,6 +15,7 @@ import com.drew.metadata.{Directory, Metadata} import com.gu.mediaservice.lib.imaging.im4jwrapper.ImageMagick._ import com.gu.mediaservice.lib.metadata.ImageMetadataConverter import com.gu.mediaservice.model._ +import model.UploadRequest import org.joda.time.{DateTime, DateTimeZone} import org.joda.time.format.ISODateTimeFormat import play.api.libs.json.JsValue @@ -56,6 +57,9 @@ object FileMetadataReader { } yield getMetadataWithICPTCHeaders(metadata, imageId) // FIXME: JPEG, JFIF, Photoshop, GPS, File + def fromICPTCHeadersWithColorInfo(uploadRequest: UploadRequest): Future[FileMetadata] = + fromICPTCHeadersWithColorInfo(uploadRequest.tempFile, uploadRequest.imageId, uploadRequest.mimeType.get) + def fromICPTCHeadersWithColorInfo(image: File, imageId:String, mimeType: MimeType): Future[FileMetadata] = for { metadata <- readMetadata(image) @@ -217,12 +221,12 @@ object FileMetadataReader { "paletteSize" -> Option(metaDir.getDescription(PngDirectory.TAG_PALETTE_SIZE)), "iccProfileName" -> Option(metaDir.getDescription(PngDirectory.TAG_ICC_PROFILE_NAME)) ).flattenOptions - case _ => val metaDir = metadata.getFirstDirectoryOfType(classOf[ExifIFD0Directory]) + case _ => val metaDir = Option(metadata.getFirstDirectoryOfType(classOf[ExifIFD0Directory])) Map( "hasAlpha" -> hasAlpha, "colorType" -> maybeImageType, - "photometricInterpretation" -> Option(metaDir.getDescription(ExifDirectoryBase.TAG_PHOTOMETRIC_INTERPRETATION)), - "bitsPerSample" -> Option(metaDir.getDescription(ExifDirectoryBase.TAG_BITS_PER_SAMPLE)) + "photometricInterpretation" -> metaDir.map(_.getDescription(ExifDirectoryBase.TAG_PHOTOMETRIC_INTERPRETATION)), + "bitsPerSample" -> metaDir.map(_.getDescription(ExifDirectoryBase.TAG_BITS_PER_SAMPLE)) ).flattenOptions } diff --git a/image-loader/app/model/ImageUpload.scala b/image-loader/app/model/ImageUpload.scala index fc48f23742..1f0d31949a 100644 --- a/image-loader/app/model/ImageUpload.scala +++ b/image-loader/app/model/ImageUpload.scala @@ -258,51 +258,50 @@ object Uploader extends GridLogging { val sourceDimensionsFuture = FileMetadataReader.dimensions(originalUploadRequest.tempFile, originalUploadRequest.mimeType) // if the file needs pre-processing into a supported type of file, do it now and create the new upload request. - - // we don't create a new upload request, we just override the old one. This is the bug! - -// We have three actions to take. -// 1) storeOrProjectOriginalFile - takes original upload request -// 2) storeOrProjectOptimisedPNG - takes a new upload request, possibly for the extracted tiff file -// 3) storeOrProjectThumbFile - takes a new upload request + // We have three actions to take. + // 1) storeOrProjectOriginalFile - takes original upload request + // 2) storeOrProjectOptimisedPNG - takes a new upload request, possibly for the extracted tiff file + // 3) storeOrProjectThumbFile - takes a new upload request val sourceStoreFuture = storeOrProjectOriginalFile(originalUploadRequest) + // todo convert to for comp createOptimisedFileFuture(originalUploadRequest, deps).flatMap(optimisedUploadRequest => { - val thumbFuture = createThumbFuture(fileMetadata, colourModelFuture, optimisedUploadRequest, deps) - logger.info("thumbnail created") - - val optimisedPng: Option[OptimisedPng] = if (pngOptimiser.shouldOptimise(optimisedUploadRequest.mimeType, fileMetadata)) { - val optimisedFile: File = pngOptimiser.toOptimisedFile(optimisedUploadRequest.tempFile, optimisedUploadRequest, config) - val pngStoreFuture: Future[S3Object] = - storeOrProjectOptimisedPNG(optimisedUploadRequest, optimisedFile) - .andThen{case _ => optimisedFile.delete()} - Some(OptimisedPng(pngStoreFuture, optimisedFile)) - } else { - None - } - - bracket(thumbFuture)(_.delete) { thumb => - // Run the operations in parallel - val thumbStoreFuture = storeOrProjectThumbFile(optimisedUploadRequest, thumb) - val thumbDimensionsFuture = FileMetadataReader.dimensions(thumb, Some(Jpeg)) - - val finalImage = toFinalImage( - sourceStoreFuture, - thumbStoreFuture, - sourceDimensionsFuture, - thumbDimensionsFuture, - fileMetadata, - colourModelFuture, - optimisedPng, - optimisedUploadRequest - ) - logger.info(s"Deleting temp file ${originalUploadRequest.tempFile.getAbsolutePath}") - originalUploadRequest.tempFile.delete() - optimisedUploadRequest.tempFile.delete() - - finalImage - } + FileMetadataReader.fromICPTCHeadersWithColorInfo(optimisedUploadRequest).flatMap( + optimisedFileMetadata => { + val thumbFuture = createThumbFuture(optimisedFileMetadata, colourModelFuture, optimisedUploadRequest, deps) + logger.info("thumbnail created") + + val optimisedPng: Option[OptimisedPng] = if (pngOptimiser.shouldOptimise(optimisedUploadRequest.mimeType, optimisedFileMetadata)) { + val optimisedFile: File = pngOptimiser.toOptimisedFile(optimisedUploadRequest.tempFile, optimisedUploadRequest, config) + val pngStoreFuture: Future[S3Object] = + storeOrProjectOptimisedPNG(optimisedUploadRequest, optimisedFile) + Some(OptimisedPng(pngStoreFuture, optimisedFile)) + } else + None + + bracket(thumbFuture)(_.delete) { thumb => + // Run the operations in parallel + val thumbStoreFuture = storeOrProjectThumbFile(optimisedUploadRequest, thumb) + val thumbDimensionsFuture = FileMetadataReader.dimensions(thumb, Some(Jpeg)) + + val finalImage = toFinalImage( + sourceStoreFuture, + thumbStoreFuture, + sourceDimensionsFuture, + thumbDimensionsFuture, + fileMetadata, + colourModelFuture, + optimisedPng, + originalUploadRequest + ) + logger.info(s"Deleting temp file ${originalUploadRequest.tempFile.getAbsolutePath}") + originalUploadRequest.tempFile.delete() + optimisedUploadRequest.tempFile.delete() + + finalImage + } + }) }) } @@ -386,11 +385,10 @@ object Uploader extends GridLogging { uploadRequest.mimeType match { case Some(mime) if config.transcodedMimeTypes.contains(mime) => for { - transformedImage <- imageOps.transformImage(uploadRequest.tempFile, uploadRequest.mimeType, config.tempDir) + (file, filetype) <- imageOps.transformImage(uploadRequest.tempFile, uploadRequest.mimeType, config.tempDir) } yield uploadRequest - // This file has been converted. - .copy(mimeType = Some(MimeType(transformedImage._2))) - .copy(tempFile = transformedImage._1) + .copy(mimeType = Some(MimeType(filetype))) + .copy(tempFile = file) case _ => Future.successful(uploadRequest) } From 84141be7f8fa6467250ad62439660bdfd61ff7ae Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Wed, 2 Dec 2020 16:46:28 +0000 Subject: [PATCH 13/36] Massive refactor --- .../lib/ImageIngestOperations.scala | 46 +- .../lib/imaging/ImageOperations.scala | 3 +- image-loader/app/ImageLoaderComponents.scala | 2 +- .../app/lib/imaging/FileMetadataReader.scala | 7 +- image-loader/app/model/Projector.scala | 30 +- .../{ImageUpload.scala => Uploader.scala} | 428 ++++++++---------- .../app/model/upload/OptimiseOps.scala | 45 ++ .../model/{ => upload}/UploadRequest.scala | 27 +- .../test/resources/thisisnotanimage.jpg | 0 .../test/resources/thisisnotanimage.stupid | 0 .../test/scala/model/ImageUploadTest.scala | 61 ++- 11 files changed, 341 insertions(+), 308 deletions(-) rename image-loader/app/model/{ImageUpload.scala => Uploader.scala} (52%) create mode 100644 image-loader/app/model/upload/OptimiseOps.scala rename image-loader/app/model/{ => upload}/UploadRequest.scala (62%) create mode 100644 image-loader/test/resources/thisisnotanimage.jpg create mode 100644 image-loader/test/resources/thisisnotanimage.stupid diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala index fd561fe09f..0757e8fc36 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala @@ -20,19 +20,43 @@ class ImageIngestOperations(imageBucket: String, thumbnailBucket: String, config import ImageIngestOperations.{fileKeyFromId, optimisedPngKeyFromId} - def storeOriginal(id: String, file: File, mimeType: Option[MimeType], meta: Map[String, String] = Map.empty) - (implicit logMarker: LogMarker): Future[S3Object] = - storeImage(imageBucket, fileKeyFromId(id), file, mimeType, meta) - - def storeThumbnail(id: String, file: File, mimeType: Option[MimeType]) - (implicit logMarker: LogMarker): Future[S3Object] = - storeImage(thumbnailBucket, fileKeyFromId(id), file, mimeType) - - def storeOptimisedPng(id: String, file: File) + def store(storableImage: StorableImage) + (implicit logMarker: LogMarker): Future[S3Object] = storableImage match { + case s:StorableOriginalImage => storeOriginalImage(s) + case s:StorableThumbImage => storeThumbnailImage(s) + case s:StorableOptimisedImage => storeOptimisedImage(s) + } + + private def storeOriginalImage(storableImage: StorableImage) + (implicit logMarker: LogMarker): Future[S3Object] = + storeImage(imageBucket, fileKeyFromId(storableImage.id), storableImage.file, Some(storableImage.mimeType), storableImage.meta) + + private def storeThumbnailImage(storableImage: StorableImage) + (implicit logMarker: LogMarker): Future[S3Object] = + storeImage(thumbnailBucket, fileKeyFromId(storableImage.id), storableImage.file, Some(storableImage.mimeType)) + + private def storeOptimisedImage(storableImage: StorableImage) (implicit logMarker: LogMarker): Future[S3Object] = - storeImage(imageBucket, optimisedPngKeyFromId(id), file, Some(Png)) - + storeImage(imageBucket, optimisedPngKeyFromId(storableImage.id), storableImage.file, Some(Png)) // TODO remove hard coding! + def deleteOriginal(id: String): Future[Unit] = if(isVersionedS3) deleteVersionedImage(imageBucket, fileKeyFromId(id)) else deleteImage(imageBucket, fileKeyFromId(id)) def deleteThumbnail(id: String): Future[Unit] = deleteImage(thumbnailBucket, fileKeyFromId(id)) def deletePng(id: String): Future[Unit] = deleteImage(imageBucket, optimisedPngKeyFromId(id)) } + + + +trait StorableImage { + val id: String + val file: File + val mimeType: MimeType + val meta: Map[String, String] +} +case class StorableThumbImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty) extends StorableImage +case class StorableOriginalImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty) extends StorableImage +case class StorableOptimisedImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty) extends StorableImage +case class StorableBrowserViewableImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty, mustUpload: Boolean = false) extends StorableImage { + def asStorableOptimisedImage = StorableOptimisedImage(id, file, mimeType, meta) + def asStorableThumbImage = StorableThumbImage(id, file, mimeType, meta) + +} diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala index 83adeec193..317548f8de 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala @@ -133,7 +133,8 @@ class ImageOperations(playPath: String) extends GridLogging { def transformImage(sourceFile: File, sourceMimeType: Option[MimeType], tempDir: File): Future[(File, String)] = { for { - outputFile <- createTempFile(s"transformed-", ".png", tempDir) + // png suffix is used by imagemagick to infer the required type + outputFile <- createTempFile(s"transformed-", Png.fileExtension, tempDir) transformSource = addImage(sourceFile) addOutput = addDestImage(transformSource)(outputFile) _ <- runConvertCmd(addOutput, useImageMagick = sourceMimeType.contains(Tiff)) diff --git a/image-loader/app/ImageLoaderComponents.scala b/image-loader/app/ImageLoaderComponents.scala index c896b4af8e..d5d03b7949 100644 --- a/image-loader/app/ImageLoaderComponents.scala +++ b/image-loader/app/ImageLoaderComponents.scala @@ -3,7 +3,7 @@ import com.gu.mediaservice.lib.play.GridComponents import controllers.ImageLoaderController import lib._ import lib.storage.ImageLoaderStore -import model.{Uploader, Projector} +import model.{Projector, Uploader} import play.api.ApplicationLoader.Context import router.Routes diff --git a/image-loader/app/lib/imaging/FileMetadataReader.scala b/image-loader/app/lib/imaging/FileMetadataReader.scala index 43ab1dadcc..7b010e424f 100644 --- a/image-loader/app/lib/imaging/FileMetadataReader.scala +++ b/image-loader/app/lib/imaging/FileMetadataReader.scala @@ -12,10 +12,11 @@ import com.drew.metadata.jpeg.JpegDirectory import com.drew.metadata.png.PngDirectory import com.drew.metadata.xmp.XmpDirectory import com.drew.metadata.{Directory, Metadata} +import com.gu.mediaservice.lib.StorableImage import com.gu.mediaservice.lib.imaging.im4jwrapper.ImageMagick._ import com.gu.mediaservice.lib.metadata.ImageMetadataConverter import com.gu.mediaservice.model._ -import model.UploadRequest +import model.upload.UploadRequest import org.joda.time.{DateTime, DateTimeZone} import org.joda.time.format.ISODateTimeFormat import play.api.libs.json.JsValue @@ -57,8 +58,8 @@ object FileMetadataReader { } yield getMetadataWithICPTCHeaders(metadata, imageId) // FIXME: JPEG, JFIF, Photoshop, GPS, File - def fromICPTCHeadersWithColorInfo(uploadRequest: UploadRequest): Future[FileMetadata] = - fromICPTCHeadersWithColorInfo(uploadRequest.tempFile, uploadRequest.imageId, uploadRequest.mimeType.get) + def fromICPTCHeadersWithColorInfo(image: StorableImage): Future[FileMetadata] = + fromICPTCHeadersWithColorInfo(image.file, image.id, image.mimeType) def fromICPTCHeadersWithColorInfo(image: File, imageId:String, mimeType: MimeType): Future[FileMetadata] = for { diff --git a/image-loader/app/model/Projector.scala b/image-loader/app/model/Projector.scala index 35fc655a6d..edd3a4dcb3 100644 --- a/image-loader/app/model/Projector.scala +++ b/image-loader/app/model/Projector.scala @@ -5,7 +5,7 @@ import java.util.UUID import com.amazonaws.services.s3.AmazonS3 import com.amazonaws.services.s3.model.{ObjectMetadata, S3Object} -import com.gu.mediaservice.lib.ImageIngestOperations +import com.gu.mediaservice.lib.{ImageIngestOperations, StorableOptimisedImage, StorableOriginalImage, StorableThumbImage} import com.gu.mediaservice.lib.aws.S3Ops import com.gu.mediaservice.lib.imaging.ImageOperations import com.gu.mediaservice.lib.logging.LogMarker @@ -13,6 +13,7 @@ import com.gu.mediaservice.lib.net.URI import com.gu.mediaservice.model.{Image, Jpeg, Png, UploadInfo} import lib.imaging.{MimeTypeDetection, NoSuchImageExistsInS3} import lib.{DigestedFile, ImageLoaderConfig} +import model.upload.UploadRequest import org.apache.tika.io.IOUtils import org.joda.time.{DateTime, DateTimeZone} import play.api.{Logger, MarkerContext} @@ -133,37 +134,36 @@ class ImageUploadProjectionOps(config: ImageUploadOpsCfg, fromUploadRequestShared(uploadRequest, dependenciesWithProjectionsOnly) } - private def projectOriginalFileAsS3Model(uploadRequest: UploadRequest) + private def projectOriginalFileAsS3Model(storableOriginalImage: StorableOriginalImage) (implicit ec: ExecutionContext)= Future { - val meta: Map[String, String] = toMetaMap(uploadRequest) - val key = ImageIngestOperations.fileKeyFromId(uploadRequest.imageId) + val key = ImageIngestOperations.fileKeyFromId(storableOriginalImage.id) S3Ops.projectFileAsS3Object( config.originalFileBucket, key, - uploadRequest.tempFile, - uploadRequest.mimeType, - meta + storableOriginalImage.file, + Some(storableOriginalImage.mimeType), + storableOriginalImage.meta ) } - private def projectThumbnailFileAsS3Model(uploadRequest: UploadRequest, thumbFile: File)(implicit ec: ExecutionContext) = Future { - val key = ImageIngestOperations.fileKeyFromId(uploadRequest.imageId) - val thumbMimeType = Some(Jpeg) + private def projectThumbnailFileAsS3Model(storableThumbImage: StorableThumbImage)(implicit ec: ExecutionContext) = Future { + val key = ImageIngestOperations.fileKeyFromId(storableThumbImage.id) + val thumbMimeType = Some(Jpeg) // todo remove hard coding S3Ops.projectFileAsS3Object( config.thumbBucket, key, - thumbFile, + storableThumbImage.file, thumbMimeType ) } - private def projectOptimisedPNGFileAsS3Model(uploadRequest: UploadRequest, optimisedPngFile: File)(implicit ec: ExecutionContext) = Future { - val key = ImageIngestOperations.optimisedPngKeyFromId(uploadRequest.imageId) - val optimisedPngMimeType = Some(Png) + private def projectOptimisedPNGFileAsS3Model(storableOptimisedImage: StorableOptimisedImage)(implicit ec: ExecutionContext) = Future { + val key = ImageIngestOperations.optimisedPngKeyFromId(storableOptimisedImage.id) + val optimisedPngMimeType = Some(Png) // todo remove hard coding S3Ops.projectFileAsS3Object( config.originalFileBucket, key, - optimisedPngFile, + storableOptimisedImage.file, optimisedPngMimeType ) } diff --git a/image-loader/app/model/ImageUpload.scala b/image-loader/app/model/Uploader.scala similarity index 52% rename from image-loader/app/model/ImageUpload.scala rename to image-loader/app/model/Uploader.scala index 1f0d31949a..e90626cb0f 100644 --- a/image-loader/app/model/ImageUpload.scala +++ b/image-loader/app/model/Uploader.scala @@ -3,11 +3,13 @@ package model import java.io.File import java.net.URLEncoder import java.nio.charset.StandardCharsets +import java.nio.file.Files import java.util.UUID import com.gu.mediaservice.lib.argo.ArgoHelpers import com.gu.mediaservice.lib.auth.Authentication import com.gu.mediaservice.lib.auth.Authentication.Principal +import com.gu.mediaservice.lib.{StorableBrowserViewableImage, StorableOptimisedImage, StorableOriginalImage, StorableThumbImage} import com.gu.mediaservice.lib.aws.{S3Object, UpdateMessage} import com.gu.mediaservice.lib.cleanup.{MetadataCleaners, SupplierProcessors} import com.gu.mediaservice.lib.config.MetadataConfig @@ -15,52 +17,16 @@ import com.gu.mediaservice.lib.formatting._ import com.gu.mediaservice.lib.imaging.ImageOperations import com.gu.mediaservice.lib.logging._ import com.gu.mediaservice.lib.metadata.{FileMetadataHelper, ImageMetadataConverter} -import com.gu.mediaservice.lib.resource.FutureResources._ import com.gu.mediaservice.model._ import lib.{DigestedFile, ImageLoaderConfig, Notifications} import lib.imaging.{FileMetadataReader, MimeTypeDetection} import lib.storage.ImageLoaderStore +import model.Uploader.{fromUploadRequestShared, toImageUploadOpsCfg} +import model.upload.{OptimiseOps, OptimiseWithPngQuant, UploadRequest} import org.joda.time.DateTime import play.api.libs.json.{JsObject, Json} import scala.concurrent.{ExecutionContext, Future} -import scala.sys.process._ - -case class OptimisedPng(optimisedFileStoreFuture: Future[S3Object], - optimisedTempFile: File) - -trait OptimisedPngOps { - def toOptimisedFile(file: File, uploadRequest: UploadRequest, config: ImageUploadOpsCfg) - (implicit logMarker: LogMarker): File - def isTransformedFilePath(filePath: String): Boolean - def shouldOptimise(mimeType: Option[MimeType], fileMetadata: FileMetadata): Boolean -} - -object OptimisedPngQuantOps extends OptimisedPngOps { - - def toOptimisedFile(file: File, uploadRequest: UploadRequest, config: ImageUploadOpsCfg) - (implicit logMarker: LogMarker): File = { - val optimisedFilePath = config.tempDir.getAbsolutePath + "/optimisedpng - " + uploadRequest.imageId + ".png" - Stopwatch("pngquant") { - Seq("pngquant", "--quality", "1-85", file.getAbsolutePath, "--output", optimisedFilePath).! - } - new File(optimisedFilePath) - } - - def isTransformedFilePath(filePath: String): Boolean = filePath.contains("transformed-") - - def shouldOptimise(mimeType: Option[MimeType], fileMetadata: FileMetadata): Boolean = - mimeType match { - case Some(Png) => - fileMetadata.colourModelInformation.get("colorType") match { - case Some("True Color") => true - case Some("True Color with Alpha") => true - case _ => false - } - case Some(Tiff) => true - case _ => false - } -} case class ImageUpload(uploadRequest: UploadRequest, image: Image) @@ -92,103 +58,6 @@ case object ImageUpload { } } -class Uploader(val store: ImageLoaderStore, - val config: ImageLoaderConfig, - val imageOps: ImageOperations, - val notifications: Notifications) - (implicit val ec: ExecutionContext) extends ArgoHelpers { - - - import Uploader.{fromUploadRequestShared, toMetaMap, toImageUploadOpsCfg} - - - def fromUploadRequest(uploadRequest: UploadRequest) - (implicit logMarker: LogMarker): Future[ImageUpload] = { - val sideEffectDependencies = ImageUploadOpsDependencies(toImageUploadOpsCfg(config), imageOps, - storeSource, storeThumbnail, storeOptimisedPng) - val finalImage = fromUploadRequestShared(uploadRequest, sideEffectDependencies) - finalImage.map(img => Stopwatch("finalImage"){ImageUpload(uploadRequest, img)}) - } - - private def storeSource(uploadRequest: UploadRequest) - (implicit logMarker: LogMarker) = { - val meta = toMetaMap(uploadRequest) - store.storeOriginal( - uploadRequest.imageId, - uploadRequest.tempFile, - uploadRequest.mimeType, - meta - ) - } - - private def storeThumbnail(uploadRequest: UploadRequest, thumbFile: File) - (implicit logMarker: LogMarker) = store.storeThumbnail( - uploadRequest.imageId, - thumbFile, - Some(Jpeg) - ) - - private def storeOptimisedPng(uploadRequest: UploadRequest, optimisedPngFile: File) - (implicit logMarker: LogMarker) = { - store.storeOptimisedPng( - uploadRequest.imageId, - optimisedPngFile - ) - } - - def loadFile(digestedFile: DigestedFile, - user: Principal, - uploadedBy: Option[String], - identifiers: Option[String], - uploadTime: DateTime, - filename: Option[String], - requestId: UUID) - (implicit ec:ExecutionContext, - logMarker: LogMarker): Future[UploadRequest] = Future { - val DigestedFile(tempFile, id) = digestedFile - - // TODO: should error if the JSON parsing failed - val identifiersMap = identifiers.map(Json.parse(_).as[Map[String, String]]) getOrElse Map() - - MimeTypeDetection.guessMimeType(tempFile) match { - case util.Left(unsupported) => - logger.error(s"Unsupported mimetype", unsupported) - throw unsupported - case util.Right(mimeType) => - logger.info(s"Detected mimetype as $mimeType") - UploadRequest( - requestId = requestId, - imageId = id, - tempFile = tempFile, - mimeType = Some(mimeType), - uploadTime = uploadTime, - uploadedBy = uploadedBy.getOrElse(Authentication.getIdentity(user)), - identifiers = identifiersMap, - uploadInfo = UploadInfo(filename) - ) - } - } - - def storeFile(uploadRequest: UploadRequest) - (implicit ec:ExecutionContext, - logMarker: LogMarker): Future[JsObject] = { - - logger.info("Storing file") - - for { - imageUpload <- fromUploadRequest(uploadRequest) - updateMessage = UpdateMessage(subject = "image", image = Some(imageUpload.image)) - _ <- Future { notifications.publish(updateMessage) } - // TODO: centralise where all these URLs are constructed - uri = s"${config.apiUri}/images/${uploadRequest.imageId}" - } yield { - Json.obj("uri" -> uri) - } - - } - -} - case class ImageUploadOpsCfg( tempDir: File, thumbWidth: Int, @@ -199,11 +68,11 @@ case class ImageUploadOpsCfg( ) case class ImageUploadOpsDependencies( - config: ImageUploadOpsCfg, - imageOps: ImageOperations, - storeOrProjectOriginalFile: UploadRequest => Future[S3Object], - storeOrProjectThumbFile: (UploadRequest, File) => Future[S3Object], - storeOrProjectOptimisedPNG: (UploadRequest, File) => Future[S3Object] + config: ImageUploadOpsCfg, + imageOps: ImageOperations, + storeOrProjectOriginalFile: StorableOriginalImage => Future[S3Object], + storeOrProjectThumbFile: StorableThumbImage => Future[S3Object], + storeOrProjectOptimisedImage: StorableOptimisedImage => Future[S3Object] ) object Uploader extends GridLogging { @@ -231,108 +100,62 @@ object Uploader extends GridLogging { logger.info("Have read file headers") fileMetadataFuture.flatMap(fileMetadata => { - uploadAndStoreImage(config, + uploadAndStoreImage( storeOrProjectOriginalFile, storeOrProjectThumbFile, - storeOrProjectOptimisedPNG, - OptimisedPngQuantOps, + storeOrProjectOptimisedImage, + OptimiseWithPngQuant, uploadRequest, deps, fileMetadata)(ec, addLogMarkers(fileMetadata.toLogMarker)) }) } - private[model] def uploadAndStoreImage(config: ImageUploadOpsCfg, - storeOrProjectOriginalFile: UploadRequest => Future[S3Object], - storeOrProjectThumbFile: (UploadRequest, File) => Future[S3Object], - storeOrProjectOptimisedPNG: (UploadRequest, File) => Future[S3Object], - pngOptimiser: OptimisedPngOps, - originalUploadRequest: UploadRequest, - deps: ImageUploadOpsDependencies, - fileMetadata: FileMetadata) + private[model] def uploadAndStoreImage(storeOrProjectOriginalFile: StorableOriginalImage => Future[S3Object], + storeOrProjectThumbFile: StorableThumbImage => Future[S3Object], + storeOrProjectOptimisedFile: StorableOptimisedImage => Future[S3Object], + optimiseOps: OptimiseOps, + uploadRequest: UploadRequest, + deps: ImageUploadOpsDependencies, + fileMetadata: FileMetadata) (implicit ec: ExecutionContext, logMarker: LogMarker) = { - logger.info("Have read file metadata") - logger.info("stored source file") - // FIXME: pass mimeType - val colourModelFuture = ImageOperations.identifyColourModel(originalUploadRequest.tempFile, Jpeg) - val sourceDimensionsFuture = FileMetadataReader.dimensions(originalUploadRequest.tempFile, originalUploadRequest.mimeType) - - // if the file needs pre-processing into a supported type of file, do it now and create the new upload request. - // We have three actions to take. - // 1) storeOrProjectOriginalFile - takes original upload request - // 2) storeOrProjectOptimisedPNG - takes a new upload request, possibly for the extracted tiff file - // 3) storeOrProjectThumbFile - takes a new upload request - - val sourceStoreFuture = storeOrProjectOriginalFile(originalUploadRequest) - - // todo convert to for comp - createOptimisedFileFuture(originalUploadRequest, deps).flatMap(optimisedUploadRequest => { - FileMetadataReader.fromICPTCHeadersWithColorInfo(optimisedUploadRequest).flatMap( - optimisedFileMetadata => { - val thumbFuture = createThumbFuture(optimisedFileMetadata, colourModelFuture, optimisedUploadRequest, deps) - logger.info("thumbnail created") - - val optimisedPng: Option[OptimisedPng] = if (pngOptimiser.shouldOptimise(optimisedUploadRequest.mimeType, optimisedFileMetadata)) { - val optimisedFile: File = pngOptimiser.toOptimisedFile(optimisedUploadRequest.tempFile, optimisedUploadRequest, config) - val pngStoreFuture: Future[S3Object] = - storeOrProjectOptimisedPNG(optimisedUploadRequest, optimisedFile) - Some(OptimisedPng(pngStoreFuture, optimisedFile)) - } else - None - - bracket(thumbFuture)(_.delete) { thumb => - // Run the operations in parallel - val thumbStoreFuture = storeOrProjectThumbFile(optimisedUploadRequest, thumb) - val thumbDimensionsFuture = FileMetadataReader.dimensions(thumb, Some(Jpeg)) - - val finalImage = toFinalImage( - sourceStoreFuture, - thumbStoreFuture, - sourceDimensionsFuture, - thumbDimensionsFuture, - fileMetadata, - colourModelFuture, - optimisedPng, - originalUploadRequest - ) - logger.info(s"Deleting temp file ${originalUploadRequest.tempFile.getAbsolutePath}") - originalUploadRequest.tempFile.delete() - optimisedUploadRequest.tempFile.delete() - - finalImage - } - }) - }) - } + val originalMimeType = uploadRequest.mimeType + .orElse(MimeTypeDetection.guessMimeType(uploadRequest.tempFile).toOption) + match { + case Some(a) => a + case None => throw new Exception("No idea what you have given me") + } - def toMetaMap(uploadRequest: UploadRequest): Map[String, String] = { - val baseMeta = Map( - "uploaded_by" -> uploadRequest.uploadedBy, - "upload_time" -> printDateTime(uploadRequest.uploadTime) - ) ++ uploadRequest.identifiersMeta + import java.nio.file.Files + val makeNewDirInTempDirHere: File = Files.createTempDirectory(deps.config.tempDir.toPath, "upload").toFile - uploadRequest.uploadInfo.filename match { - case Some(f) => baseMeta ++ Map("file_name" -> URLEncoder.encode(f, StandardCharsets.UTF_8.name())) - case _ => baseMeta - } - } + val colourModelFuture = ImageOperations.identifyColourModel(uploadRequest.tempFile, originalMimeType) + val sourceDimensionsFuture = FileMetadataReader.dimensions(uploadRequest.tempFile, Some(originalMimeType)) - private def toFinalImage(sourceStoreFuture: Future[S3Object], - thumbStoreFuture: Future[S3Object], - sourceDimensionsFuture: Future[Option[Dimensions]], - thumbDimensionsFuture: Future[Option[Dimensions]], - fileMetadata: FileMetadata, - colourModelFuture: Future[Option[String]], - optimisedPng: Option[OptimisedPng], - uploadRequest: UploadRequest) - (implicit ec: ExecutionContext, logMarker: LogMarker): Future[Image] = { - logger.info("Starting image ops") - for { + val storableOriginalImage = StorableOriginalImage( + uploadRequest.imageId, + uploadRequest.tempFile, + originalMimeType, + toMetaMap(uploadRequest) + ) + val sourceStoreFuture = storeOrProjectOriginalFile(storableOriginalImage) + val eventualBrowserViewableImage = createBrowserViewableFileFuture(uploadRequest, makeNewDirInTempDirHere, deps) + + + val eventualImage = for { + browserViewableImage <- eventualBrowserViewableImage s3Source <- sourceStoreFuture - s3Thumb <- thumbStoreFuture - s3PngOption <- optimisedPng.map(_.optimisedFileStoreFuture.map(a => Some(a))).getOrElse(Future.successful(None)) + optimisedFileMetadata <- FileMetadataReader.fromICPTCHeadersWithColorInfo(browserViewableImage) + thumb <- createThumbFuture(optimisedFileMetadata, colourModelFuture, browserViewableImage, deps) + thumbViewableImage = browserViewableImage.copy(file = thumb).asStorableThumbImage + s3Thumb <- storeOrProjectThumbFile(thumbViewableImage) + maybeStorableOptimisedImage = getStorableOptimisedImage(makeNewDirInTempDirHere, optimiseOps, browserViewableImage, optimisedFileMetadata) + s3PngOption <- maybeStorableOptimisedImage match { + case Some(storableOptimisedImage) => storeOrProjectOptimisedFile(storableOptimisedImage).map(a=>Some(a)) + case None => Future.successful(None) + } sourceDimensions <- sourceDimensionsFuture - thumbDimensions <- thumbDimensionsFuture + thumbDimensions <- FileMetadataReader.dimensions(thumb, Some(Jpeg)) colourModel <- colourModelFuture fullFileMetadata = fileMetadata.copy(colourModel = colourModel) metadata = ImageMetadataConverter.fromFileMetadata(fullFileMetadata) @@ -341,20 +164,50 @@ object Uploader extends GridLogging { sourceAsset = Asset.fromS3Object(s3Source, sourceDimensions) thumbAsset = Asset.fromS3Object(s3Thumb, thumbDimensions) - pngAsset = s3PngOption.map (Asset.fromS3Object(_, sourceDimensions)) + pngAsset = s3PngOption.map(Asset.fromS3Object(_, sourceDimensions)) baseImage = ImageUpload.createImage(uploadRequest, sourceAsset, thumbAsset, pngAsset, fullFileMetadata, cleanMetadata) processedImage = SupplierProcessors.process(baseImage) + } yield { + logger.info("Ending image ops") // FIXME: dirty hack to sync the originalUsageRights and originalMetadata as well - finalImage = processedImage.copy( + processedImage.copy( originalMetadata = processedImage.metadata, originalUsageRights = processedImage.usageRights ) - } yield { - optimisedPng.foreach(_.optimisedTempFile.delete) - logger.info("Ending image ops") - finalImage + } + eventualImage.onComplete{ _ => + makeNewDirInTempDirHere.listFiles().map(f => f.delete()) + makeNewDirInTempDirHere.delete() + } + eventualImage + } + + private def getStorableOptimisedImage( + tempDir: File, + optimiseOps: OptimiseOps, + browserViewableImage: StorableBrowserViewableImage, + optimisedFileMetadata: FileMetadata) + (implicit ec: ExecutionContext, logMarker: LogMarker): Option[StorableOptimisedImage] = { + if (optimiseOps.shouldOptimise(Some(browserViewableImage.mimeType), optimisedFileMetadata)) { + val (optimisedFile: File, optimisedMimeType: MimeType) = optimiseOps.toOptimisedFile(browserViewableImage.file, browserViewableImage, tempDir) + Some(browserViewableImage.copy(file = optimisedFile).copy(mimeType = optimisedMimeType).asStorableOptimisedImage) + } else if (browserViewableImage.mustUpload) { + Some(browserViewableImage.asStorableOptimisedImage) + } else + None + } + + def toMetaMap(uploadRequest: UploadRequest): Map[String, String] = { + val baseMeta = Map( + "uploaded_by" -> uploadRequest.uploadedBy, + "upload_time" -> printDateTime(uploadRequest.uploadTime) + ) ++ uploadRequest.identifiersMeta + + uploadRequest.uploadInfo.filename match { + case Some(f) => baseMeta ++ Map("file_name" -> URLEncoder.encode(f, StandardCharsets.UTF_8.name())) + case _ => baseMeta } } @@ -367,35 +220,120 @@ object Uploader extends GridLogging { private def createThumbFuture(fileMetadata: FileMetadata, colourModelFuture: Future[Option[String]], - uploadRequest: UploadRequest, + storableBrowserViewableImage: StorableBrowserViewableImage, deps: ImageUploadOpsDependencies)(implicit ec: ExecutionContext) = { import deps._ for { colourModel <- colourModelFuture iccColourSpace = FileMetadataHelper.normalisedIccColourSpace(fileMetadata) thumb <- imageOps - .createThumbnail(uploadRequest.tempFile, uploadRequest.mimeType, config.thumbWidth, + .createThumbnail(storableBrowserViewableImage.file, Some(storableBrowserViewableImage.mimeType), config.thumbWidth, config.thumbQuality, config.tempDir, iccColourSpace, colourModel) } yield thumb } - private def createOptimisedFileFuture(uploadRequest: UploadRequest, - deps: ImageUploadOpsDependencies)(implicit ec: ExecutionContext): Future[UploadRequest] = { + private def createBrowserViewableFileFuture(uploadRequest: UploadRequest, + tempDir: File, + deps: ImageUploadOpsDependencies)(implicit ec: ExecutionContext): Future[StorableBrowserViewableImage] = { import deps._ uploadRequest.mimeType match { case Some(mime) if config.transcodedMimeTypes.contains(mime) => for { - (file, filetype) <- imageOps.transformImage(uploadRequest.tempFile, uploadRequest.mimeType, config.tempDir) - } yield uploadRequest - .copy(mimeType = Some(MimeType(filetype))) - .copy(tempFile = file) - case _ => - Future.successful(uploadRequest) + (file, filetype) <- imageOps.transformImage(uploadRequest.tempFile, uploadRequest.mimeType, tempDir) + } yield StorableBrowserViewableImage( + uploadRequest.imageId, + file = file, + mimeType = MimeType(filetype), + mustUpload = true + ) + case Some(mimeType) => + Future.successful( + StorableBrowserViewableImage( + uploadRequest.imageId, + file = uploadRequest.tempFile, + mimeType = mimeType) + ) + case None => Future.failed(new Exception("This file is not an image with an identifiable mime type")) } } +} + +class Uploader(val store: ImageLoaderStore, + val config: ImageLoaderConfig, + val imageOps: ImageOperations, + val notifications: Notifications) + (implicit val ec: ExecutionContext) extends ArgoHelpers { -} + def fromUploadRequest(uploadRequest: UploadRequest) + (implicit logMarker: LogMarker): Future[ImageUpload] = { + val sideEffectDependencies = ImageUploadOpsDependencies(toImageUploadOpsCfg(config), imageOps, + storeSource, storeThumbnail, storeOptimisedImage) + val finalImage = fromUploadRequestShared(uploadRequest, sideEffectDependencies) + finalImage.map(img => Stopwatch("finalImage"){ImageUpload(uploadRequest, img)}) + } + + private def storeSource(storableOriginalImage: StorableOriginalImage) + (implicit logMarker: LogMarker) = store.store(storableOriginalImage) + + private def storeThumbnail(storableThumbImage: StorableThumbImage) + (implicit logMarker: LogMarker) = store.store(storableThumbImage) + + private def storeOptimisedImage(storableOptimisedImage: StorableOptimisedImage) + (implicit logMarker: LogMarker) = store.store(storableOptimisedImage) + + def loadFile(digestedFile: DigestedFile, + user: Principal, + uploadedBy: Option[String], + identifiers: Option[String], + uploadTime: DateTime, + filename: Option[String], + requestId: UUID) + (implicit ec:ExecutionContext, + logMarker: LogMarker): Future[UploadRequest] = Future { + val DigestedFile(tempFile, id) = digestedFile + + // TODO: should error if the JSON parsing failed + val identifiersMap = identifiers.map(Json.parse(_).as[Map[String, String]]) getOrElse Map() + + MimeTypeDetection.guessMimeType(tempFile) match { + case util.Left(unsupported) => + logger.error(s"Unsupported mimetype", unsupported) + throw unsupported + case util.Right(mimeType) => + logger.info(s"Detected mimetype as $mimeType") + UploadRequest( + requestId = requestId, + imageId = id, + tempFile = tempFile, + mimeType = Some(mimeType), + uploadTime = uploadTime, + uploadedBy = uploadedBy.getOrElse(Authentication.getIdentity(user)), + identifiers = identifiersMap, + uploadInfo = UploadInfo(filename) + ) + } + } + + def storeFile(uploadRequest: UploadRequest) + (implicit ec:ExecutionContext, + logMarker: LogMarker): Future[JsObject] = { + + logger.info("Storing file") + + for { + imageUpload <- fromUploadRequest(uploadRequest) + updateMessage = UpdateMessage(subject = "image", image = Some(imageUpload.image)) + _ <- Future { notifications.publish(updateMessage) } + // TODO: centralise where all these URLs are constructed + uri = s"${config.apiUri}/images/${uploadRequest.imageId}" + } yield { + Json.obj("uri" -> uri) + } + + } + +} diff --git a/image-loader/app/model/upload/OptimiseOps.scala b/image-loader/app/model/upload/OptimiseOps.scala new file mode 100644 index 0000000000..4d836303a8 --- /dev/null +++ b/image-loader/app/model/upload/OptimiseOps.scala @@ -0,0 +1,45 @@ +package model.upload + +import java.io.File + +import com.gu.mediaservice.lib.StorableImage +import com.gu.mediaservice.lib.logging.{LogMarker, Stopwatch} +import com.gu.mediaservice.model.{FileMetadata, MimeType, Png, Tiff} +import model.ImageUploadOpsCfg + +import scala.sys.process._ + +trait OptimiseOps { + def toOptimisedFile(file: File, storableImage: StorableImage, tempDir: File) + (implicit logMarker: LogMarker): (File, MimeType) + def isTransformedFilePath(filePath: String): Boolean + def shouldOptimise(mimeType: Option[MimeType], fileMetadata: FileMetadata): Boolean +} + +object OptimiseWithPngQuant extends OptimiseOps { + + // TODO This really ought to be a Future, right? + def toOptimisedFile(file: File, storableImage: StorableImage, tempDir: File) + (implicit logMarker: LogMarker): (File, MimeType) = { + val optimisedFilePath = tempDir.getAbsolutePath + "/optimisedpng - " + storableImage.id + ".png" + Stopwatch("pngquant") { + Seq("pngquant", "--quality", "1-85", file.getAbsolutePath, "--output", optimisedFilePath).! + } + (new File(optimisedFilePath), Png) + } + + def isTransformedFilePath(filePath: String): Boolean = filePath.contains("transformed-") + + def shouldOptimise(mimeType: Option[MimeType], fileMetadata: FileMetadata): Boolean = + mimeType match { + case Some(Png) => + fileMetadata.colourModelInformation.get("colorType") match { + case Some("True Color") => true + case Some("True Color with Alpha") => true + case _ => false + } + case Some(Tiff) => true + case _ => false + } +} + diff --git a/image-loader/app/model/UploadRequest.scala b/image-loader/app/model/upload/UploadRequest.scala similarity index 62% rename from image-loader/app/model/UploadRequest.scala rename to image-loader/app/model/upload/UploadRequest.scala index 3d4ff79fea..b256776a0a 100644 --- a/image-loader/app/model/UploadRequest.scala +++ b/image-loader/app/model/upload/UploadRequest.scala @@ -1,31 +1,31 @@ -package model +package model.upload import java.io.File import java.util.UUID -import com.gu.mediaservice.model.{UploadInfo, MimeType} +import com.gu.mediaservice.model.{MimeType, UploadInfo} import net.logstash.logback.marker.{LogstashMarker, Markers} import org.joda.time.format.ISODateTimeFormat import org.joda.time.{DateTime, DateTimeZone} - import scala.collection.JavaConverters._ case class UploadRequest( - requestId: UUID, - imageId: String, - tempFile: File, - mimeType: Option[MimeType], - uploadTime: DateTime, - uploadedBy: String, - identifiers: Map[String, String], - uploadInfo: UploadInfo -) { + requestId: UUID, + imageId: String, + tempFile: File, + mimeType: Option[MimeType], + uploadTime: DateTime, + uploadedBy: String, + identifiers: Map[String, String], + uploadInfo: UploadInfo + ) { + val identifiersMeta: Map[String, String] = identifiers.map { case (k, v) => (s"identifier!$k", v) } def toLogMarker: LogstashMarker = { val fallback = "none" - val markers = Map ( + val markers = Map( "requestId" -> requestId, "imageId" -> imageId, "mimeType" -> mimeType.getOrElse(fallback), @@ -37,4 +37,5 @@ case class UploadRequest( Markers.appendEntries(markers.asJava) } + } diff --git a/image-loader/test/resources/thisisnotanimage.jpg b/image-loader/test/resources/thisisnotanimage.jpg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/image-loader/test/resources/thisisnotanimage.stupid b/image-loader/test/resources/thisisnotanimage.stupid new file mode 100644 index 0000000000..e69de29bb2 diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index c02621cef8..f644896949 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -4,11 +4,14 @@ import java.io.File import java.net.URI import java.util.UUID +import com.drew.imaging.ImageProcessingException +import com.gu.mediaservice.lib.{StorableOptimisedImage, StorableOriginalImage, StorableThumbImage} import com.gu.mediaservice.lib.aws.{S3Metadata, S3Object, S3ObjectMetadata} import com.gu.mediaservice.lib.imaging.ImageOperations import com.gu.mediaservice.lib.logging.LogMarker -import com.gu.mediaservice.model.{FileMetadata, Image, Jpeg, MimeType, Png, Tiff, UploadInfo} +import com.gu.mediaservice.model.{FileMetadata, Jpeg, MimeType, Png, Tiff, UploadInfo} import lib.imaging.MimeTypeDetection +import model.upload.{OptimiseWithPngQuant, UploadRequest} import org.joda.time.DateTime import org.scalatest.mockito.MockitoSugar import org.scalatest.{AsyncFunSuite, Matchers} @@ -26,7 +29,8 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { implicit val logMarker = new MockLogMarker(); // For mime type info, see https://github.com/guardian/grid/pull/2568 - val mockConfig = ImageUploadOpsCfg(new File("/tmp"), 256, 85d, List(Tiff), "img-bucket", "thumb-bucket") + val tempDir = new File("/tmp") + val mockConfig = ImageUploadOpsCfg(tempDir, 256, 85d, List(Tiff), "img-bucket", "thumb-bucket") /** * @todo: I flailed about until I found a path that worked, but @@ -40,7 +44,6 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { expectedOriginalMimeType: MimeType, expectedThumbMimeType: MimeType, expectedOptimisedMimeType: Option[MimeType] = None) = { - val willCreateOptimisedPNG = expectedOptimisedMimeType.isDefined val uuid = UUID.randomUUID() val randomId = UUID.randomUUID().toString + fileName @@ -48,38 +51,38 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { val mockS3Meta = S3Metadata(Map.empty, S3ObjectMetadata(None, None, None)) val mockS3Object = S3Object(new URI("innernets.com"), 12345, mockS3Meta) - def storeOrProjectOriginalFile: UploadRequest => Future[S3Object] = { + def storeOrProjectOriginalFile: StorableOriginalImage => Future[S3Object] = { a => { Future.successful( mockS3Object - .copy(size = a.tempFile.length()) + .copy(size = a.file.length()) .copy(metadata = mockS3Object.metadata .copy(objectMetadata = mockS3Object.metadata.objectMetadata - .copy(contentType = a.mimeType)))) + .copy(contentType = Some(a.mimeType))))) } } - def storeOrProjectThumbFile: (UploadRequest, File) => Future[S3Object] = { - (a, b) => { + def storeOrProjectThumbFile: StorableThumbImage => Future[S3Object] = { + a => { Future.successful( mockS3Object - .copy(size = b.length()) + .copy(size = a.file.length()) .copy(metadata = mockS3Object.metadata .copy(objectMetadata = mockS3Object.metadata.objectMetadata - .copy(contentType = a.mimeType))) + .copy(contentType = Some(a.mimeType)))) ) } } - def storeOrProjectOptimisedPNG: (UploadRequest, File) => Future[S3Object] = { - (a, b) => { - if (a.mimeType.contains(Jpeg)) fail("We should not create optimised jpg") + def storeOrProjectOptimisedPNG: StorableOptimisedImage => Future[S3Object] = { + a => { + if (a.mimeType == Jpeg) fail("We should not create optimised jpg") Future.successful( mockS3Object - .copy(size = b.length()) + .copy(size = a.file.length()) .copy(metadata = mockS3Object.metadata .copy(objectMetadata = mockS3Object.metadata.objectMetadata - .copy(contentType = a.mimeType))) + .copy(contentType = Some(a.mimeType)))) ) } } @@ -107,11 +110,10 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { ) val futureImage = Uploader.uploadAndStoreImage( - mockConfig, mockDependencies.storeOrProjectOriginalFile, mockDependencies.storeOrProjectThumbFile, - mockDependencies.storeOrProjectOptimisedPNG, - OptimisedPngQuantOps, + mockDependencies.storeOrProjectOptimisedImage, + OptimiseWithPngQuant, uploadRequest, mockDependencies, FileMetadata() @@ -119,11 +121,15 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { // Assertions; Failure will auto-fail futureImage.map(i => { + // Assertions on original request assert(i.id == randomId, "Correct id comes back") assert(i.source.mimeType.contains(expectedOriginalMimeType), "Should have the correct mime type") + + // Assertions on generated thumbnail image assert(i.thumbnail.isDefined, "Should always create a thumbnail") - assert(i.optimisedPng.isDefined == willCreateOptimisedPNG, "Should or should not create an optimised png") assert(i.thumbnail.get.mimeType.get == expectedThumbMimeType, "Should have correct thumb mime type") + + // Assertions on optional generated optimised png image assert(i.optimisedPng.flatMap(p => p.mimeType) == expectedOptimisedMimeType, "Should have correct optimised mime type") }) } @@ -151,6 +157,23 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { test("basn2c16_TrueColor_16bit") { imageUpload("basn2c16_TrueColor_16bit.png", Png, Png, Some(Png)) } + test("not an image but looks like one") { + imageUpload("thisisnotanimage.jpg", Png, Png, Some(Png)).transformWith{ + case Success(_) => fail("Should have thrown an error") + case Failure(e) => e match { + case e: ImageProcessingException => assert(e.getMessage == "File format could not be determined") + } + } + } + test("not an image and does not look like one") { + // this exception is thrown before the futures are resolved, and so does not need transformWith + try { + imageUpload("thisisnotanimage.stupid", Png, Png, Some(Png)) + fail("Should have thrown an error") + } catch { + case e: Exception => assert(e.getMessage == "No idea what you have given me") + } + } } // todo add to tests - tiff with layers, but not true colour so does not need optimising. MK to provide From adf3e1ae4c71460dcfd79101547af5253f4ebf2d Mon Sep 17 00:00:00 2001 From: Jonathon Herbert Date: Wed, 2 Dec 2020 17:06:28 +0000 Subject: [PATCH 14/36] Minor refactor to move synchronous code out for for comp; check optimised png exists --- image-loader/app/model/Uploader.scala | 18 +++++++++--------- .../app/model/upload/OptimiseOps.scala | 9 ++++++++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/image-loader/app/model/Uploader.scala b/image-loader/app/model/Uploader.scala index e90626cb0f..035d26604a 100644 --- a/image-loader/app/model/Uploader.scala +++ b/image-loader/app/model/Uploader.scala @@ -157,19 +157,19 @@ object Uploader extends GridLogging { sourceDimensions <- sourceDimensionsFuture thumbDimensions <- FileMetadataReader.dimensions(thumb, Some(Jpeg)) colourModel <- colourModelFuture - fullFileMetadata = fileMetadata.copy(colourModel = colourModel) - metadata = ImageMetadataConverter.fromFileMetadata(fullFileMetadata) - cleanMetadata = ImageUpload.metadataCleaners.clean(metadata) + } yield { + val fullFileMetadata = fileMetadata.copy(colourModel = colourModel) + val metadata = ImageMetadataConverter.fromFileMetadata(fullFileMetadata) + val cleanMetadata = ImageUpload.metadataCleaners.clean(metadata) - sourceAsset = Asset.fromS3Object(s3Source, sourceDimensions) - thumbAsset = Asset.fromS3Object(s3Thumb, thumbDimensions) + val sourceAsset = Asset.fromS3Object(s3Source, sourceDimensions) + val thumbAsset = Asset.fromS3Object(s3Thumb, thumbDimensions) - pngAsset = s3PngOption.map(Asset.fromS3Object(_, sourceDimensions)) - baseImage = ImageUpload.createImage(uploadRequest, sourceAsset, thumbAsset, pngAsset, fullFileMetadata, cleanMetadata) + val pngAsset = s3PngOption.map(Asset.fromS3Object(_, sourceDimensions)) + val baseImage = ImageUpload.createImage(uploadRequest, sourceAsset, thumbAsset, pngAsset, fullFileMetadata, cleanMetadata) - processedImage = SupplierProcessors.process(baseImage) + val processedImage = SupplierProcessors.process(baseImage) - } yield { logger.info("Ending image ops") // FIXME: dirty hack to sync the originalUsageRights and originalMetadata as well processedImage.copy( diff --git a/image-loader/app/model/upload/OptimiseOps.scala b/image-loader/app/model/upload/OptimiseOps.scala index 4d836303a8..b3c196b810 100644 --- a/image-loader/app/model/upload/OptimiseOps.scala +++ b/image-loader/app/model/upload/OptimiseOps.scala @@ -21,11 +21,18 @@ object OptimiseWithPngQuant extends OptimiseOps { // TODO This really ought to be a Future, right? def toOptimisedFile(file: File, storableImage: StorableImage, tempDir: File) (implicit logMarker: LogMarker): (File, MimeType) = { + val optimisedFilePath = tempDir.getAbsolutePath + "/optimisedpng - " + storableImage.id + ".png" Stopwatch("pngquant") { Seq("pngquant", "--quality", "1-85", file.getAbsolutePath, "--output", optimisedFilePath).! } - (new File(optimisedFilePath), Png) + + val optimisedFile = new File(optimisedFilePath) + if (optimisedFile.exists()) { + (optimisedFile, Png) + } else { + throw new Exception(s"Attempted to optimise PNG file ${optimisedFile.getPath}") + } } def isTransformedFilePath(filePath: String): Boolean = filePath.contains("transformed-") From cbc85f58e171fd08dc4a2e03195b7139a197d41a Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Wed, 2 Dec 2020 17:16:41 +0000 Subject: [PATCH 15/36] Comment out IM tests for CI --- .../app/model/upload/OptimiseOps.scala | 7 ++++--- .../test/scala/model/ImageUploadTest.scala | 20 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/image-loader/app/model/upload/OptimiseOps.scala b/image-loader/app/model/upload/OptimiseOps.scala index b3c196b810..21e367ac12 100644 --- a/image-loader/app/model/upload/OptimiseOps.scala +++ b/image-loader/app/model/upload/OptimiseOps.scala @@ -5,7 +5,6 @@ import java.io.File import com.gu.mediaservice.lib.StorableImage import com.gu.mediaservice.lib.logging.{LogMarker, Stopwatch} import com.gu.mediaservice.model.{FileMetadata, MimeType, Png, Tiff} -import model.ImageUploadOpsCfg import scala.sys.process._ @@ -22,9 +21,11 @@ object OptimiseWithPngQuant extends OptimiseOps { def toOptimisedFile(file: File, storableImage: StorableImage, tempDir: File) (implicit logMarker: LogMarker): (File, MimeType) = { - val optimisedFilePath = tempDir.getAbsolutePath + "/optimisedpng - " + storableImage.id + ".png" + val optimisedFilePath = tempDir.getAbsolutePath + "/optimisedpng - " + storableImage.id + Png.fileExtension Stopwatch("pngquant") { - Seq("pngquant", "--quality", "1-85", file.getAbsolutePath, "--output", optimisedFilePath).! + val result = Seq("pngquant", "--quality", "1-85", file.getAbsolutePath, "--output", optimisedFilePath).! + if (result>0) + throw new Exception(s"pngquant failed to convert to optimised png file (rc = $result)") } val optimisedFile = new File(optimisedFilePath) diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index f644896949..b377b5d82c 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -134,30 +134,28 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { }) } - // TODO check somehow that the temp files have all been cleared up. - - test("rubbish") { + ignore("rubbish") { imageUpload("rubbish.jpg", Jpeg, Jpeg) } - test("lighthouse") { + ignore("lighthouse") { imageUpload("lighthouse.tif", Tiff, Png, Some(Png)) } - test("tiff_8bpc_layered_withTransparency") { + ignore("tiff_8bpc_layered_withTransparency") { imageUpload("tiff_8bpc_layered_withTransparency.tif", Tiff, Png, Some(Png)) } - test("tiff_8bpc_flat") { + ignore("tiff_8bpc_flat") { imageUpload("tiff_8bpc_flat.tif", Tiff, Png, Some(Png)) } - test("IndexedColor") { + ignore("IndexedColor") { imageUpload("IndexedColor.png", Png, Png) } - test("bgan6a16_TrueColorWithAlpha_16bit") { + ignore("bgan6a16_TrueColorWithAlpha_16bit") { imageUpload("bgan6a16_TrueColorWithAlpha_16bit.png", Png, Png, Some(Png)) } - test("basn2c16_TrueColor_16bit") { + ignore("basn2c16_TrueColor_16bit") { imageUpload("basn2c16_TrueColor_16bit.png", Png, Png, Some(Png)) } - test("not an image but looks like one") { + ignore("not an image but looks like one") { imageUpload("thisisnotanimage.jpg", Png, Png, Some(Png)).transformWith{ case Success(_) => fail("Should have thrown an error") case Failure(e) => e match { @@ -165,7 +163,7 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { } } } - test("not an image and does not look like one") { + ignore("not an image and does not look like one") { // this exception is thrown before the futures are resolved, and so does not need transformWith try { imageUpload("thisisnotanimage.stupid", Png, Png, Some(Png)) From 2b4e608611b42aac87e7106c66cc65c0d7a2ec16 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 11:03:29 +0000 Subject: [PATCH 16/36] Enforce correct mime types for optimised files and thumbs --- .../lib/imaging/ImageOperations.scala | 36 +++++++----- image-loader/app/model/Projector.scala | 6 +- image-loader/app/model/Uploader.scala | 25 ++++---- .../app/model/upload/OptimiseOps.scala | 11 ++-- .../test/scala/model/ImageUploadTest.scala | 58 +++++++++---------- 5 files changed, 74 insertions(+), 62 deletions(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala index 317548f8de..c4ffb92dd0 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala @@ -4,6 +4,8 @@ import java.io._ import org.im4java.core.IMOperation import com.gu.mediaservice.lib.Files._ +import com.gu.mediaservice.lib.StorableThumbImage +import com.gu.mediaservice.lib.imaging.ImageOperations.thumbMimeType import com.gu.mediaservice.lib.imaging.im4jwrapper.ImageMagick.{addImage, format, runIdentifyCmd} import com.gu.mediaservice.lib.imaging.im4jwrapper.{ExifTool, ImageMagick} import com.gu.mediaservice.lib.logging.GridLogging @@ -114,21 +116,26 @@ class ImageOperations(playPath: String) extends GridLogging { val thumbUnsharpRadius = 0.5d val thumbUnsharpSigma = 0.5d val thumbUnsharpAmount = 0.8d - def createThumbnail(sourceFile: File, sourceMimeType: Option[MimeType], width: Int, qual: Double = 100d, - tempDir: File, iccColourSpace: Option[String], colourModel: Option[String]): Future[File] = { + def createThumbnail(sourceFile: File, + sourceMimeType: Option[MimeType], + width: Int, + qual: Double = 100d, + tempDir: File, + iccColourSpace: Option[String], + colourModel: Option[String]): Future[(File, MimeType)] = { + val cropSource = addImage(sourceFile) + val thumbnailed = thumbnail(cropSource)(width) + val corrected = correctColour(thumbnailed)(iccColourSpace, colourModel) + val converted = applyOutputProfile(corrected, optimised = true) + val stripped = stripMeta(converted) + val profiled = applyOutputProfile(stripped, optimised = true) + val unsharpened = unsharp(profiled)(thumbUnsharpRadius, thumbUnsharpSigma, thumbUnsharpAmount) + val qualified = quality(unsharpened)(qual) + val addOutput = {file:File => addDestImage(qualified)(file)} for { - outputFile <- createTempFile(s"thumb-", ".jpg", tempDir) - cropSource = addImage(sourceFile) - thumbnailed = thumbnail(cropSource)(width) - corrected = correctColour(thumbnailed)(iccColourSpace, colourModel) - converted = applyOutputProfile(corrected, optimised = true) - stripped = stripMeta(converted) - profiled = applyOutputProfile(stripped, optimised = true) - unsharpened = unsharp(profiled)(thumbUnsharpRadius, thumbUnsharpSigma, thumbUnsharpAmount) - qualified = quality(unsharpened)(qual) - addOutput = addDestImage(qualified)(outputFile) - _ <- runConvertCmd(addOutput, useImageMagick = sourceMimeType.contains(Tiff)) - } yield outputFile + outputFile <- createTempFile(s"thumb-", thumbMimeType.fileExtension, tempDir) + _ <- runConvertCmd(addOutput(outputFile), useImageMagick = sourceMimeType.contains(Tiff)) + } yield (outputFile, thumbMimeType) } def transformImage(sourceFile: File, sourceMimeType: Option[MimeType], tempDir: File): Future[(File, String)] = { @@ -177,6 +184,7 @@ class ImageOperations(playPath: String) extends GridLogging { } object ImageOperations { + val thumbMimeType = Jpeg def identifyColourModel(sourceFile: File, mimeType: MimeType)(implicit ec: ExecutionContext): Future[Option[String]] = { // TODO: use mimeType to lookup other properties once we support other formats diff --git a/image-loader/app/model/Projector.scala b/image-loader/app/model/Projector.scala index edd3a4dcb3..55f7c6c8ab 100644 --- a/image-loader/app/model/Projector.scala +++ b/image-loader/app/model/Projector.scala @@ -13,7 +13,7 @@ import com.gu.mediaservice.lib.net.URI import com.gu.mediaservice.model.{Image, Jpeg, Png, UploadInfo} import lib.imaging.{MimeTypeDetection, NoSuchImageExistsInS3} import lib.{DigestedFile, ImageLoaderConfig} -import model.upload.UploadRequest +import model.upload.{OptimiseWithPngQuant, UploadRequest} import org.apache.tika.io.IOUtils import org.joda.time.{DateTime, DateTimeZone} import play.api.{Logger, MarkerContext} @@ -148,7 +148,7 @@ class ImageUploadProjectionOps(config: ImageUploadOpsCfg, private def projectThumbnailFileAsS3Model(storableThumbImage: StorableThumbImage)(implicit ec: ExecutionContext) = Future { val key = ImageIngestOperations.fileKeyFromId(storableThumbImage.id) - val thumbMimeType = Some(Jpeg) // todo remove hard coding + val thumbMimeType = Some(OptimiseWithPngQuant.optimiseMimeType) // this IS what we will generate. S3Ops.projectFileAsS3Object( config.thumbBucket, key, @@ -159,7 +159,7 @@ class ImageUploadProjectionOps(config: ImageUploadOpsCfg, private def projectOptimisedPNGFileAsS3Model(storableOptimisedImage: StorableOptimisedImage)(implicit ec: ExecutionContext) = Future { val key = ImageIngestOperations.optimisedPngKeyFromId(storableOptimisedImage.id) - val optimisedPngMimeType = Some(Png) // todo remove hard coding + val optimisedPngMimeType = Some(ImageOperations.thumbMimeType) // this IS what we will generate. S3Ops.projectFileAsS3Object( config.originalFileBucket, key, diff --git a/image-loader/app/model/Uploader.scala b/image-loader/app/model/Uploader.scala index 035d26604a..789e1055ba 100644 --- a/image-loader/app/model/Uploader.scala +++ b/image-loader/app/model/Uploader.scala @@ -126,7 +126,6 @@ object Uploader extends GridLogging { case None => throw new Exception("No idea what you have given me") } - import java.nio.file.Files val makeNewDirInTempDirHere: File = Files.createTempDirectory(deps.config.tempDir.toPath, "upload").toFile val colourModelFuture = ImageOperations.identifyColourModel(uploadRequest.tempFile, originalMimeType) @@ -146,16 +145,15 @@ object Uploader extends GridLogging { browserViewableImage <- eventualBrowserViewableImage s3Source <- sourceStoreFuture optimisedFileMetadata <- FileMetadataReader.fromICPTCHeadersWithColorInfo(browserViewableImage) - thumb <- createThumbFuture(optimisedFileMetadata, colourModelFuture, browserViewableImage, deps) - thumbViewableImage = browserViewableImage.copy(file = thumb).asStorableThumbImage + thumbViewableImage <- createThumbFuture(optimisedFileMetadata, colourModelFuture, browserViewableImage, deps) s3Thumb <- storeOrProjectThumbFile(thumbViewableImage) - maybeStorableOptimisedImage = getStorableOptimisedImage(makeNewDirInTempDirHere, optimiseOps, browserViewableImage, optimisedFileMetadata) + maybeStorableOptimisedImage <- getStorableOptimisedImage(makeNewDirInTempDirHere, optimiseOps, browserViewableImage, optimisedFileMetadata) s3PngOption <- maybeStorableOptimisedImage match { case Some(storableOptimisedImage) => storeOrProjectOptimisedFile(storableOptimisedImage).map(a=>Some(a)) case None => Future.successful(None) } sourceDimensions <- sourceDimensionsFuture - thumbDimensions <- FileMetadataReader.dimensions(thumb, Some(Jpeg)) + thumbDimensions <- FileMetadataReader.dimensions(thumbViewableImage.file, Some(Jpeg)) colourModel <- colourModelFuture } yield { val fullFileMetadata = fileMetadata.copy(colourModel = colourModel) @@ -189,14 +187,15 @@ object Uploader extends GridLogging { optimiseOps: OptimiseOps, browserViewableImage: StorableBrowserViewableImage, optimisedFileMetadata: FileMetadata) - (implicit ec: ExecutionContext, logMarker: LogMarker): Option[StorableOptimisedImage] = { + (implicit ec: ExecutionContext, logMarker: LogMarker): Future[Option[StorableOptimisedImage]] = { if (optimiseOps.shouldOptimise(Some(browserViewableImage.mimeType), optimisedFileMetadata)) { - val (optimisedFile: File, optimisedMimeType: MimeType) = optimiseOps.toOptimisedFile(browserViewableImage.file, browserViewableImage, tempDir) - Some(browserViewableImage.copy(file = optimisedFile).copy(mimeType = optimisedMimeType).asStorableOptimisedImage) + for { + (optimisedFile: File, optimisedMimeType: MimeType) <- optimiseOps.toOptimisedFile(browserViewableImage.file, browserViewableImage, tempDir) + } yield Some(browserViewableImage.copy(file = optimisedFile).copy(mimeType = optimisedMimeType).asStorableOptimisedImage) } else if (browserViewableImage.mustUpload) { - Some(browserViewableImage.asStorableOptimisedImage) + Future.successful(Some(browserViewableImage.asStorableOptimisedImage)) } else - None + Future.successful(None) } def toMetaMap(uploadRequest: UploadRequest): Map[String, String] = { @@ -226,10 +225,12 @@ object Uploader extends GridLogging { for { colourModel <- colourModelFuture iccColourSpace = FileMetadataHelper.normalisedIccColourSpace(fileMetadata) - thumb <- imageOps + (thumb, thumbMimeType) <- imageOps .createThumbnail(storableBrowserViewableImage.file, Some(storableBrowserViewableImage.mimeType), config.thumbWidth, config.thumbQuality, config.tempDir, iccColourSpace, colourModel) - } yield thumb + } yield storableBrowserViewableImage + .copy(file = thumb, mimeType = thumbMimeType) + .asStorableThumbImage } private def createBrowserViewableFileFuture(uploadRequest: UploadRequest, diff --git a/image-loader/app/model/upload/OptimiseOps.scala b/image-loader/app/model/upload/OptimiseOps.scala index 21e367ac12..857b574539 100644 --- a/image-loader/app/model/upload/OptimiseOps.scala +++ b/image-loader/app/model/upload/OptimiseOps.scala @@ -6,22 +6,25 @@ import com.gu.mediaservice.lib.StorableImage import com.gu.mediaservice.lib.logging.{LogMarker, Stopwatch} import com.gu.mediaservice.model.{FileMetadata, MimeType, Png, Tiff} +import scala.concurrent.{ExecutionContext, Future} import scala.sys.process._ trait OptimiseOps { def toOptimisedFile(file: File, storableImage: StorableImage, tempDir: File) - (implicit logMarker: LogMarker): (File, MimeType) + (implicit ec: ExecutionContext, logMarker: LogMarker): Future[(File, MimeType)] def isTransformedFilePath(filePath: String): Boolean def shouldOptimise(mimeType: Option[MimeType], fileMetadata: FileMetadata): Boolean + def optimiseMimeType: MimeType } object OptimiseWithPngQuant extends OptimiseOps { - // TODO This really ought to be a Future, right? + override def optimiseMimeType: MimeType = Png + def toOptimisedFile(file: File, storableImage: StorableImage, tempDir: File) - (implicit logMarker: LogMarker): (File, MimeType) = { + (implicit ec: ExecutionContext, logMarker: LogMarker): Future[(File, MimeType)] = Future { - val optimisedFilePath = tempDir.getAbsolutePath + "/optimisedpng - " + storableImage.id + Png.fileExtension + val optimisedFilePath = tempDir.getAbsolutePath + "/optimisedpng - " + storableImage.id + optimiseMimeType.fileExtension Stopwatch("pngquant") { val result = Seq("pngquant", "--quality", "1-85", file.getAbsolutePath, "--output", optimisedFilePath).! if (result>0) diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index b377b5d82c..5ea467eaf6 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -14,23 +14,23 @@ import lib.imaging.MimeTypeDetection import model.upload.{OptimiseWithPngQuant, UploadRequest} import org.joda.time.DateTime import org.scalatest.mockito.MockitoSugar -import org.scalatest.{AsyncFunSuite, Matchers} +import org.scalatest.{Assertion, AsyncFunSuite, Matchers} import test.lib.ResourceHelpers import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success} class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { - implicit val ec = ExecutionContext.Implicits.global + private implicit val ec: ExecutionContext = ExecutionContext.Implicits.global class MockLogMarker extends LogMarker { override def markerContents: Map[String, Any] = Map() } - implicit val logMarker = new MockLogMarker(); + private implicit val logMarker: MockLogMarker = new MockLogMarker() // For mime type info, see https://github.com/guardian/grid/pull/2568 val tempDir = new File("/tmp") - val mockConfig = ImageUploadOpsCfg(tempDir, 256, 85d, List(Tiff), "img-bucket", "thumb-bucket") + val mockConfig: ImageUploadOpsCfg = ImageUploadOpsCfg(tempDir, 256, 85d, List(Tiff), "img-bucket", "thumb-bucket") /** * @todo: I flailed about until I found a path that worked, but @@ -39,11 +39,10 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { */ val imageOps: ImageOperations = new ImageOperations(System.getProperty("user.dir")) - def imageUpload( - fileName: String, - expectedOriginalMimeType: MimeType, - expectedThumbMimeType: MimeType, - expectedOptimisedMimeType: Option[MimeType] = None) = { + private def imageUpload( + fileName: String, + expectedOriginalMimeType: MimeType, + expectOptimisedFile: Boolean = false): Future[Assertion] = { val uuid = UUID.randomUUID() val randomId = UUID.randomUUID().toString + fileName @@ -127,46 +126,47 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { // Assertions on generated thumbnail image assert(i.thumbnail.isDefined, "Should always create a thumbnail") - assert(i.thumbnail.get.mimeType.get == expectedThumbMimeType, "Should have correct thumb mime type") + assert(i.thumbnail.get.mimeType.get == Jpeg, "Should have correct thumb mime type") // Assertions on optional generated optimised png image - assert(i.optimisedPng.flatMap(p => p.mimeType) == expectedOptimisedMimeType, "Should have correct optimised mime type") + assert(i.optimisedPng.isDefined == expectOptimisedFile, "Should have optimised file") + assert(!expectOptimisedFile || i.optimisedPng.flatMap(p => p.mimeType).contains(Png), "Should have correct optimised mime type") }) } - ignore("rubbish") { - imageUpload("rubbish.jpg", Jpeg, Jpeg) + test("rubbish") { + imageUpload("rubbish.jpg", Jpeg) } - ignore("lighthouse") { - imageUpload("lighthouse.tif", Tiff, Png, Some(Png)) + test("lighthouse") { + imageUpload("lighthouse.tif", Tiff, expectOptimisedFile = true) } - ignore("tiff_8bpc_layered_withTransparency") { - imageUpload("tiff_8bpc_layered_withTransparency.tif", Tiff, Png, Some(Png)) + test("tiff_8bpc_layered_withTransparency") { + imageUpload("tiff_8bpc_layered_withTransparency.tif", Tiff, expectOptimisedFile = true) } - ignore("tiff_8bpc_flat") { - imageUpload("tiff_8bpc_flat.tif", Tiff, Png, Some(Png)) + test("tiff_8bpc_flat") { + imageUpload("tiff_8bpc_flat.tif", Tiff, expectOptimisedFile = true) } - ignore("IndexedColor") { - imageUpload("IndexedColor.png", Png, Png) + test("IndexedColor") { + imageUpload("IndexedColor.png", Png) } - ignore("bgan6a16_TrueColorWithAlpha_16bit") { - imageUpload("bgan6a16_TrueColorWithAlpha_16bit.png", Png, Png, Some(Png)) + test("bgan6a16_TrueColorWithAlpha_16bit") { + imageUpload("bgan6a16_TrueColorWithAlpha_16bit.png", Png, expectOptimisedFile = true) } - ignore("basn2c16_TrueColor_16bit") { - imageUpload("basn2c16_TrueColor_16bit.png", Png, Png, Some(Png)) + test("basn2c16_TrueColor_16bit") { + imageUpload("basn2c16_TrueColor_16bit.png", Png, expectOptimisedFile = true) } - ignore("not an image but looks like one") { - imageUpload("thisisnotanimage.jpg", Png, Png, Some(Png)).transformWith{ + test("not an image but looks like one") { + imageUpload("thisisnotanimage.jpg", Png, expectOptimisedFile = true).transformWith{ case Success(_) => fail("Should have thrown an error") case Failure(e) => e match { case e: ImageProcessingException => assert(e.getMessage == "File format could not be determined") } } } - ignore("not an image and does not look like one") { + test("not an image and does not look like one") { // this exception is thrown before the futures are resolved, and so does not need transformWith try { - imageUpload("thisisnotanimage.stupid", Png, Png, Some(Png)) + imageUpload("thisisnotanimage.stupid", Png, expectOptimisedFile = true) fail("Should have thrown an error") } catch { case e: Exception => assert(e.getMessage == "No idea what you have given me") From cebe0c465736e9f9149e27c3e9adb7ce81bfe4f6 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 11:14:49 +0000 Subject: [PATCH 17/36] Turn off image magick tests for CI --- .../test/scala/model/ImageUploadTest.scala | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index 5ea467eaf6..ff4d7a56ef 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -134,28 +134,28 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { }) } - test("rubbish") { + ignore("rubbish") { imageUpload("rubbish.jpg", Jpeg) } - test("lighthouse") { + ignore("lighthouse") { imageUpload("lighthouse.tif", Tiff, expectOptimisedFile = true) } - test("tiff_8bpc_layered_withTransparency") { + ignore("tiff_8bpc_layered_withTransparency") { imageUpload("tiff_8bpc_layered_withTransparency.tif", Tiff, expectOptimisedFile = true) } - test("tiff_8bpc_flat") { + ignore("tiff_8bpc_flat") { imageUpload("tiff_8bpc_flat.tif", Tiff, expectOptimisedFile = true) } - test("IndexedColor") { + ignore("IndexedColor") { imageUpload("IndexedColor.png", Png) } - test("bgan6a16_TrueColorWithAlpha_16bit") { + ignore("bgan6a16_TrueColorWithAlpha_16bit") { imageUpload("bgan6a16_TrueColorWithAlpha_16bit.png", Png, expectOptimisedFile = true) } - test("basn2c16_TrueColor_16bit") { + ignore("basn2c16_TrueColor_16bit") { imageUpload("basn2c16_TrueColor_16bit.png", Png, expectOptimisedFile = true) } - test("not an image but looks like one") { + ignore("not an image but looks like one") { imageUpload("thisisnotanimage.jpg", Png, expectOptimisedFile = true).transformWith{ case Success(_) => fail("Should have thrown an error") case Failure(e) => e match { @@ -163,7 +163,7 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { } } } - test("not an image and does not look like one") { + ignore("not an image and does not look like one") { // this exception is thrown before the futures are resolved, and so does not need transformWith try { imageUpload("thisisnotanimage.stupid", Png, expectOptimisedFile = true) From 965a467f2768c5f659507935686f36b08841b76a Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 12:00:07 +0000 Subject: [PATCH 18/36] Remove hard coded type --- .../scala/com/gu/mediaservice/lib/ImageIngestOperations.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala index 0757e8fc36..409a328823 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala @@ -37,7 +37,7 @@ class ImageIngestOperations(imageBucket: String, thumbnailBucket: String, config private def storeOptimisedImage(storableImage: StorableImage) (implicit logMarker: LogMarker): Future[S3Object] = - storeImage(imageBucket, optimisedPngKeyFromId(storableImage.id), storableImage.file, Some(Png)) // TODO remove hard coding! + storeImage(imageBucket, optimisedPngKeyFromId(storableImage.id), storableImage.file, Some(storableImage.mimeType)) def deleteOriginal(id: String): Future[Unit] = if(isVersionedS3) deleteVersionedImage(imageBucket, fileKeyFromId(id)) else deleteImage(imageBucket, fileKeyFromId(id)) def deleteThumbnail(id: String): Future[Unit] = deleteImage(thumbnailBucket, fileKeyFromId(id)) From 8ca9d58a5eda57f4051b88e359fc72d48d8c1df2 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 12:04:56 +0000 Subject: [PATCH 19/36] Correct typoed method name --- .../app/lib/imaging/FileMetadataReader.scala | 6 +++--- image-loader/app/model/Uploader.scala | 4 ++-- .../scala/lib/imaging/FileMetadataReaderTest.scala | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/image-loader/app/lib/imaging/FileMetadataReader.scala b/image-loader/app/lib/imaging/FileMetadataReader.scala index 7b010e424f..f9994de7b1 100644 --- a/image-loader/app/lib/imaging/FileMetadataReader.scala +++ b/image-loader/app/lib/imaging/FileMetadataReader.scala @@ -58,10 +58,10 @@ object FileMetadataReader { } yield getMetadataWithICPTCHeaders(metadata, imageId) // FIXME: JPEG, JFIF, Photoshop, GPS, File - def fromICPTCHeadersWithColorInfo(image: StorableImage): Future[FileMetadata] = - fromICPTCHeadersWithColorInfo(image.file, image.id, image.mimeType) + def fromIPTCHeadersWithColorInfo(image: StorableImage): Future[FileMetadata] = + fromIPTCHeadersWithColorInfo(image.file, image.id, image.mimeType) - def fromICPTCHeadersWithColorInfo(image: File, imageId:String, mimeType: MimeType): Future[FileMetadata] = + def fromIPTCHeadersWithColorInfo(image: File, imageId:String, mimeType: MimeType): Future[FileMetadata] = for { metadata <- readMetadata(image) colourModelInformation <- getColorModelInformation(image, metadata, mimeType) diff --git a/image-loader/app/model/Uploader.scala b/image-loader/app/model/Uploader.scala index 789e1055ba..e2efee1524 100644 --- a/image-loader/app/model/Uploader.scala +++ b/image-loader/app/model/Uploader.scala @@ -144,7 +144,7 @@ object Uploader extends GridLogging { val eventualImage = for { browserViewableImage <- eventualBrowserViewableImage s3Source <- sourceStoreFuture - optimisedFileMetadata <- FileMetadataReader.fromICPTCHeadersWithColorInfo(browserViewableImage) + optimisedFileMetadata <- FileMetadataReader.fromIPTCHeadersWithColorInfo(browserViewableImage) thumbViewableImage <- createThumbFuture(optimisedFileMetadata, colourModelFuture, browserViewableImage, deps) s3Thumb <- storeOrProjectThumbFile(thumbViewableImage) maybeStorableOptimisedImage <- getStorableOptimisedImage(makeNewDirInTempDirHere, optimiseOps, browserViewableImage, optimisedFileMetadata) @@ -212,7 +212,7 @@ object Uploader extends GridLogging { private def toFileMetadata(f: File, imageId: String, mimeType: Option[MimeType]): Future[FileMetadata] = { mimeType match { - case Some(Png | Tiff) => FileMetadataReader.fromICPTCHeadersWithColorInfo(f, imageId, mimeType.get) + case Some(Png | Tiff) => FileMetadataReader.fromIPTCHeadersWithColorInfo(f, imageId, mimeType.get) case _ => FileMetadataReader.fromIPTCHeaders(f, imageId) } } diff --git a/image-loader/test/scala/lib/imaging/FileMetadataReaderTest.scala b/image-loader/test/scala/lib/imaging/FileMetadataReaderTest.scala index b21143d44e..a05be8e859 100644 --- a/image-loader/test/scala/lib/imaging/FileMetadataReaderTest.scala +++ b/image-loader/test/scala/lib/imaging/FileMetadataReaderTest.scala @@ -596,7 +596,7 @@ class FileMetadataReaderTest extends FunSpec with Matchers with ScalaFutures { it("should read the correct metadata for a grayscale png") { val image = fileAt("schaik.com_pngsuite/basn0g08.png") - val metadataFuture = FileMetadataReader.fromICPTCHeadersWithColorInfo(image, "dummy", Png) + val metadataFuture = FileMetadataReader.fromIPTCHeadersWithColorInfo(image, "dummy", Png) whenReady(metadataFuture) { metadata => metadata.colourModelInformation should contain( "colorType" -> "Greyscale" @@ -606,7 +606,7 @@ class FileMetadataReaderTest extends FunSpec with Matchers with ScalaFutures { it("should read the correct metadata for a colour 8bit paletted png") { val image = fileAt("schaik.com_pngsuite/basn3p08.png") - val metadataFuture = FileMetadataReader.fromICPTCHeadersWithColorInfo(image, "dummy", Png) + val metadataFuture = FileMetadataReader.fromIPTCHeadersWithColorInfo(image, "dummy", Png) whenReady(metadataFuture) { metadata => metadata.colourModelInformation should contain( "colorType" -> "Indexed Color" @@ -616,7 +616,7 @@ class FileMetadataReaderTest extends FunSpec with Matchers with ScalaFutures { it("should read the correct metadata for a truecolour png without alpha channel") { val image = fileAt("schaik.com_pngsuite/basn2c08.png") - val metadataFuture = FileMetadataReader.fromICPTCHeadersWithColorInfo(image, "dummy", Png) + val metadataFuture = FileMetadataReader.fromIPTCHeadersWithColorInfo(image, "dummy", Png) whenReady(metadataFuture) { metadata => metadata.colourModelInformation should contain( "colorType" -> "True Color" @@ -626,7 +626,7 @@ class FileMetadataReaderTest extends FunSpec with Matchers with ScalaFutures { it("should read the correct metadata for a truecolour pnd with alpha channel") { val image = fileAt("schaik.com_pngsuite/basn6a08.png") - val metadataFuture = FileMetadataReader.fromICPTCHeadersWithColorInfo(image, "dummy", Png) + val metadataFuture = FileMetadataReader.fromIPTCHeadersWithColorInfo(image, "dummy", Png) whenReady(metadataFuture) { metadata => metadata.colourModelInformation should contain( "colorType" -> "True Color with Alpha" @@ -636,7 +636,7 @@ class FileMetadataReaderTest extends FunSpec with Matchers with ScalaFutures { it("should read the correct colour metadata for a greyscale tiff") { val image = fileAt("flower.tif") - val metadataFuture = FileMetadataReader.fromICPTCHeadersWithColorInfo(image, "dummy", Tiff) + val metadataFuture = FileMetadataReader.fromIPTCHeadersWithColorInfo(image, "dummy", Tiff) whenReady(metadataFuture) { metadata => metadata.colourModelInformation should contain( "photometricInterpretation" -> "BlackIsZero" @@ -646,7 +646,7 @@ class FileMetadataReaderTest extends FunSpec with Matchers with ScalaFutures { it("should read the correct colour metadata for an alpha tiff") { val image = fileAt("lighthouse.tif") - val metadataFuture = FileMetadataReader.fromICPTCHeadersWithColorInfo(image, "dummy", Tiff) + val metadataFuture = FileMetadataReader.fromIPTCHeadersWithColorInfo(image, "dummy", Tiff) whenReady(metadataFuture) { metadata => metadata.colourModelInformation should contain( "photometricInterpretation" -> "RGB" From 59faf03a7a0409ffbb05441c88e25f5a5e7609a3 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 13:30:50 +0000 Subject: [PATCH 20/36] Rename tests to state what they are testing for --- image-loader/app/model/Uploader.scala | 2 +- .../test/scala/model/ImageUploadTest.scala | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/image-loader/app/model/Uploader.scala b/image-loader/app/model/Uploader.scala index e2efee1524..32251db63f 100644 --- a/image-loader/app/model/Uploader.scala +++ b/image-loader/app/model/Uploader.scala @@ -123,7 +123,7 @@ object Uploader extends GridLogging { .orElse(MimeTypeDetection.guessMimeType(uploadRequest.tempFile).toOption) match { case Some(a) => a - case None => throw new Exception("No idea what you have given me") + case None => throw new Exception("File of unknown and undetectable mime type") } val makeNewDirInTempDirHere: File = Files.createTempDirectory(deps.config.tempDir.toPath, "upload").toFile diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index ff4d7a56ef..780e3c6fb4 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -134,25 +134,25 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { }) } - ignore("rubbish") { + ignore("A jpg which is suitable for UI viewing") { imageUpload("rubbish.jpg", Jpeg) } - ignore("lighthouse") { + ignore("An opaque tiff file which requires optimising for UI") { imageUpload("lighthouse.tif", Tiff, expectOptimisedFile = true) } - ignore("tiff_8bpc_layered_withTransparency") { + ignore("A layered tiff file (will require renaming extracted file) which requires optimising for UI") { imageUpload("tiff_8bpc_layered_withTransparency.tif", Tiff, expectOptimisedFile = true) } - ignore("tiff_8bpc_flat") { + ignore("Another opaque tiff file which requires optimising for UI") { imageUpload("tiff_8bpc_flat.tif", Tiff, expectOptimisedFile = true) } - ignore("IndexedColor") { + ignore("A png which is suitable for UI viewing") { imageUpload("IndexedColor.png", Png) } - ignore("bgan6a16_TrueColorWithAlpha_16bit") { + ignore("A png which is not suitable (too many colours + transparency) for UI viewing") { imageUpload("bgan6a16_TrueColorWithAlpha_16bit.png", Png, expectOptimisedFile = true) } - ignore("basn2c16_TrueColor_16bit") { + ignore("A png which is not suitable (too many colours) for UI viewing") { imageUpload("basn2c16_TrueColor_16bit.png", Png, expectOptimisedFile = true) } ignore("not an image but looks like one") { @@ -169,7 +169,7 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { imageUpload("thisisnotanimage.stupid", Png, expectOptimisedFile = true) fail("Should have thrown an error") } catch { - case e: Exception => assert(e.getMessage == "No idea what you have given me") + case e: Exception => assert(e.getMessage == "File of unknown and undetectable mime type") } } } From 145f3602f78be9d3b462d0830acc62483f411c81 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 13:34:17 +0000 Subject: [PATCH 21/36] Correct typoed method name --- image-loader/app/lib/imaging/FileMetadataReader.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/image-loader/app/lib/imaging/FileMetadataReader.scala b/image-loader/app/lib/imaging/FileMetadataReader.scala index f9994de7b1..ae2397369a 100644 --- a/image-loader/app/lib/imaging/FileMetadataReader.scala +++ b/image-loader/app/lib/imaging/FileMetadataReader.scala @@ -56,7 +56,7 @@ object FileMetadataReader { for { metadata <- readMetadata(image) } - yield getMetadataWithICPTCHeaders(metadata, imageId) // FIXME: JPEG, JFIF, Photoshop, GPS, File + yield getMetadataWithIPTCHeaders(metadata, imageId) // FIXME: JPEG, JFIF, Photoshop, GPS, File def fromIPTCHeadersWithColorInfo(image: StorableImage): Future[FileMetadata] = fromIPTCHeadersWithColorInfo(image.file, image.id, image.mimeType) @@ -66,9 +66,9 @@ object FileMetadataReader { metadata <- readMetadata(image) colourModelInformation <- getColorModelInformation(image, metadata, mimeType) } - yield getMetadataWithICPTCHeaders(metadata, imageId).copy(colourModelInformation = colourModelInformation) + yield getMetadataWithIPTCHeaders(metadata, imageId).copy(colourModelInformation = colourModelInformation) - private def getMetadataWithICPTCHeaders(metadata: Metadata, imageId:String): FileMetadata = + private def getMetadataWithIPTCHeaders(metadata: Metadata, imageId:String): FileMetadata = FileMetadata( iptc = exportDirectory(metadata, classOf[IptcDirectory]), exif = exportDirectory(metadata, classOf[ExifIFD0Directory]), From 2c86e23c74e987e4d7d74d9f70dd05ad314649ec Mon Sep 17 00:00:00 2001 From: Jonathon Herbert Date: Thu, 3 Dec 2020 14:21:36 +0000 Subject: [PATCH 22/36] Adjust image traits to prevent browser image from being labelled storable --- .../lib/ImageIngestOperations.scala | 10 ++-- .../app/lib/imaging/FileMetadataReader.scala | 4 +- image-loader/app/model/Uploader.scala | 22 ++++----- .../app/model/upload/OptimiseOps.scala | 8 ++-- .../test/scala/model/ImageUploadTest.scala | 48 +++++-------------- 5 files changed, 34 insertions(+), 58 deletions(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala index 409a328823..8675adb1cf 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala @@ -44,19 +44,19 @@ class ImageIngestOperations(imageBucket: String, thumbnailBucket: String, config def deletePng(id: String): Future[Unit] = deleteImage(imageBucket, optimisedPngKeyFromId(id)) } - - -trait StorableImage { +trait ImageWrapper { val id: String val file: File val mimeType: MimeType val meta: Map[String, String] } +trait StorableImage extends ImageWrapper + case class StorableThumbImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty) extends StorableImage case class StorableOriginalImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty) extends StorableImage case class StorableOptimisedImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty) extends StorableImage -case class StorableBrowserViewableImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty, mustUpload: Boolean = false) extends StorableImage { +case class BrowserViewableImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty, mustUpload: Boolean = false) extends ImageWrapper { def asStorableOptimisedImage = StorableOptimisedImage(id, file, mimeType, meta) def asStorableThumbImage = StorableThumbImage(id, file, mimeType, meta) - } + diff --git a/image-loader/app/lib/imaging/FileMetadataReader.scala b/image-loader/app/lib/imaging/FileMetadataReader.scala index ae2397369a..9bc49be092 100644 --- a/image-loader/app/lib/imaging/FileMetadataReader.scala +++ b/image-loader/app/lib/imaging/FileMetadataReader.scala @@ -12,7 +12,7 @@ import com.drew.metadata.jpeg.JpegDirectory import com.drew.metadata.png.PngDirectory import com.drew.metadata.xmp.XmpDirectory import com.drew.metadata.{Directory, Metadata} -import com.gu.mediaservice.lib.StorableImage +import com.gu.mediaservice.lib.{ImageWrapper, StorableImage} import com.gu.mediaservice.lib.imaging.im4jwrapper.ImageMagick._ import com.gu.mediaservice.lib.metadata.ImageMetadataConverter import com.gu.mediaservice.model._ @@ -58,7 +58,7 @@ object FileMetadataReader { } yield getMetadataWithIPTCHeaders(metadata, imageId) // FIXME: JPEG, JFIF, Photoshop, GPS, File - def fromIPTCHeadersWithColorInfo(image: StorableImage): Future[FileMetadata] = + def fromIPTCHeadersWithColorInfo(image: ImageWrapper): Future[FileMetadata] = fromIPTCHeadersWithColorInfo(image.file, image.id, image.mimeType) def fromIPTCHeadersWithColorInfo(image: File, imageId:String, mimeType: MimeType): Future[FileMetadata] = diff --git a/image-loader/app/model/Uploader.scala b/image-loader/app/model/Uploader.scala index 32251db63f..8702691cde 100644 --- a/image-loader/app/model/Uploader.scala +++ b/image-loader/app/model/Uploader.scala @@ -9,7 +9,7 @@ import java.util.UUID import com.gu.mediaservice.lib.argo.ArgoHelpers import com.gu.mediaservice.lib.auth.Authentication import com.gu.mediaservice.lib.auth.Authentication.Principal -import com.gu.mediaservice.lib.{StorableBrowserViewableImage, StorableOptimisedImage, StorableOriginalImage, StorableThumbImage} +import com.gu.mediaservice.lib.{BrowserViewableImage, StorableOptimisedImage, StorableOriginalImage, StorableThumbImage} import com.gu.mediaservice.lib.aws.{S3Object, UpdateMessage} import com.gu.mediaservice.lib.cleanup.{MetadataCleaners, SupplierProcessors} import com.gu.mediaservice.lib.config.MetadataConfig @@ -183,10 +183,10 @@ object Uploader extends GridLogging { } private def getStorableOptimisedImage( - tempDir: File, - optimiseOps: OptimiseOps, - browserViewableImage: StorableBrowserViewableImage, - optimisedFileMetadata: FileMetadata) + tempDir: File, + optimiseOps: OptimiseOps, + browserViewableImage: BrowserViewableImage, + optimisedFileMetadata: FileMetadata) (implicit ec: ExecutionContext, logMarker: LogMarker): Future[Option[StorableOptimisedImage]] = { if (optimiseOps.shouldOptimise(Some(browserViewableImage.mimeType), optimisedFileMetadata)) { for { @@ -219,29 +219,29 @@ object Uploader extends GridLogging { private def createThumbFuture(fileMetadata: FileMetadata, colourModelFuture: Future[Option[String]], - storableBrowserViewableImage: StorableBrowserViewableImage, + browserViewableImage: BrowserViewableImage, deps: ImageUploadOpsDependencies)(implicit ec: ExecutionContext) = { import deps._ for { colourModel <- colourModelFuture iccColourSpace = FileMetadataHelper.normalisedIccColourSpace(fileMetadata) (thumb, thumbMimeType) <- imageOps - .createThumbnail(storableBrowserViewableImage.file, Some(storableBrowserViewableImage.mimeType), config.thumbWidth, + .createThumbnail(browserViewableImage.file, Some(browserViewableImage.mimeType), config.thumbWidth, config.thumbQuality, config.tempDir, iccColourSpace, colourModel) - } yield storableBrowserViewableImage + } yield browserViewableImage .copy(file = thumb, mimeType = thumbMimeType) .asStorableThumbImage } private def createBrowserViewableFileFuture(uploadRequest: UploadRequest, tempDir: File, - deps: ImageUploadOpsDependencies)(implicit ec: ExecutionContext): Future[StorableBrowserViewableImage] = { + deps: ImageUploadOpsDependencies)(implicit ec: ExecutionContext): Future[BrowserViewableImage] = { import deps._ uploadRequest.mimeType match { case Some(mime) if config.transcodedMimeTypes.contains(mime) => for { (file, filetype) <- imageOps.transformImage(uploadRequest.tempFile, uploadRequest.mimeType, tempDir) - } yield StorableBrowserViewableImage( + } yield BrowserViewableImage( uploadRequest.imageId, file = file, mimeType = MimeType(filetype), @@ -249,7 +249,7 @@ object Uploader extends GridLogging { ) case Some(mimeType) => Future.successful( - StorableBrowserViewableImage( + BrowserViewableImage( uploadRequest.imageId, file = uploadRequest.tempFile, mimeType = mimeType) diff --git a/image-loader/app/model/upload/OptimiseOps.scala b/image-loader/app/model/upload/OptimiseOps.scala index 857b574539..6bd497227e 100644 --- a/image-loader/app/model/upload/OptimiseOps.scala +++ b/image-loader/app/model/upload/OptimiseOps.scala @@ -2,7 +2,7 @@ package model.upload import java.io.File -import com.gu.mediaservice.lib.StorableImage +import com.gu.mediaservice.lib.{ImageWrapper, StorableImage} import com.gu.mediaservice.lib.logging.{LogMarker, Stopwatch} import com.gu.mediaservice.model.{FileMetadata, MimeType, Png, Tiff} @@ -10,7 +10,7 @@ import scala.concurrent.{ExecutionContext, Future} import scala.sys.process._ trait OptimiseOps { - def toOptimisedFile(file: File, storableImage: StorableImage, tempDir: File) + def toOptimisedFile(file: File, imageWrapper: ImageWrapper, tempDir: File) (implicit ec: ExecutionContext, logMarker: LogMarker): Future[(File, MimeType)] def isTransformedFilePath(filePath: String): Boolean def shouldOptimise(mimeType: Option[MimeType], fileMetadata: FileMetadata): Boolean @@ -21,10 +21,10 @@ object OptimiseWithPngQuant extends OptimiseOps { override def optimiseMimeType: MimeType = Png - def toOptimisedFile(file: File, storableImage: StorableImage, tempDir: File) + def toOptimisedFile(file: File, imageWrapper: ImageWrapper, tempDir: File) (implicit ec: ExecutionContext, logMarker: LogMarker): Future[(File, MimeType)] = Future { - val optimisedFilePath = tempDir.getAbsolutePath + "/optimisedpng - " + storableImage.id + optimiseMimeType.fileExtension + val optimisedFilePath = tempDir.getAbsolutePath + "/optimisedpng - " + imageWrapper.id + optimiseMimeType.fileExtension Stopwatch("pngquant") { val result = Seq("pngquant", "--quality", "1-85", file.getAbsolutePath, "--output", optimisedFilePath).! if (result>0) diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index 780e3c6fb4..d8aabc884b 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -5,7 +5,7 @@ import java.net.URI import java.util.UUID import com.drew.imaging.ImageProcessingException -import com.gu.mediaservice.lib.{StorableOptimisedImage, StorableOriginalImage, StorableThumbImage} +import com.gu.mediaservice.lib.{StorableImage, StorableOptimisedImage, StorableOriginalImage, StorableThumbImage} import com.gu.mediaservice.lib.aws.{S3Metadata, S3Object, S3ObjectMetadata} import com.gu.mediaservice.lib.imaging.ImageOperations import com.gu.mediaservice.lib.logging.LogMarker @@ -50,41 +50,17 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { val mockS3Meta = S3Metadata(Map.empty, S3ObjectMetadata(None, None, None)) val mockS3Object = S3Object(new URI("innernets.com"), 12345, mockS3Meta) - def storeOrProjectOriginalFile: StorableOriginalImage => Future[S3Object] = { - a => { - Future.successful( - mockS3Object - .copy(size = a.file.length()) - .copy(metadata = mockS3Object.metadata - .copy(objectMetadata = mockS3Object.metadata.objectMetadata - .copy(contentType = Some(a.mimeType))))) - } - } - - def storeOrProjectThumbFile: StorableThumbImage => Future[S3Object] = { - a => { - Future.successful( - mockS3Object - .copy(size = a.file.length()) - .copy(metadata = mockS3Object.metadata - .copy(objectMetadata = mockS3Object.metadata.objectMetadata - .copy(contentType = Some(a.mimeType)))) - ) - } - } - - def storeOrProjectOptimisedPNG: StorableOptimisedImage => Future[S3Object] = { - a => { - if (a.mimeType == Jpeg) fail("We should not create optimised jpg") - Future.successful( - mockS3Object - .copy(size = a.file.length()) - .copy(metadata = mockS3Object.metadata - .copy(objectMetadata = mockS3Object.metadata.objectMetadata - .copy(contentType = Some(a.mimeType)))) - ) - } - } + def mockStore = (a: StorableImage) => + Future.successful( + mockS3Object + .copy(size = a.file.length()) + .copy(metadata = mockS3Object.metadata + .copy(objectMetadata = mockS3Object.metadata.objectMetadata + .copy(contentType = Some(a.mimeType))))) + + def storeOrProjectOriginalFile: StorableOriginalImage => Future[S3Object] = mockStore + def storeOrProjectThumbFile: StorableThumbImage => Future[S3Object] = mockStore + def storeOrProjectOptimisedPNG: StorableOptimisedImage => Future[S3Object] = mockStore val mockDependencies = ImageUploadOpsDependencies( mockConfig, From 637df1ebb7b33f9d97a9b4bcfc14db65f45298ee Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 14:36:03 +0000 Subject: [PATCH 23/36] Remove association between S3 and generic store --- .../com/gu/mediaservice/lib/S3ImageStorage.scala | 12 +++++++++--- .../main/scala/com/gu/mediaservice/lib/aws/S3.scala | 12 +++++++----- image-loader/test/scala/model/ImageUploadTest.scala | 9 +++------ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/S3ImageStorage.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/S3ImageStorage.scala index a8fbfd9cf4..0c7ed5d767 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/S3ImageStorage.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/S3ImageStorage.scala @@ -2,7 +2,7 @@ package com.gu.mediaservice.lib import java.io.File -import com.gu.mediaservice.lib.aws.S3 +import com.gu.mediaservice.lib.aws.{S3, S3Ops} import com.gu.mediaservice.lib.config.CommonConfig import com.gu.mediaservice.lib.logging.LogMarker import com.gu.mediaservice.model.MimeType @@ -15,9 +15,15 @@ import scala.concurrent.Future class S3ImageStorage(config: CommonConfig) extends S3(config) with ImageStorage { private val log = LoggerFactory.getLogger(getClass) + private val cacheSetting = Some(cacheForever) def storeImage(bucket: String, id: String, file: File, mimeType: Option[MimeType], meta: Map[String, String] = Map.empty) - (implicit logMarker: LogMarker) = - store(bucket, id, file, mimeType, meta, Some(cacheForever)) + (implicit logMarker: LogMarker) = { + store(bucket, id, file, mimeType, meta, cacheSetting) + .map( _ => + // TODO this is just giving back the stuff we passed in and should be factored out. + S3Ops.projectFileAsS3Object(bucket, id, file, mimeType, meta, cacheSetting) + ) + } def deleteImage(bucket: String, id: String) = Future { client.deleteObject(bucket, id) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/aws/S3.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/aws/S3.scala index d16509c6c9..b57e4997f0 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/aws/S3.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/aws/S3.scala @@ -116,7 +116,7 @@ class S3(config: CommonConfig) extends GridLogging { } def store(bucket: Bucket, id: Key, file: File, mimeType: Option[MimeType], meta: UserMetadata = Map.empty, cacheControl: Option[String] = None) - (implicit ex: ExecutionContext, logMarker: LogMarker): Future[S3Object] = + (implicit ex: ExecutionContext, logMarker: LogMarker): Future[Unit] = Future { val metadata = new ObjectMetadata mimeType.foreach(m => metadata.setContentType(m.name)) @@ -127,8 +127,6 @@ class S3(config: CommonConfig) extends GridLogging { Stopwatch(s"S3 client.putObject ($req)"){ client.putObject(req) } - - S3Ops.projectFileAsS3Object(bucket, id, file, mimeType, meta, cacheControl) } def list(bucket: Bucket, prefixDir: String) @@ -199,9 +197,9 @@ object S3Ops { new URI("http", bucketUrl, s"/$key", null) } - def projectFileAsS3Object(bucket: String, key: String, file: File, mimeType: Option[MimeType], meta: Map[String, String] = Map.empty, cacheControl: Option[String] = None): S3Object = { + def projectFileAsS3Object(url: URI, file: File, mimeType: Option[MimeType], meta: Map[String, String] = Map.empty, cacheControl: Option[String] = None): S3Object = { S3Object( - objectUrl(bucket, key), + url, file.length, S3Metadata( meta, @@ -212,4 +210,8 @@ object S3Ops { ) ) } + + def projectFileAsS3Object(bucket: String, key: String, file: File, mimeType: Option[MimeType], meta: Map[String, String] = Map.empty, cacheControl: Option[String] = None): S3Object = { + projectFileAsS3Object(objectUrl(bucket, key), file, mimeType, meta, cacheControl) + } } diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index d8aabc884b..7f1dfbabe2 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -6,7 +6,7 @@ import java.util.UUID import com.drew.imaging.ImageProcessingException import com.gu.mediaservice.lib.{StorableImage, StorableOptimisedImage, StorableOriginalImage, StorableThumbImage} -import com.gu.mediaservice.lib.aws.{S3Metadata, S3Object, S3ObjectMetadata} +import com.gu.mediaservice.lib.aws.{S3Metadata, S3Object, S3ObjectMetadata, S3Ops} import com.gu.mediaservice.lib.imaging.ImageOperations import com.gu.mediaservice.lib.logging.LogMarker import com.gu.mediaservice.model.{FileMetadata, Jpeg, MimeType, Png, Tiff, UploadInfo} @@ -52,11 +52,8 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { def mockStore = (a: StorableImage) => Future.successful( - mockS3Object - .copy(size = a.file.length()) - .copy(metadata = mockS3Object.metadata - .copy(objectMetadata = mockS3Object.metadata.objectMetadata - .copy(contentType = Some(a.mimeType))))) + S3Ops.projectFileAsS3Object(new URI("http://madeupname/"), a.file, Some(a.mimeType), a.meta, None) + ) def storeOrProjectOriginalFile: StorableOriginalImage => Future[S3Object] = mockStore def storeOrProjectThumbFile: StorableThumbImage => Future[S3Object] = mockStore From bfa9dc7cf3b7d461ebb62c0e7215bb1e8b017fc2 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 15:01:26 +0000 Subject: [PATCH 24/36] Linting storable image types --- .../com/gu/mediaservice/lib/ImageIngestOperations.scala | 6 +++--- .../src/main/scala/com/gu/mediaservice/lib/aws/S3.scala | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala index 8675adb1cf..b11964f522 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala @@ -27,15 +27,15 @@ class ImageIngestOperations(imageBucket: String, thumbnailBucket: String, config case s:StorableOptimisedImage => storeOptimisedImage(s) } - private def storeOriginalImage(storableImage: StorableImage) + private def storeOriginalImage(storableImage: StorableOriginalImage) (implicit logMarker: LogMarker): Future[S3Object] = storeImage(imageBucket, fileKeyFromId(storableImage.id), storableImage.file, Some(storableImage.mimeType), storableImage.meta) - private def storeThumbnailImage(storableImage: StorableImage) + private def storeThumbnailImage(storableImage: StorableThumbImage) (implicit logMarker: LogMarker): Future[S3Object] = storeImage(thumbnailBucket, fileKeyFromId(storableImage.id), storableImage.file, Some(storableImage.mimeType)) - private def storeOptimisedImage(storableImage: StorableImage) + private def storeOptimisedImage(storableImage: StorableOptimisedImage) (implicit logMarker: LogMarker): Future[S3Object] = storeImage(imageBucket, optimisedPngKeyFromId(storableImage.id), storableImage.file, Some(storableImage.mimeType)) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/aws/S3.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/aws/S3.scala index b57e4997f0..7320fe5f37 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/aws/S3.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/aws/S3.scala @@ -197,7 +197,7 @@ object S3Ops { new URI("http", bucketUrl, s"/$key", null) } - def projectFileAsS3Object(url: URI, file: File, mimeType: Option[MimeType], meta: Map[String, String] = Map.empty, cacheControl: Option[String] = None): S3Object = { + def projectFileAsS3Object(url: URI, file: File, mimeType: Option[MimeType], meta: Map[String, String], cacheControl: Option[String]): S3Object = { S3Object( url, file.length, From c14e43bc48e01ab0c0961799e01a53e40bbe65fd Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 15:05:47 +0000 Subject: [PATCH 25/36] Correct information in documentation --- docs/06-objects-of-interest/06.01-tiffs.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/06-objects-of-interest/06.01-tiffs.md b/docs/06-objects-of-interest/06.01-tiffs.md index ffdfda3108..0467ee66ab 100644 --- a/docs/06-objects-of-interest/06.01-tiffs.md +++ b/docs/06-objects-of-interest/06.01-tiffs.md @@ -5,14 +5,15 @@ Tiff files have special handling for importing. Like all files, we upload the original, but create an optimised and thumbnail png version. -For TIFF files, these pngs derive from the first image file found inside the -container format, which, in a file named `xxx.tif` will explode out as -`xxx.png` or `xxx.jpg`. +For TIFF files, these pngs derive from the first image file created by image +magic or graphics magic. The `convert` function will extract a file of the +specified type (png in our case), which, in a file named `xxx.tif` will be +`xxx.png`. However, there is additional complexity with tiff files which contain layered -images. Specifically, the layer files will explode as `xxx-n.jpg` or +content. Specifically, the layer files will explode as `xxx-n.jpg` or `xxx-n.png` where `n` is a numeric index. Our code looks for this special case (see `ImageOperations.checkForOutputFileChange`) -and simply moves the layer file to the expected location. +and simply moves the `-n` layer file to the expected location. From fc65b4d68396a8df30abcf8689831c8ea2d2732e Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 15:11:36 +0000 Subject: [PATCH 26/36] Correct information in documentation --- docs/06-objects-of-interest/06.01-tiffs.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/06-objects-of-interest/06.01-tiffs.md b/docs/06-objects-of-interest/06.01-tiffs.md index 0467ee66ab..72e5c629ff 100644 --- a/docs/06-objects-of-interest/06.01-tiffs.md +++ b/docs/06-objects-of-interest/06.01-tiffs.md @@ -2,10 +2,10 @@ Tiff files have special handling for importing. -Like all files, we upload the original, but create an optimised and thumbnail -png version. +Like all files, we upload the original, but create an (optional) optimised +png, and (mandatory) thumbnail jpg version for use in the UI. -For TIFF files, these pngs derive from the first image file created by image +For TIFF files, these pngs derive from the first image file extracted by image magic or graphics magic. The `convert` function will extract a file of the specified type (png in our case), which, in a file named `xxx.tif` will be `xxx.png`. From a737edf69b68ef0540efc67c8aee0e1e831dc750 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 15:26:29 +0000 Subject: [PATCH 27/36] Correct information in documentation --- docs/06-objects-of-interest/06.01-tiffs.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/06-objects-of-interest/06.01-tiffs.md b/docs/06-objects-of-interest/06.01-tiffs.md index 72e5c629ff..7bb4d48fb8 100644 --- a/docs/06-objects-of-interest/06.01-tiffs.md +++ b/docs/06-objects-of-interest/06.01-tiffs.md @@ -3,11 +3,11 @@ Tiff files have special handling for importing. Like all files, we upload the original, but create an (optional) optimised -png, and (mandatory) thumbnail jpg version for use in the UI. +PNG, and (mandatory) thumbnail JPEG version for use in the UI. -For TIFF files, these pngs derive from the first image file extracted by image -magic or graphics magic. The `convert` function will extract a file of the -specified type (png in our case), which, in a file named `xxx.tif` will be +For TIFF files, these pngs derive from the first image file extracted by +ImageMagick. The `convert` function will extract a file of the +specified type (PNG in our case), which, in a file named `xxx.tif` will be `xxx.png`. However, there is additional complexity with tiff files which contain layered From 66fd580ffe3b2f467f46a6cdcaebd69dedc6a411 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 15:27:09 +0000 Subject: [PATCH 28/36] Improve method signature and add scaladoc --- .../lib/imaging/ImageOperations.scala | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala index c4ffb92dd0..6a0f95051c 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala @@ -116,6 +116,20 @@ class ImageOperations(playPath: String) extends GridLogging { val thumbUnsharpRadius = 0.5d val thumbUnsharpSigma = 0.5d val thumbUnsharpAmount = 0.8d + + /** + * Given a source file containing a png (the 'browser viewable' file), + * construct a thumbnail file in the provided temp directory, and return + * the file with metadata about it. + * @param sourceFile File containing browser viewable (ie not too big or colourful) image + * @param sourceMimeType Mime time of browser viewable file + * @param width Desired with of thumbnail + * @param qual Desired quality of thumbnail + * @param tempDir Location to create thumbnail file + * @param iccColourSpace (Approximately) number of colours to use + * @param colourModel Colour model - eg RGB or CMYK + * @return The file created and the mimetype of the content of that file, in a future. + */ def createThumbnail(sourceFile: File, sourceMimeType: Option[MimeType], width: Int, @@ -138,7 +152,16 @@ class ImageOperations(playPath: String) extends GridLogging { } yield (outputFile, thumbMimeType) } - def transformImage(sourceFile: File, sourceMimeType: Option[MimeType], tempDir: File): Future[(File, String)] = { + /** + * Given a source file containing a file which requires optimising to make it suitable for viewing in + * a browser, construct a new image file in the provided temp directory, and return + * * the file with metadata about it. + * @param sourceFile File containing browser viewable (ie not too big or colourful) image + * @param sourceMimeType Mime time of browser viewable file + * @param tempDir Location to create optimised file + * @return The file created and the mimetype of the content of that file, in a future. + */ + def transformImage(sourceFile: File, sourceMimeType: Option[MimeType], tempDir: File): Future[(File, MimeType)] = { for { // png suffix is used by imagemagick to infer the required type outputFile <- createTempFile(s"transformed-", Png.fileExtension, tempDir) @@ -146,7 +169,7 @@ class ImageOperations(playPath: String) extends GridLogging { addOutput = addDestImage(transformSource)(outputFile) _ <- runConvertCmd(addOutput, useImageMagick = sourceMimeType.contains(Tiff)) extension <- checkForOutputFileChange(outputFile) - } yield (outputFile, extension) + } yield (outputFile, MimeType(extension)) } // When a layered tiff is unpacked, the temp file (blah.something) is moved From 5b5fbcf32c69848ce78bd15c7023f58248347a71 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 15:27:28 +0000 Subject: [PATCH 29/36] Use new method signature --- image-loader/app/model/Uploader.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/image-loader/app/model/Uploader.scala b/image-loader/app/model/Uploader.scala index 8702691cde..8f86e7cc04 100644 --- a/image-loader/app/model/Uploader.scala +++ b/image-loader/app/model/Uploader.scala @@ -240,11 +240,11 @@ object Uploader extends GridLogging { uploadRequest.mimeType match { case Some(mime) if config.transcodedMimeTypes.contains(mime) => for { - (file, filetype) <- imageOps.transformImage(uploadRequest.tempFile, uploadRequest.mimeType, tempDir) + (file, mimeType) <- imageOps.transformImage(uploadRequest.tempFile, uploadRequest.mimeType, tempDir) } yield BrowserViewableImage( uploadRequest.imageId, file = file, - mimeType = MimeType(filetype), + mimeType = mimeType, mustUpload = true ) case Some(mimeType) => From 7f6419fc4a6a658d6420a794a807114896b60f11 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 15:50:26 +0000 Subject: [PATCH 30/36] Turn off tests again --- image-loader/test/scala/model/ImageUploadTest.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index 7f1dfbabe2..e23c37f1ff 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -107,13 +107,13 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { }) } - ignore("A jpg which is suitable for UI viewing") { + test("A jpg which is suitable for UI viewing") { imageUpload("rubbish.jpg", Jpeg) } - ignore("An opaque tiff file which requires optimising for UI") { + test("An opaque tiff file which requires optimising for UI") { imageUpload("lighthouse.tif", Tiff, expectOptimisedFile = true) } - ignore("A layered tiff file (will require renaming extracted file) which requires optimising for UI") { + test("A layered tiff file (will require renaming extracted file) which requires optimising for UI") { imageUpload("tiff_8bpc_layered_withTransparency.tif", Tiff, expectOptimisedFile = true) } ignore("Another opaque tiff file which requires optimising for UI") { @@ -147,4 +147,4 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { } } -// todo add to tests - tiff with layers, but not true colour so does not need optimising. MK to provide +// todo add to ignores - tiff with layers, but not true colour so does not need optimising. MK to provide From 42ce9642bd8f66d0f1d64880c2aa2b649e674590 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 15:52:17 +0000 Subject: [PATCH 31/36] Turn off tests again --- image-loader/test/scala/model/ImageUploadTest.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index e23c37f1ff..7f1dfbabe2 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -107,13 +107,13 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { }) } - test("A jpg which is suitable for UI viewing") { + ignore("A jpg which is suitable for UI viewing") { imageUpload("rubbish.jpg", Jpeg) } - test("An opaque tiff file which requires optimising for UI") { + ignore("An opaque tiff file which requires optimising for UI") { imageUpload("lighthouse.tif", Tiff, expectOptimisedFile = true) } - test("A layered tiff file (will require renaming extracted file) which requires optimising for UI") { + ignore("A layered tiff file (will require renaming extracted file) which requires optimising for UI") { imageUpload("tiff_8bpc_layered_withTransparency.tif", Tiff, expectOptimisedFile = true) } ignore("Another opaque tiff file which requires optimising for UI") { @@ -147,4 +147,4 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { } } -// todo add to ignores - tiff with layers, but not true colour so does not need optimising. MK to provide +// todo add to tests - tiff with layers, but not true colour so does not need optimising. MK to provide From 08f0696a41e3800d1fbc81b108d6c1d1cd87f4c2 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 16:19:27 +0000 Subject: [PATCH 32/36] Seal traits --- .../scala/com/gu/mediaservice/lib/ImageIngestOperations.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala index b11964f522..1b070331fd 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/ImageIngestOperations.scala @@ -44,13 +44,13 @@ class ImageIngestOperations(imageBucket: String, thumbnailBucket: String, config def deletePng(id: String): Future[Unit] = deleteImage(imageBucket, optimisedPngKeyFromId(id)) } -trait ImageWrapper { +sealed trait ImageWrapper { val id: String val file: File val mimeType: MimeType val meta: Map[String, String] } -trait StorableImage extends ImageWrapper +sealed trait StorableImage extends ImageWrapper case class StorableThumbImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty) extends StorableImage case class StorableOriginalImage(id: String, file: File, mimeType: MimeType, meta: Map[String, String] = Map.empty) extends StorableImage From 9d7b9f5ddf6754f87fe685b75337df9bd111ca6b Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 16:38:03 +0000 Subject: [PATCH 33/36] Tiny lint to use defined mimetype rather than infer it from the extension we just specified --- .../com/gu/mediaservice/lib/imaging/ImageOperations.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala index 6a0f95051c..09209208e4 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala @@ -5,7 +5,7 @@ import java.io._ import org.im4java.core.IMOperation import com.gu.mediaservice.lib.Files._ import com.gu.mediaservice.lib.StorableThumbImage -import com.gu.mediaservice.lib.imaging.ImageOperations.thumbMimeType +import com.gu.mediaservice.lib.imaging.ImageOperations.{optimisedMimeType, thumbMimeType} import com.gu.mediaservice.lib.imaging.im4jwrapper.ImageMagick.{addImage, format, runIdentifyCmd} import com.gu.mediaservice.lib.imaging.im4jwrapper.{ExifTool, ImageMagick} import com.gu.mediaservice.lib.logging.GridLogging @@ -164,12 +164,12 @@ class ImageOperations(playPath: String) extends GridLogging { def transformImage(sourceFile: File, sourceMimeType: Option[MimeType], tempDir: File): Future[(File, MimeType)] = { for { // png suffix is used by imagemagick to infer the required type - outputFile <- createTempFile(s"transformed-", Png.fileExtension, tempDir) + outputFile <- createTempFile(s"transformed-", optimisedMimeType.fileExtension, tempDir) transformSource = addImage(sourceFile) addOutput = addDestImage(transformSource)(outputFile) _ <- runConvertCmd(addOutput, useImageMagick = sourceMimeType.contains(Tiff)) extension <- checkForOutputFileChange(outputFile) - } yield (outputFile, MimeType(extension)) + } yield (outputFile, optimisedMimeType) } // When a layered tiff is unpacked, the temp file (blah.something) is moved @@ -208,6 +208,7 @@ class ImageOperations(playPath: String) extends GridLogging { object ImageOperations { val thumbMimeType = Jpeg + val optimisedMimeType = Png def identifyColourModel(sourceFile: File, mimeType: MimeType)(implicit ec: ExecutionContext): Future[Option[String]] = { // TODO: use mimeType to lookup other properties once we support other formats From 35ab3fbb4ed8d21ee6a573f5fffff60bb6ad4836 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 16:39:35 +0000 Subject: [PATCH 34/36] Remove unnecessary return values --- .../com/gu/mediaservice/lib/imaging/ImageOperations.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala index 09209208e4..11195b1874 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala @@ -168,7 +168,7 @@ class ImageOperations(playPath: String) extends GridLogging { transformSource = addImage(sourceFile) addOutput = addDestImage(transformSource)(outputFile) _ <- runConvertCmd(addOutput, useImageMagick = sourceMimeType.contains(Tiff)) - extension <- checkForOutputFileChange(outputFile) + _ <- checkForOutputFileChange(outputFile) } yield (outputFile, optimisedMimeType) } @@ -178,7 +178,7 @@ class ImageOperations(playPath: String) extends GridLogging { // As the file has been renamed, the file object still exists, but has the wrong name // We will need to put it back where it is expected to be found, and clean up the other // files. - private def checkForOutputFileChange(f: File): Future[String] = Future { + private def checkForOutputFileChange(f: File): Future[Unit] = Future { val fileBits = f.getAbsolutePath.split("\\.").toList val mainPart = fileBits.dropRight(1).mkString(".") val extension = fileBits.last @@ -191,7 +191,6 @@ class ImageOperations(playPath: String) extends GridLogging { // Tidy up any other files (blah-1,2,3 etc will be created for each subsequent layer) cleanUpLayerFiles(mainPart, extension, 1) } - fileBits.last } @scala.annotation.tailrec From 4021d7b4b1aa406e69f2ec2e0d24beae1ab93439 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Thu, 3 Dec 2020 18:00:57 +0000 Subject: [PATCH 35/36] Improve file handling when cropping layered tiffs --- .../com/gu/mediaservice/lib/imaging/ImageOperations.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala index 11195b1874..c8f12e0580 100644 --- a/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala +++ b/common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/ImageOperations.scala @@ -59,7 +59,7 @@ class ImageOperations(playPath: String) extends GridLogging { def cropImage(sourceFile: File, sourceMimeType: Option[MimeType], bounds: Bounds, qual: Double = 100d, tempDir: File, iccColourSpace: Option[String], colourModel: Option[String], fileType: MimeType): Future[File] = { for { - outputFile <- createTempFile(s"crop-", s".${fileType.fileExtension}", tempDir) + outputFile <- createTempFile(s"crop-", s"${fileType.fileExtension}", tempDir) cropSource = addImage(sourceFile) qualified = quality(cropSource)(qual) corrected = correctColour(qualified)(iccColourSpace, colourModel) @@ -70,6 +70,7 @@ class ImageOperations(playPath: String) extends GridLogging { depthAdjusted = depth(cropped)(8) addOutput = addDestImage(depthAdjusted)(outputFile) _ <- runConvertCmd(addOutput, useImageMagick = sourceMimeType.contains(Tiff)) + _ <- checkForOutputFileChange(outputFile) } yield outputFile } From a739c61c6274e67e0d5096dd92bd3aabc36728e8 Mon Sep 17 00:00:00 2001 From: Justin Rowles Date: Fri, 4 Dec 2020 08:29:38 +0000 Subject: [PATCH 36/36] Rewrite test for better scalatest idiom when handling exceptions --- image-loader/test/scala/model/ImageUploadTest.scala | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/image-loader/test/scala/model/ImageUploadTest.scala b/image-loader/test/scala/model/ImageUploadTest.scala index 7f1dfbabe2..c740a523f7 100644 --- a/image-loader/test/scala/model/ImageUploadTest.scala +++ b/image-loader/test/scala/model/ImageUploadTest.scala @@ -138,12 +138,9 @@ class ImageUploadTest extends AsyncFunSuite with Matchers with MockitoSugar { } ignore("not an image and does not look like one") { // this exception is thrown before the futures are resolved, and so does not need transformWith - try { - imageUpload("thisisnotanimage.stupid", Png, expectOptimisedFile = true) - fail("Should have thrown an error") - } catch { - case e: Exception => assert(e.getMessage == "File of unknown and undetectable mime type") - } + val caught = the [Exception] thrownBy + imageUpload("thisisnotanimage.stupid", Png, expectOptimisedFile = true) + assert(caught.getMessage == "File of unknown and undetectable mime type") } }