<commit_before>#include "pch.h"
#include "image.h"

struct read_data
{
    read_data(size_t ppos, const void* sourcedata, size_t buffersize)
        : ppos(ppos),
          sourcedata(sourcedata),
          buffersize(buffersize)
    {
    }

    size_t ppos;
    const void* sourcedata;
    const size_t buffersize;
};

struct write_data
{
    write_data() : ppos(0), buffersize(0)
    {
    }

    size_t ppos;
    std::vector<unsigned char> buffer;
    size_t buffersize;
};

int gifreadfunc(GifFileType *handle, GifByteType *destinationbuffer, int amount)
{
    auto rdata = reinterpret_cast<read_data*>(handle->UserData);
    auto& pos = rdata->ppos;
    auto buffersize = rdata->buffersize;
    auto sourcedata = rdata->sourcedata;

    auto src = reinterpret_cast<const unsigned char*>(sourcedata);
    auto dst = reinterpret_cast<unsigned char*>(destinationbuffer);

    auto remain = buffersize - pos;
    auto willread = remain < amount ? remain : amount;

    auto err = memcpy_s(dst, willread, src + pos, willread);
    if (err) throw std::system_error(err, std::system_category());

    pos += willread;
    return static_cast<int>(willread);
}

void png_error(png_structp png, png_const_charp msg)
{
    throw std::runtime_error(msg);
}

void png_warning(png_structp png, png_const_charp msg)
{
}

void png_write(png_structp png, png_bytep buffer, png_size_t amt)
{
    auto ioptr = png_get_io_ptr(png);
    auto& obuffer = *reinterpret_cast<std::vector<unsigned char>*>(ioptr);

    obuffer.insert(obuffer.end(), buffer, buffer + amt);
}

void png_read(png_structp png, png_bytep buffer, png_size_t amt)
{

}

void png_flush(png_structp png)
{
    
}

typedef GifFileType *PGifFileType;
void closegif(PGifFileType &pgif)
{
    int error;
    auto rclose = DGifCloseFile(pgif, &error);
    if (rclose == GIF_ERROR) throw std::runtime_error(std::string("error decoding gif: ") + GifErrorString(error));
    pgif = nullptr;
}

void throwgiferror(PGifFileType &pgif)
{
    closegif(pgif);
    throw std::runtime_error(std::string("error decoding gif: ") + GifErrorString(pgif->Error));
}

void blit(const unsigned char* src, int w, int h, unsigned char* dst, int dw, int dh, int top, int left, const GifColorType* colormap, int transparent_color_index)
{
    GifColorType* cdst = reinterpret_cast<GifColorType*>(dst);

    for(int y = 0;y<h;++y)
    {
        for(int x=0;x<w;++x)
        {
            auto spixel = src[y*w + x];
            auto scolor = colormap[spixel];

            if (static_cast<int>(spixel) != transparent_color_index)
            {
                cdst[(y + top)*dw + x + left] = scolor;
            }
        }
    }
}

image image::from_gif(const void* sourcedata, size_t buffersize)
{
    read_data rdata{ 0, sourcedata, buffersize };
    int error;
    auto pgif = DGifOpen(&rdata, gifreadfunc, &error);
    if (!pgif) throw std::runtime_error(std::string("error decoding gif: ") + GifErrorString(error));

    auto rslurp = DGifSlurp(pgif);
    if (rslurp == GIF_ERROR) throwgiferror(pgif);

    auto frames = pgif->ImageCount;
    auto w = pgif->SWidth;
    auto h = pgif->SHeight;
    image result(w, h, frames);
    auto framesize = w * h * 3;
    GraphicsControlBlock gcb;

    for(auto i=0;i<frames;++i)
    {
        bool first = i == 0;
        auto sframe = pgif->SavedImages[i];
        auto cframe = result.get_frame_ptr(i);
        auto pframe = !first ? result.get_frame_ptr(i - 1) : nullptr;
        auto colormap = sframe.ImageDesc.ColorMap
            ? sframe.ImageDesc.ColorMap
            : pgif->SColorMap;

        DGifSavedExtensionToGCB(pgif, i, &gcb);

        if(!first)
        {
            memcpy_s(cframe, framesize, pframe, framesize);
        }

        blit(sframe.RasterBits,
            sframe.ImageDesc.Width,
            sframe.ImageDesc.Height,
            cframe,
            w, h,
            sframe.ImageDesc.Top,
            sframe.ImageDesc.Left,
            colormap->Colors,
            gcb.TransparentColor);
    }

    closegif(pgif);

    return result;
}<commit_msg>Some optimizations to gif decoding<commit_after>#include "pch.h"
#include "image.h"

struct read_data
{
    read_data(size_t ppos, const void* sourcedata, size_t buffersize)
        : ppos(ppos),
          sourcedata(sourcedata),
          buffersize(buffersize)
    {
    }

    size_t ppos;
    const void* sourcedata;
    const size_t buffersize;
};

struct write_data
{
    write_data() : ppos(0), buffersize(0)
    {
    }

    size_t ppos;
    std::vector<unsigned char> buffer;
    size_t buffersize;
};

int gifreadfunc(GifFileType *handle, GifByteType *destinationbuffer, int amount)
{
    auto rdata = reinterpret_cast<read_data*>(handle->UserData);
    auto& pos = rdata->ppos;
    auto buffersize = rdata->buffersize;
    auto sourcedata = rdata->sourcedata;

    auto src = reinterpret_cast<const unsigned char*>(sourcedata);
    auto dst = reinterpret_cast<unsigned char*>(destinationbuffer);

    auto remain = buffersize - pos;
    auto willread = remain < amount ? remain : amount;

    auto err = memcpy_s(dst, willread, src + pos, willread);
    if (err) throw std::system_error(err, std::system_category());

    pos += willread;
    return static_cast<int>(willread);
}

void png_error(png_structp png, png_const_charp msg)
{
    throw std::runtime_error(msg);
}

void png_warning(png_structp png, png_const_charp msg)
{
}

void png_write(png_structp png, png_bytep buffer, png_size_t amt)
{
    auto ioptr = png_get_io_ptr(png);
    auto& obuffer = *reinterpret_cast<std::vector<unsigned char>*>(ioptr);

    obuffer.insert(obuffer.end(), buffer, buffer + amt);
}

void png_read(png_structp png, png_bytep buffer, png_size_t amt)
{

}

void png_flush(png_structp png)
{
    
}

typedef GifFileType *PGifFileType;
void closegif(PGifFileType &pgif)
{
    int error;
    auto rclose = DGifCloseFile(pgif, &error);
    if (rclose == GIF_ERROR) throw std::runtime_error(std::string("error decoding gif: ") + GifErrorString(error));
    pgif = nullptr;
}

void throwgiferror(PGifFileType &pgif)
{
    closegif(pgif);
    throw std::runtime_error(std::string("error decoding gif: ") + GifErrorString(pgif->Error));
}

void blit(const unsigned char* src, int w, int h, unsigned char* dst, int dw, int dh, int top, int left, const GifColorType* colormap, int transparent_color_index)
{
    GifColorType* cdst = reinterpret_cast<GifColorType*>(dst);

    for(int y = 0;y<h;++y)
    {
        for(int x=0;x<w;++x)
        {
            auto spixel = src[y*w + x];
            auto scolor = colormap[spixel];

            if (static_cast<int>(spixel) != transparent_color_index)
            {
                cdst[(y + top)*dw + x + left] = scolor;
            }
        }
    }
}

image image::from_gif(const void* sourcedata, size_t buffersize)
{
    read_data rdata{ 0, sourcedata, buffersize };
    int error;
    auto pgif = DGifOpen(&rdata, gifreadfunc, &error);
    if (!pgif) throw std::runtime_error(std::string("error decoding gif: ") + GifErrorString(error));

    auto rslurp = DGifSlurp(pgif);
    if (rslurp == GIF_ERROR) throwgiferror(pgif);

    auto frames = pgif->ImageCount;
    auto w = pgif->SWidth;
    auto h = pgif->SHeight;
    image result(w, h, frames);
    auto framesize = w * h * 3;
    GraphicsControlBlock gcb;

    for(auto i=0;i<frames;++i)
    {
        bool first = i == 0;
        const auto& source_image = pgif->SavedImages[i];
        const auto& image_desc = source_image.ImageDesc;
        auto pdestination_frame = result.get_frame_ptr(i);
        auto pprevious_frame = !first ? result.get_frame_ptr(i - 1) : nullptr;
        auto colormap = source_image.ImageDesc.ColorMap
            ? source_image.ImageDesc.ColorMap
            : pgif->SColorMap;

        DGifSavedExtensionToGCB(pgif, i, &gcb);

        if (!first && (
            image_desc.Top != 0 ||
            image_desc.Left != 0 ||
            image_desc.Width != w ||
            image_desc.Height != h))
        {
            memcpy_s(pdestination_frame, framesize, pprevious_frame, framesize);
        }

        blit(source_image.RasterBits,
            source_image.ImageDesc.Width,
            source_image.ImageDesc.Height,
            pdestination_frame,
            w, h,
            source_image.ImageDesc.Top,
            source_image.ImageDesc.Left,
            colormap->Colors,
            gcb.TransparentColor);
    }

    closegif(pgif);

    return result;
}
{'fraction_non_alphanumeric': 0.11871227364185111, 'fraction_numerical': 0.0023671440407148775, 'mean_word_length': 2.9302325581395348, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6358503', 'n_tokens_mistral': 3009, 'n_tokens_neox': 2878, 'n_words': 628}