"Fossies" - the Fresh Open Source Software Archive

Member "motion-Release-4.3.0/src/picture.c" (14 Jan 2020, 31091 Bytes) of package /linux/misc/motion-Release-4.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "picture.c" see the Fossies "Dox" file reference documentation.

    1 /*    picture.c
    2  *
    3  *    Various funtions for saving/loading pictures.
    4  *    Copyright 2002 by Jeroen Vreeken (pe1rxq@amsat.org)
    5  *    Portions of this file are Copyright by Lionnel Maugis
    6  *    Portions of this file are Copyright 2010 by Wim Lewis (wiml@hhhh.org)
    7  *    This software is distributed under the GNU public license version 2
    8  *    See also the file 'COPYING'.
    9  *
   10  */
   11 #include "translate.h"
   12 #include "picture.h"
   13 #include "jpegutils.h"
   14 #include "event.h"
   15 
   16 #include <assert.h>
   17 
   18 #ifdef HAVE_WEBP
   19 #include <webp/encode.h>
   20 #include <webp/mux.h>
   21 #endif /* HAVE_WEBP */
   22 
   23 
   24 /* EXIF image data is always in TIFF format, even if embedded in another
   25  * file type. This consists of a constant header (TIFF file header,
   26  * IFD header) followed by the tags in the IFD and then the data
   27  * from any tags which do not fit inline in the IFD.
   28  *
   29  * The tags we write in the main IFD are:
   30  *  0x010E   Image description
   31  *  0x8769   Exif sub-IFD
   32  *  0x882A   Time zone of time stamps
   33  * and in the Exif sub-IFD:
   34  *  0x9000   Exif version
   35  *  0x9003   File date and time
   36  *  0x9291   File date and time subsecond info
   37  * But we omit any empty IFDs.
   38  */
   39 
   40 #define TIFF_TAG_IMAGE_DESCRIPTION    0x010E
   41 #define TIFF_TAG_DATETIME             0x0132
   42 #define TIFF_TAG_EXIF_IFD             0x8769
   43 #define TIFF_TAG_TZ_OFFSET            0x882A
   44 
   45 #define EXIF_TAG_EXIF_VERSION         0x9000
   46 #define EXIF_TAG_ORIGINAL_DATETIME    0x9003
   47 #define EXIF_TAG_SUBJECT_AREA         0x9214
   48 #define EXIF_TAG_TIFF_DATETIME_SS     0x9290
   49 #define EXIF_TAG_ORIGINAL_DATETIME_SS 0x9291
   50 
   51 #define TIFF_TYPE_ASCII  2  /* ASCII text */
   52 #define TIFF_TYPE_USHORT 3  /* Unsigned 16-bit int */
   53 #define TIFF_TYPE_LONG   4  /* Unsigned 32-bit int */
   54 #define TIFF_TYPE_UNDEF  7  /* Byte blob */
   55 #define TIFF_TYPE_SSHORT 8  /* Signed 16-bit int */
   56 
   57 static const char exif_marker_start[14] = {
   58     'E', 'x', 'i', 'f', 0, 0,   /* EXIF marker signature */
   59     'M', 'M', 0, 42,            /* TIFF file header (big-endian) */
   60     0, 0, 0, 8,                 /* Offset to first toplevel IFD */
   61 };
   62 
   63 static const char exif_version_tag[12] = {
   64     0x90, 0x00,                 /* EXIF version tag, 0x9000 */
   65     0x00, 0x07,                 /* Data type 7 = "unknown" (raw byte blob) */
   66     0x00, 0x00, 0x00, 0x04,     /* Data length */
   67     0x30, 0x32, 0x32, 0x30      /* Inline data, EXIF version 2.2 */
   68 };
   69 
   70 static const char exif_subifd_tag[8] = {
   71     0x87, 0x69,                 /* EXIF Sub-IFD tag */
   72     0x00, 0x04,                 /* Data type 4 = uint32 */
   73     0x00, 0x00, 0x00, 0x01,     /* Number of values */
   74 };
   75 
   76 static const char exif_tzoffset_tag[12] = {
   77     0x88, 0x2A,                 /* TIFF/EP time zone offset tag */
   78     0x00, 0x08,                 /* Data type 8 = sint16 */
   79     0x00, 0x00, 0x00, 0x01,     /* Number of values */
   80     0, 0, 0, 0                  /* Dummy data */
   81 };
   82 
   83 static void put_uint16(JOCTET *buf, unsigned value)
   84 {
   85     buf[0] = ( value & 0xFF00 ) >> 8;
   86     buf[1] = ( value & 0x00FF );
   87 }
   88 
   89 static void put_sint16(JOCTET *buf, int value)
   90 {
   91     buf[0] = ( value & 0xFF00 ) >> 8;
   92     buf[1] = ( value & 0x00FF );
   93 }
   94 
   95 static void put_uint32(JOCTET *buf, unsigned value)
   96 {
   97     buf[0] = ( value & 0xFF000000 ) >> 24;
   98     buf[1] = ( value & 0x00FF0000 ) >> 16;
   99     buf[2] = ( value & 0x0000FF00 ) >> 8;
  100     buf[3] = ( value & 0x000000FF );
  101 }
  102 
  103 struct tiff_writing {
  104     JOCTET * const base;
  105     JOCTET *buf;
  106     unsigned data_offset;
  107 };
  108 
  109 static void put_direntry(struct tiff_writing *into, const char *data, unsigned length)
  110 {
  111     if (length <= 4) {
  112         /* Entries that fit in the directory entry are stored there */
  113         memset(into->buf, 0, 4);
  114         memcpy(into->buf, data, length);
  115     } else {
  116         /* Longer entries are stored out-of-line */
  117         unsigned offset = into->data_offset;
  118 
  119         while ((offset & 0x03) != 0) {  /* Alignment */
  120             into->base[offset] = 0;
  121             offset ++;
  122         }
  123 
  124         put_uint32(into->buf, offset);
  125         memcpy(into->base + offset, data, length);
  126         into->data_offset = offset + length;
  127     }
  128 }
  129 
  130 static void put_stringentry(struct tiff_writing *into, unsigned tag, const char *str, int with_nul)
  131 {
  132     unsigned stringlength = strlen(str) + (with_nul?1:0);
  133 
  134     put_uint16(into->buf, tag);
  135     put_uint16(into->buf + 2, TIFF_TYPE_ASCII);
  136     put_uint32(into->buf + 4, stringlength);
  137     into->buf += 8;
  138     put_direntry(into, str, stringlength);
  139     into->buf += 4;
  140 }
  141 
  142 static void put_subjectarea(struct tiff_writing *into, const struct coord *box)
  143 {
  144     put_uint16(into->buf    , EXIF_TAG_SUBJECT_AREA);
  145     put_uint16(into->buf + 2, TIFF_TYPE_USHORT);
  146     put_uint32(into->buf + 4, 4 /* Four USHORTs */);
  147     put_uint32(into->buf + 8, into->data_offset);
  148     into->buf += 12;
  149     JOCTET *ool = into->base + into->data_offset;
  150     put_uint16(ool  , box->x); /* Center.x */
  151     put_uint16(ool+2, box->y); /* Center.y */
  152     put_uint16(ool+4, box->width);
  153     put_uint16(ool+6, box->height);
  154     into->data_offset += 8;
  155 }
  156 
  157 /*
  158  * prepare_exif() is a comon function used to prepare
  159  * exif data to be inserted into jpeg or webp files
  160  *
  161  */
  162 unsigned prepare_exif(unsigned char **exif,
  163               const struct context *cnt,
  164               const struct timeval *tv_in1,
  165               const struct coord *box)
  166 {
  167     /* description, datetime, and subtime are the values that are actually
  168      * put into the EXIF data
  169     */
  170     char *description, *datetime, *subtime;
  171     char datetime_buf[22];
  172     char tmpbuf[45];
  173     struct tm timestamp_tm;
  174     struct timeval tv1;
  175 
  176     gettimeofday(&tv1, NULL);
  177     if (tv_in1 != NULL) {
  178         tv1.tv_sec = tv_in1->tv_sec;
  179         tv1.tv_usec = tv_in1->tv_usec;
  180     }
  181 
  182     localtime_r(&tv1.tv_sec, &timestamp_tm);
  183     /* Exif requires this exact format */
  184     /* The compiler is twitchy on truncating formats and the exif is twitchy
  185      * on the length of the whole string.  So we do it in two steps of printing
  186      * into a large buffer which compiler wants, then print that into the smaller
  187      * buffer that exif wants..TODO  Find better method
  188      */
  189     snprintf(tmpbuf, 45, "%04d:%02d:%02d %02d:%02d:%02d",
  190             timestamp_tm.tm_year + 1900,
  191             timestamp_tm.tm_mon + 1,
  192             timestamp_tm.tm_mday,
  193             timestamp_tm.tm_hour,
  194             timestamp_tm.tm_min,
  195             timestamp_tm.tm_sec);
  196     snprintf(datetime_buf, 22,"%.21s",tmpbuf);
  197     datetime = datetime_buf;
  198 
  199     // TODO: Extract subsecond timestamp from somewhere, but only
  200     // use as much of it as is indicated by conf->frame_limit
  201     subtime = NULL;
  202 
  203     if (cnt->conf.picture_exif) {
  204         description = malloc(PATH_MAX);
  205         mystrftime(cnt, description, PATH_MAX-1, cnt->conf.picture_exif, &tv1, NULL, 0);
  206     } else {
  207         description = NULL;
  208     }
  209 
  210     /* Calculate an upper bound on the size of the APP1 marker so
  211      * we can allocate a buffer for it.
  212      */
  213 
  214     /* Count up the number of tags and max amount of OOL data */
  215     int ifd0_tagcount = 0;
  216     int ifd1_tagcount = 0;
  217     unsigned datasize = 0;
  218 
  219     if (description) {
  220         ifd0_tagcount ++;
  221         datasize += 5 + strlen(description); /* Add 5 for NUL and alignment */
  222     }
  223 
  224     if (datetime) {
  225     /* We write this to both the TIFF datetime tag (which most programs
  226      * treat as "last-modified-date") and the EXIF "time of creation of
  227      * original image" tag (which many programs ignore). This is
  228      * redundant but seems to be the thing to do.
  229      */
  230         ifd0_tagcount++;
  231         ifd1_tagcount++;
  232         /* We also write the timezone-offset tag in IFD0 */
  233         ifd0_tagcount++;
  234         /* It would be nice to use the same offset for both tags' values,
  235         * but I don't want to write the bookkeeping for that right now */
  236         datasize += 2 * (5 + strlen(datetime));
  237     }
  238 
  239     if (subtime) {
  240         ifd1_tagcount++;
  241         datasize += 5 + strlen(subtime);
  242     }
  243 
  244     if (box) {
  245         ifd1_tagcount++;
  246         datasize += 2 * 4;  /* Four 16-bit ints */
  247     }
  248 
  249     if (ifd1_tagcount > 0) {
  250         /* If we're writing the Exif sub-IFD, account for the
  251         * two tags that requires */
  252         ifd0_tagcount ++; /* The tag in IFD0 that points to IFD1 */
  253         ifd1_tagcount ++; /* The EXIF version tag */
  254     }
  255 
  256     /* Each IFD takes 12 bytes per tag, plus six more (the tag count and the
  257      * pointer to the next IFD, always zero in our case)
  258      */
  259     int ifds_size =
  260     ( ifd1_tagcount > 0 ? ( 12 * ifd1_tagcount + 6 ) : 0 ) +
  261     ( ifd0_tagcount > 0 ? ( 12 * ifd0_tagcount + 6 ) : 0 );
  262 
  263     if (ifds_size == 0) {
  264         /* We're not actually going to write any information. */
  265         return 0;
  266     }
  267 
  268     unsigned int buffer_size = 6 /* EXIF marker signature */ +
  269                                8 /* TIFF file header */ +
  270                                ifds_size /* the tag directories */ +
  271                                datasize;
  272 
  273     JOCTET *marker = malloc(buffer_size);
  274     memcpy(marker, exif_marker_start, 14); /* EXIF and TIFF headers */
  275 
  276     struct tiff_writing writing = (struct tiff_writing) {
  277     .base = marker + 6, /* base address for intra-TIFF offsets */
  278     .buf = marker + 14, /* current write position */
  279     .data_offset = 8 + ifds_size, /* where to start storing data */
  280     };
  281 
  282     /* Write IFD 0 */
  283     /* Note that tags are stored in numerical order */
  284     put_uint16(writing.buf, ifd0_tagcount);
  285     writing.buf += 2;
  286 
  287     if (description)
  288         put_stringentry(&writing, TIFF_TAG_IMAGE_DESCRIPTION, description, 1);
  289 
  290     if (datetime)
  291         put_stringentry(&writing, TIFF_TAG_DATETIME, datetime, 1);
  292 
  293     if (ifd1_tagcount > 0) {
  294         /* Offset of IFD1 - TIFF header + IFD0 size. */
  295         unsigned ifd1_offset = 8 + 6 + ( 12 * ifd0_tagcount );
  296         memcpy(writing.buf, exif_subifd_tag, 8);
  297         put_uint32(writing.buf + 8, ifd1_offset);
  298         writing.buf += 12;
  299     }
  300 
  301     if (datetime) {
  302         memcpy(writing.buf, exif_tzoffset_tag, 12);
  303         put_sint16(writing.buf+8, timestamp_tm.tm_gmtoff / 3600);
  304         writing.buf += 12;
  305     }
  306 
  307     put_uint32(writing.buf, 0); /* Next IFD offset = 0 (no next IFD) */
  308     writing.buf += 4;
  309 
  310     /* Write IFD 1 */
  311     if (ifd1_tagcount > 0) {
  312         /* (remember that the tags in any IFD must be in numerical order
  313         * by tag) */
  314         put_uint16(writing.buf, ifd1_tagcount);
  315         memcpy(writing.buf + 2, exif_version_tag, 12); /* tag 0x9000 */
  316         writing.buf += 14;
  317 
  318         if (datetime)
  319             put_stringentry(&writing, EXIF_TAG_ORIGINAL_DATETIME, datetime, 1);
  320 
  321         if (box)
  322             put_subjectarea(&writing, box);
  323 
  324         if (subtime)
  325             put_stringentry(&writing, EXIF_TAG_ORIGINAL_DATETIME_SS, subtime, 0);
  326 
  327         put_uint32(writing.buf, 0); /* Next IFD = 0 (no next IFD) */
  328         writing.buf += 4;
  329     }
  330 
  331     /* We should have met up with the OOL data */
  332     assert( (writing.buf - writing.base) == 8 + ifds_size );
  333 
  334     /* The buffer is complete; write it out */
  335     unsigned marker_len = 6 + writing.data_offset;
  336 
  337     /* assert we didn't underestimate the original buffer size */
  338     assert(marker_len <= buffer_size);
  339 
  340     free(description);
  341 
  342     *exif = marker;
  343     return marker_len;
  344 }
  345 
  346 
  347 #ifdef HAVE_WEBP
  348 /*
  349  * put_webp_exif writes the EXIF APP1 chunk to the webp file.
  350  * It must be called after WebPEncode() and the result
  351  * can then be written out to webp a file
  352  */
  353 static void put_webp_exif(WebPMux* webp_mux,
  354               const struct context *cnt,
  355               const struct timeval *tv1,
  356               const struct coord *box)
  357 {
  358     unsigned char *exif = NULL;
  359     unsigned exif_len = prepare_exif(&exif, cnt, tv1, box);
  360 
  361     if(exif_len > 0) {
  362         WebPData webp_exif;
  363         /* EXIF in WEBP does not need the EXIF marker signature (6 bytes) that are needed by jpeg */
  364         webp_exif.bytes = exif + 6;
  365         webp_exif.size = exif_len - 6;
  366 
  367         WebPMuxError err = WebPMuxSetChunk(webp_mux, "EXIF", &webp_exif, 1);
  368         if (err != WEBP_MUX_OK) {
  369             MOTION_LOG(ERR, TYPE_CORE, NO_ERRNO
  370                 , _("Unable to set set EXIF to webp chunk"));
  371         }
  372         free(exif);
  373     }
  374 }
  375 #endif /* HAVE_WEBP */
  376 
  377 
  378 
  379 #ifdef HAVE_WEBP
  380 /**
  381  * put_webp_yuv420p_file
  382  *      Converts an YUV420P coded image to a webp image and writes
  383  *      it to an already open file.
  384  *
  385  * Inputs:
  386  * - image is the image in YUV420P format.
  387  * - width and height are the dimensions of the image
  388  * - quality is the webp encoding quality 0-100%
  389  *
  390  * Output:
  391  * - The webp is written directly to the file given by the file pointer fp
  392  *
  393  * Returns nothing
  394  */
  395 static void put_webp_yuv420p_file(FILE *fp,
  396                   unsigned char *image, int width, int height,
  397                   int quality, struct context *cnt, struct timeval *tv1, struct coord *box)
  398 {
  399     /* Create a config present and check for compatible library version */
  400     WebPConfig webp_config;
  401     if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, (float) quality)){
  402         MOTION_LOG(ERR, TYPE_CORE, NO_ERRNO, _("libwebp version error"));
  403         return;
  404     }
  405 
  406     /* Create the input data structure and check for compatible library version */
  407     WebPPicture webp_image;
  408     if (!WebPPictureInit(&webp_image)){
  409         MOTION_LOG(ERR, TYPE_CORE, NO_ERRNO,_("libwebp version error"));
  410         return;
  411     }
  412 
  413     /* Allocate the image buffer based on image width and height */
  414     webp_image.width = width;
  415     webp_image.height = height;
  416     if (!WebPPictureAlloc(&webp_image)){
  417         MOTION_LOG(ERR, TYPE_CORE, NO_ERRNO,_("libwebp image buffer allocation error"));
  418         return;
  419     }
  420 
  421     /* Map the input YUV420P buffer as individual Y, U and V pointers */
  422     webp_image.y = image;
  423     webp_image.u = image + width * height;
  424     webp_image.v = webp_image.u + (width * height) / 4;
  425 
  426     /* Setup the memory writting method */
  427     WebPMemoryWriter webp_writer;
  428     WebPMemoryWriterInit(&webp_writer);
  429     webp_image.writer = WebPMemoryWrite;
  430     webp_image.custom_ptr = (void*) &webp_writer;
  431 
  432     /* Encode the YUV image as webp */
  433     if (!WebPEncode(&webp_config, &webp_image))
  434         MOTION_LOG(WRN, TYPE_CORE, NO_ERRNO,_("libwebp image compression error"));
  435 
  436     /* A bitstream object is needed for the muxing proces */
  437     WebPData webp_bitstream;
  438     webp_bitstream.bytes = webp_writer.mem;
  439     webp_bitstream.size = webp_writer.size;
  440 
  441     /* Create a mux from the prepared image data */
  442     WebPMux* webp_mux = WebPMuxCreate(&webp_bitstream, 1);
  443     put_webp_exif(webp_mux, cnt, tv1, box);
  444 
  445     /* Add Exif data to the webp image data */
  446     WebPData webp_output;
  447     WebPMuxError err = WebPMuxAssemble(webp_mux, &webp_output);
  448     if (err != WEBP_MUX_OK) {
  449         MOTION_LOG(ERR, TYPE_CORE, NO_ERRNO,_("unable to assemble webp image"));
  450     }
  451 
  452     /* Write the webp final bitstream to the file */
  453     if (fwrite(webp_output.bytes, sizeof(uint8_t), webp_output.size, fp) != webp_output.size)
  454         MOTION_LOG(ERR, TYPE_CORE, NO_ERRNO,_("unable to save webp image to file"));
  455 
  456 #if WEBP_ENCODER_ABI_VERSION > 0x0202
  457     /* writer.mem must be freed by calling WebPMemoryWriterClear */
  458     WebPMemoryWriterClear(&webp_writer);
  459 #else
  460     /* writer.mem must be freed by calling 'free(writer.mem)' */
  461     free(webp_writer.mem);
  462 #endif /* WEBP_ENCODER_ABI_VERSION */
  463 
  464     /* free the memory used by webp for image data */
  465     WebPPictureFree(&webp_image);
  466     /* free the memory used by webp mux object */
  467     WebPMuxDelete(webp_mux);
  468     /* free the memory used by webp for output data */
  469     WebPDataClear(&webp_output);
  470 }
  471 #endif /* HAVE_WEBP */
  472 
  473 /**
  474  * put_jpeg_yuv420p_file
  475  *      Converts an YUV420P coded image to a jpeg image and writes
  476  *      it to an already open file.
  477  *
  478  * Inputs:
  479  * - image is the image in YUV420P format.
  480  * - width and height are the dimensions of the image
  481  * - quality is the jpeg encoding quality 0-100%
  482  *
  483  * Output:
  484  * - The jpeg is written directly to the file given by the file pointer fp
  485  *
  486  * Returns nothing
  487  */
  488 static void put_jpeg_yuv420p_file(FILE *fp,
  489                   unsigned char *image, int width, int height,
  490                   int quality,
  491                   struct context *cnt, struct timeval *tv1, struct coord *box)
  492 {
  493     int sz = 0;
  494     int image_size = cnt->imgs.size_norm;
  495     unsigned char *buf = mymalloc(image_size);
  496 
  497     sz = jpgutl_put_yuv420p(buf, image_size, image, width, height, quality, cnt ,tv1, box);
  498     fwrite(buf, sz, 1, fp);
  499 
  500     free(buf);
  501 
  502 }
  503 
  504 
  505 /**
  506  * put_jpeg_grey_file
  507  *      Converts an greyscale image to a jpeg image and writes
  508  *      it to an already open file.
  509  *
  510  * Inputs:
  511  * - image is the image in greyscale format.
  512  * - width and height are the dimensions of the image
  513  * - quality is the jpeg encoding quality 0-100%
  514  * Output:
  515  * - The jpeg is written directly to the file given by the file pointer fp
  516  *
  517  * Returns nothing
  518  */
  519 static void put_jpeg_grey_file(FILE *picture, unsigned char *image, int width, int height,
  520                   int quality, struct context *cnt, struct timeval *tv1, struct coord *box)
  521 
  522 {
  523     int sz = 0;
  524     int image_size = cnt->imgs.size_norm;
  525     unsigned char *buf = mymalloc(image_size);
  526 
  527     sz = jpgutl_put_grey(buf, image_size, image, width, height, quality, cnt ,tv1, box);
  528     fwrite(buf, sz, 1, picture);
  529 
  530     free(buf);
  531 }
  532 
  533 
  534 /**
  535  * put_ppm_bgr24_file
  536  *      Converts an greyscale image to a PPM image and writes
  537  *      it to an already open file.
  538  * Inputs:
  539  * - image is the image in YUV420P format.
  540  * - width and height are the dimensions of the image
  541  *
  542  * Output:
  543  * - The PPM is written directly to the file given by the file pointer fp
  544  *
  545  * Returns nothing
  546  */
  547 static void put_ppm_bgr24_file(FILE *picture, unsigned char *image, int width, int height)
  548 {
  549     int x, y;
  550     unsigned char *l = image;
  551     unsigned char *u = image + width * height;
  552     unsigned char *v = u + (width * height) / 4;
  553     int r, g, b;
  554     unsigned char rgb[3];
  555 
  556     /*
  557      *  ppm header
  558      *  width height
  559      *  maxval
  560      */
  561     fprintf(picture, "P6\n");
  562     fprintf(picture, "%d %d\n", width, height);
  563     fprintf(picture, "%d\n", 255);
  564     for (y = 0; y < height; y++) {
  565 
  566         for (x = 0; x < width; x++) {
  567             r = 76283 * (((int)*l) - 16)+104595*(((int)*u) - 128);
  568             g = 76283 * (((int)*l) - 16)- 53281*(((int)*u) - 128) - 25625 * (((int)*v) - 128);
  569             b = 76283 * (((int)*l) - 16) + 132252 * (((int)*v) - 128);
  570             r = r >> 16;
  571             g = g >> 16;
  572             b = b >> 16;
  573             if (r < 0)
  574                 r = 0;
  575             else if (r > 255)
  576                 r = 255;
  577             if (g < 0)
  578                 g = 0;
  579             else if (g > 255)
  580                 g = 255;
  581             if (b < 0)
  582                 b = 0;
  583             else if (b > 255)
  584                 b = 255;
  585 
  586             rgb[0] = b;
  587             rgb[1] = g;
  588             rgb[2] = r;
  589 
  590             l++;
  591             if (x%2 != 0) {
  592                 u++;
  593                 v++;
  594             }
  595             /* ppm is rgb not bgr */
  596             fwrite(rgb, 1, 3, picture);
  597         }
  598         if (y%2 == 0) {
  599             u -= width / 2;
  600             v -= width / 2;
  601         }
  602     }
  603 }
  604 
  605 /**
  606  * overlay_smartmask
  607  *      Copies smartmask as an overlay into motion images and movies.
  608  *
  609  * Returns nothing.
  610  */
  611 void overlay_smartmask(struct context *cnt, unsigned char *out)
  612 {
  613     int i, x, v, width, height, line;
  614     struct images *imgs = &cnt->imgs;
  615     unsigned char *smartmask = imgs->smartmask_final;
  616     unsigned char *out_y, *out_u, *out_v;
  617 
  618     i = imgs->motionsize;
  619     v = i + ((imgs->motionsize) / 4);
  620     width = imgs->width;
  621     height = imgs->height;
  622 
  623     /* Set V to 255 to make smartmask appear red. */
  624     out_v = out + v;
  625     out_u = out + i;
  626     for (i = 0; i < height; i += 2) {
  627         line = i * width;
  628         for (x = 0; x < width; x += 2) {
  629             if (smartmask[line + x] == 0 || smartmask[line + x + 1] == 0 ||
  630                 smartmask[line + width + x] == 0 ||
  631                 smartmask[line + width + x + 1] == 0) {
  632 
  633                 *out_v = 255;
  634                 *out_u = 128;
  635             }
  636             out_v++;
  637             out_u++;
  638         }
  639     }
  640     out_y = out;
  641     /* Set colour intensity for smartmask. */
  642     for (i = 0; i < imgs->motionsize; i++) {
  643         if (smartmask[i] == 0)
  644             *out_y = 0;
  645         out_y++;
  646     }
  647 }
  648 
  649 /**
  650  * overlay_fixed_mask
  651  *      Copies fixed mask as green overlay into motion images and movies.
  652  *
  653  * Returns nothing.
  654  */
  655 void overlay_fixed_mask(struct context *cnt, unsigned char *out)
  656 {
  657     int i, x, v, width, height, line;
  658     struct images *imgs = &cnt->imgs;
  659     unsigned char *mask = imgs->mask;
  660     unsigned char *out_y, *out_u, *out_v;
  661 
  662     i = imgs->motionsize;
  663     v = i + ((imgs->motionsize) / 4);
  664     width = imgs->width;
  665     height = imgs->height;
  666 
  667     /* Set U and V to 0 to make fixed mask appear green. */
  668     out_v = out + v;
  669     out_u = out + i;
  670     for (i = 0; i < height; i += 2) {
  671         line = i * width;
  672         for (x = 0; x < width; x += 2) {
  673             if (mask[line + x] == 0 || mask[line + x + 1] == 0 ||
  674                 mask[line + width + x] == 0 ||
  675                 mask[line + width + x + 1] == 0) {
  676 
  677                 *out_v = 0;
  678                 *out_u = 0;
  679             }
  680             out_v++;
  681             out_u++;
  682         }
  683     }
  684     out_y = out;
  685     /* Set colour intensity for mask. */
  686     for (i = 0; i < imgs->motionsize; i++) {
  687         if (mask[i] == 0)
  688             *out_y = 0;
  689         out_y++;
  690     }
  691 }
  692 
  693 /**
  694  * overlay_largest_label
  695  *      Copies largest label as an overlay into motion images and movies.
  696  *
  697  * Returns nothing.
  698  */
  699 void overlay_largest_label(struct context *cnt, unsigned char *out)
  700 {
  701     int i, x, v, width, height, line;
  702     struct images *imgs = &cnt->imgs;
  703     int *labels = imgs->labels;
  704     unsigned char *out_y, *out_u, *out_v;
  705 
  706     i = imgs->motionsize;
  707     v = i + ((imgs->motionsize) / 4);
  708     width = imgs->width;
  709     height = imgs->height;
  710 
  711     /* Set U to 255 to make label appear blue. */
  712     out_u = out + i;
  713     out_v = out + v;
  714     for (i = 0; i < height; i += 2) {
  715         line = i * width;
  716         for (x = 0; x < width; x += 2) {
  717             if (labels[line + x] & 32768 || labels[line + x + 1] & 32768 ||
  718                 labels[line + width + x] & 32768 ||
  719                 labels[line + width + x + 1] & 32768) {
  720 
  721                 *out_u = 255;
  722                 *out_v = 128;
  723             }
  724             out_u++;
  725             out_v++;
  726         }
  727     }
  728     out_y = out;
  729     /* Set intensity for coloured label to have better visibility. */
  730     for (i = 0; i < imgs->motionsize; i++) {
  731         if (*labels++ & 32768)
  732             *out_y = 0;
  733         out_y++;
  734     }
  735 }
  736 
  737 /**
  738  * put_picture_mem
  739  *      Is used for the webcam feature. Depending on the image type
  740  *      (colour YUV420P or greyscale) the corresponding put_jpeg_X_memory function is called.
  741  * Inputs:
  742  * - cnt is the thread context struct
  743  * - image_size is the size of the input image buffer
  744  * - *image points to the image buffer that contains the YUV420P or Grayscale image about to be put
  745  * - quality is the jpeg quality setting from the config file.
  746  *
  747  * Output:
  748  * - **dest_image is a pointer to a pointer that points to the destination buffer in which the
  749  *   converted image it put
  750  *
  751  * Returns the dest_image_size if successful. Otherwise 0.
  752  */
  753 int put_picture_memory(struct context *cnt, unsigned char* dest_image, int image_size, unsigned char *image,
  754         int quality, int width, int height)
  755 {
  756     struct timeval tv1;
  757 
  758     /*
  759      * Reset the time for the current image since it is not reliable
  760      * for putting images to memory.
  761      */
  762     gettimeofday(&tv1, NULL);
  763 
  764     if (!cnt->conf.stream_grey){
  765         return jpgutl_put_yuv420p(dest_image, image_size, image,
  766                                        width, height, quality, cnt ,&tv1,NULL);
  767     } else {
  768         return jpgutl_put_grey(dest_image, image_size, image,
  769                                        width, height, quality, cnt,&tv1,NULL);
  770     }
  771 
  772     return 0;
  773 }
  774 
  775 static void put_picture_fd(struct context *cnt, FILE *picture, unsigned char *image, int quality, int ftype){
  776     int width, height;
  777     int passthrough;
  778     int dummy = 1;
  779 
  780     /* See comment in put_picture_memory regarding dummy*/
  781 
  782     passthrough = util_check_passthrough(cnt);
  783     if ((ftype == FTYPE_IMAGE) && (cnt->imgs.size_high > 0) && (!passthrough)) {
  784         width = cnt->imgs.width_high;
  785         height = cnt->imgs.height_high;
  786     } else {
  787         width = cnt->imgs.width;
  788         height = cnt->imgs.height;
  789     }
  790 
  791     if (cnt->imgs.picture_type == IMAGE_TYPE_PPM) {
  792         put_ppm_bgr24_file(picture, image, width, height);
  793     } else {
  794         if (dummy == 1){
  795             #ifdef HAVE_WEBP
  796             if (cnt->imgs.picture_type == IMAGE_TYPE_WEBP)
  797                 put_webp_yuv420p_file(picture, image, width, height, quality, cnt, &(cnt->current_image->timestamp_tv), &(cnt->current_image->location));
  798             #endif /* HAVE_WEBP */
  799             if (cnt->imgs.picture_type == IMAGE_TYPE_JPEG)
  800                 put_jpeg_yuv420p_file(picture, image, width, height, quality, cnt, &(cnt->current_image->timestamp_tv), &(cnt->current_image->location));
  801         } else {
  802             put_jpeg_grey_file(picture, image, width, height, quality, cnt, &(cnt->current_image->timestamp_tv), &(cnt->current_image->location));
  803        }
  804     }
  805 }
  806 
  807 
  808 void put_picture(struct context *cnt, char *file, unsigned char *image, int ftype)
  809 {
  810     FILE *picture;
  811 
  812     picture = myfopen(file, "w");
  813     if (!picture) {
  814         /* Report to syslog - suggest solution if the problem is access rights to target dir. */
  815         if (errno ==  EACCES) {
  816             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
  817                 ,_("Can't write picture to file %s - check access rights to target directory\n"
  818                 "Thread is going to finish due to this fatal error"), file);
  819             cnt->finish = 1;
  820             cnt->restart = 0;
  821             return;
  822         } else {
  823             /* If target dir is temporarily unavailable we may survive. */
  824             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
  825                 ,_("Can't write picture to file %s"), file);
  826             return;
  827         }
  828     }
  829 
  830     put_picture_fd(cnt, picture, image, cnt->conf.picture_quality, ftype);
  831 
  832     myfclose(picture);
  833 }
  834 
  835 /**
  836  * get_pgm
  837  *      Get the pgm file used as fixed mask
  838  *
  839  */
  840 unsigned char *get_pgm(FILE *picture, int width, int height)
  841 {
  842     int x, y, mask_width, mask_height, maxval;
  843     char line[256];
  844     unsigned char *image, *resized_image;
  845 
  846     line[255] = 0;
  847 
  848     if (!fgets(line, 255, picture)) {
  849         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO,_("Could not read from pgm file"));
  850         return NULL;
  851     }
  852 
  853     if (strncmp(line, "P5", 2)) {
  854         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
  855             ,_("This is not a pgm file, starts with '%s'"), line);
  856         return NULL;
  857     }
  858 
  859     /* Skip comment */
  860     line[0] = '#';
  861     while (line[0] == '#')
  862         if (!fgets(line, 255, picture))
  863             return NULL;
  864 
  865     /* Read image size */
  866     if (sscanf(line, "%d %d", &mask_width, &mask_height) != 2) {
  867         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
  868             ,_("Failed reading size in pgm file"));
  869         return NULL;
  870     }
  871 
  872     /* Maximum value */
  873     line[0] = '#';
  874     while (line[0] == '#')
  875         if (!fgets(line, 255, picture))
  876             return NULL;
  877 
  878     if (sscanf(line, "%d", &maxval) != 1) {
  879         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
  880             ,_("Failed reading maximum value in pgm file"));
  881         return NULL;
  882     }
  883 
  884     /* Read data */
  885     /* We allocate the size for a 420P since we will use
  886     ** this image for masking privacy which needs the space for
  887     ** the cr / cb components
  888     */
  889     image = mymalloc((mask_width * mask_height * 3) / 2);
  890 
  891     for (y = 0; y < mask_height; y++) {
  892         if ((int)fread(&image[y * mask_width], 1, mask_width, picture) != mask_width)
  893             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, _("Failed reading image data from pgm file"));
  894 
  895         for (x = 0; x < mask_width; x++)
  896             image[y * mask_width + x] = (int)image[y * mask_width + x] * 255 / maxval;
  897 
  898     }
  899 
  900     /* Resize mask if required */
  901     if (mask_width != width || mask_height != height) {
  902         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
  903             ,_("The mask file specified is not the same size as image from camera."));
  904         MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO
  905             ,_("Attempting to resize mask image from %dx%d to %dx%d")
  906             ,mask_width, mask_height, width, height);
  907 
  908         resized_image = mymalloc((width * height * 3) / 2);
  909 
  910         for (y = 0; y < height; y++) {
  911             for (x = 0; x < width; x++) {
  912                 resized_image[y * width + x] = image[
  913                         (mask_height - 1) * y / (height - 1) * mask_width +
  914                         (mask_width  - 1) * x / (width  - 1)];
  915             }
  916         }
  917 
  918         free(image);
  919         image = resized_image;
  920     }
  921 
  922     return image;
  923 }
  924 
  925 /**
  926  * put_fixed_mask
  927  *      If a mask file is asked for but does not exist this function
  928  *      creates an empty mask file in the right binary pgm format and
  929  *      and the right size - easy to edit with Gimp or similar tool.
  930  *
  931  * Returns nothing.
  932  */
  933 void put_fixed_mask(struct context *cnt, const char *file)
  934 {
  935     FILE *picture;
  936 
  937     picture = myfopen(file, "w");
  938     if (!picture) {
  939         /* Report to syslog - suggest solution if the problem is access rights to target dir. */
  940         if (errno ==  EACCES) {
  941             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
  942                 ,_("can't write mask file %s - check access rights to target directory")
  943                 ,file);
  944         } else {
  945             /* If target dir is temporarily unavailable we may survive. */
  946             MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
  947                 ,_("can't write mask file %s"), file);
  948         }
  949         return;
  950     }
  951     memset(cnt->imgs.img_motion.image_norm, 255, cnt->imgs.motionsize); /* Initialize to unset */
  952 
  953     /* Write pgm-header. */
  954     fprintf(picture, "P5\n");
  955     fprintf(picture, "%d %d\n", cnt->conf.width, cnt->conf.height);
  956     fprintf(picture, "%d\n", 255);
  957 
  958     /* Write pgm image data at once. */
  959     if ((int)fwrite(cnt->imgs.img_motion.image_norm, cnt->conf.width, cnt->conf.height, picture) != cnt->conf.height) {
  960         MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO
  961             ,_("Failed writing default mask as pgm file"));
  962         return;
  963     }
  964 
  965     myfclose(picture);
  966 
  967     MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO
  968         ,_("Creating empty mask %s\nPlease edit this file and "
  969         "re-run motion to enable mask feature"), cnt->conf.mask_file);
  970 }
  971 
  972 void pic_scale_img(int width_src, int height_src, unsigned char *img_src, unsigned char *img_dst){
  973 
  974     int i = 0, x, y;
  975     for (y = 0; y < height_src; y+=2)
  976         for (x = 0; x < width_src; x+=2)
  977             img_dst[i++] = img_src[y * width_src + x];
  978 
  979     for (y = 0; y < height_src / 2; y+=2)
  980        for (x = 0; x < width_src; x += 4)
  981        {
  982           img_dst[i++] = img_src[(width_src * height_src) + (y * width_src) + x];
  983           img_dst[i++] = img_src[(width_src * height_src) + (y * width_src) + (x + 1)];
  984        }
  985 
  986     return;
  987 }
  988