Exemplo n.º 1
0
bool KPWriteImage::write2PNG(const QString& destPath)
{
    FILE* file = fopen(QFile::encodeName(destPath), "wb");
    if (!file)
    {
        kDebug( 51000 ) << "Failed to open PNG file for writing" << endl;
        return false;
    }

    uchar       *data       = 0;
    int          bitsDepth  = d->sixteenBit ? 16 : 8;
    png_color_8  sig_bit;
    png_bytep    row_ptr;
    png_structp  png_ptr    = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop    info_ptr   = png_create_info_struct(png_ptr);
    png_init_io(png_ptr, file);

    if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)      // Intel
        png_set_bgr(png_ptr);
    else                                                    // PPC
        png_set_swap_alpha(png_ptr);

    if (d->hasAlpha)
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB_ALPHA,  PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 8 * sizeof(uchar)];
        else
            data = new uchar[d->width * 4 * sizeof(uchar)];
    }
    else
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB,        PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 6 * sizeof(uchar)];
        else
            data = new uchar[d->width * 3 * sizeof(uchar)];
    }

    sig_bit.red   = bitsDepth;
    sig_bit.green = bitsDepth;
    sig_bit.blue  = bitsDepth;
    sig_bit.alpha = bitsDepth;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
    png_set_compression_level(png_ptr, 9);

    // Write ICC profil.
    if (!d->iccProfile.isEmpty())
    {
        png_set_iCCP(png_ptr, info_ptr, (png_charp)"icc", PNG_COMPRESSION_TYPE_BASE,
                     d->iccProfile.data(), d->iccProfile.size());
    }

    // Write Software info.
    QString libpngver(PNG_HEADER_VERSION_STRING);
    libpngver.replace('\n', ' ');
    QString soft = d->kipipluginsVer;
    soft.append(QString(" (%1)").arg(libpngver));
    png_text text;
    text.key  = (png_charp)"Software";
    text.text = soft.toAscii().data();
    text.compression = PNG_TEXT_COMPRESSION_zTXt;
    png_set_text(png_ptr, info_ptr, &(text), 1);

    // Store Exif data.
    QByteArray ba = d->metadata.getExif(true);
    writeRawProfile(png_ptr, info_ptr, (png_charp)"exif", ba.data(), (png_uint_32) ba.size());

    // Store Iptc data.
    QByteArray ba2 = d->metadata.getIptc();
    writeRawProfile(png_ptr, info_ptr, (png_charp)"iptc", ba2.data(), (png_uint_32) ba2.size());

    // Store Xmp data.
    QByteArray ba3 = d->metadata.getXmp();
    writeRawProfile(png_ptr, info_ptr, (png_charp)("xmp"), ba3.data(), (png_uint_32) ba3.size());

    png_write_info(png_ptr, info_ptr);
    png_set_shift(png_ptr, &sig_bit);
    png_set_packing(png_ptr);

    uchar* ptr = (uchar*)d->data.data();
    uint   x, y, j;

    for (y = 0; y < d->height; y++)
    {
        if (cancel())
        {
            delete [] data;
            fclose(file);
            png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
            png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
            return false;
        }

        j = 0;

        for (x = 0; x < d->width*bytesDepth(); x+=bytesDepth())
        {
            if (d->sixteenBit)
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                    data[j++] = ptr[x+7];  // Alpha
                    data[j++] = ptr[x+6];
                }
                else
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                }
            }
            else
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                    data[j++] = ptr[x+3];  // Alpha
                }
                else
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                }
            }
        }

        row_ptr = (png_bytep) data;

        png_write_rows(png_ptr, &row_ptr, 1);
        ptr += (d->width * bytesDepth());
    }

    delete [] data;

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
    png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
    fclose(file);

    return true;
}
Exemplo n.º 2
0
DEF_TEST(Codec_pngChunkReader, r) {
    // Create a dummy bitmap. Use unpremul RGBA for libpng.
    SkBitmap bm;
    const int w = 1;
    const int h = 1;
    const SkImageInfo bmInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
                                                 kUnpremul_SkAlphaType);
    bm.setInfo(bmInfo);
    bm.allocPixels();
    bm.eraseColor(SK_ColorBLUE);
    SkMD5::Digest goodDigest;
    md5(bm, &goodDigest);

    // Write to a png file.
    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    REPORTER_ASSERT(r, png);
    if (!png) {
        return;
    }

    png_infop info = png_create_info_struct(png);
    REPORTER_ASSERT(r, info);
    if (!info) {
        png_destroy_write_struct(&png, nullptr);
        return;
    }

    if (setjmp(png_jmpbuf(png))) {
        ERRORF(r, "failed writing png");
        png_destroy_write_struct(&png, &info);
        return;
    }

    SkDynamicMemoryWStream wStream;
    png_set_write_fn(png, (void*) (&wStream), codex_test_write_fn, nullptr);

    png_set_IHDR(png, info, (png_uint_32)w, (png_uint_32)h, 8,
                 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

    // Create some chunks that match the Android framework's use.
    static png_unknown_chunk gUnknowns[] = {
        { "npOl", (png_byte*)"outline", sizeof("outline"), PNG_HAVE_IHDR },
        { "npLb", (png_byte*)"layoutBounds", sizeof("layoutBounds"), PNG_HAVE_IHDR },
        { "npTc", (png_byte*)"ninePatchData", sizeof("ninePatchData"), PNG_HAVE_IHDR },
    };

    png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"npOl\0npLb\0npTc\0", 3);
    png_set_unknown_chunks(png, info, gUnknowns, SK_ARRAY_COUNT(gUnknowns));
#if PNG_LIBPNG_VER < 10600
    /* Deal with unknown chunk location bug in 1.5.x and earlier */
    png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_IHDR);
    png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_IHDR);
#endif

    png_write_info(png, info);

    for (int j = 0; j < h; j++) {
        png_bytep row = (png_bytep)(bm.getAddr(0, j));
        png_write_rows(png, &row, 1);
    }
    png_write_end(png, info);
    png_destroy_write_struct(&png, &info);

    class ChunkReader : public SkPngChunkReader {
    public:
        ChunkReader(skiatest::Reporter* r)
            : fReporter(r)
        {
            this->reset();
        }

        bool readChunk(const char tag[], const void* data, size_t length) override {
            for (size_t i = 0; i < SK_ARRAY_COUNT(gUnknowns); ++i) {
                if (!strcmp(tag, (const char*) gUnknowns[i].name)) {
                    // Tag matches. This should have been the first time we see it.
                    REPORTER_ASSERT(fReporter, !fSeen[i]);
                    fSeen[i] = true;

                    // Data and length should match
                    REPORTER_ASSERT(fReporter, length == gUnknowns[i].size);
                    REPORTER_ASSERT(fReporter, !strcmp((const char*) data,
                                                       (const char*) gUnknowns[i].data));
                    return true;
                }
            }
            ERRORF(fReporter, "Saw an unexpected unknown chunk.");
            return true;
        }

        bool allHaveBeenSeen() {
            bool ret = true;
            for (auto seen : fSeen) {
                ret &= seen;
            }
            return ret;
        }

        void reset() {
            sk_bzero(fSeen, sizeof(fSeen));
        }

    private:
        skiatest::Reporter* fReporter;  // Unowned
        bool fSeen[3];
    };

    ChunkReader chunkReader(r);

    // Now read the file with SkCodec.
    SkAutoTUnref<SkData> data(wStream.copyToData());
    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data, &chunkReader));
    REPORTER_ASSERT(r, codec);
    if (!codec) {
        return;
    }

    // Now compare to the original.
    SkBitmap decodedBm;
    decodedBm.setInfo(codec->getInfo());
    decodedBm.allocPixels();
    SkCodec::Result result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(),
                                              decodedBm.rowBytes());
    REPORTER_ASSERT(r, SkCodec::kSuccess == result);

    if (decodedBm.colorType() != bm.colorType()) {
        SkBitmap tmp;
        bool success = decodedBm.copyTo(&tmp, bm.colorType());
        REPORTER_ASSERT(r, success);
        if (!success) {
            return;
        }

        tmp.swap(decodedBm);
    }

    compare_to_good_digest(r, goodDigest, decodedBm);
    REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());

    // Decoding again will read the chunks again.
    chunkReader.reset();
    REPORTER_ASSERT(r, !chunkReader.allHaveBeenSeen());
    result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), decodedBm.rowBytes());
    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
    REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
}
Exemplo n.º 3
0
/*!
 *  pixWriteStreamPng()
 *
 *      Input:  stream
 *              pix
 *              gamma (use 0.0 if gamma is not defined)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) If called from pixWriteStream(), the stream is positioned
 *          at the beginning of the file.
 *      (2) To do sequential writes of png format images to a stream,
 *          use pixWriteStreamPng() directly.
 *      (3) gamma is an optional png chunk.  If no gamma value is to be
 *          placed into the file, use gamma = 0.0.  Otherwise, if
 *          gamma > 0.0, its value is written into the header.
 *      (4) The use of gamma in png is highly problematic.  For an illuminating
 *          discussion, see:  http://hsivonen.iki.fi/png-gamma/
 *      (5) What is the effect/meaning of gamma in the png file?  This
 *          gamma, which we can call the 'source' gamma, is the
 *          inverse of the gamma that was used in enhance.c to brighten
 *          or darken images.  The 'source' gamma is supposed to indicate
 *          the intensity mapping that was done at the time the
 *          image was captured.  Display programs typically apply a
 *          'display' gamma of 2.2 to the output, which is intended
 *          to linearize the intensity based on the response of
 *          thermionic tubes (CRTs).  Flat panel LCDs have typically
 *          been designed to give a similar response as CRTs (call it
 *          "backward compatibility").  The 'display' gamma is
 *          in some sense the inverse of the 'source' gamma.
 *          jpeg encoders attached to scanners and cameras will lighten
 *          the pixels, applying a gamma corresponding to approximately
 *          a square-root relation of output vs input:
 *                output = input^(gamma)
 *          where gamma is often set near 0.4545  (1/gamma is 2.2).
 *          This is stored in the image file.  Then if the display
 *          program reads the gamma, it will apply a display gamma,
 *          typically about 2.2; the product is 1.0, and the
 *          display program produces a linear output.  This works because
 *          the dark colors were appropriately boosted by the scanner,
 *          as described by the 'source' gamma, so they should not
 *          be further boosted by the display program.
 *      (6) As an example, with xv and display, if no gamma is stored,
 *          the program acts as if gamma were 0.4545, multiplies this by 2.2,
 *          and does a linear rendering.  Taking this as a baseline
 *          brightness, if the stored gamma is:
 *              > 0.4545, the image is rendered lighter than baseline
 *              < 0.4545, the image is rendered darker than baseline
 *          In contrast, gqview seems to ignore the gamma chunk in png.
 *      (7) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
 *          and 32.  However, it is possible, and in some cases desirable,
 *          to write out a png file using an rgb pix that has 24 bpp.
 *          For example, the open source xpdf SplashBitmap class generates
 *          24 bpp rgb images.  Consequently, we anble writing 24 bpp pix.
 *          To generate such a pix, you can make a 24 bpp pix without data
 *          and assign the data array to the pix; e.g.,
 *              pix = pixCreateHeader(w, h, 24);
 *              pixSetData(pix, rgbdata);
 *          See pixConvert32To24() for an example, where we get rgbdata
 *          from the 32 bpp pix.  Caution: do not call pixSetPadBits(),
 *          because the alignment is wrong and you may erase part of the
 *          last pixel on each line.
 */
l_int32
pixWriteStreamPng(FILE      *fp,
                  PIX       *pix,
                  l_float32  gamma)
{
char         commentstring[] = "Comment";
l_int32      i, j, k;
l_int32      wpl, d, cmflag;
l_int32      ncolors;
l_int32     *rmap, *gmap, *bmap;
l_uint32    *data, *ppixel;
png_byte     bit_depth, color_type;
png_uint_32  w, h;
png_uint_32  xres, yres;
png_bytep   *row_pointers;
png_bytep    rowbuffer;
png_structp  png_ptr;
png_infop    info_ptr;
png_colorp   palette;
PIX         *pixt;
PIXCMAP     *cmap;
char        *text;

    PROCNAME("pixWriteStreamPng");

    if (!fp)
        return ERROR_INT("stream not open", procName, 1);
    if (!pix)
        return ERROR_INT("pix not defined", procName, 1);

        /* Allocate the 2 data structures */
    if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                   (png_voidp)NULL, NULL, NULL)) == NULL)
        return ERROR_INT("png_ptr not made", procName, 1);

    if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        return ERROR_INT("info_ptr not made", procName, 1);
    }

        /* Set up png setjmp error handling */
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return ERROR_INT("internal png error", procName, 1);
    }

    png_init_io(png_ptr, fp);

        /* With best zlib compression (9), get between 1 and 10% improvement
         * over default (5), but the compression is 3 to 10 times slower.
         * Our default compression is the zlib default (5). */
    png_set_compression_level(png_ptr, var_ZLIB_COMPRESSION);

    w = pixGetWidth(pix);
    h = pixGetHeight(pix);
    d = pixGetDepth(pix);
    if ((cmap = pixGetColormap(pix)))
        cmflag = 1;
    else
        cmflag = 0;

        /* Set the color type and bit depth. */
    if (d == 32 && var_PNG_WRITE_ALPHA == 1) {
        bit_depth = 8;
        color_type = PNG_COLOR_TYPE_RGBA;   /* 6 */
        cmflag = 0;  /* ignore if it exists */
    }
    else if (d == 24 || d == 32) {
        bit_depth = 8;
        color_type = PNG_COLOR_TYPE_RGB;   /* 2 */
        cmflag = 0;  /* ignore if it exists */
    }
    else {
        bit_depth = d;
        color_type = PNG_COLOR_TYPE_GRAY;  /* 0 */
    }
    if (cmflag)
        color_type = PNG_COLOR_TYPE_PALETTE;  /* 3 */

#if  DEBUG
    fprintf(stderr, "cmflag = %d, bit_depth = %d, color_type = %d\n",
            cmflag, bit_depth, color_type);
#endif  /* DEBUG */

    png_set_IHDR(png_ptr, info_ptr, w, h, bit_depth, color_type,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                 PNG_FILTER_TYPE_BASE);

        /* Store resolution in ppm, if known */
    xres = (png_uint_32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5);
    yres = (png_uint_32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5);
    if ((xres == 0) || (yres == 0))
        png_set_pHYs(png_ptr, info_ptr, 0, 0, PNG_RESOLUTION_UNKNOWN);
    else
        png_set_pHYs(png_ptr, info_ptr, xres, yres, PNG_RESOLUTION_METER);

    if (cmflag) {
        pixcmapToArrays(cmap, &rmap, &gmap, &bmap);
        ncolors = pixcmapGetCount(cmap);

            /* Make and save the palette */
        if ((palette = (png_colorp)(CALLOC(ncolors, sizeof(png_color))))
                == NULL)
            return ERROR_INT("palette not made", procName, 1);

        for (i = 0; i < ncolors; i++) {
            palette[i].red = (png_byte)rmap[i];
            palette[i].green = (png_byte)gmap[i];
            palette[i].blue = (png_byte)bmap[i];
        }

        png_set_PLTE(png_ptr, info_ptr, palette, (int)ncolors);
        FREE(rmap);
        FREE(gmap);
        FREE(bmap);
    }

        /* 0.4545 is treated as the default by some image
         * display programs (not gqview).  A value > 0.4545 will
         * lighten an image as displayed by xv, display, etc. */
    if (gamma > 0.0)
        png_set_gAMA(png_ptr, info_ptr, (l_float64)gamma);

    if ((text = pixGetText(pix))) {
        png_text text_chunk;
        text_chunk.compression = PNG_TEXT_COMPRESSION_NONE;
        text_chunk.key = commentstring;
        text_chunk.text = text;
        text_chunk.text_length = strlen(text);
#ifdef PNG_ITXT_SUPPORTED
        text_chunk.itxt_length = 0;
        text_chunk.lang = NULL;
        text_chunk.lang_key = NULL;
#endif
        png_set_text(png_ptr, info_ptr, &text_chunk, 1);
    }

        /* Write header and palette info */
    png_write_info(png_ptr, info_ptr);

    if ((d != 32) && (d != 24)) {  /* not rgb color */
            /* Generate a temporary pix with bytes swapped.
             * For a binary image, there are two conditions in
             * which you must first invert the data for writing png:
             *    (a) no colormap
             *    (b) colormap with BLACK set to 0
             * png writes binary with BLACK = 0, unless contradicted
             * by a colormap.  If the colormap has BLACK = "1"
             * (typ. about 255), do not invert the data.  If there
             * is no colormap, you must invert the data to store
             * in default BLACK = 0 state.  */
        if (d == 1 &&
            (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) {
            pixt = pixInvert(NULL, pix);
            pixEndianByteSwap(pixt);
        }
        else
            pixt = pixEndianByteSwapNew(pix);
        if (!pixt) {
            png_destroy_write_struct(&png_ptr, &info_ptr);
            return ERROR_INT("pixt not made", procName, 1);
        }

            /* Make and assign array of image row pointers */
        if ((row_pointers = (png_bytep *)CALLOC(h, sizeof(png_bytep))) == NULL)
            return ERROR_INT("row-pointers not made", procName, 1);
        wpl = pixGetWpl(pixt);
        data = pixGetData(pixt);
        for (i = 0; i < h; i++)
            row_pointers[i] = (png_bytep)(data + i * wpl);
        png_set_rows(png_ptr, info_ptr, row_pointers);

            /* Transfer the data */
        png_write_image(png_ptr, row_pointers);
        png_write_end(png_ptr, info_ptr);

        if (cmflag)
            FREE(palette);
        FREE(row_pointers);
        pixDestroy(&pixt);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return 0;
    }

        /* For rgb, compose and write a row at a time */
    data = pixGetData(pix);
    wpl = pixGetWpl(pix);
    if (d == 24) {  /* See note 7 above: special case of 24 bpp rgb */
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            png_write_rows(png_ptr, (png_bytepp)&ppixel, 1);
        }
    }
    else {  /* 32 bpp rgb and rgba */
        if ((rowbuffer = (png_bytep)CALLOC(w, 4)) == NULL)
            return ERROR_INT("rowbuffer not made", procName, 1);
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            for (j = k = 0; j < w; j++) {
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
                if (var_PNG_WRITE_ALPHA == 1)
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL);
                ppixel++;
            }

            png_write_rows(png_ptr, &rowbuffer, 1);
        }
        FREE(rowbuffer);
    }

    png_write_end(png_ptr, info_ptr);

    if (cmflag)
        FREE(palette);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return 0;

}
Exemplo n.º 4
0
void PNGImageFileWriter::write(
    const char*             filename,
    const ICanvas&          image,
    const ImageAttributes&  image_attributes)
{
    // Retrieve canvas properties.
    const CanvasProperties& props = image.properties();

    // todo: lift these limitations.
    assert(props.m_channel_count == 3 || props.m_channel_count == 4);

    // Open the file in write mode.
    FILE* fp = fopen(filename, "wb");
    if (fp == 0)
        throw ExceptionIOError();

    // Allocate and initialize the png_struct structure.
    png_structp png_ptr =
        png_create_write_struct(
            PNG_LIBPNG_VER_STRING,
            fp,
            error_callback,
            warning_callback);
    if (png_ptr == 0)
    {
        fclose(fp);
        throw ExceptionMemoryError();
    }

    // Allocate the png_info structure.
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == 0)
    {
        png_destroy_write_struct(&png_ptr, 0);
        fclose(fp);
        throw ExceptionMemoryError();
    }

    // Set up the output control.
    png_init_io(png_ptr, fp);

    // Set image information.
    png_set_IHDR(
        png_ptr,
        info_ptr,
        static_cast<png_uint_32>(props.m_canvas_width),
        static_cast<png_uint_32>(props.m_canvas_height),
        8,                                  // bit depth -- todo: allow higher bit depths
        props.m_channel_count == 4
            ? PNG_COLOR_TYPE_RGB_ALPHA
            : PNG_COLOR_TYPE_RGB,
        PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT,
        PNG_FILTER_TYPE_DEFAULT);

    // Mark the image as being sRGB (implying specific gamma and color matching functions).
    // See http://www.vias.org/pngguide/chapter10_07.html for details about intents.
    png_set_sRGB_gAMA_and_cHRM(
        png_ptr,
        info_ptr,
        PNG_sRGB_INTENT_PERCEPTUAL);        // todo: allow the user to select different intents

    // Set the number of significant bits for each of the R, G, B and A channels.
    // todo: are we required to provide these information?
    png_color_8 sig_bit;
    sig_bit.red = 8;
    sig_bit.green = 8;
    sig_bit.blue = 8;
    sig_bit.alpha = 8;
    sig_bit.gray = 8;                       // for completeness
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

    // Add image attributes.
    vector<png_text_struct> text_chunks;
    add_attributes(
        png_ptr,
        info_ptr,
        text_chunks,
        image_attributes);
    if (!text_chunks.empty())
    {
        png_set_text(
            png_ptr,
            info_ptr,
            &text_chunks[0],
            static_cast<int>(text_chunks.size()));
    }

    // Write the file header information.
    png_write_info(png_ptr, info_ptr);

    // Create the temporary buffer holding one row of tiles in target format.
    vector<uint8> buffer(
          props.m_canvas_width
        * props.m_tile_height
        * props.m_channel_count);

    // Construct pointers to each row of the temporary buffer.
    vector<uint8*> buffer_rows(props.m_tile_height);
    for (size_t y = 0; y < props.m_tile_height; ++y)
        buffer_rows[y] = &buffer[y * props.m_canvas_width * props.m_channel_count];

    // Loop over the rows of tiles.
    for (size_t tile_y = 0; tile_y < props.m_tile_count_y; ++tile_y)
    {
        // Convert this row of tiles to target format.
        for (size_t tile_x = 0; tile_x < props.m_tile_count_x; ++tile_x)
        {
            const Tile& tile = image.tile(tile_x, tile_y);
            assert(tile.get_height() <= props.m_tile_height);
            for (size_t y = 0; y < tile.get_height(); ++y)
            {
                for (size_t x = 0; x < tile.get_width(); ++x)
                {
                    // Horizontal coordinate of the pixel in the temporary buffer.
                    const size_t buffer_x = tile_x * props.m_tile_width + x;

                    // Index of the pixel in the temporary buffer.
                    const size_t buffer_index =
                        (y * props.m_canvas_width + buffer_x) * props.m_channel_count;

                    // Fetch the pixel at coordinates (x, y) in the tile,
                    // perform format conversion if necessary, and store
                    // the converted pixel into the temporary buffer.
                    if (tile.get_channel_count() == 3)
                    {
                        Color3i pixel;
                        tile.get_pixel(x, y, pixel);
                        buffer[buffer_index + 0] = pixel[0];
                        buffer[buffer_index + 1] = pixel[1];
                        buffer[buffer_index + 2] = pixel[2];
                    }
                    else
                    {
                        assert(tile.get_channel_count() == 4);
                        Color4i pixel;
                        tile.get_pixel(x, y, pixel);
                        buffer[buffer_index + 0] = pixel[0];
                        buffer[buffer_index + 1] = pixel[1];
                        buffer[buffer_index + 2] = pixel[2];
                        buffer[buffer_index + 3] = pixel[3];
                    }
                }
            }
        }

        // Write this row of tiles to the file.
        const size_t row_count = image.tile(0, tile_y).get_height();
        png_write_rows(
            png_ptr,
            &buffer_rows[0],
            static_cast<png_uint_32>(row_count));
    }

    // Finish writing the file.
    png_write_end(png_ptr, 0);

    // Deallocate the png_struct and png_info structures.
    png_destroy_write_struct(&png_ptr, &info_ptr);

    // Deallocate text chunks.
    destroy_text_chunks(text_chunks);

    // Close the file.
    fclose(fp);
}
Exemplo n.º 5
0
bool writePixelsToBuffer(unsigned char *pixels,
                         unsigned width, unsigned height, unsigned numChannels,
                         bool flipped,
                         char **buffer,
                         int *size)
{
    struct png_tmp_buffer png_mem;
    png_structp png_ptr;
    png_infop info_ptr;
    int type;

    png_mem.buffer = NULL;
    png_mem.size = 0;

    switch (numChannels) {
    case 4:
        type = PNG_COLOR_TYPE_RGB_ALPHA;
        break;
    case 3:
        type = PNG_COLOR_TYPE_RGB;
        break;
    case 2:
        type = PNG_COLOR_TYPE_GRAY_ALPHA;
        break;
    case 1:
        type = PNG_COLOR_TYPE_GRAY;
        break;
    default:
        goto no_png;
    }

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        goto no_png;

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_write_struct(&png_ptr,  NULL);
        goto no_png;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        goto no_png;
    }

    png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL);

    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
                 type, PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

    png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);

    png_write_info(png_ptr, info_ptr);

    if (!flipped) {
        for (unsigned y = 0; y < height; ++y) {
            png_bytep row = (png_bytep)(pixels + y*width*numChannels);
            png_write_rows(png_ptr, &row, 1);
        }
    } else {
        unsigned y = height;
        while (y--) {
            png_bytep row = (png_bytep)(pixels + y*width*numChannels);
            png_write_rows(png_ptr, &row, 1);
        }
    }

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);

    *buffer = png_mem.buffer;
    *size = png_mem.size;

    return true;

no_png:
    *buffer = NULL;
    *size = 0;

    if (png_mem.buffer)
        free(png_mem.buffer);
    return false;
}
Exemplo n.º 6
0
bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
{
    wxPNGInfoStruct wxinfo;

    wxinfo.verbose = verbose;
    wxinfo.stream.out = &stream;

    png_structp png_ptr = png_create_write_struct
                          (
                              PNG_LIBPNG_VER_STRING,
                              NULL,
                              wx_png_error,
                              wx_png_warning
                          );
    if (!png_ptr)
    {
        if (verbose)
        {
            wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
            wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    if (setjmp(wxinfo.jmpbuf))
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
            wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    // NB: please see the comment near wxPNGInfoStruct declaration for
    //     explanation why this line is mandatory
    png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL);

    const int iColorType = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT)
                           ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT)
                           : wxPNG_TYPE_COLOUR;
    const int iBitDepth = image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH)
                          ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH)
                          : 8;

    bool bHasAlpha = image->HasAlpha();
    bool bHasMask = image->HasMask();
    bool bUseAlpha = bHasAlpha || bHasMask;

    int iPngColorType;
    if ( iColorType==wxPNG_TYPE_COLOUR )
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA
                        : PNG_COLOR_TYPE_RGB;
    }
    else
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA
                        : PNG_COLOR_TYPE_GRAY;
    }

    if (image->HasOption(wxIMAGE_OPTION_PNG_FILTER))
        png_set_filter( png_ptr, PNG_FILTER_TYPE_BASE, image->GetOptionInt(wxIMAGE_OPTION_PNG_FILTER) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL))
        png_set_compression_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL))
        png_set_compression_mem_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY))
        png_set_compression_strategy( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE))
        png_set_compression_buffer_size( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE) );

    png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(),
                  iBitDepth, iPngColorType,
                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                  PNG_FILTER_TYPE_BASE);

    int iElements;
    png_color_8 sig_bit;

    if ( iPngColorType & PNG_COLOR_MASK_COLOR )
    {
        sig_bit.red =
            sig_bit.green =
                sig_bit.blue = (png_byte)iBitDepth;
        iElements = 3;
    }
    else // grey
    {
        sig_bit.gray = (png_byte)iBitDepth;
        iElements = 1;
    }

    if ( iPngColorType & PNG_COLOR_MASK_ALPHA )
    {
        sig_bit.alpha = (png_byte)iBitDepth;
        iElements++;
    }

    if ( iBitDepth == 16 )
        iElements *= 2;

    // save the image resolution if we have it
    int resX, resY;
    switch ( GetResolutionFromOptions(*image, &resX, &resY) )
    {
    case wxIMAGE_RESOLUTION_INCHES:
    {
        const double INCHES_IN_METER = 10000.0 / 254;
        resX = int(resX * INCHES_IN_METER);
        resY = int(resY * INCHES_IN_METER);
    }
    break;

    case wxIMAGE_RESOLUTION_CM:
        resX *= 100;
        resY *= 100;
        break;

    case wxIMAGE_RESOLUTION_NONE:
        break;

    default:
        wxFAIL_MSG( wxT("unsupported image resolution units") );
    }

    if ( resX && resY )
        png_set_pHYs( png_ptr, info_ptr, resX, resY, PNG_RESOLUTION_METER );

    png_set_sBIT( png_ptr, info_ptr, &sig_bit );
    png_write_info( png_ptr, info_ptr );
    png_set_shift( png_ptr, &sig_bit );
    png_set_packing( png_ptr );

    unsigned char *
    data = (unsigned char *)malloc( image->GetWidth() * iElements );
    if ( !data )
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        return false;
    }

    unsigned char *
    pAlpha = (unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL);
    int iHeight = image->GetHeight();
    int iWidth = image->GetWidth();

    unsigned char uchMaskRed = 0, uchMaskGreen = 0, uchMaskBlue = 0;

    if ( bHasMask )
    {
        uchMaskRed = image->GetMaskRed();
        uchMaskGreen = image->GetMaskGreen();
        uchMaskBlue = image->GetMaskBlue();
    }

    unsigned char *pColors = image->GetData();

    for (int y = 0; y != iHeight; ++y)
    {
        unsigned char *pData = data;
        for (int x = 0; x != iWidth; x++)
        {
            unsigned char uchRed = *pColors++;
            unsigned char uchGreen = *pColors++;
            unsigned char uchBlue = *pColors++;

            switch ( iColorType )
            {
            default:
                wxFAIL_MSG( wxT("unknown wxPNG_TYPE_XXX") );
            // fall through

            case wxPNG_TYPE_COLOUR:
                *pData++ = uchRed;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                *pData++ = uchGreen;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                *pData++ = uchBlue;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                break;

            case wxPNG_TYPE_GREY:
            {
                // where do these coefficients come from? maybe we
                // should have image options for them as well?
                unsigned uiColor =
                    (unsigned) (76.544*(unsigned)uchRed +
                                150.272*(unsigned)uchGreen +
                                36.864*(unsigned)uchBlue);

                *pData++ = (unsigned char)((uiColor >> 8) & 0xFF);
                if ( iBitDepth == 16 )
                    *pData++ = (unsigned char)(uiColor & 0xFF);
            }
            break;

            case wxPNG_TYPE_GREY_RED:
                *pData++ = uchRed;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
                break;
            }

            if ( bUseAlpha )
            {
                unsigned char uchAlpha = 255;
                if ( bHasAlpha )
                    uchAlpha = *pAlpha++;

                if ( bHasMask )
                {
                    if ( (uchRed == uchMaskRed)
                            && (uchGreen == uchMaskGreen)
                            && (uchBlue == uchMaskBlue) )
                        uchAlpha = 0;
                }

                *pData++ = uchAlpha;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
            }
        }

        png_bytep row_ptr = data;
        png_write_rows( png_ptr, &row_ptr, 1 );
    }

    free(data);
    png_write_end( png_ptr, info_ptr );
    png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );

    return true;
}
Exemplo n.º 7
0
static bool
sp_png_write_rgba_striped(SPDocument *doc,
                          gchar const *filename, unsigned long int width, unsigned long int height, double xdpi, double ydpi,
                          int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data),
                          void *data)
{
    struct SPEBP *ebp = (struct SPEBP *) data;
    FILE *fp;
    png_structp png_ptr;
    png_infop info_ptr;
    png_color_8 sig_bit;
    png_uint_32 r;

    g_return_val_if_fail(filename != NULL, false);
    g_return_val_if_fail(data != NULL, false);

    /* open the file */

    Inkscape::IO::dump_fopen_call(filename, "M");
    fp = Inkscape::IO::fopen_utf8name(filename, "wb");
    g_return_val_if_fail(fp != NULL, false);

    /* Create and initialize the png_struct with the desired error handler
     * functions.  If you want to use the default stderr and longjump method,
     * you can supply NULL for the last three parameters.  We also check that
     * the library version is compatible with the one used at compile time,
     * in case we are using dynamically linked libraries.  REQUIRED.
     */
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    if (png_ptr == NULL) {
        fclose(fp);
        return false;
    }

    /* Allocate/initialize the image information data.  REQUIRED */
    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        fclose(fp);
        png_destroy_write_struct(&png_ptr, NULL);
        return false;
    }

    /* Set error handling.  REQUIRED if you aren't supplying your own
     * error hadnling functions in the png_create_write_struct() call.
     */
    if (setjmp(png_jmpbuf(png_ptr))) {
        // If we get here, we had a problem reading the file
        fclose(fp);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return false;
    }

    /* set up the output control if you are using standard C streams */
    png_init_io(png_ptr, fp);

    /* Set the image information here.  Width and height are up to 2^31,
     * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
     * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
     * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
     * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
     * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
     * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
     */
    png_set_IHDR(png_ptr, info_ptr,
                 width,
                 height,
                 8, /* bit_depth */
                 PNG_COLOR_TYPE_RGB_ALPHA,
                 PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_BASE,
                 PNG_FILTER_TYPE_BASE);

    /* otherwise, if we are dealing with a color image then */
    sig_bit.red = 8;
    sig_bit.green = 8;
    sig_bit.blue = 8;
    /* if the image has an alpha channel then */
    sig_bit.alpha = 8;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

    PngTextList textList;

    textList.add("Software", "www.inkscape.org"); // Made by Inkscape comment
    {
        const gchar* pngToDc[] = {"Title", "title",
                               "Author", "creator",
                               "Description", "description",
                               //"Copyright", "",
                               "Creation Time", "date",
                               //"Disclaimer", "",
                               //"Warning", "",
                               "Source", "source"
                               //"Comment", ""
        };
        for (size_t i = 0; i < G_N_ELEMENTS(pngToDc); i += 2) {
            struct rdf_work_entity_t * entity = rdf_find_entity ( pngToDc[i + 1] );
            if (entity) {
                gchar const* data = rdf_get_work_entity(doc, entity);
                if (data && *data) {
                    textList.add(pngToDc[i], data);
                }
            } else {
                g_warning("Unable to find entity [%s]", pngToDc[i + 1]);
            }
        }


        struct rdf_license_t *license =  rdf_get_license(doc);
        if (license) {
            if (license->name && license->uri) {
                gchar* tmp = g_strdup_printf("%s %s", license->name, license->uri);
                textList.add("Copyright", tmp);
                g_free(tmp);
            } else if (license->name) {
                textList.add("Copyright", license->name);
            } else if (license->uri) {
                textList.add("Copyright", license->uri);
            }
        }
    }
    if (textList.getCount() > 0) {
        png_set_text(png_ptr, info_ptr, textList.getPtext(), textList.getCount());
    }

    /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
    /* note that if sRGB is present the cHRM chunk must be ignored
     * on read and must be written in accordance with the sRGB profile */
    png_set_pHYs(png_ptr, info_ptr, unsigned(xdpi / 0.0254 + 0.5), unsigned(ydpi / 0.0254 + 0.5), PNG_RESOLUTION_METER);

    /* Write the file header information.  REQUIRED */
    png_write_info(png_ptr, info_ptr);

    /* Once we write out the header, the compression type on the text
     * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
     * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
     * at the end.
     */

    /* set up the transformations you want.  Note that these are
     * all optional.  Only call them if you want them.
     */

    /* --- CUT --- */

    /* The easiest way to write the image (you may have a different memory
     * layout, however, so choose what fits your needs best).  You need to
     * use the first method if you aren't handling interlacing yourself.
     */

    png_bytep* row_pointers = new png_bytep[ebp->sheight];

    r = 0;
    while (r < static_cast<png_uint_32>(height)) {
        void *to_free;
        int n = get_rows((unsigned char const **) row_pointers, &to_free, r, height-r, data);
        if (!n) break;
        png_write_rows(png_ptr, row_pointers, n);
        g_free(to_free);
        r += n;
    }

    delete[] row_pointers;

    /* You can write optional chunks like tEXt, zTXt, and tIME at the end
     * as well.
     */

    /* It is REQUIRED to call this to finish writing the rest of the file */
    png_write_end(png_ptr, info_ptr);

    /* if you allocated any text comments, free them here */

    /* clean up after the write, and free any memory allocated */
    png_destroy_write_struct(&png_ptr, &info_ptr);

    /* close the file */
    fclose(fp);

    /* that's it */
    return true;
}
Exemplo n.º 8
0
RADRT_API bool RADRT_CALL Encode(const Image &in, const Mipmap &mip, bool interlaced, void *&outData, AddrSize &outSize)
{
	RAD_ASSERT(in.format == Format_A8 || in.format == Format_RGB888 || in.format == Format_RGBA8888);

	if (in.format != Format_A8 &&
		in.format != Format_RGB888 &&
		in.format != Format_RGBA8888) return false;

	png_structp png;
	png_infop   info;

	png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, 0, PNGErrorHandler, PNGWarningHandler, 0,
		PNGMalloc, PNGFree);

	if (!png) return false;

	info = png_create_info_struct(png);

	if (!info)
	{
		png_destroy_write_struct(&png, 0);
		return false;
	}

	stream::DynamicMemOutputBuffer ob(ZImageCodec);
	stream::OutputStream os(ob);

	png_set_write_fn(png, &os, PNGWrite, PNGFlush);
	png_set_IHDR(png, info, mip.width, mip.height, 8,
		(in.format == Format_A8) ? PNG_COLOR_TYPE_GRAY :
		(in.format == Format_RGB888) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
		interlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	png_color_8 sig;
	memset(&sig, 0, sizeof(sig));
	
	if (in.format == Format_A8)
	{
		sig.gray = 8;
	}
	else
	{
		sig.red = 8;
		sig.green = 8;
		sig.blue = 8;
		sig.alpha = (in.format == Format_RGBA8888) ? 8 : 0;
	}

	png_set_sBIT(png, info, &sig);

	try
	{
		png_write_info(png, info);
	}
	catch (PNGException&)
	{
		png_destroy_write_struct(&png, &info);
		return false;
	}

	png_set_shift(png, &sig);

	int passes = 1;

	if (interlaced)
	{
		passes = png_set_interlace_handling(png);
	}

	for (int pass = 0; pass < passes; ++pass)
	{
		png_bytep src = (png_bytep)mip.data;

		for (int y = 0; y < mip.height; ++y)
		{
			png_write_rows(png, (png_bytepp)&src, 1);
			src += mip.stride;
		}
	}

	png_write_end(png, info);
	png_destroy_write_struct(&png, &info);

	outData = ob.OutputBuffer().Ptr();
	outSize = ob.OutputBuffer().Size();
	ob.OutputBuffer().Set(0, 0); // don't let the output buffer release the memory.

	return true;

}
Exemplo n.º 9
0
bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, const QString &description,
                                 int off_x_in, int off_y_in)
{
    QPoint offset = image.offset();
    int off_x = off_x_in + offset.x();
    int off_y = off_y_in + offset.y();

    png_structp png_ptr;
    png_infop info_ptr;

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0);
    if (!png_ptr) {
        return false;
    }

    png_set_error_fn(png_ptr, 0, 0, qt_png_warning);

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_write_struct(&png_ptr, 0);
        return false;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return false;
    }

    int quality = quality_in;
    if (quality >= 0) {
        if (quality > 9) {
            qWarning("PNG: Quality %d out of range", quality);
            quality = 9;
        }
        png_set_compression_level(png_ptr, quality);
    }

    png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn);


    int color_type = 0;
    if (image.colorCount()) {
        if (image.isGrayscale())
            color_type = PNG_COLOR_TYPE_GRAY;
        else
            color_type = PNG_COLOR_TYPE_PALETTE;
    }
    else if (image.format() == QImage::Format_Grayscale8)
        color_type = PNG_COLOR_TYPE_GRAY;
    else if (image.hasAlphaChannel())
        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
    else
        color_type = PNG_COLOR_TYPE_RGB;

    png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(),
                 image.depth() == 1 ? 1 : 8, // per channel
                 color_type, 0, 0, 0);       // sets #channels

    if (gamma != 0.0) {
        png_set_gAMA(png_ptr, info_ptr, 1.0/gamma);
    }

    if (image.format() == QImage::Format_MonoLSB)
       png_set_packswap(png_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        // Paletted
        int num_palette = qMin(256, image.colorCount());
        png_color palette[256];
        png_byte trans[256];
        int num_trans = 0;
        for (int i=0; i<num_palette; i++) {
            QRgb rgba=image.color(i);
            palette[i].red = qRed(rgba);
            palette[i].green = qGreen(rgba);
            palette[i].blue = qBlue(rgba);
            trans[i] = qAlpha(rgba);
            if (trans[i] < 255) {
                num_trans = i+1;
            }
        }
        png_set_PLTE(png_ptr, info_ptr, palette, num_palette);

        if (num_trans) {
            png_set_tRNS(png_ptr, info_ptr, trans, num_trans, 0);
        }
    }

    // Swap ARGB to RGBA (normal PNG format) before saving on
    // BigEndian machines
    if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
        png_set_swap_alpha(png_ptr);
    }

    // Qt==ARGB==Big(ARGB)==Little(BGRA). But RGB888 is RGB regardless
    if (QSysInfo::ByteOrder == QSysInfo::LittleEndian
        && image.format() != QImage::Format_RGB888) {
        png_set_bgr(png_ptr);
    }

    if (off_x || off_y) {
        png_set_oFFs(png_ptr, info_ptr, off_x, off_y, PNG_OFFSET_PIXEL);
    }

    if (frames_written > 0)
        png_set_sig_bytes(png_ptr, 8);

    if (image.dotsPerMeterX() > 0 || image.dotsPerMeterY() > 0) {
        png_set_pHYs(png_ptr, info_ptr,
                image.dotsPerMeterX(), image.dotsPerMeterY(),
                PNG_RESOLUTION_METER);
    }

    set_text(image, png_ptr, info_ptr, description);

    png_write_info(png_ptr, info_ptr);

    if (image.depth() != 1)
        png_set_packing(png_ptr);

    if (color_type == PNG_COLOR_TYPE_RGB && image.format() != QImage::Format_RGB888)
        png_set_filler(png_ptr, 0,
            QSysInfo::ByteOrder == QSysInfo::BigEndian ?
                PNG_FILLER_BEFORE : PNG_FILLER_AFTER);

    if (looping >= 0 && frames_written == 0) {
        uchar data[13] = "NETSCAPE2.0";
        //                0123456789aBC
        data[0xB] = looping%0x100;
        data[0xC] = looping/0x100;
        png_write_chunk(png_ptr, const_cast<png_bytep>((const png_byte *)"gIFx"), data, 13);
    }
    if (ms_delay >= 0 || disposal!=Unspecified) {
        uchar data[4];
        data[0] = disposal;
        data[1] = 0;
        data[2] = (ms_delay/10)/0x100; // hundredths
        data[3] = (ms_delay/10)%0x100;
        png_write_chunk(png_ptr, const_cast<png_bytep>((const png_byte *)"gIFg"), data, 4);
    }

    int height = image.height();
    int width = image.width();
    switch (image.format()) {
    case QImage::Format_Mono:
    case QImage::Format_MonoLSB:
    case QImage::Format_Indexed8:
    case QImage::Format_Grayscale8:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32:
    case QImage::Format_RGB888:
        {
            png_bytep* row_pointers = new png_bytep[height];
            for (int y=0; y<height; y++)
                row_pointers[y] = const_cast<png_bytep>(image.constScanLine(y));
            png_write_image(png_ptr, row_pointers);
            delete [] row_pointers;
        }
        break;
    default:
        {
            QImage::Format fmt = image.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32;
            QImage row;
            png_bytep row_pointers[1];
            for (int y=0; y<height; y++) {
                row = image.copy(0, y, width, 1).convertToFormat(fmt);
                row_pointers[0] = const_cast<png_bytep>(row.constScanLine(0));
                png_write_rows(png_ptr, row_pointers, 1);
            }
        }
        break;
    }

    png_write_end(png_ptr, info_ptr);
    frames_written++;

    png_destroy_write_struct(&png_ptr, &info_ptr);

    return true;
}
Exemplo n.º 10
0
    void image::write_png(std::string filename)
    {
#ifdef HAVE_LIBPNG
        INFO("Writing PNG file: " << filename);
        //open file
        FILE *fp = fopen(filename.c_str(), "wb");
        if (!fp)
            throw image_file_exception("image::write_png - could not open file: " + filename);
        //create structures
        png_structp png_ptr = png_create_write_struct ( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
        if(!png_ptr)
            throw image_write_exception("image::write_png - Couldnt create PNG write structure");
        png_infop info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
        {
            png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
            throw image_write_exception("image::write_png - Couldnt create PNG info structure");
        }
        //handle errors
        if(setjmp(png_jmpbuf(png_ptr)))
        {
            png_destroy_write_struct(&png_ptr, &info_ptr);
            fclose(fp);
            throw image_read_exception("image::load_png - PNG error");
        }
        //FIXME - should we have a write row function call back?
        //set the io
        png_init_io(png_ptr, fp);
        //set up the header info
        png_set_IHDR(png_ptr, info_ptr, offscreen_surface->rect().width(), offscreen_surface->rect().height(), 
                8/*bit depth*/, PNG_COLOR_TYPE_RGB_ALPHA,  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                PNG_FILTER_TYPE_BASE);
        //set color palette
        png_colorp palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));
        png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
        //write header information
        png_write_info(png_ptr, info_ptr);
        //write image
        unsigned int y,x;
        unsigned int height = offscreen_surface->rect().height();
        unsigned int width = offscreen_surface->rect().width();
        png_byte *img_row = new png_byte[width*4];
        png_bytep row_pointers[1];
        row_pointers[0] = &img_row[0];
        for (y = 0; y < height; y++)
        {
            for (x = 0; x < width; x++)
            {
                color pix = offscreen_surface->read_pixel(x, y);
                pix = offscreen_surface->rgba_color(pix);
                //printf("%x ",pix);
                img_row[x*4] =  (pix & 0xFF000000) >> 24; //red
                img_row[x*4+1] = (pix & 0x00FF0000) >> 16;//green
                img_row[x*4+2] = (pix & 0x0000FF00) >> 8;//blue
                img_row[x*4+3] = 255 - (pix && 0x000000FF);//alpha
            }
            png_write_rows(png_ptr, &row_pointers[0], 1);
        }
        //write end
        png_write_end(png_ptr, info_ptr);
        //free the pallate
        png_free(png_ptr, palette);
        palette=NULL;
        delete(img_row);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        fclose(fp);
#else
        throw image_write_exception("image::write_png() No support for writting PNG files compiled in!");
#endif
    }
static gsize
photos_operation_png_guess_sizes_count (GeglBuffer *buffer,
                                        gint compression,
                                        gint bitdepth,
                                        gboolean background,
                                        gdouble zoom,
                                        gint src_x,
                                        gint src_y,
                                        gint width,
                                        gint height)
{
  gint bpp;
  gint i;
  gint png_color_type;
  gchar format_string[16];
  const Babl *format;
  const Babl *format_buffer;
  gsize ret_val = 0;
  gsize size;
  guchar *pixels = NULL;
  png_infop info_ptr = NULL;
  png_structp png_ptr = NULL;

  format_buffer = gegl_buffer_get_format (buffer);
  if (babl_format_has_alpha (format_buffer))
    {
      if (babl_format_get_n_components (format_buffer) != 2)
        {
          png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
          strcpy (format_string, "R'G'B'A ");
        }
      else
        {
          png_color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
          strcpy (format_string, "Y'A ");
        }
    }
  else
    {
      if (babl_format_get_n_components (format_buffer) != 1)
        {
          png_color_type = PNG_COLOR_TYPE_RGB;
          strcpy (format_string, "R'G'B' ");
        }
      else
        {
          png_color_type = PNG_COLOR_TYPE_GRAY;
          strcpy (format_string, "Y' ");
        }
    }

  if (bitdepth == 16)
    strcat (format_string, "u16");
  else
    strcat (format_string, "u8");

  png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL)
    goto out;

  info_ptr = png_create_info_struct (png_ptr);
  if (info_ptr == NULL)
    goto out;

  if (setjmp (png_jmpbuf (png_ptr)))
    {
      ret_val = 0;
      goto out;
    }

  if (compression >= 0)
    png_set_compression_level (png_ptr, compression);

  photos_png_init_count (png_ptr, &size);

  png_set_IHDR (png_ptr,
                info_ptr,
                width,
                height,
                bitdepth,
                png_color_type,
                PNG_INTERLACE_NONE,
                PNG_COMPRESSION_TYPE_BASE,
                PNG_FILTER_TYPE_DEFAULT);

  if (background)
    {
      png_color_16 white;

      if (png_color_type == PNG_COLOR_TYPE_RGB || png_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        {
          white.red = 0xff;
          white.blue = 0xff;
          white.green = 0xff;
        }
      else
        {
          white.gray = 0xff;
        }

      png_set_bKGD (png_ptr, info_ptr, &white);
    }

  png_write_info (png_ptr, info_ptr);

#if BYTE_ORDER == LITTLE_ENDIAN
  if (bitdepth > 8)
    png_set_swap (png_ptr);
#endif

  format = babl_format (format_string);
  bpp = babl_format_get_bytes_per_pixel (format);
  pixels = g_malloc0 (width * bpp);

  for (i = 0; i < height; i++)
    {
      GeglRectangle rect;

      rect.x = src_x;
      rect.y = src_y + i;
      rect.width = width;
      rect.height = 1;
      gegl_buffer_get (buffer, &rect, zoom, format, pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
      png_write_rows (png_ptr, &pixels, 1);
    }

  png_write_end (png_ptr, info_ptr);
  ret_val = size;

 out:
  g_free (pixels);
  png_destroy_write_struct (&png_ptr, &info_ptr);
  return ret_val;
}
Exemplo n.º 12
0
static void
do_png_write(struct png_writer * writer, void * buffer, int w, int h, int type)
{
	TRACE(SYSTEM, "write a %dx%d image into a png stream\n", w, h);
	
	png_structp write_ptr;
	png_infop info_ptr;
	png_text texts[1];

	/* if png handler is passed from writer, we needn't
	 * create them again, however, we also needn't chain
	 * them into cleanup */
	if (writer->write_ptr == NULL) {
		/* if we create a writer_ptr, then we can only use
		 * a new info_ptr */
		writer->info_ptr = NULL;
		write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
				NULL, png_error, png_warning);
		writer->write_ptr = write_ptr;
	} else {
		write_ptr = writer->write_ptr;
		writer->write_ptr_save = write_ptr;
	}

	if (write_ptr == NULL) {
		ERROR(SYSTEM, "libpng: create write_ptr error\n");
		THROW(EXCEPTION_CONTINUE, "libpng error");
	}

	/* We have to use setjmp here, because if we 
	 * neglect to set up our own setjmp(), libpng will
	 * call abort(). */
	if (setjmp(png_jmpbuf(write_ptr))) {
		ERROR(SYSTEM, "libpng: write error\n");
		THROW(EXCEPTION_CONTINUE, "libpng: write error");
	}
	
	if (writer->info_ptr == NULL) {
		info_ptr = png_create_info_struct(write_ptr);
		writer->info_ptr = info_ptr;
	} else {
		info_ptr = writer->info_ptr;
	}

	/* use our custom writer  */
	png_set_write_fn(write_ptr, writer->io_ptr,
			writer->write_fn, writer->flush_fn);

	/* write routine */
	png_set_IHDR(write_ptr, info_ptr, w, h, 8, type,
			PNG_INTERLACE_NONE,
			PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	texts[0].key = "Software";
	texts[0].text = "yaavg";
	texts[0].compression = PNG_TEXT_COMPRESSION_NONE;

	png_set_text(write_ptr, info_ptr, texts, 1);
	png_write_info(write_ptr, info_ptr);

	int n, row_size;
	switch (type) {
		case PNG_COLOR_TYPE_RGB:
			row_size = 3 * w;
			break;
		case PNG_COLOR_TYPE_RGBA:
			row_size = 4 * w;
			break;
		default:
			FATAL(SYSTEM, "png write format error: %d\n", type);
			THROW(FATAL, "png write format error");
	}

	VERBOSE(SYSTEM, "png stream write start\n");
	for (n = h - 1; n >= 0; n--) {
		uint8_t * prow = buffer + n * row_size;
		png_write_rows(write_ptr, &prow, 1);
	}
	png_write_end(write_ptr, info_ptr);
	cleanup_writer(writer);
}
Exemplo n.º 13
0
BOOL CScreenCapture::PngWriteRow(LPBYTE pRow)
{
  png_bytep rows[1] = {pRow};
  png_write_rows(m_png_ptr, (png_bytepp)&rows, 1);
  return TRUE;
}
Exemplo n.º 14
0
CONVERT_IMAGERESULT
write_PNG_file (CONVERT_IMG_ARRAY p_rowarray,CONVERT_IMGCONTEXT *output,CONVERT_IMG_INFO *p_imageinfo,CONVERT_CALLBACKS p_callbacks)
{
    int16 colors,i;
    int16 maxcolor=MAXCOLORS-1;
    colorhist_vector chv;
    pixval maxval=MAXCOLORS-1;
    colorhash_table cht=NULL;
    png_structp write_ptr;
    png_infop info_ptr;/* important!*/
    png_bytep rowbuf=NULL;

    int32 y;
    int num_pass, pass;
    CONVERT_IMAGERESULT result=CONV_OK;

    if (!output||!p_imageinfo)
    {
        return CONVERR_INVALIDPARAMS;
    }

    /* Figure out the colormap. */
    chv = ppm_computecolorhist( (pixel **)p_rowarray, p_imageinfo->m_image_width, p_imageinfo->m_image_height, MAXCOLORS, &colors );
    if ( chv == (colorhist_vector) 0 )/*more than 256 colors*/
    {
        result=quantize_colors(p_rowarray,p_imageinfo->m_image_width,p_imageinfo->m_image_height,&maxcolor,&colors,&chv);
        if (result!=CONV_OK)
            return result;
        if ( chv == (colorhist_vector) 0 )
            return CONVERR_INVALIDCOLORMAP;
    }

    /* And make a hash table for fast lookup. */
    cht = ppm_colorhisttocolorhash( chv, colors );
    if (!cht)
    {
        XP_ASSERT(FALSE);
        return CONVERR_OUTOFMEMORY;
    }

    write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)NULL,
      (png_error_ptr)NULL, (png_error_ptr)NULL);

    info_ptr=png_create_info_struct(write_ptr);
    info_ptr->width=p_imageinfo->m_image_width;
    info_ptr->height=p_imageinfo->m_image_height;
    info_ptr->bit_depth=8;
    info_ptr->color_type=3; /*3= indexed color*/
    info_ptr->compression_type=0; /* only option available*/
    info_ptr->filter_type=0; /* only valid value for adaptive filtering*/
    info_ptr->interlace_type=0;/*0= no interlacing*/
    info_ptr->num_palette=colors; /*from quantize_colors*/
    info_ptr->palette=XP_ALLOC(3*colors);/*remember to free this*/
    info_ptr->valid|=PNG_INFO_PLTE;
    for (i=0;i<colors;i++)
    {
	    info_ptr->palette[i].red = PPM_GETR( chv[i].color );
	    info_ptr->palette[i].green = PPM_GETG( chv[i].color );
	    info_ptr->palette[i].blue = PPM_GETB( chv[i].color );
    }
    ppm_freecolorhist( chv );
    if (!info_ptr->palette)
    {
      png_destroy_write_struct(&write_ptr, &info_ptr);
    }

    /*transparancy???*/

    if (setjmp(write_ptr->jmpbuf))
    {
      png_destroy_write_struct(&write_ptr, &info_ptr);
      return CONVERR_BADWRITE;
    }

    png_init_io(write_ptr, output->m_stream.m_file);

    png_write_info(write_ptr, info_ptr);

    num_pass = 1;
    /*we need to look up each RGB  and change it to the index of the color table*/
    rowbuf=(png_bytep) XP_ALLOC(p_imageinfo->m_image_width);
    if (!rowbuf)
    {
      png_destroy_write_struct(&write_ptr, &info_ptr);
      return CONVERR_BADWRITE;
    }

    for (pass = 0; pass < num_pass; pass++)
    {
      for (y = 0; y < p_imageinfo->m_image_height; y++)
      {
         fill_png_row(p_rowarray[y],rowbuf,p_imageinfo->m_image_width,cht);
         png_write_rows(write_ptr, &rowbuf, 1);
      }
    }
    XP_FREE(rowbuf);
    png_write_end(write_ptr, NULL);
    XP_FREE(info_ptr->palette);
    png_destroy_write_struct(&write_ptr, &info_ptr);
    fclose(output->m_stream.m_file);
    return CONV_OK;
}
Exemplo n.º 15
0
int main( int argc, char *argv[] ) {
	int f, rowbytes;
	char buf[256];
	static FILE *fpout;  /* "static" prevents setjmp corruption */
	png_structp write_ptr;
	png_infop write_info_ptr, end_info_ptr;
	png_bytep row_buf, here;
	png_uint_32 y;
	png_textp text_ptr, new_text_ptr;
	int num_text;

	int interlace_type, compression_type, filter_type, bit_depth, color_type;
	int it, ct, ft, bd, clrt;
	png_uint_32 width, height, w, h;

	int duration;

	if( argc < 4 ) {
		printf( "makeanim v0.2\nusage: makeanim <duration in milliseconds> <input files ...> <output file>\n" );
		printf( "example: makeanim 1500 a00.png a01.png a02.png a03.png a04.png a.anim\n" );
		return 1;
		}

	duration = atoi( argv[1] );
	if( duration < 1 ) {
		printf( "duration is incorrect\n" );
		return 1;
		}

	numfiles = argc - 3;
	input = (struct inputstruct *)malloc( sizeof( struct inputstruct ) * numfiles );
	if( !input ) return 1;

	for( f = 0; f < numfiles; f++ ) {
		input[f].name = argv[f + 2];
		printf( "opening file %d, \"%s\"\n", f, input[f].name );

		/* open the file handle */
		input[f].file = fopen( input[f].name, "rb" );
		if( input[f].file == NULL ) {
			printf( "fopen() failed\n" );
			return 1;
			}

		/* check if it's PNG */
		if( fread( buf, 1, 8, input[f].file ) != 8 ) {
			printf( "fread() failed for file \"%s\"\n", input[f].name );
			return 1;
			}
		if( png_sig_cmp( buf, (png_size_t)0, 8 ) ) {
			printf( "not a PNG file\n" );
			return 1;
			}
		fseek( input[f].file, 0, SEEK_SET );

		/* allocate read structure */
		input[f].read_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL );
		if( input[f].read_ptr == NULL ) {
			printf( "png_create_read_struct() failed\n" );
			return 1;
			}
		
		/* allocate read info structure */
		input[f].read_info_ptr = png_create_info_struct( input[f].read_ptr );
		if( input[f].read_info_ptr == NULL ) {
			printf( "png_create_info_struct() failed\n" );
			return 1;
			}


		/* set error handler code */
		if( setjmp( input[f].read_ptr->jmpbuf ) ) {
			printf( "libpng read error\n" );
			return 1;
			}

		/* initialize stream */
		png_init_io( input[f].read_ptr, input[f].file );
		png_set_read_status_fn( input[f].read_ptr, NULL );

		/* read png info struct */
		png_read_info( input[f].read_ptr, input[f].read_info_ptr );

		/* get the info */
		if( !png_get_IHDR( input[f].read_ptr, input[f].read_info_ptr, &w, &h, &bd, &clrt, &it, &ct, &ft ) ) {
			printf( "png_get_IHDR() failed\n" );
			return 1;
			}

		/* save the info of the first frame */
		if( f == 0 ) {
			width = w;
			height = h;
			bit_depth = bd;
			color_type = clrt;
			interlace_type = it;
			compression_type = ct;
			filter_type = ft;
			}
		/* compare all other frames to first frame */
		else if( (w != width) ||
				(h != height) ||
				(bd != bit_depth) ||
				(clrt != color_type) ||
				(it != interlace_type) ||
				(ct != compression_type) ||
				(ft != filter_type) ) {
			if( w != width ) printf( "width is different\n" );
			if( h != height ) printf( "height  is different\n" );
			if( bd != bit_depth ) printf( "bit depth is different\n" );
			if( clrt != color_type ) printf( "color type is different\n" );
			if( it != interlace_type ) printf( "interlace type is different\n" );
			if( ct != compression_type ) printf( "compression type is different\n" );
			if( ft != filter_type ) printf( "filter type is different\n" );
			return 1;
			}
		}
	
	row_buf = (png_bytep)NULL;
	
	/* open output file */
	printf( "opening file \"%s\"\n", argv[numfiles + 2] );
	fpout = fopen( argv[numfiles + 2], "wb" );
	if( fpout == NULL ) {
		printf( "fopen() failed\n" );
		return 1;
		}

	/* allocate write structure */
	write_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL );

	/* allocate info structures */
	write_info_ptr = png_create_info_struct( write_ptr );
	end_info_ptr = png_create_info_struct( write_ptr );

	/* error handling */
	if( setjmp( write_ptr->jmpbuf ) ) {
		printf( "libpng write error\n" );
		return 1;
		}

	/* initialize output stream */
	png_init_io( write_ptr, fpout );
	png_set_write_status_fn( write_ptr, NULL );

	/* set info */
	png_set_IHDR( write_ptr, write_info_ptr, width * numfiles, height, bit_depth, color_type, PNG_INTERLACE_NONE, compression_type, filter_type);

	/* image characteristics */
	{
		png_color_16p background;
		double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
		double gamma;
		int intent;
		png_uint_16p hist;
		png_uint_32 offset_x, offset_y;
		int unit_type;
		png_charp purpose, units;
		png_charpp params;
		png_int_32 X0, X1;
		int type, nparams;
		png_uint_32 res_x, res_y;
		png_colorp palette;
		int num_palette;
		png_color_8p sig_bit;
		png_bytep trans;
		int num_trans;
		png_color_16p trans_values;

		/* background color */
		if( png_get_bKGD( input[0].read_ptr, input[0].read_info_ptr, &background ) ) {
			png_set_bKGD( write_ptr, write_info_ptr, background );
			}

		if( png_get_cHRM( input[0].read_ptr, input[0].read_info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y ) ) {
			png_set_cHRM( write_ptr, write_info_ptr, white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y );
			}

		/* gamma */
		if( png_get_gAMA( input[0].read_ptr, input[0].read_info_ptr, &gamma ) ) {
			png_set_gAMA( write_ptr, write_info_ptr, gamma );
			}

		/* rendering intent */
		if( png_get_sRGB( input[0].read_ptr, input[0].read_info_ptr, &intent ) ) {
			png_set_sRGB( write_ptr, write_info_ptr, intent );
			}

		/* Histogram */
		if( png_get_hIST( input[0].read_ptr, input[0].read_info_ptr, &hist ) ) {
			png_set_hIST( write_ptr, write_info_ptr, hist );
			}

		/* offsets */
		if( png_get_oFFs( input[0].read_ptr, input[0].read_info_ptr, &offset_x, &offset_y, &unit_type ) ) {
			png_set_oFFs( write_ptr, write_info_ptr, offset_x, offset_y, unit_type );
			}

		if( png_get_pCAL( input[0].read_ptr, input[0].read_info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, &params ) ) {
			png_set_pCAL( write_ptr, write_info_ptr, purpose, X0, X1, type, nparams, units, params );
			}

		/* pixel density */
		if( png_get_pHYs( input[0].read_ptr, input[0].read_info_ptr, &res_x, &res_y, &unit_type ) ) {
			png_set_pHYs( write_ptr, write_info_ptr, res_x, res_y, unit_type );
			}

		/* text chunks */
/*		if( png_get_text( input[0].read_ptr, input[0].read_info_ptr, &text_ptr, &num_text ) > 0 ) {
			printf( "Handling %d tEXt/zTXt chunks\n", num_text );
			png_set_text( write_ptr, write_info_ptr, text_ptr, num_text );
			}
*/
		/* palette */
		if( png_get_PLTE( input[0].read_ptr, input[0].read_info_ptr, &palette, &num_palette ) ) {
			png_set_PLTE( write_ptr, write_info_ptr, palette, num_palette );
			}

		/* significant bits */
		if( png_get_sBIT( input[0].read_ptr, input[0].read_info_ptr, &sig_bit ) ) {
			png_set_sBIT( write_ptr, write_info_ptr, sig_bit );
			}

		/* transparency */
		if( png_get_tRNS( input[0].read_ptr, input[0].read_info_ptr, &trans, &num_trans, &trans_values ) ) {
			png_set_tRNS( write_ptr, write_info_ptr, trans, num_trans, trans_values );
			}
		}

	/* text chunks */
	num_text = 0;
	if( !png_get_text( input[0].read_ptr, input[0].read_info_ptr, &text_ptr, &num_text ) ) num_text = 0;
	new_text_ptr = (struct png_text_struct *)malloc( sizeof( struct png_text_struct ) * num_text + 1 );
	if( !new_text_ptr ) {
		printf( "malloc() failed\n" );
		return 1;
		}
	
	memcpy( new_text_ptr, text_ptr, sizeof( struct png_text_struct ) * num_text );

	snprintf( buf, 255, "SDL_anim %d %d %d", duration, width, numfiles );
	buf[255] = 0;
	new_text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
	new_text_ptr[num_text].key = "format";
	new_text_ptr[num_text].text = buf;
	new_text_ptr[num_text].text_length = strlen( buf );
	num_text++;
	png_set_text( write_ptr, write_info_ptr, new_text_ptr, num_text );

	/* write info */
	png_write_info( write_ptr, write_info_ptr );

	/* allocate buffer */
	rowbytes = png_get_rowbytes( input[0].read_ptr, input[0].read_info_ptr );
	row_buf = (png_bytep)png_malloc( write_ptr, rowbytes * numfiles );
	if( row_buf == NULL ) {
		printf( "png_malloc() failed\n" );
		return 1;
		}

	/* copy raw data */
	for( y = 0; y < height; y++ ) {
		/* grab a scanline from each file */
		here = row_buf;
		for( f = 0; f < numfiles; f++ ) {
			png_read_rows( input[f].read_ptr, (png_bytepp)&here, (png_bytepp)NULL, 1 );
			here += rowbytes;
			}
		/* write the long scanline */
		png_write_rows( write_ptr, (png_bytepp)&row_buf, 1 );
		}

	/* end io */
	for( f = 0; f < numfiles; f++ ) png_read_end( input[f].read_ptr, end_info_ptr );
	png_write_end( write_ptr, end_info_ptr );

	/* cleanup */
	png_free( write_ptr, row_buf );
	for( f = 0; f < numfiles; f++ ) {
		png_destroy_read_struct( &input[f].read_ptr, &input[f].read_info_ptr, &end_info_ptr);
		fclose( input[f].file );
		}
	png_destroy_write_struct( &write_ptr, &write_info_ptr );
	fclose( fpout );

	return 0;
	}
Exemplo n.º 16
0
static gint
export_png (GeglOperation       *operation,
            GeglBuffer          *input,
            const GeglRectangle *result,
            png_structp          png,
            png_infop            info,
            gint                 compression,
            gint                 bit_depth)
{
  gint           i, src_x, src_y;
  png_uint_32    width, height;
  guchar        *pixels;
  png_color_16   white;
  int            png_color_type;
  gchar          format_string[16];
  const Babl    *format;

  src_x = result->x;
  src_y = result->y;
  width = result->width;
  height = result->height;

  {
    const Babl *babl = gegl_buffer_get_format (input);

    if (bit_depth != 16)
      bit_depth = 8;

    if (babl_format_has_alpha (babl))
      if (babl_format_get_n_components (babl) != 2)
        {
          png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
          strcpy (format_string, "R'G'B'A ");
        }
      else
        {
          png_color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
          strcpy (format_string, "Y'A ");
        }
    else
      if (babl_format_get_n_components (babl) != 1)
        {
          png_color_type = PNG_COLOR_TYPE_RGB;
          strcpy (format_string, "R'G'B' ");
        }
      else
        {
          png_color_type = PNG_COLOR_TYPE_GRAY;
          strcpy (format_string, "Y' ");
        }
  }

  if (bit_depth == 16)
    strcat (format_string, "u16");
  else
    strcat (format_string, "u8");

  if (setjmp (png_jmpbuf (png)))
    return -1;

  png_set_compression_level (png, compression);

  png_set_IHDR (png, info,
     width, height, bit_depth, png_color_type,
     PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT);

  if (png_color_type == PNG_COLOR_TYPE_RGB || png_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    {
      white.red = 0xff;
      white.blue = 0xff;
      white.green = 0xff;
      png_set_sRGB_gAMA_and_cHRM (png, info, PNG_sRGB_INTENT_RELATIVE);
    }
  else
    white.gray = 0xff;
  png_set_bKGD (png, info, &white);

  png_write_info (png, info);

#if BYTE_ORDER == LITTLE_ENDIAN
  if (bit_depth > 8)
    png_set_swap (png);
#endif

  format = babl_format (format_string);
  pixels = g_malloc0 (width * babl_format_get_bytes_per_pixel (format));

  for (i=0; i< height; i++)
    {
      GeglRectangle rect;

      rect.x = src_x;
      rect.y = src_y+i;
      rect.width = width;
      rect.height = 1;

      gegl_buffer_get (input, &rect, 1.0, babl_format (format_string), pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

      png_write_rows (png, &pixels, 1);
    }

  png_write_end (png, info);

  g_free (pixels);

  return 0;
}
Exemplo n.º 17
0
bool
Image::writePNG(std::ostream &os, bool strip_alpha) const
{
    png_structp png_ptr;
    png_infop info_ptr;
    int color_type;

    switch (channels) {
    case 4:
        color_type = strip_alpha ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
        break;
    case 3:
        color_type = PNG_COLOR_TYPE_RGB;
        break;
    case 2:
        color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
        break;
    case 1:
        color_type = PNG_COLOR_TYPE_GRAY;
        break;
    default:
        assert(0);
        goto no_png;
    }

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        goto no_png;

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_write_struct(&png_ptr,  NULL);
        goto no_png;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        goto no_png;
    }

    png_set_write_fn(png_ptr, &os, pngWriteCallback, NULL);

    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
                 color_type, PNG_INTERLACE_NONE,
                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

    png_set_compression_level(png_ptr, png_compression_level);

    png_write_info(png_ptr, info_ptr);

    if (channels == 4 && strip_alpha) {
        png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
    }

    switch (channelType) {
    case TYPE_UNORM8:
        for (const unsigned char *row = start(); row != end(); row += stride()) {
            png_write_rows(png_ptr, (png_bytepp) &row, 1);
        }
        break;
    case TYPE_FLOAT:
        png_bytep rowUnorm8 = new png_byte[width * channels];
        for (const unsigned char *row = start(); row != end(); row += stride()) {
            const float *rowFloat = (const float *)row;
            for (unsigned x = 0, i = 0; x < width; ++x) {
                for (unsigned channel = 0; channel < channels; ++channel, ++i) {
                    float c = rowFloat[i];
                    bool srgb = channels >= 3 && channel < 3;
                    rowUnorm8[i] = srgb ? floatToSRGB(c) : floatToUnorm8(c);
                }
            }
            png_write_rows(png_ptr, (png_bytepp) &rowUnorm8, 1);
        }
        delete [] rowUnorm8;
        break;
    }

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);

    return true;

no_png:
    return false;
}
Exemplo n.º 18
0
UT_Error IE_ImpGraphic_BMP::Convert_BMP(UT_ByteBuf* pBB)
{
	/* Reset error handling for libpng */
	if (setjmp(png_jmpbuf(m_pPNG)))
	{
		png_destroy_write_struct(&m_pPNG, &m_pPNGInfo);
		return UT_ERROR;
	}
	png_write_info(m_pPNG,m_pPNGInfo);

	const UT_Byte*  row_data;
	UT_sint32 row;
	UT_uint32 position;
	UT_uint32 row_width = m_iWidth * m_iBitsPerPlane / 8;
	while ((row_width & 3) != 0) row_width++;
	UT_Byte* row_transformed_data = new UT_Byte[row_width];

	switch (m_iBitsPerPlane)
	{
	case 1:
	case 4:
	case 8:
	case 16:
		for (row=m_iHeight-1; row >= 0; row--)
		{
			/* Calculating the start of each row */
			position=m_iOffset + row*row_width;
			row_data = reinterpret_cast<const unsigned char *>(pBB->getPointer(position));
			png_write_rows(m_pPNG,const_cast<png_byte **>(reinterpret_cast<const png_byte **>(&row_data)),1);
		}	
		break;
	case 24:
	case 48:
		for (row=m_iHeight-1; row >= 0; row--)
		{
			/* Calculating the start of each row */
			position=m_iOffset + row*row_width;
			/* Transforming the b/r to r/b */
			for (UT_sint32 i=0, col=0; i < m_iWidth; i++,col+=3)
			{
				row_transformed_data[col+0] = (UT_Byte)*pBB->getPointer(position+col+2);
				row_transformed_data[col+1] = (UT_Byte)*pBB->getPointer(position+col+1);
				row_transformed_data[col+2] = (UT_Byte)*pBB->getPointer(position+col+0);
			}
			png_write_rows(m_pPNG,&row_transformed_data,1);
		}	
		break;
	case 32: 
	case 64:
		for (row=m_iHeight-1; row >= 0; row--)
		{
			/* Calculating the start of each row */
			position=m_iOffset + row*row_width;
			/* Transforming the b/r to r/b */
			for (UT_sint32 i=0, col=0; i < m_iWidth; i++,col+=4)
			{
				row_transformed_data[col+0] = (UT_Byte)*pBB->getPointer(position+col+2);
				row_transformed_data[col+1] = (UT_Byte)*pBB->getPointer(position+col+1);
				row_transformed_data[col+2] = (UT_Byte)*pBB->getPointer(position+col+0);
				row_transformed_data[col+3] = (UT_Byte)*pBB->getPointer(position+col+3);				
			}
			png_write_rows(m_pPNG,&row_transformed_data,1);
		}	
		break;			
	default:
		return UT_IE_BOGUSDOCUMENT;
		break;
	}
	delete [] row_transformed_data;

	png_write_end(m_pPNG,m_pPNGInfo);
	return UT_OK;
}
Exemplo n.º 19
0
cache Png_Create(int width, int height, int numpal, dPalette_t* pal,
				 int bits, cache data, int lump, int* size)
{
	int i = 0;
	int x = 0;
	int j = 0;
	cache image;
	cache out;
	cache* row_pointers;
	png_structp png_ptr;
	png_infop info_ptr;
	png_colorp palette;

	// setup png pointer
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	if(png_ptr == NULL)
	{
		WGen_Complain("Png_Create: Failed getting png_ptr");
		return NULL;
	}

	// setup info pointer
	info_ptr = png_create_info_struct(png_ptr);
	if(info_ptr == NULL)
	{
		png_destroy_write_struct(&png_ptr, NULL);
		WGen_Complain("Png_Create: Failed getting info_ptr");
		return NULL;
	}

	// what does this do again?
	if(setjmp(png_jmpbuf(png_ptr)))
	{
		png_destroy_write_struct(&png_ptr, &info_ptr);
		WGen_Complain("Png_Create: Failed on setjmp");
		return NULL;
	}

	// setup custom data writing procedure
	png_set_write_fn(png_ptr, NULL, Png_WriteData, NULL);

	// setup image
	png_set_IHDR(
		png_ptr,
		info_ptr,
		width,
		height,
		bits,
		PNG_COLOR_TYPE_PALETTE,
		PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_BASE,
		PNG_FILTER_TYPE_DEFAULT);

	// setup palette
	palette = (png_colorp)Mem_Alloc((16 * numpal) * png_sizeof(png_color));

	// copy dPalette_t data over to png_colorp
	for(x = 0, j = 0; x < numpal; x++)
	{
		for(i = 0; i < 16; i++)
		{
			palette[j].red = pal[j].r;
			palette[j].green = pal[j].g;
			palette[j].blue = pal[j].b;
			j++;
		}
	}

    i = 0;

	// add palette to png
	png_set_PLTE(png_ptr, info_ptr, palette, (16 * numpal));

    // set transparent index
    if(palette[0].red == 0 && palette[0].green == 0 && palette[0].blue == 0)
    {
        char tmp[9];

        strncpy(tmp, romWadFile.lump[lump].name, 8);
        tmp[0] -= (char)0x80;
        tmp[8] = 0;

        // Exempt these lumps
        if(strcmp(tmp, "FIRE") && /*strcmp(tmp, "USLEGAL") &&
            strcmp(tmp, "TITLE") &&*/ strcmp(tmp, "EVIL") &&
            /*strcmp(tmp, "IDCRED1") && strcmp(tmp, "WMSCRED1") &&*/
            strcmp(tmp, "SPACE") && strcmp(tmp, "CLOUD") &&
            strcmp(tmp, "FINAL"))
            png_set_tRNS(png_ptr, info_ptr, (png_bytep)&i, 1, NULL);
    }

	// add png info to data
	png_write_info(png_ptr, info_ptr);

	// add offset chunk if png is a sprite
	if(INSPRITELIST(lump))
	{
		for(i = 0; i < spriteExCount; i++)
		{
			if(exSpriteLump[i].lumpRef == lump)
			{
				int offs[2];

				offs[0] = WGen_Swap32(exSpriteLump[i].sprite.offsetx);
				offs[1] = WGen_Swap32(exSpriteLump[i].sprite.offsety);

				png_write_chunk(png_ptr, "grAb", (byte*)offs, 8);
				break;
			}
		}
	}

	// setup packing if needed
	png_set_packing(png_ptr);
	png_set_packswap(png_ptr);

	// copy data over
	image = data;
	row_pointers = (cache*)Mem_Alloc(sizeof(byte*) * height);

	for(i = 0; i < height; i++)
	{
		row_pointers[i] = (cache)Mem_Alloc(width);
		if(bits == 4)
		{
			for(j = 0; j < width; j += 2)
			{
				row_pointers[i][j] = *image & 0xf;
				row_pointers[i][j+1] = *image >> 4;
				image++;
			}
		}
		else
		{
			for(j = 0; j < width; j++)
			{
				row_pointers[i][j] = *image;
				image++;
			}
		}

		png_write_rows(png_ptr, &row_pointers[i], 1);
	}
Exemplo n.º 20
0
bool writePng(const Bitmap &image, FILE *fp) {
  png_structp png_ptr;
  png_infop info_ptr;

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL) {
    fclose(fp);
    return false;
  }

  /* Allocate/initialize the image information data.  REQUIRED */
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL) {
    fclose(fp);
    png_destroy_write_struct(&png_ptr,  NULL);
    return false;
  }

  /* Set error handling.  REQUIRED if you aren't supplying your own
   * error handling functions in the png_create_write_struct() call.
   */
  if (setjmp(png_jmpbuf(png_ptr)))
  {
    /* If we get here, we had a problem writing the file */
    fclose(fp);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return false;
  }

  /* Set up the output control if you are using standard C streams */
  png_init_io(png_ptr, fp);

  png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(),
               1, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
               PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

  /* Optional gamma chunk is strongly suggested if you have any guess
   * as to the correct gamma of the image.
   */
  png_set_gAMA(png_ptr, info_ptr, 1.0);

  png_set_pHYs(png_ptr, info_ptr, image.xRes(), image.yRes(), image.resUnit());

  /* Write the file header information.  REQUIRED */
  png_write_info(png_ptr, info_ptr);

  int width_bytes = (image.width() + 7) >> 3;
  png_bytep row = new png_byte[width_bytes];

  for (int y = 0; y < image.height(); y++) {
    for (int x = 0; x < image.width(); x += 8) {
      uint8_t b = 0;
      uint8_t mask = 0x80;
      for (int xx = x; xx < x+8 && xx < image.width(); xx++) {
        if (image.get(xx, y)) {
          b |= mask;
        }
        mask >>= 1;
      }
      row[x >> 3] = ~b;
    }

    png_write_rows(png_ptr, &row, 1);
  }

  delete [] row;

  /* It is REQUIRED to call this to finish writing the rest of the file */
  png_write_end(png_ptr, info_ptr);

  /* Clean up after the write, and free any memory allocated */
  png_destroy_write_struct(&png_ptr, &info_ptr);

  /* Close the file */
  fclose(fp);

  return true;
}
Exemplo n.º 21
0
bool KIPIWriteImage::write2PNG(const QString& destPath)
{
    /*
    check this out for b/w support:
    http://lxr.kde.org/source/playground/graphics/krita-exp/kis_png_converter.cpp#607
    */
    QFile file(destPath);

    if (!file.open(QIODevice::ReadWrite))
    {
        qDebug() << "Failed to open PNG file for writing" ;
        return false;
    }

    uchar*       data       = 0;
    int          bitsDepth  = d->sixteenBit ? 16 : 8;
    png_color_8  sig_bit;
    png_bytep    row_ptr;
    png_structp  png_ptr    = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop    info_ptr   = png_create_info_struct(png_ptr);

    png_set_write_fn(png_ptr, (void*)&file, kipi_png_write_fn, kipi_png_flush_fn);

    if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)      // Intel
        png_set_bgr(png_ptr);
    else                                                    // PPC
        png_set_swap_alpha(png_ptr);

    if (d->hasAlpha)
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB_ALPHA,  PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 8 * sizeof(uchar)];
        else
            data = new uchar[d->width * 4 * sizeof(uchar)];
    }
    else
    {
        png_set_IHDR(png_ptr, info_ptr, d->width, d->height, bitsDepth,
                     PNG_COLOR_TYPE_RGB,        PNG_INTERLACE_NONE,
                     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

        if (d->sixteenBit)
            data = new uchar[d->width * 6 * sizeof(uchar)];
        else
            data = new uchar[d->width * 3 * sizeof(uchar)];
    }

    sig_bit.red   = bitsDepth;
    sig_bit.green = bitsDepth;
    sig_bit.blue  = bitsDepth;
    sig_bit.alpha = bitsDepth;
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
    png_set_compression_level(png_ptr, 9);

    // Write Software info.
    QString libpngver(QLatin1String(PNG_HEADER_VERSION_STRING));
    libpngver.replace(QLatin1Char('\n'), QLatin1Char(' '));
    QByteArray softAscii = libpngver.toLatin1();
    png_text text;
    text.key         = (png_charp)"Software";
    text.text        = softAscii.data();
    text.compression = PNG_TEXT_COMPRESSION_zTXt;
    png_set_text(png_ptr, info_ptr, &(text), 1);

    png_write_info(png_ptr, info_ptr);
    png_set_shift(png_ptr, &sig_bit);
    png_set_packing(png_ptr);

    uchar* ptr = (uchar*)d->data.data();
    uint   x, y, j;

    for (y = 0; y < d->height; ++y)
    {
        if (cancel())
        {
            delete [] data;
            file.close();
            png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
            png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
            return false;
        }

        j = 0;

        for (x = 0; x < d->width*bytesDepth(); x+=bytesDepth())
        {
            if (d->sixteenBit)
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                    data[j++] = ptr[x+7];  // Alpha
                    data[j++] = ptr[x+6];
                }
                else
                {
                    data[j++] = ptr[x+1];  // Blue
                    data[j++] = ptr[ x ];
                    data[j++] = ptr[x+3];  // Green
                    data[j++] = ptr[x+2];
                    data[j++] = ptr[x+5];  // Red
                    data[j++] = ptr[x+4];
                }
            }
            else
            {
                if (d->hasAlpha)
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                    data[j++] = ptr[x+3];  // Alpha
                }
                else
                {
                    data[j++] = ptr[ x ];  // Blue
                    data[j++] = ptr[x+1];  // Green
                    data[j++] = ptr[x+2];  // Red
                }
            }
        }

        row_ptr = (png_bytep) data;

        png_write_rows(png_ptr, &row_ptr, 1);
        ptr += (d->width * bytesDepth());
    }

    delete [] data;

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
    png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
    file.close();

    return true;
}
Exemplo n.º 22
0
bool GR_Win32Image::convertToBuffer(UT_ByteBuf** ppBB) const
{
	/*
	  The purpose of this routine is to convert our DIB (m_pDIB)
	  into a PNG image, storing it in a ByteBuf and returning it
	  to the caller.
	*/

	// Create our bytebuf
	UT_ByteBuf* pBB = new UT_ByteBuf();

	png_structp png_ptr;
	png_infop info_ptr;

	// initialize some libpng stuff
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
									  (png_error_ptr)NULL, (png_error_ptr)NULL);
	
	info_ptr = png_create_info_struct(png_ptr);

	// libpng will longjmp back to here if a fatal error occurs
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		/* If we get here, we had a problem reading the file */
		png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
		*ppBB = NULL;
		
		return false;
	}

	// We want libpng to write to our ByteBuf, not stdio
	png_set_write_fn(png_ptr, (void *)pBB, _png_write, _png_flush);

	UT_uint32 iWidth = m_pDIB->bmiHeader.biWidth;
	UT_uint32 iHeight;

	/*
	  DIBs are usually bottom-up (backwards, if you ask me), but
	  sometimes they are top-down.
	*/
	bool		bTopDown = false;

	if (m_pDIB->bmiHeader.biHeight < 0)
	{
		iHeight = -(m_pDIB->bmiHeader.biHeight);
		bTopDown = true;
	}
	else
	{
		iHeight =  (m_pDIB->bmiHeader.biHeight);
	}
	
	png_set_IHDR(png_ptr,
				 info_ptr,
				 iWidth,
				 iHeight,
				 8,							// 8 bits per channel (24 bits)
				 PNG_COLOR_TYPE_RGB,
				 PNG_INTERLACE_NONE,
				 PNG_COMPRESSION_TYPE_BASE,
				 PNG_FILTER_TYPE_BASE);

	/* Write the file header information.  REQUIRED */
	png_write_info(png_ptr, info_ptr);

	/*
	  The next big thing is writing out all of the pixels into the PNG
	  file.  We've got quite a bit of code here to handle various kinds
	  of DIB images.
	*/
	
	UT_uint32 iSizeOfColorData = m_pDIB->bmiHeader.biClrUsed * sizeof(RGBQUAD);
	RGBQUAD* pColors = (RGBQUAD*) (((unsigned char*) m_pDIB) + m_pDIB->bmiHeader.biSize);
	UT_Byte* pBits = ((unsigned char*) m_pDIB) + m_pDIB->bmiHeader.biSize + iSizeOfColorData;
	
	UT_Byte* pData = (UT_Byte*) g_try_malloc(iWidth * iHeight * 3);
	UT_return_val_if_fail(pData, false); // TODO outofmem
		
	UT_uint32 	iRow;
	UT_uint32 	iCol;
	UT_Byte* 	pRow;
	UT_uint32 	iBytesInRow;

	/*
	  We can handle a DIB in either 4-bit, 8-bit, or 24-bit format.
	  The way we do this is allocate a single 24-bit buffer, and
	  regardless of what the format of the DIB is, we convert it to
	  our 24-bit buffer.  Below, we will copy our 24-bit buffer into
	  the PNG file.
	*/
	switch (m_pDIB->bmiHeader.biBitCount)
	{
	case 4:
	{
		iBytesInRow = iWidth / 2;
		if (iWidth % 2)
		{
			iBytesInRow++;
		}

		if (iBytesInRow % 4)
		{
			iBytesInRow += (4 - (iBytesInRow % 4));
		}
		
		for (iRow = 0; iRow<iHeight; iRow++)
		{
			if (bTopDown)
			{
				pRow = pBits + iRow * iBytesInRow;
			}
			else
			{
				pRow = pBits + (iHeight - iRow - 1) * iBytesInRow;
			}

			for (iCol=0; iCol<iWidth; iCol++)
			{
				UT_Byte byt = pRow[iCol / 2];
				UT_Byte pixel;
				if (iCol % 2)
				{
					pixel = byt & 0xf;
				}
				else
				{
					pixel = byt >> 4;
				}

				UT_ASSERT(pixel < m_pDIB->bmiHeader.biClrUsed);

				pData[(iRow*iWidth + iCol)*3 + 0] = pColors[pixel].rgbRed;
				pData[(iRow*iWidth + iCol)*3 + 1] = pColors[pixel].rgbGreen;
				pData[(iRow*iWidth + iCol)*3 + 2] = pColors[pixel].rgbBlue;
			}
		}

		break;
	}
	
	case 8:
	{
		iBytesInRow = iWidth;
		if (iBytesInRow % 4)
		{
			iBytesInRow += (4 - (iBytesInRow % 4));
		}

		for (iRow = 0; iRow<iHeight; iRow++)
		{
			if (bTopDown)
			{
				pRow = pBits + iRow * iBytesInRow;
			}
			else
			{
				pRow = pBits + (iHeight - iRow - 1) * iBytesInRow;
			}

			for (iCol=0; iCol<iWidth; iCol++)
			{
				UT_Byte pixel = pRow[iCol];

				UT_ASSERT(pixel < m_pDIB->bmiHeader.biClrUsed);

				pData[(iRow*iWidth + iCol)*3 + 0] = pColors[pixel].rgbRed;
				pData[(iRow*iWidth + iCol)*3 + 1] = pColors[pixel].rgbGreen;
				pData[(iRow*iWidth + iCol)*3 + 2] = pColors[pixel].rgbBlue;
			}
		}

		break;
	}

	case 24:
	{
		iBytesInRow = iWidth * 3;
		if (iBytesInRow % 4)
		{
			iBytesInRow += (4 - (iBytesInRow % 4));
		}

		for (iRow = 0; iRow<iHeight; iRow++)
		{
			if (bTopDown)
			{
				pRow = pBits + iRow * iBytesInRow;
			}
			else
			{
				pRow = pBits + (iHeight - iRow - 1) * iBytesInRow;
			}

			for (iCol=0; iCol<iWidth; iCol++)
			{
				pData[(iRow*iWidth + iCol)*3 + 0] = pRow[iCol*3 + 2];
				pData[(iRow*iWidth + iCol)*3 + 1] = pRow[iCol*3 + 1];
				pData[(iRow*iWidth + iCol)*3 + 2] = pRow[iCol*3 + 0];
			}
		}

		break;
	}

	default:
		// there are DIB formats we do not support.
		UT_ASSERT_HARMLESS(UT_TODO);
		break;
	}

	/*
	  Now that we have converted the image to a normalized 24-bit
	  representation, we can save it out to the PNG file.
	*/
	for (UT_uint32 i=0; i<iHeight; i++)
	{
		UT_Byte *pRow = pData + i * iWidth * 3;
		
		png_write_rows(png_ptr, &pRow, 1);
	}

	/*
	  We then g_free our 24-bit buffer.
	*/
	g_free(pData);

	/*
	  Wrap things up with libpng
	*/
	png_write_end(png_ptr, info_ptr);

	/* clean up after the write, and g_free any memory allocated */
	png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

	// And pass the ByteBuf back to our caller
	*ppBB = pBB;

	return true;
}
Exemplo n.º 23
0
bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
{
    wxPNGInfoStruct wxinfo;

    wxinfo.verbose = verbose;
    wxinfo.stream.out = &stream;

    png_structp png_ptr = png_create_write_struct
                          (
                            PNG_LIBPNG_VER_STRING,
                            NULL,
                            wx_PNG_error,
                            wx_PNG_warning
                          );
    if (!png_ptr)
    {
        if (verbose)
        {
           wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
           wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    if (setjmp(wxinfo.jmpbuf))
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        if (verbose)
        {
           wxLogError(_("Couldn't save PNG image."));
        }
        return false;
    }

    // NB: please see the comment near wxPNGInfoStruct declaration for
    //     explanation why this line is mandatory
    png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL);

    const int iHeight = image->GetHeight();
    const int iWidth = image->GetWidth();

    const bool bHasPngFormatOption
        = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT);

    int iColorType = bHasPngFormatOption
                            ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT)
                            : wxPNG_TYPE_COLOUR;

    bool bHasAlpha = image->HasAlpha();
    bool bHasMask = image->HasMask();

    bool bUsePalette = iColorType == wxPNG_TYPE_PALETTE
#if wxUSE_PALETTE
        || (!bHasPngFormatOption && image->HasPalette() )
#endif
    ;

    png_color_8 mask = { 0, 0, 0, 0, 0 };

    if (bHasMask)
    {
        mask.red   = image->GetMaskRed();
        mask.green = image->GetMaskGreen();
        mask.blue  = image->GetMaskBlue();
    }

    PaletteMap palette;

    if (bUsePalette)
    {
        png_color png_rgb  [PNG_MAX_PALETTE_LENGTH];
        png_byte  png_trans[PNG_MAX_PALETTE_LENGTH];

        const unsigned char *pColors = image->GetData();
        const unsigned char* pAlpha  = image->GetAlpha();

        if (bHasMask && !pAlpha)
        {
            // Mask must be first
            PaletteAdd(&palette, mask);
        }

        for (int y = 0; y < iHeight; y++)
        {
            for (int x = 0; x < iWidth; x++)
            {
                png_color_8 rgba;

                rgba.red   = *pColors++;
                rgba.green = *pColors++;
                rgba.blue  = *pColors++;
                rgba.gray  = 0;
                rgba.alpha = (pAlpha && !bHasMask) ? *pAlpha++ : 0;

                // save in our palette
                long index = PaletteAdd(&palette, rgba);

                if (index < PNG_MAX_PALETTE_LENGTH)
                {
                    // save in libpng's palette
                    png_rgb[index].red   = rgba.red;
                    png_rgb[index].green = rgba.green;
                    png_rgb[index].blue  = rgba.blue;
                    png_trans[index]     = rgba.alpha;
                }
                else
                {
                    bUsePalette = false;
                    break;
                }
            }
        }

        if (bUsePalette)
        {
            png_set_PLTE(png_ptr, info_ptr, png_rgb, palette.size());

            if (bHasMask && !pAlpha)
            {
                wxASSERT(PaletteFind(palette, mask) == 0);
                png_trans[0] = 0;
                png_set_tRNS(png_ptr, info_ptr, png_trans, 1, NULL);
            }
            else if (pAlpha && !bHasMask)
            {
                png_set_tRNS(png_ptr, info_ptr, png_trans, palette.size(), NULL);
            }
        }
    }

    /*
    If saving palettised was requested but it was decided we can't use a
    palette then reset the colour type to RGB.
    */
    if (!bUsePalette && iColorType == wxPNG_TYPE_PALETTE)
    {
        iColorType = wxPNG_TYPE_COLOUR;
    }

    bool bUseAlpha = !bUsePalette && (bHasAlpha || bHasMask);

    int iPngColorType;

    if (bUsePalette)
    {
        iPngColorType = PNG_COLOR_TYPE_PALETTE;
        iColorType = wxPNG_TYPE_PALETTE;
    }
    else if ( iColorType==wxPNG_TYPE_COLOUR )
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA
                                  : PNG_COLOR_TYPE_RGB;
    }
    else
    {
        iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA
                                  : PNG_COLOR_TYPE_GRAY;
    }

    if (image->HasOption(wxIMAGE_OPTION_PNG_FILTER))
        png_set_filter( png_ptr, PNG_FILTER_TYPE_BASE, image->GetOptionInt(wxIMAGE_OPTION_PNG_FILTER) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL))
        png_set_compression_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL))
        png_set_compression_mem_level( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY))
        png_set_compression_strategy( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY) );

    if (image->HasOption(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE))
        png_set_compression_buffer_size( png_ptr, image->GetOptionInt(wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE) );

    int iBitDepth = !bUsePalette && image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH)
                            ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH)
                            : 8;

    png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(),
                  iBitDepth, iPngColorType,
                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                  PNG_FILTER_TYPE_BASE);

    int iElements;
    png_color_8 sig_bit;

    if ( iPngColorType & PNG_COLOR_MASK_COLOR )
    {
        sig_bit.red =
        sig_bit.green =
        sig_bit.blue = (png_byte)iBitDepth;
        iElements = 3;
    }
    else // grey
    {
        sig_bit.gray = (png_byte)iBitDepth;
        iElements = 1;
    }

    if ( bUseAlpha )
    {
        sig_bit.alpha = (png_byte)iBitDepth;
        iElements++;
    }

    if ( iBitDepth == 16 )
        iElements *= 2;

    // save the image resolution if we have it
    int resX, resY;
    switch ( GetResolutionFromOptions(*image, &resX, &resY) )
    {
        case wxIMAGE_RESOLUTION_INCHES:
            {
                const double INCHES_IN_METER = 10000.0 / 254;
                resX = int(resX * INCHES_IN_METER);
                resY = int(resY * INCHES_IN_METER);
            }
            break;

        case wxIMAGE_RESOLUTION_CM:
            resX *= 100;
            resY *= 100;
            break;

        case wxIMAGE_RESOLUTION_NONE:
            break;

        default:
            wxFAIL_MSG( wxT("unsupported image resolution units") );
    }

    if ( resX && resY )
        png_set_pHYs( png_ptr, info_ptr, resX, resY, PNG_RESOLUTION_METER );

    png_set_sBIT( png_ptr, info_ptr, &sig_bit );
    png_write_info( png_ptr, info_ptr );
    png_set_shift( png_ptr, &sig_bit );
    png_set_packing( png_ptr );

    unsigned char *
        data = (unsigned char *)malloc( image->GetWidth() * iElements );
    if ( !data )
    {
        png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
        return false;
    }

    const unsigned char *
        pAlpha = (const unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL);

    const unsigned char *pColors = image->GetData();

    for (int y = 0; y != iHeight; ++y)
    {
        unsigned char *pData = data;
        for (int x = 0; x != iWidth; x++)
        {
            png_color_8 clr;
            clr.red   = *pColors++;
            clr.green = *pColors++;
            clr.blue  = *pColors++;
            clr.gray  = 0;
            clr.alpha = (bUsePalette && pAlpha) ? *pAlpha++ : 0; // use with wxPNG_TYPE_PALETTE only

            switch ( iColorType )
            {
                default:
                    wxFAIL_MSG( wxT("unknown wxPNG_TYPE_XXX") );
                    // fall through

                case wxPNG_TYPE_COLOUR:
                    *pData++ = clr.red;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    *pData++ = clr.green;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    *pData++ = clr.blue;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    break;

                case wxPNG_TYPE_GREY:
                    {
                        // where do these coefficients come from? maybe we
                        // should have image options for them as well?
                        unsigned uiColor =
                            (unsigned) (76.544*(unsigned)clr.red +
                                        150.272*(unsigned)clr.green +
                                        36.864*(unsigned)clr.blue);

                        *pData++ = (unsigned char)((uiColor >> 8) & 0xFF);
                        if ( iBitDepth == 16 )
                            *pData++ = (unsigned char)(uiColor & 0xFF);
                    }
                    break;

                case wxPNG_TYPE_GREY_RED:
                    *pData++ = clr.red;
                    if ( iBitDepth == 16 )
                        *pData++ = 0;
                    break;

                case wxPNG_TYPE_PALETTE:
                    *pData++ = (unsigned char) PaletteFind(palette, clr);
                    break;
            }

            if ( bUseAlpha )
            {
                unsigned char uchAlpha = 255;
                if ( bHasAlpha )
                    uchAlpha = *pAlpha++;

                if ( bHasMask )
                {
                    if ( (clr.red == mask.red)
                            && (clr.green == mask.green)
                                && (clr.blue == mask.blue) )
                        uchAlpha = 0;
                }

                *pData++ = uchAlpha;
                if ( iBitDepth == 16 )
                    *pData++ = 0;
            }
        }

        png_bytep row_ptr = data;
        png_write_rows( png_ptr, &row_ptr, 1 );
    }

    free(data);
    png_write_end( png_ptr, info_ptr );
    png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );

    return true;
}
Exemplo n.º 24
0
/* This routine is used for all formats. */
static int
png_print_page(gx_device_printer * pdev, FILE * file)
{
    gs_memory_t *mem = pdev->memory;
    int raster = gdev_prn_raster(pdev);

    /* PNG structures */
    byte *row = gs_alloc_bytes(mem, raster, "png raster buffer");
    png_struct *png_ptr =
    png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_info *info_ptr =
    png_create_info_struct(png_ptr);
    int height = pdev->height;
    int depth = pdev->color_info.depth;
    int y;
    int code;			/* return code */
    char software_key[80];
    char software_text[256];
    png_text text_png;

    if (row == 0 || png_ptr == 0 || info_ptr == 0) {
	code = gs_note_error(gs_error_VMerror);
	goto done;
    }
    /* set error handling */
    if (setjmp(png_ptr->jmpbuf)) {
	/* If we get here, we had a problem reading the file */
	code = gs_note_error(gs_error_VMerror);
	goto done;
    }
    code = 0;			/* for normal path */
    /* set up the output control */
    png_init_io(png_ptr, file);

    /* set the file information here */
    info_ptr->width = pdev->width;
    info_ptr->height = pdev->height;
    /* resolution is in pixels per meter vs. dpi */
    info_ptr->x_pixels_per_unit =
	(png_uint_32) (pdev->HWResolution[0] * (100.0 / 2.54));
    info_ptr->y_pixels_per_unit =
	(png_uint_32) (pdev->HWResolution[1] * (100.0 / 2.54));
    info_ptr->phys_unit_type = PNG_RESOLUTION_METER;
    info_ptr->valid |= PNG_INFO_pHYs;
    switch (depth) {
	case 32:
	    info_ptr->bit_depth = 8;
	    info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
	    png_set_invert_alpha(png_ptr);
	    {   gx_device_pngalpha *ppdev = (gx_device_pngalpha *)pdev;
		png_color_16 background;
		background.index = 0;
		background.red =   (ppdev->background >> 16) & 0xff;
		background.green = (ppdev->background >> 8)  & 0xff;
		background.blue =  (ppdev->background)       & 0xff;
		background.gray = 0;
		png_set_bKGD(png_ptr, info_ptr, &background);
	    }
	    break;
	case 48:
	    info_ptr->bit_depth = 16;
	    info_ptr->color_type = PNG_COLOR_TYPE_RGB;
#if defined(ARCH_IS_BIG_ENDIAN) && (!ARCH_IS_BIG_ENDIAN) 
	    png_set_swap(png_ptr);
#endif
	    break;
	case 24:
	    info_ptr->bit_depth = 8;
	    info_ptr->color_type = PNG_COLOR_TYPE_RGB;
	    break;
	case 8:
	    info_ptr->bit_depth = 8;
	    if (gx_device_has_color(pdev))
		info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
	    else
		info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
	    break;
	case 4:
	    info_ptr->bit_depth = 4;
	    info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
	    break;
	case 1:
	    info_ptr->bit_depth = 1;
	    info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
	    /* invert monocrome pixels */
	    png_set_invert_mono(png_ptr);
	    break;
    }

    /* set the palette if there is one */
    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
	int i;
	int num_colors = 1 << depth;
	gx_color_value rgb[3];

	info_ptr->palette =
	    (void *)gs_alloc_bytes(mem, 256 * sizeof(png_color),
				   "png palette");
	if (info_ptr->palette == 0) {
	    code = gs_note_error(gs_error_VMerror);
	    goto done;
	}
	info_ptr->num_palette = num_colors;
	info_ptr->valid |= PNG_INFO_PLTE;
	for (i = 0; i < num_colors; i++) {
	    (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
					      (gx_color_index) i, rgb);
	    info_ptr->palette[i].red = gx_color_value_to_byte(rgb[0]);
	    info_ptr->palette[i].green = gx_color_value_to_byte(rgb[1]);
	    info_ptr->palette[i].blue = gx_color_value_to_byte(rgb[2]);
	}
    }
    /* add comment */
    strncpy(software_key, "Software", sizeof(software_key));
    sprintf(software_text, "%s %d.%02d", gs_product,
	    (int)(gs_revision / 100), (int)(gs_revision % 100));
    text_png.compression = -1;	/* uncompressed */
    text_png.key = software_key;
    text_png.text = software_text;
    text_png.text_length = strlen(software_text);
    info_ptr->text = &text_png;
    info_ptr->num_text = 1;

    /* write the file information */
    png_write_info(png_ptr, info_ptr);

    /* don't write the comments twice */
    info_ptr->num_text = 0;
    info_ptr->text = NULL;

    /* Write the contents of the image. */
    for (y = 0; y < height; y++) {
	gdev_prn_copy_scan_lines(pdev, y, row, raster);
	png_write_rows(png_ptr, &row, 1);
    }

    /* write the rest of the file */
    png_write_end(png_ptr, info_ptr);

    /* if you alloced the palette, free it here */
    gs_free_object(mem, info_ptr->palette, "png palette");

  done:
    /* free the structures */
    png_destroy_write_struct(&png_ptr, &info_ptr);
    gs_free_object(mem, row, "png raster buffer");

    return code;
}
Exemplo n.º 25
0
bool
Image::writePNG(const char *filename) const {
    FILE *fp;
    png_structp png_ptr;
    png_infop info_ptr;

    fp = fopen(filename, "wb");
    if (!fp)
        goto no_fp;

    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        goto no_png;

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_write_struct(&png_ptr,  NULL);
        goto no_png;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        goto no_png;
    }

    png_init_io(png_ptr, fp);

    int color_type;
    switch (channels) {
    case 4:
        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
        break;
    case 3:
        color_type = PNG_COLOR_TYPE_RGB;
        break;
    case 2:
        color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
        break;
    case 1:
        color_type = PNG_COLOR_TYPE_GRAY;
        break;
    default:
        assert(0);
        return false;
    }

    png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

    png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);

    png_write_info(png_ptr, info_ptr);

    if (!flipped) {
        for (unsigned y = 0; y < height; ++y) {
            png_bytep row = (png_bytep)(pixels + y*width*channels);
            png_write_rows(png_ptr, &row, 1);
        }
    } else {
        unsigned y = height;
        while (y--) {
            png_bytep row = (png_bytep)(pixels + y*width*channels);
            png_write_rows(png_ptr, &row, 1);
        }
    }

    png_write_end(png_ptr, info_ptr);
    png_destroy_write_struct(&png_ptr, &info_ptr);

    fclose(fp);
    return true;

no_png:
    fclose(fp);
no_fp:
    return false;
}
Exemplo n.º 26
0
static gboolean real_save_png (GdkPixbuf        *pixbuf, 
                               gchar           **keys,
                               gchar           **values,
                               GError          **error,
                               gboolean          to_callback,
                               FILE             *f,
                               GdkPixbufSaveFunc save_func,
                               gpointer          user_data)
{
       png_structp png_ptr = NULL;
       png_infop info_ptr;
       png_textp text_ptr = NULL;
       guchar *ptr;
       guchar *pixels;
       int y;
       int i;
       png_bytep row_ptr;
       png_color_8 sig_bit;
       int w, h, rowstride;
       int has_alpha;
       int bpc;
       int num_keys;
       int compression = -1;
       gboolean success = TRUE;
       guchar *icc_profile = NULL;
       gsize icc_profile_size = 0;
       SaveToFunctionIoPtr to_callback_ioptr;

       num_keys = 0;

       if (keys && *keys) {
               gchar **kiter = keys;
               gchar **viter = values;

               while (*kiter) {
                       if (strncmp (*kiter, "tEXt::", 6) == 0) {
                               gchar  *key = *kiter + 6;
                               int     len = strlen (key);
                               if (len < 1 || len > 79) {
                                       g_set_error_literal (error,
                                                            GDK_PIXBUF_ERROR,
                                                            GDK_PIXBUF_ERROR_BAD_OPTION,
                                                            _("Keys for PNG text chunks must have at least 1 and at most 79 characters."));
                                       success = FALSE;
                                       goto cleanup;
                               }
                               for (i = 0; i < len; i++) {
                                       if ((guchar) key[i] > 127) {
                                               g_set_error_literal (error,
                                                                    GDK_PIXBUF_ERROR,
                                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                                    _("Keys for PNG text chunks must be ASCII characters."));
                                               success = FALSE;
                                               goto cleanup;
                                       }
                               }
                               num_keys++;
                       } else if (strcmp (*kiter, "icc-profile") == 0) {
                               /* decode from base64 */
                               icc_profile = g_base64_decode (*viter, &icc_profile_size);
                               if (icc_profile_size < 127) {
                                       /* This is a user-visible error */
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("Color profile has invalid length %d."),
                                                    (gint)icc_profile_size);
                                       success = FALSE;
                                       goto cleanup;
                               }
                       } else if (strcmp (*kiter, "compression") == 0) {
                               char *endptr = NULL;
                               compression = strtol (*viter, &endptr, 10);

                               if (endptr == *viter) {
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("PNG compression level must be a value between 0 and 9; value '%s' could not be parsed."),
                                                    *viter);
                                       success = FALSE;
                                       goto cleanup;
                               }
                               if (compression < 0 || compression > 9) {
                                       /* This is a user-visible error;
                                        * lets people skip the range-checking
                                        * in their app.
                                        */
                                       g_set_error (error,
                                                    GDK_PIXBUF_ERROR,
                                                    GDK_PIXBUF_ERROR_BAD_OPTION,
                                                    _("PNG compression level must be a value between 0 and 9; value '%d' is not allowed."),
                                                    compression);
                                       success = FALSE;
                                       goto cleanup;
                               }
                       } else {
                               g_warning ("Unrecognized parameter (%s) passed to PNG saver.", *kiter);
                       }

                       ++kiter;
                       ++viter;
               }
       }

       if (num_keys > 0) {
               gchar **kiter = keys;
               gchar **viter = values;

               text_ptr = g_new0 (png_text, num_keys);
               for (i = 0; i < num_keys; i++) {
                       if (strncmp (*kiter, "tEXt::", 6) != 0) {
                                kiter++;
                                viter++;
                       }

                       text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE;
                       text_ptr[i].key  = *kiter + 6;
                       text_ptr[i].text = g_convert (*viter, -1, 
                                                     "ISO-8859-1", "UTF-8", 
                                                     NULL, &text_ptr[i].text_length, 
                                                     NULL);

#ifdef PNG_iTXt_SUPPORTED 
                       if (!text_ptr[i].text) {
                               text_ptr[i].compression = PNG_ITXT_COMPRESSION_NONE;
                               text_ptr[i].text = g_strdup (*viter);
                               text_ptr[i].text_length = 0;
                               text_ptr[i].itxt_length = strlen (text_ptr[i].text);
                               text_ptr[i].lang = NULL;
                               text_ptr[i].lang_key = NULL;
                       }
#endif

                       if (!text_ptr[i].text) {
                               gint j;
                               g_set_error (error,
                                            GDK_PIXBUF_ERROR,
                                            GDK_PIXBUF_ERROR_BAD_OPTION,
                                            _("Value for PNG text chunk %s cannot be converted to ISO-8859-1 encoding."), *kiter + 6);
                               for (j = 0; j < i; j++)
                                       g_free (text_ptr[j].text);
                               g_free (text_ptr);
                               return FALSE;
                       }

                        kiter++;
                        viter++;
               }
       }

       bpc = gdk_pixbuf_get_bits_per_sample (pixbuf);
       w = gdk_pixbuf_get_width (pixbuf);
       h = gdk_pixbuf_get_height (pixbuf);
       rowstride = gdk_pixbuf_get_rowstride (pixbuf);
       has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
       pixels = gdk_pixbuf_get_pixels (pixbuf);

       png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
                                          error,
                                          png_simple_error_callback,
                                          png_simple_warning_callback);
       if (png_ptr == NULL) {
	       success = FALSE;
	       goto cleanup;
       }

       info_ptr = png_create_info_struct (png_ptr);
       if (info_ptr == NULL) {
	       success = FALSE;
	       goto cleanup;
       }
       if (setjmp (png_jmpbuf(png_ptr))) {
	       success = FALSE;
	       goto cleanup;
       }

       if (num_keys > 0) {
               png_set_text (png_ptr, info_ptr, text_ptr, num_keys);
       }

       if (to_callback) {
               to_callback_ioptr.save_func = save_func;
               to_callback_ioptr.user_data = user_data;
               to_callback_ioptr.error = error;
               png_set_write_fn (png_ptr, &to_callback_ioptr,
                                 png_save_to_callback_write_func,
                                 png_save_to_callback_flush_func);
       } else {
               png_init_io (png_ptr, f);
       }

       if (compression >= 0)
               png_set_compression_level (png_ptr, compression);

#if defined(PNG_iCCP_SUPPORTED)
        /* the proper ICC profile title is encoded in the profile */
        if (icc_profile != NULL) {
                png_set_iCCP (png_ptr, info_ptr,
                              "ICC profile", PNG_COMPRESSION_TYPE_BASE,
                              (png_bytep) icc_profile, icc_profile_size);
        }
#endif

       if (has_alpha) {
               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
                             PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
       } else {
               png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
                             PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
       }
       sig_bit.red = bpc;
       sig_bit.green = bpc;
       sig_bit.blue = bpc;
       sig_bit.alpha = bpc;
       png_set_sBIT (png_ptr, info_ptr, &sig_bit);
       png_write_info (png_ptr, info_ptr);
       png_set_shift (png_ptr, &sig_bit);
       png_set_packing (png_ptr);

       ptr = pixels;
       for (y = 0; y < h; y++) {
               row_ptr = (png_bytep)ptr;
               png_write_rows (png_ptr, &row_ptr, 1);
               ptr += rowstride;
       }

       png_write_end (png_ptr, info_ptr);

cleanup:
        if (png_ptr != NULL)
                png_destroy_write_struct (&png_ptr, &info_ptr);

        g_free (icc_profile);

        if (text_ptr != NULL) {
                for (i = 0; i < num_keys; i++)
                        g_free (text_ptr[i].text);
                g_free (text_ptr);
        }

       return success;
}
Exemplo n.º 27
0
gint
gegl_buffer_export_png (GeglBuffer  *gegl_buffer,
                        const gchar *path,
                        gint         compression,
                        gint         bd,
                        gint         src_x,
                        gint         src_y,
                        gint         width,
                        gint         height)
{
    FILE          *fp;
    gint           i;
    png_struct    *png;
    png_info      *info;
    guchar        *pixels;
    png_color_16   white;
    int            png_color_type;
    gchar          format_string[16];
    const Babl    *format;
    gint           bit_depth = 8;

    if (!strcmp (path, "-"))
    {
        fp = stdout;
    }
    else
    {
        fp = fopen (path, "wb");
    }
    if (!fp)
    {
        return -1;
    }

    {
        const Babl *babl = gegl_buffer_get_format (gegl_buffer);

        if (bd == 16)
            bit_depth = 16;
        else
            bit_depth = 8;

        if (babl_format_has_alpha (babl))
            if (babl_format_get_n_components (babl) != 2)
            {
                png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
                strcpy (format_string, "R'G'B'A ");
            }
            else
            {
                png_color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
                strcpy (format_string, "Y'A ");
            }
        else if (babl_format_get_n_components (babl) != 1)
        {
            png_color_type = PNG_COLOR_TYPE_RGB;
            strcpy (format_string, "R'G'B' ");
        }
        else
        {
            png_color_type = PNG_COLOR_TYPE_GRAY;
            strcpy (format_string, "Y' ");
        }
    }

    if (bit_depth == 16)
        strcat (format_string, "u16");
    else
        strcat (format_string, "u8");

    png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png == NULL)
    {
        if (stdout != fp)
            fclose (fp);

        return -1;
    }

    info = png_create_info_struct (png);

    if (setjmp (png_jmpbuf (png)))
    {
        if (stdout != fp)
            fclose (fp);

        return -1;
    }

    png_set_compression_level (png, compression);
    png_init_io (png, fp);

    png_set_IHDR (png, info,
                  width, height, bit_depth, png_color_type,
                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT);

    if (png_color_type == PNG_COLOR_TYPE_RGB || png_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    {
        white.red = 0xff;
        white.blue = 0xff;
        white.green = 0xff;
    }
    else
        white.gray = 0xff;
    png_set_bKGD (png, info, &white);

    png_write_info (png, info);

#if BYTE_ORDER == LITTLE_ENDIAN
    if (bit_depth > 8)
        png_set_swap (png);
#endif

    format = babl_format (format_string);
    pixels = g_malloc0 (width * babl_format_get_bytes_per_pixel (format));

    for (i=0; i< height; i++)
    {
        GeglRectangle rect;

        rect.x = src_x;
        rect.y = src_y+i;
        rect.width = width;
        rect.height = 1;

        gegl_buffer_get (gegl_buffer, &rect, 1.0, babl_format (format_string), pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

        png_write_rows (png, &pixels, 1);
    }

    png_write_end (png, info);

    png_destroy_write_struct (&png, &info);
    g_free (pixels);

    if (stdout != fp)
        fclose (fp);

    return 0;
}
Exemplo n.º 28
0
/*
    WritePNG - writes the contents of a BMGImageStruct to a JPEG file.

    Inputs:
        filename    - the name of the file to be opened
        img         - the BMGImageStruct containing the image data

    Returns:
        0 - if the file could not be written or a resource error occurred
        1 - if the file was written

    Comments:
		16-BPP BMG Images are converted to 24-BPP images

    Limitations:
        Color Type is limited to PNG_COLOR_TYPE_GRAY, PNG_COLOR_TYPE_RGB_ALPHA,
        PNG_COLOR_TYPE_RGB, & PNG_COLOR_TYPE_PALETTE;
*/
BMGError WritePNG( const char *filename,
                   struct BMGImageStruct img )
{
    jmp_buf             err_jmp;
    int                 error;

    int                 BitDepth;
    int                 ColorType;
    png_structp         png_ptr = NULL;
    png_infop           info_ptr = NULL;
    png_colorp          PNGPalette = NULL;
    int                 GrayScale;

    unsigned char      *bits, *p, *q;
    unsigned char     **rows = NULL;
    int                 NumColors = 0;

    int                DIBScanWidth;
    int                HasPalette;
    FILE              *outfile = NULL;
    int                i;
	BMGError           tmp;

    /* error handler */
    error = setjmp( err_jmp );
    if ( error != 0 )
    {
        if ( png_ptr != NULL )
            png_destroy_write_struct( &png_ptr, NULL );
        if ( rows )
        {
            if ( rows[0] )
            {
                free( rows[0] );
            }
            free( rows );
        }
        if ( PNGPalette )
            free( PNGPalette );
		if ( outfile)
			fclose( outfile );
        return (BMGError)error;
    }

    /* open the file */
    if ((outfile = fopen(filename, "wb")) == NULL)
        longjmp( err_jmp, (int)errFileOpen );

	/* 16 BPP DIBS do not have palettes.  libPNG expects 16 BPP images to have
	   a palette.  To correct this situation we must convert 16 BPP images to
	   24 BPP images before saving the data to the file */
	if ( img.bits_per_pixel == 16 )
	{
		tmp = Convert16to24( &img ); 
		if (  tmp != BMG_OK )
	        longjmp( err_jmp, (int)tmp );
	}

    HasPalette = img.bits_per_pixel <= 8;
    if ( HasPalette )
    {
        NumColors = img.palette_size;
        /* if this is a grayscale image then set the flag and delete the palette*/
        i = 0;
        bits = img.palette;
        while ( i < NumColors && bits[0] == bits[1] && bits[0] == bits[2] )
        {
            i++;
            bits += img.bytes_per_palette_entry;
        }
        GrayScale = i == NumColors;
    }
    else
        GrayScale = 0;

    /* dimensions */
    DIBScanWidth = ( img.width * img.bits_per_pixel + 7 ) / 8;

    /* create the png pointer */
    png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if ( !png_ptr )
        longjmp( err_jmp, (int)errMemoryAllocation );

    /* create the info pointer */
    info_ptr = png_create_info_struct( png_ptr );
    if ( !info_ptr )
        longjmp( err_jmp, (int)errMemoryAllocation );

    /* bamboozle the png error handler */
	/* error will always == 1 which equals errLib */
//    error = png_setjmp(png_ptr);
    error = setjmp( png_jmpbuf( png_ptr ) );
	if ( error > 0 )
        longjmp( err_jmp, error );

    /* setup the output control */
    png_init_io( png_ptr, outfile );

    /* prepare variables needed to create PNG header */
    BitDepth = img.bits_per_pixel < 8 ? img.bits_per_pixel : 8;

    /* determine color type */
    if ( GrayScale )
        ColorType = PNG_COLOR_TYPE_GRAY;
    else if ( img.bits_per_pixel == 32 )
        ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
    else if ( img.bits_per_pixel == 24 )
        ColorType = PNG_COLOR_TYPE_RGB;
    else
        ColorType = PNG_COLOR_TYPE_PALETTE;

    /* create the PNG header */
    png_set_IHDR( png_ptr, info_ptr, img.width, img.height, BitDepth, ColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );

    /* store the palette information if there is any */
    if ( img.palette != NULL && !GrayScale )
    {
        PNGPalette = (png_colorp)png_malloc( png_ptr,
                                             NumColors*sizeof(png_color));
        if ( PNGPalette )
        {
            bits = img.palette;
            for ( i = 0; i < NumColors; i++, bits += img.bytes_per_palette_entry )
            {
                PNGPalette[i].red   = bits[2];
                PNGPalette[i].green = bits[1];
                PNGPalette[i].blue  = bits[0];
            }
            png_set_PLTE( png_ptr, info_ptr, PNGPalette, NumColors );
        }
        else
            longjmp( err_jmp, (int)errMemoryAllocation );
    }

    /* write the file header information */
    png_write_info( png_ptr, info_ptr );

    /* create array to store data in */
    rows = (unsigned char **)malloc(sizeof(unsigned char*));
    if ( !rows )
        longjmp( err_jmp, (int)errMemoryAllocation );
    rows[0] = (unsigned char *)malloc( DIBScanWidth * sizeof(unsigned char));
    if ( !rows[0] )
        longjmp( err_jmp, (int)errMemoryAllocation );

    /* point to the bottom row of the DIB data.  DIBs are stored bottom-to-top,
        PNGs are stored top-to-bottom. */
    bits = img.bits + (img.height - 1) * img.scan_width;

    /* store bits */
    for ( i = 0; i < (int)img.height; i++ )
    {
        switch ( img.bits_per_pixel )
        {
            case 1:
            case 4:
            case 8:
                memcpy( (void *)rows[0], (void *)bits, DIBScanWidth );
                break;
            case 24:
                q = bits;
                for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 3, q += 3 )
                {
                    p[0] = q[2];
                    p[1] = q[1];
                    p[2] = q[0];
                }
                break;
            case 32:
                q = bits;
                for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 4, q += 4 )
                {
                    p[3] = q[3];
                    p[0] = q[2];
                    p[1] = q[1];
                    p[2] = q[0];
                }
                break;
        }

        png_write_rows( png_ptr, rows, 1 );
        bits -= img.scan_width;
    }

    /* finish writing the rest of the file */
    png_write_end( png_ptr, info_ptr );

    /* clean up and exit */
    if ( PNGPalette )
        free( PNGPalette );
    free( rows[0] );
    free( rows );
    png_destroy_write_struct( &png_ptr, NULL );
    fclose( outfile );

    return BMG_OK;
}
Exemplo n.º 29
0
static gboolean
_cairo_surface_write_as_png (cairo_surface_t  *image,
			     char            **buffer,
			     gsize            *buffer_size,
			     char            **keys,
			     char            **values,
			     GError          **error)
{
	int            compression_level;
	int            width, height;
	gboolean       alpha;
	guchar        *pixels, *ptr, *buf;
	int            rowstride;
	CairoPngData  *cairo_png_data;
	png_color_8    sig_bit;
	int            bpp;
	int            row;

	compression_level = 6;

	if (keys && *keys) {
		char **kiter = keys;
		char **viter = values;

		while (*kiter) {
			if (strcmp (*kiter, "compression") == 0) {
				if (*viter == NULL) {
					g_set_error (error,
						     G_IO_ERROR,
						     G_IO_ERROR_INVALID_DATA,
						     "Must specify a compression level");
					return FALSE;
				}

				compression_level = atoi (*viter);

				if (compression_level < 0 || compression_level > 9) {
					g_set_error (error,
						     G_IO_ERROR,
						     G_IO_ERROR_INVALID_DATA,
						     "Unsupported compression level passed to the PNG saver");
					return FALSE;
				}
			}
			else {
				g_warning ("Bad option name '%s' passed to the PNG saver", *kiter);
				return FALSE;
			}

			++kiter;
			++viter;
		}
	}

	width     = cairo_image_surface_get_width (image);
	height    = cairo_image_surface_get_height (image);
	alpha     = _cairo_image_surface_get_has_alpha (image);
	pixels    = _cairo_image_surface_flush_and_get_data (image);
	rowstride = cairo_image_surface_get_stride (image);

	cairo_png_data = g_new0 (CairoPngData, 1);
	cairo_png_data->error = error;
	cairo_png_data->buffer_data = gth_buffer_data_new ();

	cairo_png_data->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
							   &cairo_png_data->error,
							   gerror_error_func,
							   gerror_warning_func);
	if (cairo_png_data->png_ptr == NULL) {
		_cairo_png_data_destroy (cairo_png_data);
	        return FALSE;
	}

	cairo_png_data->png_info_ptr = png_create_info_struct (cairo_png_data->png_ptr);
	if (cairo_png_data->png_info_ptr == NULL) {
		_cairo_png_data_destroy (cairo_png_data);
	        return FALSE;
	}

	if (PNG_SETJMP (cairo_png_data->png_ptr)) {
		_cairo_png_data_destroy (cairo_png_data);
	        return FALSE;
	}

	png_set_write_fn (cairo_png_data->png_ptr,
			  cairo_png_data,
			  cairo_png_write_data_func,
			  cairo_png_flush_data_func);

	/* Set the image information here */

	png_set_IHDR (cairo_png_data->png_ptr,
		      cairo_png_data->png_info_ptr,
		      width,
		      height,
		      8,
		      (alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB),
		      PNG_INTERLACE_NONE,
		      PNG_COMPRESSION_TYPE_BASE,
		      PNG_FILTER_TYPE_BASE);

	/* Options */

	sig_bit.red = 8;
	sig_bit.green = 8;
	sig_bit.blue = 8;
	if (alpha)
		sig_bit.alpha = 8;
	png_set_sBIT (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr, &sig_bit);

	png_set_compression_level (cairo_png_data->png_ptr, compression_level);

	/* Write the file header information. */

	png_write_info (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr);

	/* Write the image */

	bpp = alpha ? 4 : 3;
	buf = g_new (guchar, width * bpp);
	ptr = pixels;
	for (row = 0; row < height; ++row) {
		_cairo_copy_line_as_rgba_big_endian (buf, ptr, width, alpha);
		png_write_rows (cairo_png_data->png_ptr, &buf, 1);

		ptr += rowstride;
	}
	g_free (buf);

	png_write_end (cairo_png_data->png_ptr, cairo_png_data->png_info_ptr);
	gth_buffer_data_get (cairo_png_data->buffer_data, buffer, buffer_size);

	_cairo_png_data_destroy (cairo_png_data);

	return TRUE;
}
Exemplo n.º 30
0
	bool PNG::Encode (ImageBuffer *imageBuffer, ByteArray *bytes) {
		
		png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, user_error_fn, user_warning_fn);
		
		if (!png_ptr) {
			
			return false;
			
		}
		
		png_infop info_ptr = png_create_info_struct (png_ptr);
		
		if (!info_ptr) {
			
			return false;
			
		}
		
		if (setjmp (png_jmpbuf (png_ptr))) {
			
			png_destroy_write_struct (&png_ptr, &info_ptr);
			return false;
			
		}
		
		QuickVec<uint8> out_buffer;
		
		png_set_write_fn (png_ptr, &out_buffer, user_write_data, user_flush_data);
		
		int w = imageBuffer->width;
		int h = imageBuffer->height;
		
		int bit_depth = 8;
		//int color_type = (inSurface->Format () & pfHasAlpha) ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
		int color_type = PNG_COLOR_TYPE_RGB_ALPHA;
		png_set_IHDR (png_ptr, info_ptr, w, h, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
		
		png_write_info (png_ptr, info_ptr);
		
		bool do_alpha = (color_type == PNG_COLOR_TYPE_RGBA);
		unsigned char* imageData = imageBuffer->data->Bytes();
		int stride = w * imageBuffer->bpp;
		
		{
			QuickVec<uint8> row_data (w * 4);
			png_bytep row = &row_data[0];
			
			for (int y = 0; y < h; y++) {
				
				uint8 *buf = &row_data[0];
				const uint8 *src = (const uint8 *)(imageData + (stride * y));
				
				for (int x = 0; x < w; x++) {
					
					buf[0] = src[0];
					buf[1] = src[1];
					buf[2] = src[2];
					src += 3;
					buf += 3;
					
					if (do_alpha) {
						
						*buf++ = *src;
						
					}
					
					src++;
					
				}
				
				png_write_rows (png_ptr, &row, 1);
				
			}
			
		}
		
		png_write_end (png_ptr, NULL);
		
		*bytes = ByteArray (out_buffer);
		
		return true;
		
	}