17abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <stdio.h>
27abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <debug.h>
37abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <cmdline.h>
47abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <sys/types.h>
57abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <sys/stat.h>
67abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <sys/mman.h>
77abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <fcntl.h>
87abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <string.h>
97abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <errno.h>
107abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#include <unistd.h>
117abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
127abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#ifndef max
137abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#define max(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; })
147abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#define min(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; })
157abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#endif
167abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
177abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#define CONVERT_TYPE_PPM 0
187abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#define CONVERT_TYPE_RGB 1
197abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev#define CONVERT_TYPE_ARGB 2
207abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
217abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev/*
227abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev   YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved
237abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev   U/V plane containing 8 bit 2x2 subsampled chroma samples.
247abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev   except the interleave order of U and V is reversed.
257abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
267abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                        H V
277abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev   Y Sample Period      1 1
287abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev   U (Cb) Sample Period 2 2
297abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev   V (Cr) Sample Period 2 2
307abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev */
317abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
327abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevtypedef struct rgb_context {
337abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char *buffer;
347abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int width;
357abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int height;
367abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int rotate;
377abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int i;
387abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int j;
397abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int size; /* for debugging */
407abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev} rgb_context;
417abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
427abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevtypedef void (*rgb_cb)(
437abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char r,
447abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char g,
457abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char b,
467abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    rgb_context *ctx);
477abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
487abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevconst int bytes_per_pixel = 2;
497abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
507abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevstatic void color_convert_common(
517abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char *pY, unsigned char *pUV,
527abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int width, int height,
537abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char *buffer,
547abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int size, /* buffer size in bytes */
557abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int gray,
567abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int rotate,
577abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    rgb_cb cb)
587abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev{
597abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev	int i, j;
607abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev	int nR, nG, nB;
617abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev	int nY, nU, nV;
627abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    rgb_context ctx;
637abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
647abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    ctx.buffer = buffer;
657abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    ctx.size = size; /* debug */
667abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    ctx.width = width;
677abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    ctx.height = height;
687abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    ctx.rotate = rotate;
697abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
707abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    if (gray) {
717abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        for (i = 0; i < height; i++) {
727abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev            for (j = 0; j < width; j++) {
737abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nB = *(pY + i * width + j);
747abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                ctx.i = i;
757abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                ctx.j = j;
767abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                cb(nB, nB, nB, &ctx);
777abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev            }
787abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        }
797abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    } else {
807abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        // YUV 4:2:0
817abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        for (i = 0; i < height; i++) {
827abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev            for (j = 0; j < width; j++) {
837abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nY = *(pY + i * width + j);
847abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nV = *(pUV + (i/2) * width + bytes_per_pixel * (j/2));
857abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nU = *(pUV + (i/2) * width + bytes_per_pixel * (j/2) + 1);
867abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
877abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                // Yuv Convert
887abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nY -= 16;
897abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nU -= 128;
907abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nV -= 128;
917abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
927abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                if (nY < 0)
937abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                    nY = 0;
947abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
957abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                // nR = (int)(1.164 * nY + 2.018 * nU);
967abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                // nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
977abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                // nB = (int)(1.164 * nY + 1.596 * nV);
987abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
997abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nB = (int)(1192 * nY + 2066 * nU);
1007abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nG = (int)(1192 * nY - 833 * nV - 400 * nU);
1017abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nR = (int)(1192 * nY + 1634 * nV);
1027abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1037abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nR = min(262143, max(0, nR));
1047abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nG = min(262143, max(0, nG));
1057abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nB = min(262143, max(0, nB));
1067abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1077abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nR >>= 10; nR &= 0xff;
1087abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nG >>= 10; nG &= 0xff;
1097abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                nB >>= 10; nB &= 0xff;
1107abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1117abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                ctx.i = i;
1127abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                ctx.j = j;
1137abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                cb(nR, nG, nB, &ctx);
1147abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev            }
1157abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        }
1167abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    }
1177abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev}
1187abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1197abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevstatic void rgb16_cb(
1207abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char r,
1217abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char g,
1227abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char b,
1237abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    rgb_context *ctx)
1247abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev{
1257abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned short *rgb16 = (unsigned short *)ctx->buffer;
1267abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    *(rgb16 + ctx->i * ctx->width + ctx->j) = b | (g << 5) | (r << 11);
1277abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev}
1287abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1297abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevstatic void common_rgb_cb(
1307abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char r,
1317abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char g,
1327abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char b,
1337abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    rgb_context *ctx,
1347abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int alpha)
1357abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev{
1367abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char *out = ctx->buffer;
1377abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int offset = 0;
1387abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int bpp;
1397abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int i = 0;
1407abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    switch(ctx->rotate) {
1417abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    case 0: /* no rotation */
1427abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        offset = ctx->i * ctx->width + ctx->j;
1437abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        break;
1447abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    case 1: /* 90 degrees */
1457abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        offset = ctx->height * (ctx->j + 1) - ctx->i;
1467abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        break;
1477abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    case 2: /* 180 degrees */
1487abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        offset = (ctx->height - 1 - ctx->i) * ctx->width + ctx->j;
1497abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        break;
1507abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    case 3: /* 270 degrees */
1517abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        offset = (ctx->width - 1 - ctx->j) * ctx->height + ctx->i;
1527abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        break;
1537abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    default:
1547abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        FAILIF(1, "Unexpected roation value %d!\n", ctx->rotate);
1557abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    }
1567abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1577abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    bpp = 3 + !!alpha;
1587abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    offset *= bpp;
1597abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    FAILIF(offset < 0, "point (%d, %d) generates a negative offset.\n", ctx->i, ctx->j);
1607abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    FAILIF(offset + bpp > ctx->size, "point (%d, %d) at offset %d exceeds the size %d of the buffer.\n",
1617abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           ctx->i, ctx->j,
1627abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           offset,
1637abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           ctx->size);
1647abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1657abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    out += offset;
1667abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1677abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    if (alpha) out[i++] = 0xff;
1687abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    out[i++] = r;
1697abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    out[i++] = g;
1707abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    out[i] = b;
1717abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev}
1727abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1737abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevstatic void rgb24_cb(
1747abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char r,
1757abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char g,
1767abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char b,
1777abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    rgb_context *ctx)
1787abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev{
1797abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    return common_rgb_cb(r,g,b,ctx,0);
1807abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev}
1817abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1827abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevstatic void argb_cb(
1837abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char r,
1847abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char g,
1857abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    unsigned char b,
1867abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    rgb_context *ctx)
1877abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev{
1887abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    return common_rgb_cb(r,g,b,ctx,1);
1897abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev}
1907abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
1917abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevstatic void convert(const char *infile,
1927abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                    const char *outfile,
1937abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                    int height,
1947abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                    int width,
1957abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                    int gray,
1967abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                    int type,
1977abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                    int rotate)
1987abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev{
1997abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    void *in, *out;
2007abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int ifd, ofd, rc;
2017abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int psz = getpagesize();
2027abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    static char header[1024];
2037abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int header_size;
2047abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    size_t outsize;
2057abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2067abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int bpp = 3;
2077abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    switch (type) {
2087abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    case CONVERT_TYPE_PPM:
2097abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        PRINT("encoding PPM\n");
2107abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        if (rotate & 1)
2117abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev            header_size = snprintf(header, sizeof(header), "P6\n%d %d\n255\n", height, width);
2127abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        else
2137abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev            header_size = snprintf(header, sizeof(header), "P6\n%d %d\n255\n", width, height);
2147abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev	break;
2157abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    case CONVERT_TYPE_RGB:
2167abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        PRINT("encoding raw RGB24\n");
2177abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        header_size = 0;
2187abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        break;
2197abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    case CONVERT_TYPE_ARGB:
2207abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        PRINT("encoding raw ARGB\n");
2217abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        header_size = 0;
2227abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        bpp = 4;
2237abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        break;
2247abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    }
2257abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2267abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    outsize = header_size + width * height * bpp;
2277abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    outsize = (outsize + psz - 1) & ~(psz - 1);
2287abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2297abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("Opening input file %s\n", infile);
2307abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    ifd = open(infile, O_RDONLY);
2317abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    FAILIF(ifd < 0, "open(%s) failed: %s (%d)\n",
2327abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           infile, strerror(errno), errno);
2337abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2347abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("Opening output file %s\n", outfile);
2357abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    ofd = open(outfile, O_RDWR | O_CREAT, 0664);
2367abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    FAILIF(ofd < 0, "open(%s) failed: %s (%d)\n",
2377abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           outfile, strerror(errno), errno);
2387abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2397abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("Memory-mapping input file %s\n", infile);
2407abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    in = mmap(0, width * height * 3 / 2, PROT_READ, MAP_PRIVATE, ifd, 0);
2417abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    FAILIF(in == MAP_FAILED, "could not mmap input file: %s (%d)\n",
2427abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           strerror(errno), errno);
2437abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2447abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("Truncating output file %s to %d bytes\n", outfile, outsize);
2457abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    FAILIF(ftruncate(ofd, outsize) < 0,
2467abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           "Could not truncate output file to required size: %s (%d)\n",
2477abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           strerror(errno), errno);
2487abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2497abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("Memory mapping output file %s\n", outfile);
2507abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    out = mmap(0, outsize, PROT_WRITE, MAP_SHARED, ofd, 0);
2517abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    FAILIF(out == MAP_FAILED, "could not mmap output file: %s (%d)\n",
2527abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           strerror(errno), errno);
2537abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2547abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("PPM header (%d) bytes:\n%s\n", header_size, header);
2557abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    FAILIF(write(ofd, header, header_size) != header_size,
2567abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           "Error wrinting PPM header: %s (%d)\n",
2577abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev           strerror(errno), errno);
2587abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2597abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("Converting %dx%d YUV 4:2:0 to RGB24...\n", width, height);
2607abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    color_convert_common(in, in + width * height,
2617abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                         width, height,
2627abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                         out + header_size, outsize - header_size,
2637abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                         gray, rotate,
2647abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                         type == CONVERT_TYPE_ARGB ? argb_cb : rgb24_cb);
2657abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev}
2667abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2677abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevint verbose_flag;
2687abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevint quiet_flag;
2697abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2707abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchevint main(int argc, char **argv) {
2717abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2727abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    char *infile, *outfile, *type;
2737abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int height, width, gray, rotate;
2747abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int cmdline_error = 0;
2757abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2767abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    /* Parse command-line arguments. */
2777abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2787abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int first = get_options(argc, argv,
2797abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                            &outfile,
2807abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                            &height,
2817abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                            &width,
2827abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                            &gray,
2837abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                            &type,
2847abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                            &rotate,
2857abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev                            &verbose_flag);
2867abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
2877abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    if (first == argc) {
2887abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        ERROR("You must specify an input file!\n");
2897abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        cmdline_error++;
2907abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    }
2917abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    if (!outfile) {
2927abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        ERROR("You must specify an output file!\n");
2937abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        cmdline_error++;
2947abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    }
2957abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    if (height < 0 || width < 0) {
2967abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        ERROR("You must specify both image height and width!\n");
2977abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        cmdline_error++;
2987abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    }
2997abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
3007abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    FAILIF(rotate % 90, "Rotation angle must be a multiple of 90 degrees!\n");
3017abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
3027abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    rotate /= 90;
3037abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    rotate %= 4;
3047abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    if (rotate < 0) rotate += 4;
3057abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
3067abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    if (cmdline_error) {
3077abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        print_help(argv[0]);
3087abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        exit(1);
3097abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    }
3107abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
3117abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    infile = argv[first];
3127abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
3137abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("input file: [%s]\n", infile);
3147abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("output file: [%s]\n", outfile);
3157abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("height: %d\n", height);
3167abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("width: %d\n", width);
3177abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("gray only: %d\n", gray);
3187abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("encode as: %s\n", type);
3197abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    INFO("rotation: %d\n", rotate);
3207abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
3217abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    /* Convert the image */
3227abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
3237abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    int conv_type;
3247abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    if (!type || !strcmp(type, "ppm"))
3257abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        conv_type = CONVERT_TYPE_PPM;
3267abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    else if (!strcmp(type, "rgb"))
3277abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        conv_type = CONVERT_TYPE_RGB;
3287abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    else if (!strcmp(type, "argb"))
3297abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev        conv_type = CONVERT_TYPE_ARGB;
3307abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    else FAILIF(1, "Unknown encoding type %s.\n", type);
3317abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
3327abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    convert(infile, outfile,
3337abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev            height, width, gray,
3347abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev            conv_type,
3357abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev            rotate);
3367abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev
3377abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    free(outfile);
3387abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev    return 0;
3397abfb48551224ac2b4a8d1820c023915e31ffb5fIliyan Malchev}
340