aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/mot-encoder.cpp191
1 files changed, 135 insertions, 56 deletions
diff --git a/src/mot-encoder.cpp b/src/mot-encoder.cpp
index 897333f..2de98c7 100644
--- a/src/mot-encoder.cpp
+++ b/src/mot-encoder.cpp
@@ -339,48 +339,26 @@ int main(int argc, char *argv[])
return 1;
}
-int encodeFile(int output_fd, std::string& fname, int fidx, int padlen)
+// Resize the image or add a black border around it
+// so that it is 320x240 pixels.
+// Automatically reduce the quality to make sure the
+// blobsize is not too large.
+//
+// Returns: the blobsize
+size_t resizeImage(MagickWand* m_wand, unsigned char** blob)
{
- int ret = 0;
- int fd=0, mothdrlen, nseg, lastseglen, i, last, curseglen;
- unsigned char mothdr[32];
- MagickWand *m_wand = NULL;
- PixelWand *p_wand = NULL;
- size_t blobsize, height, width;
- unsigned char *blob = NULL, *curseg = NULL;
- MagickBooleanType err;
- MSCDG msc;
- unsigned char mscblob[8200];
- unsigned short int mscblobsize;
- int quality = 100;
-
- m_wand = NewMagickWand();
- p_wand = NewPixelWand();
- PixelSetColor(p_wand, "black");
-
- err = MagickReadImage(m_wand, fname.c_str());
- if (err == MagickFalse) {
- fprintf(stderr, "Error - Unable to load image %s\n", fname.c_str());
- goto encodefile_out;
- }
-
- height = MagickGetImageHeight(m_wand);
- width = MagickGetImageWidth(m_wand);
- //aspectRatio = (width * 1.0)/height;
+ size_t blobsize;
+ size_t height = MagickGetImageHeight(m_wand);
+ size_t width = MagickGetImageWidth(m_wand);
- if (verbose) {
- fprintf(stderr, "mot-encoder image: %s (id=%d). Original size: %zu x %zu. ",
- fname.c_str(), fidx, width, height);
- }
+ PixelWand *p_wand = NULL;
while (height > 240 || width > 320) {
if (height/240.0 > width/320.0) {
- //width = height * aspectRatio;
width = width * 240.0 / height;
height = 240;
}
else {
- //height = width * (1.0/aspectRatio);
height = height * 320.0 / width;
width = 320;
}
@@ -390,63 +368,164 @@ int encodeFile(int output_fd, std::string& fname, int fidx, int padlen)
height = MagickGetImageHeight(m_wand);
width = MagickGetImageWidth(m_wand);
+ // Make sure smaller images are 320x240 pixels, and
+ // add a black border
+ p_wand = NewPixelWand();
+ PixelSetColor(p_wand, "black");
MagickBorderImage(m_wand, p_wand, (320-width)/2, (240-height)/2);
+ DestroyPixelWand(p_wand);
MagickSetImageFormat(m_wand, "jpg");
+ int quality = 100;
+
do {
quality -= 5;
MagickSetImageCompressionQuality(m_wand, quality);
- blob = MagickGetImagesBlob(m_wand, &blobsize);
+ *blob = MagickGetImagesBlob(m_wand, &blobsize);
} while (blobsize > MAXSLIDESIZE && quality > MINQUALITY);
if (blobsize > MAXSLIDESIZE) {
fprintf(stderr, "mot-encoder: Image Size too large after compression: %zu bytes\n",
blobsize);
- goto encodefile_out;
+
+ return 0;
}
if (verbose) {
fprintf(stderr, "mot-encoder resized image to %zu x %zu. Size after compression %zu bytes (q=%d)\n",
width, height, blobsize, quality);
}
+ return blobsize;
+}
- nseg = blobsize / MAXSEGLEN;
- lastseglen = blobsize % MAXSEGLEN;
- if (lastseglen != 0) {
- nseg++;
+int encodeFile(int output_fd, std::string& fname, int fidx, int padlen)
+{
+ int ret = 0;
+ int fd=0, mothdrlen, nseg, lastseglen, i, last, curseglen;
+ unsigned char mothdr[32];
+ MagickWand *m_wand = NULL;
+ size_t blobsize, height, width;
+ unsigned char *blob = NULL;
+ unsigned char *curseg = NULL;
+ MagickBooleanType err;
+ MSCDG msc;
+ unsigned char mscblob[8200];
+ unsigned short int mscblobsize;
+
+ size_t orig_quality;
+ char* orig_format = NULL;
+ /* We handle JPEG differently, because we want to avoid recompressing the
+ * image if it is suitable as is
+ */
+ bool orig_is_jpeg = false;
+
+ /* By default, we do resize the image to 320x240, with a quality such that
+ * the blobsize is at most MAXSLIDESIZE.
+ *
+ * For JPEG input files that are already at the right resolution and at the
+ * right blobsize, we disable this to avoid quality loss due to recompression
+ */
+ bool resize_required = true;
+
+ m_wand = NewMagickWand();
+
+ err = MagickReadImage(m_wand, fname.c_str());
+ if (err == MagickFalse) {
+ fprintf(stderr, "mot-encoder Error: Unable to load image %s\n",
+ fname.c_str());
+
+ goto encodefile_out;
}
- createMotHeader(blobsize, fidx, mothdr, &mothdrlen);
- // Create the MSC Data Group C-Structure
- createMscDG(&msc, 3, 0, 1, fidx, mothdr, mothdrlen);
- // Generate the MSC DG frame (Figure 9 en 300 401)
- packMscDG(mscblob, &msc, &mscblobsize);
- writeMotPAD(output_fd, mscblob, mscblobsize, padlen);
+ height = MagickGetImageHeight(m_wand);
+ width = MagickGetImageWidth(m_wand);
+ orig_format = MagickGetImageFormat(m_wand);
- for (i = 0; i < nseg; i++) {
- curseg = blob + i * MAXSEGLEN;
- if (i == nseg-1) {
- curseglen = lastseglen;
- last = 1;
+ // By default assume that the image has full quality and can be reduced
+ orig_quality = 100;
+
+ if (orig_format) {
+ if (strcmp(orig_format, "JPEG") == 0) {
+ orig_quality = MagickGetImageCompressionQuality(m_wand);
+ orig_is_jpeg = true;
+
+ if (verbose) {
+ fprintf(stderr, "mot-encoder image: %s (id=%d)."
+ " Original size: %zu x %zu. (%s, q=%zu)\n",
+ fname.c_str(), fidx, width, height, orig_format, orig_quality);
+ }
}
- else {
- curseglen = MAXSEGLEN;
- last = 0;
+ else if (verbose) {
+ fprintf(stderr, "mot-encoder image: %s (id=%d)."
+ " Original size: %zu x %zu. (%s)\n",
+ fname.c_str(), fidx, width, height, orig_format);
}
- createMscDG(&msc, 4, i, last, fidx, curseg, curseglen);
+ free(orig_format);
+ }
+ else {
+ fprintf(stderr, "mot-encoder Warning: Unable to detect image format %s\n",
+ fname.c_str());
+
+ fprintf(stderr, "mot-encoder image: %s (id=%d). Original size: %zu x %zu.\n",
+ fname.c_str(), fidx, width, height);
+ }
+
+ if (orig_is_jpeg && height == 240 && width == 320) {
+ // Don't recompress the image and check if the blobsize is suitable
+ blob = MagickGetImagesBlob(m_wand, &blobsize);
+
+ if (blobsize < MAXSLIDESIZE) {
+ fprintf(stderr, "mot-encoder image: %s (id=%d). No resize needed: %zu Bytes\n",
+ fname.c_str(), fidx, blobsize);
+ resize_required = false;
+ }
+ }
+
+ if (resize_required) {
+ blobsize = resizeImage(m_wand, &blob);
+ }
+
+ if (blobsize) {
+ nseg = blobsize / MAXSEGLEN;
+ lastseglen = blobsize % MAXSEGLEN;
+ if (lastseglen != 0) {
+ nseg++;
+ }
+
+ createMotHeader(blobsize, fidx, mothdr, &mothdrlen);
+ // Create the MSC Data Group C-Structure
+ createMscDG(&msc, 3, 0, 1, fidx, mothdr, mothdrlen);
+ // Generate the MSC DG frame (Figure 9 en 300 401)
packMscDG(mscblob, &msc, &mscblobsize);
writeMotPAD(output_fd, mscblob, mscblobsize, padlen);
- }
- ret = 1;
+ for (i = 0; i < nseg; i++) {
+ curseg = blob + i * MAXSEGLEN;
+ if (i == nseg-1) {
+ curseglen = lastseglen;
+ last = 1;
+ }
+ else {
+ curseglen = MAXSEGLEN;
+ last = 0;
+ }
+
+ createMscDG(&msc, 4, i, last, fidx, curseg, curseglen);
+ packMscDG(mscblob, &msc, &mscblobsize);
+ writeMotPAD(output_fd, mscblob, mscblobsize, padlen);
+ }
+
+ ret = 1;
+ }
encodefile_out:
if (m_wand) {
m_wand = DestroyMagickWand(m_wand);
}
+
if (blob) {
free(blob);
}