Ticket #12207: 0001-12207-render-hvif-icon-files-as-png.patch

File 0001-12207-render-hvif-icon-files-as-png.patch, 8.9 KB (added by apl-haiku, 4 years ago)
  • src/tools/Jamfile

    From 976777bc74689ff66bfcbbf38d17fb712663a4bc Mon Sep 17 00:00:00 2001
    From: Andrew Lindesay <apl@lindesay.co.nz>
    Date: Wed, 15 Jul 2015 00:00:59 +1200
    Subject: [PATCH] 12207 - render hvif icon files as png
    
    ---
     src/tools/Jamfile               |   1 +
     src/tools/hvif2png/Jamfile      |  11 ++
     src/tools/hvif2png/hvif2png.cpp | 350 ++++++++++++++++++++++++++++++++++++++++
     3 files changed, 362 insertions(+)
     create mode 100644 src/tools/hvif2png/Jamfile
     create mode 100644 src/tools/hvif2png/hvif2png.cpp
    
    diff --git a/src/tools/Jamfile b/src/tools/Jamfile
    index 2ef9e60..ba76c0f 100644
    a b SubInclude HAIKU_TOP src tools translation ; 
    111111SubInclude HAIKU_TOP src tools unflatten ;
    112112SubInclude HAIKU_TOP src tools unzip ;
    113113SubInclude HAIKU_TOP src tools update_package_requires ;
     114SubInclude HAIKU_TOP src tools hvif2png ;
    114115SubInclude HAIKU_TOP src tools vmdkimage ;
    115116SubInclude HAIKU_TOP src tools zip ;
  • new file src/tools/hvif2png/Jamfile

    diff --git a/src/tools/hvif2png/Jamfile b/src/tools/hvif2png/Jamfile
    new file mode 100644
    index 0000000..10b698c
    - +  
     1SubDir HAIKU_TOP src tools hvif2png ;
     2
     3UsePrivateBuildHeaders shared ;
     4
     5USES_BE_API on <build>hvif2png = true ;
     6
     7BuildPlatformMain <build>hvif2png :
     8    hvif2png.cpp
     9    :
     10    $(HOST_LIBBE) $(HOST_LIBROOT) png
     11;
  • new file src/tools/hvif2png/hvif2png.cpp

    diff --git a/src/tools/hvif2png/hvif2png.cpp b/src/tools/hvif2png/hvif2png.cpp
    new file mode 100644
    index 0000000..1f5a09f
    - +  
     1/*
     2 * Copyright 2015 Haiku, Inc. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Authors:
     6 *      Andrew Lindesay
     7 */
     8
     9
     10// This command line program was created in order to be able to render
     11// HVIF files and then save the resultant bitmap into a PNG image file.
     12// The tool can be compiled for linux and was initially created for
     13// use with the Haiku Depot Server application server so that it was
     14// able to render HVIFs in the web page.
     15
     16
     17#include <stdio.h>
     18#include <string.h>
     19#include <unistd.h>
     20#include <stdlib.h>
     21
     22#include <png.h>
     23
     24#include "InterfaceDefs.h"
     25#include "Bitmap.h"
     26#include "SupportDefs.h"
     27#include "IconUtils.h"
     28
     29
     30#define SIZE_HVIF_BUFFER_STEP 1024
     31
     32
     33typedef struct h2p_hvif_buffer {
     34    uint8 *buffer;
     35    size_t used;
     36    size_t allocated;
     37} h2p_hvif_buffer;
     38
     39
     40typedef struct h2p_parameters {
     41    int size;
     42    char *in_filename;
     43    char *out_filename;
     44} h2p_parameters;
     45
     46
     47typedef struct h2p_state {
     48    FILE *in;
     49    FILE *out;
     50    BBitmap *bitmap;
     51    h2p_hvif_buffer hvif_buffer;
     52    h2p_parameters params;
     53} h2p_state;
     54
     55
     56static int
     57h2p_fprintsyntax(FILE *stream) {
     58        return fprintf(stream, "syntax: hvif2png -s <size> [-i <input-file>] [-o <output-file>]\n");
     59}
     60
     61
     62static void
     63h2p_close_state(h2p_state *state) {
     64    if (NULL != state->hvif_buffer.buffer) {
     65        free(state->hvif_buffer.buffer);
     66    }
     67
     68    if (NULL != state->in) {
     69        fclose(state->in);
     70    }
     71
     72    if (NULL != state->out) {
     73        fclose(state->out);
     74    }
     75}
     76
     77
     78/*
     79Returns 0 if there was some problem in opening the streams; otherwise non-zero.
     80*/
     81
     82static int
     83h2p_open_streams(h2p_state *state) {
     84    if (NULL != state->params.in_filename) {
     85        state->in = fopen(state->params.in_filename, "rb");
     86
     87        if (NULL == state->in) {
     88            fprintf(stderr, "unable to open the input file; '%s'\n", state->params.in_filename);
     89        }
     90    } else {
     91        state->in = stdin;
     92    }
     93
     94    if (NULL != state->params.out_filename) {
     95        state->out = fopen(state->params.out_filename, "wb");
     96
     97        if (NULL == state->out) {
     98            fprintf(stderr, "unable to open the output file; '%s'\n", state->params.out_filename);
     99        }
     100    } else {
     101        state->out = stdout;
     102    }
     103
     104    if (NULL != state->out && NULL!=state->in) {
     105        return 1;
     106    }
     107
     108    return 0;
     109}
     110
     111
     112static int
     113h2p_write_png(BBitmap *bitmap, FILE *out) {
     114
     115    int result = 0;
     116    png_structp png_ptr = NULL;
     117    png_infop info_ptr = NULL;
     118
     119    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
     120
     121    if (NULL == png_ptr) {
     122        fprintf(stderr, "unable to setup png write data structures\n");
     123    } else {
     124
     125        png_init_io(png_ptr, out);
     126        info_ptr = png_create_info_struct(png_ptr);
     127
     128        if (NULL == info_ptr) {
     129            fprintf(stderr, "unable to setup png info data structures\n");
     130        } else {
     131            BRect rect = bitmap->Bounds();
     132            png_uint_32 width = (png_uint_32) rect.Width()+1;
     133            png_uint_32 height = (png_uint_32) rect.Height()+1;
     134
     135            png_set_IHDR(
     136                png_ptr, info_ptr, width, height,
     137                8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
     138                PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
     139
     140            png_set_bgr(png_ptr);
     141
     142            png_write_info(png_ptr, info_ptr);
     143
     144            uint8 *bitmap_data = (uint8 *) bitmap->Bits();
     145            int32 bitmap_bytes_per_row = bitmap->BytesPerRow();
     146
     147            for (png_uint_32 i = 0; i < height;i++) {
     148                png_write_row(png_ptr, (png_bytep) &bitmap_data[i * bitmap_bytes_per_row]);
     149            }
     150
     151            png_write_end(png_ptr, NULL);
     152
     153            result = 1;
     154        }
     155    }
     156
     157    if (NULL != info_ptr) {
     158        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
     159    }
     160
     161    if (NULL != png_ptr) {
     162        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
     163    }
     164
     165    return result;
     166}
     167
     168
     169/*
     170This function will return the quantity of bytes that were read from the HVIF file or 0
     171if there was a problem reading the HVIF data.
     172*/
     173
     174static size_t
     175h2p_read_hvif_input(h2p_hvif_buffer *result, FILE *in) {
     176    result->buffer = (uint8 *) malloc(SIZE_HVIF_BUFFER_STEP); // hvifs are typically quite small.
     177    result->allocated = SIZE_HVIF_BUFFER_STEP;
     178    result->used = 0;
     179
     180    if (NULL == result->buffer) {
     181        fprintf(stderr,"out of memory\n");
     182        return 0;
     183    }
     184
     185    while (!feof(in)) {
     186        if (result->used == result->allocated) {
     187            result->buffer = (uint8 *) realloc(
     188                result->buffer,
     189                result->allocated + SIZE_HVIF_BUFFER_STEP);
     190
     191            if (NULL == result->buffer) {
     192                fprintf(stderr,"out of memory\n");
     193                return 0;
     194            }
     195        }
     196
     197        result->used += fread(
     198            &result->buffer[result->used],
     199            sizeof(uint8),
     200            result->allocated - result->used, in);
     201
     202        int err = ferror(in);
     203
     204        if (0 != err) {
     205            fprintf(stderr, "error reading input; %s\n", strerror(err));
     206            return 0;
     207        }
     208    }
     209
     210    return result->used;
     211}
     212
     213
     214/*
     215Returns 0 if there was a problem reading the parameters and non-zero otherwise.
     216*/
     217
     218static int
     219h2p_parse_args(h2p_parameters *result, int argc, char *argv[]) {
     220
     221    for (int i = 1;i < argc;) {
     222
     223        if ('-' != argv[i][0]) {
     224            fprintf(stderr, "was expecting a switch; found '%s'\n",argv[i]);
     225            h2p_fprintsyntax(stderr);
     226            return 0;
     227        }
     228
     229        if (2 != strlen(argv[i])) {
     230            fprintf(stderr, "illegal switch; '%s'\n",argv[i]);
     231            h2p_fprintsyntax(stderr);
     232            return 0;
     233        }
     234
     235        switch (argv[i][1]) {
     236
     237            case 's':
     238               
     239                if (i == argc - 1) {
     240                    fprintf(stderr,"the size has not been specified\n");
     241                    h2p_fprintsyntax(stderr);
     242                    return 0;
     243                } 
     244
     245                result->size = atoi(argv[i + 1]);
     246
     247                if (result->size <= 0 || result->size > 1024) {
     248                    fprintf(stderr,"bad size specified; '%s'\n", argv[i]);
     249                    h2p_fprintsyntax(stderr);
     250                    return 0;
     251                }
     252
     253                i+=2;
     254
     255                break;
     256
     257            case 'i':
     258
     259                if (i == argc - 1) {
     260                    fprintf(stderr,"the input filename has not been specified\n");
     261                    h2p_fprintsyntax(stderr);
     262                    return 0;
     263                }
     264
     265                result->in_filename = argv[i + 1];
     266                i+=2;
     267                break;
     268
     269            case 'o':
     270
     271                if (i == argc - 1) {
     272                    fprintf(stderr,"the output filename has not been specified\n");
     273                    h2p_fprintsyntax(stderr);
     274                    return 0;
     275                }
     276
     277                result->out_filename = argv[i + 1];
     278                i += 2;
     279                break;
     280
     281            default:
     282                fprintf(stderr, "unrecognized switch; '%s'\n", argv[i]);
     283                h2p_fprintsyntax(stderr);
     284                return 0;
     285        }
     286
     287    }
     288
     289    if (0 == result->size) {
     290        fprintf(stderr, "size has not been specified\n");
     291        h2p_fprintsyntax(stderr);
     292        return 0;
     293    }
     294 
     295    return 1;
     296}
     297
     298
     299int main(int argc, char *argv[]) {
     300
     301    int exit_result = 1;
     302
     303    if (1 == argc) {
     304        h2p_fprintsyntax(stderr);
     305    } else {
     306
     307        h2p_state state;
     308        bzero(&state, sizeof(state));
     309
     310        if (h2p_parse_args(&(state.params), argc, argv)) {
     311
     312            if (h2p_open_streams(&state)) {
     313
     314                if (h2p_read_hvif_input(&(state.hvif_buffer), state.in) > 0) {
     315
     316                    // create the bitmap and then parse and render the HVIF icon data into
     317                    // the bitmap.
     318
     319                    state.bitmap = new BBitmap(
     320                        BRect(0.0, 0.0, state.params.size - 1, state.params.size - 1),
     321                        B_RGBA32); // actual storage is BGRA
     322
     323                    status_t gvi_status = BIconUtils::GetVectorIcon(
     324                        state.hvif_buffer.buffer,
     325                        state.hvif_buffer.used,
     326                        state.bitmap);
     327
     328                    if (B_OK != gvi_status) {
     329                        fprintf(stderr, "the hvif data (%zdB) was not able to be parsed / rendered\n", state.hvif_buffer.used);
     330                    } else {
     331
     332                        // write the bitmap data out again as a PNG.
     333
     334                        if (h2p_write_png(state.bitmap, state.out)) {
     335                            exit_result = 0;
     336                        }
     337
     338                    }
     339                }
     340
     341            }
     342        }
     343
     344        // clean up
     345        h2p_close_state(&state);
     346    }
     347
     348    return exit_result;
     349
     350}