<commit_before>#include "writer.h"
#include "octree.h"


void Blend_WritePNG(png_structp png_ptr, png_bytep data, png_size_t length) {
    BlendBaton* baton = (BlendBaton*)png_get_io_ptr(png_ptr);

    if (baton->result == NULL || baton->max < baton->length + length) {
        int increase = baton->length ? 4 * length : 32768;
        baton->result = (unsigned char*)realloc(baton->result, baton->max + increase);
        baton->max += increase;
    }

    // TODO: implement OOM check
    assert(baton->result);

    memcpy(baton->result + baton->length, data, length);
    baton->length += length;
}

void Blend_EncodePNG(unsigned const char* source, BlendBaton* baton,
                     unsigned long width, unsigned long height, bool alpha) {
    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_compression_level(png_ptr, Z_BEST_SPEED);
    png_set_compression_buffer_size(png_ptr, 32768);

    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
                 alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);

    png_bytep row_pointers[height];
    for (unsigned i = 0; i < height; i++) {
        row_pointers[i] = (png_bytep)(source + (4 * width * i));
    }
    png_set_rows(png_ptr, info_ptr, (png_bytepp)&row_pointers);
    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);

    png_set_write_fn(png_ptr, (png_voidp)baton, Blend_WritePNG, NULL);
    png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_FILLER_AFTER, NULL);
    png_destroy_write_struct(&png_ptr, &info_ptr);
}



#define MAX_OCTREE_LEVELS 4

void Blend_ReduceColors(unsigned const char* source, unsigned long width,
                        unsigned long height, unsigned char* out,
                        octree<rgb> trees[], unsigned limits[], unsigned levels,
                        std::vector<unsigned> & alpha) {
    std::vector<unsigned> alphaCount(alpha.size());
    for (unsigned i = 0; i < alpha.size(); i++) {
        alpha[i] = 0;
        alphaCount[i] = 0;
    }

    for (unsigned y = 0; y < height; ++y) {
        unsigned const char* row = &(source[y * 4 * width]);
        unsigned char* row_out = &(out[y * width]);
        for (unsigned x = 0; x < width; ++x) {
            unsigned const char* val = &row[x * 4];
            rgb c(val[0], val[1], val[2]);
            byte index = 0;
            int idx = -1;
            for (int j = levels - 1; j > 0; j--) {
                if (val[3] >= limits[j] && trees[j].colors() > 0) {
                    index = idx = trees[j].quantize(c);
                    break;
                }
            }
            if (idx >= 0 && idx < (int)alpha.size()) {
                alpha[idx] += val[3];
                alphaCount[idx]++;
            }

            row_out[x] = index;
        }
    }
    for (unsigned i = 0; i < alpha.size(); i++) {
        if (alphaCount[i] != 0) {
            alpha[i] /= alphaCount[i];
        }
    }
}


void Blend_EncodePNG(unsigned const char* image, BlendBaton* baton,
                     unsigned long width, unsigned long height,
                     unsigned color_depth, std::vector<rgb> & palette,
                     std::vector<unsigned> &alpha) {
    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_compression_level(png_ptr, Z_BEST_SPEED);
    png_set_compression_buffer_size(png_ptr, 32768);

    png_set_IHDR(png_ptr, info_ptr, width, height, color_depth,
                 PNG_COLOR_TYPE_PALETTE,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);

    png_set_PLTE(png_ptr, info_ptr, reinterpret_cast<png_color*>(&palette[0]), palette.size());

    // make transparent lowest indexes, so tRNS is small
    if (alpha.size() > 0) {
        std::vector<png_byte> trans(alpha.size());
        unsigned alphaSize = 0; //truncate to nonopaque values
        for (unsigned i = 0; i < alpha.size(); i++) {
            trans[i] = alpha[i];
            if (alpha[i] < 255) {
                alphaSize = i + 1;
            }
        }
        if (alphaSize > 0) {
            png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0);
        }
    }

    png_set_write_fn(png_ptr, (png_voidp)baton, Blend_WritePNG, NULL);
    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);

    png_write_info(png_ptr, info_ptr);
    png_set_packing(png_ptr);

    for (int y = 0; y < height; y++) {
        png_write_row(png_ptr, (png_bytep)(image + (width * y)));<commit_msg>don't compare unsigned with signed numbers<commit_after>#include "writer.h"
#include "octree.h"


void Blend_WritePNG(png_structp png_ptr, png_bytep data, png_size_t length) {
    BlendBaton* baton = (BlendBaton*)png_get_io_ptr(png_ptr);

    if (baton->result == NULL || baton->max < baton->length + length) {
        int increase = baton->length ? 4 * length : 32768;
        baton->result = (unsigned char*)realloc(baton->result, baton->max + increase);
        baton->max += increase;
    }

    // TODO: implement OOM check
    assert(baton->result);

    memcpy(baton->result + baton->length, data, length);
    baton->length += length;
}

void Blend_EncodePNG(unsigned const char* source, BlendBaton* baton,
                     unsigned long width, unsigned long height, bool alpha) {
    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_compression_level(png_ptr, Z_BEST_SPEED);
    png_set_compression_buffer_size(png_ptr, 32768);

    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
                 alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);

    png_bytep row_pointers[height];
    for (unsigned i = 0; i < height; i++) {
        row_pointers[i] = (png_bytep)(source + (4 * width * i));
    }
    png_set_rows(png_ptr, info_ptr, (png_bytepp)&row_pointers);
    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);

    png_set_write_fn(png_ptr, (png_voidp)baton, Blend_WritePNG, NULL);
    png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_FILLER_AFTER, NULL);
    png_destroy_write_struct(&png_ptr, &info_ptr);
}



#define MAX_OCTREE_LEVELS 4

void Blend_ReduceColors(unsigned const char* source, unsigned long width,
                        unsigned long height, unsigned char* out,
                        octree<rgb> trees[], unsigned limits[], unsigned levels,
                        std::vector<unsigned> & alpha) {
    std::vector<unsigned> alphaCount(alpha.size());
    for (unsigned i = 0; i < alpha.size(); i++) {
        alpha[i] = 0;
        alphaCount[i] = 0;
    }

    for (unsigned y = 0; y < height; ++y) {
        unsigned const char* row = &(source[y * 4 * width]);
        unsigned char* row_out = &(out[y * width]);
        for (unsigned x = 0; x < width; ++x) {
            unsigned const char* val = &row[x * 4];
            rgb c(val[0], val[1], val[2]);
            byte index = 0;
            int idx = -1;
            for (int j = levels - 1; j > 0; j--) {
                if (val[3] >= limits[j] && trees[j].colors() > 0) {
                    index = idx = trees[j].quantize(c);
                    break;
                }
            }
            if (idx >= 0 && idx < (int)alpha.size()) {
                alpha[idx] += val[3];
                alphaCount[idx]++;
            }

            row_out[x] = index;
        }
    }
    for (unsigned i = 0; i < alpha.size(); i++) {
        if (alphaCount[i] != 0) {
            alpha[i] /= alphaCount[i];
        }
    }
}


void Blend_EncodePNG(unsigned const char* image, BlendBaton* baton,
                     unsigned long width, unsigned long height,
                     unsigned color_depth, std::vector<rgb> & palette,
                     std::vector<unsigned> &alpha) {
    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_compression_level(png_ptr, Z_BEST_SPEED);
    png_set_compression_buffer_size(png_ptr, 32768);

    png_set_IHDR(png_ptr, info_ptr, width, height, color_depth,
                 PNG_COLOR_TYPE_PALETTE,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);

    png_set_PLTE(png_ptr, info_ptr, reinterpret_cast<png_color*>(&palette[0]), palette.size());

    // make transparent lowest indexes, so tRNS is small
    if (alpha.size() > 0) {
        std::vector<png_byte> trans(alpha.size());
        unsigned alphaSize = 0; //truncate to nonopaque values
        for (unsigned i = 0; i < alpha.size(); i++) {
            trans[i] = alpha[i];
            if (alpha[i] < 255) {
                alphaSize = i + 1;
            }
        }
        if (alphaSize > 0) {
            png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0);
        }
    }

    png_set_write_fn(png_ptr, (png_voidp)baton, Blend_WritePNG, NULL);
    png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);

    png_write_info(png_ptr, info_ptr);
    png_set_packing(png_ptr);

    for (unsigned int y = 0; y < height; y++) {
        png_write_row(png_ptr, (png_bytep)(image + (width * y)));
{'fraction_non_alphanumeric': 0.12213660974593919, 'fraction_numerical': 0.010828821324448146, 'mean_word_length': 2.4838592673195503, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 53, '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': '600110', 'n_tokens_mistral': 3451, 'n_tokens_neox': 3215, 'n_words': 687}