Write a program in C to read the MNIST characters and display them as .png.

1 answer below »
Write a program in C to read the MNIST characters and display them as .png.
Answered Same DayMar 21, 2021

Answer To: Write a program in C to read the MNIST characters and display them as .png.

Pritam answered on Mar 22 2021
141 Votes
TinyPngOut.c
/** Tiny PNG Output (C) **/
#include
#include
#include "TinyPngOut.h"
static const uint16_t DEFLATE_MAX_BLOCK_SIZE = 65535;
static bool writePNG (struct TinyPngOut this[static 1], const uint8_t data[], size_t len);
static void crc32 (struct TinyPngOut this[static 1], const uint8_t data[], size_t len);
static void adler32(struct TinyPngOut this[static 1], const uint8_t data[], size_t len);
static void putBigUint32(uint32_t val, uint8_t array[static 4]);
enum TinyPngOut_Status TinyPngOut_init(struct TinyPngOut this[static 1],
uint32_t w, uint32_t h, FILE out[static 1]) {
    // Check arguments
    if (w == 0 || h == 0 || out == NULL)
        return TINYPNGOUT_INVALID_ARGUMENT;
    this->width = w;
    this->height = h;
    // Compute and check data siezs
    uint64_t lineSz = (uint64_t)this->width * 3 + 1;
    if (lineSz > UINT32_MAX)
        return TINYPNGOUT_IMAGE_TOO_LARGE;
    this->lineSize = (uint32_t)lineSz;
    uint64_t uncompRm = this->lineSize * this->height;
    if (uncompRm > UINT32_MAX)
        return TINYPNGOUT_IMAGE_TOO_LARGE;
    this->uncompRemain = (uint32_t)uncompRm;
    uint32_t numBlocks = this->uncompRemain / DEFLATE_MAX_BLOCK_SIZE;
    if (this->uncompRemain % DEFLATE_MAX_BLOCK_SIZE != 0)
        numBlocks++; // Round up
    // 5 bytes per DEFLATE uncompressed block header, 2 bytes for zlib header, 4 bytes for zlib Adler-32 footer
    uint64_t idatSize = (uint64_t)numBlocks * 5 + 6;
    idatSize += this->uncompRemain;
    if (idatSize > (uint32_t)INT32_MAX)
        return TINYPNGOUT_IMAGE_TOO_LARGE;
    // Write header (not a pure header, but a couple of things concatenated together)
    uint8_t header[] = { // 43 bytes long
        // PNG header
        0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
        // IHDR chunk
        0x00, 0x00, 0x00, 0x0D,
        0x49, 0x48, 0x44, 0x52,
        0, 0, 0, 0, // 'width' placeholder
        0, 0, 0, 0, // 'height' placeholder
        0x08, 0x02, 0x00, 0x00, 0x00,
        0, 0, 0, 0, // IHDR CRC-32 placeholder
        // IDAT chunk
        0, 0, 0, 0, // 'idatSize' placeholder
        0x49, 0x44, 0x41, 0x54,
        // DEFLATE data
        0x08, 0x1D,
    };
    putBigUint32(this->width, &header[16]);
    putBigUint32(this->height, &header[20]);
    putBigUint32(idatSize, &header[33]);
    this->crc = 0;
    crc32(this, &header[12], 17);
    putBigUint32(this->crc, &header[29]);
    this->output = out;
    if (!writePNG(this, header, sizeof(header) / sizeof(header[0])))
        return TINYPNGOUT_IO_ERROR;
    this->crc = 0;
    crc32(this, &header[37], 6); // 0xD7245B6B
    this->adler = 1;
    this->positionX = 0;
    this->positionY = 0;
    this->deflateFilled = 0;
    return TINYPNGOUT_OK;
}
enum TinyPngOut_Status TinyPngOut_write(struct TinyPngOut this[static 1], const uint8_t pixels[], size_t count) {
    if (count > SIZE_MAX / 3)
        return TINYPNGOUT_INVALID_ARGUMENT;
    count *= 3; // Convert pixel count to byte count
    while (count > 0) {
        if (pixels == NULL)
            return TINYPNGOUT_INVALID_ARGUMENT;
        if (this->positionY >= this->height)
            return TINYPNGOUT_INVALID_ARGUMENT; // All image pixels already written
        if (this->deflateFilled == 0) { // Start DEFLATE block
            uint16_t size = DEFLATE_MAX_BLOCK_SIZE;
            if (this->uncompRemain < size)
                size = (uint16_t)this->uncompRemain;
            const uint8_t header[] = { // 5 bytes long
                (uint8_t)(this->uncompRemain <= DEFLATE_MAX_BLOCK_SIZE ? 1 : 0),
                (uint8_t)(size >> 0),
                (uint8_t)(size >> 8),
                (uint8_t)((size >> 0) ^ 0xFF),
                (uint8_t)((size >> 8) ^ 0xFF),
            };
            if (!writePNG(this, header, sizeof(header) / sizeof(header[0])))
                return TINYPNGOUT_IO_ERROR;
            crc32(this, header, sizeof(header) / sizeof(header[0]));
        }
        assert(this->positionX < this->lineSize && this->deflateFilled < DEFLATE_MAX_BLOCK_SIZE);
        if (this->positionX == 0) { // Beginning of line - write filter method byte
            uint8_t b[] = {0};
            if (!writePNG(this, b, sizeof(b) / sizeof(b[0])))
                return TINYPNGOUT_IO_ERROR;
            crc32(this, b, 1);
            adler32(this, b, 1);
            this->positionX++;
            this->uncompRemain--;
            this->deflateFilled++;
        } else { // Write some pixel bytes for current line
            uint16_t n = DEFLATE_MAX_BLOCK_SIZE - this->deflateFilled;
            if (this->lineSize - this->positionX < n)
                n = (uint16_t)(this->lineSize - this->positionX);
            if (count < n)
                n = (uint16_t)count;
            assert(n > 0);
            if (!writePNG(this, pixels, n))
                return TINYPNGOUT_IO_ERROR;
            // Update checksums
            crc32(this, pixels, n);
            adler32(this, pixels, n);
            // Increment positions
            count -= n;
            pixels += n;
            this->positionX += n;
            this->uncompRemain -= n;
            this->deflateFilled += n;
        }
        if (this->deflateFilled >= DEFLATE_MAX_BLOCK_SIZE)
            this->deflateFilled = 0; // End current block
        if (this->positionX == this->lineSize) { // Increment line
            this->positionX = 0;
            this->positionY++;
            if (this->positionY == this->height) { // Reached end of pixels
                uint8_t footer[] = { // 20 bytes long
                    0, 0, 0, 0, // DEFLATE Adler-32 placeholder
                    0, 0, 0, 0, // IDAT CRC-32 placeholder
                    // IEND chunk
                    0x00, 0x00, 0x00, 0x00,
                    0x49, 0x45, 0x4E, 0x44,
                    0xAE, 0x42, 0x60, 0x82,
                };
                putBigUint32(this->adler, &footer[0]);
                crc32(this, &footer[0], 4);
                putBigUint32(this->crc, &footer[4]);
                if (!writePNG(this, footer, sizeof(footer) / sizeof(footer[0])))
                    return TINYPNGOUT_IO_ERROR;
            }
        }
    }
    return TINYPNGOUT_OK;
}
/*---- Private utility functions ----*/
// Returns whether the write was successful.
static bool writePNG(struct TinyPngOut this[static 1], const uint8_t data[], size_t len) {
    return fwrite(data, sizeof(data[0]), len, this->output) == len;
}
// Reads the 'crc' field and updates its value based on the given array of new data.
static void...
SOLUTION.PDF

Answer To This Question Is Available To Download

Related Questions & Answers

More Questions »

Submit New Assignment

Copy and Paste Your Assignment Here