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

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

    From f09fa217fd46d7427d365a745747c34a1d2c734d 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 | 363 ++++++++++++++++++++++++++++++++++++++++
     3 files changed, 375 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..22de36c 100644
    a b SubInclude HAIKU_TOP src tools fs_shell ;  
    9797SubInclude HAIKU_TOP src tools gensyscalls ;
    9898SubInclude HAIKU_TOP src tools get_package_dependencies ;
    9999SubInclude HAIKU_TOP src tools hack_coff ;
     100SubInclude HAIKU_TOP src tools hvif2png ;
    100101SubInclude HAIKU_TOP src tools keymap ;
    101102SubInclude HAIKU_TOP src tools locale ;
    102103SubInclude HAIKU_TOP src tools makebootable ;
  • 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..66d1f8e
    - +  
     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#include <stdio.h>
     17#include <stdlib.h>
     18#include <string.h>
     19#include <unistd.h>
     20
     21#include <png.h>
     22
     23#include "AutoDeleter.h"
     24#include "Bitmap.h"
     25#include "IconUtils.h"
     26#include "InterfaceDefs.h"
     27#include "SupportDefs.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{
     59        return fprintf(
     60            stream,
     61            "syntax: hvif2png -s <size> [-i <input-file>] [-o <output-file>]\n");
     62}
     63
     64
     65static void
     66h2p_close_state(h2p_state* state)
     67{
     68    if (state->hvif_buffer.buffer != NULL)
     69        free(state->hvif_buffer.buffer);
     70
     71    if (state->in != NULL)
     72        fclose(state->in);
     73
     74    if (state->out != NULL)
     75        fclose(state->out);
     76}
     77
     78
     79static void fclose_quietly(FILE** f) {
     80    fclose(*f);
     81}
     82
     83
     84/*! Opens the input and output streams for the conversion
     85    \return 0 if there was some problem in opening the streams; otherwise
     86        non-zero.
     87*/
     88
     89static int
     90h2p_open_streams(h2p_state* state)
     91{
     92    if (state->params.in_filename != NULL)
     93        state->in = fopen(state->params.in_filename, "rb");
     94    else
     95        state->in = stdin;
     96
     97    if (state->in == NULL) {
     98        fprintf(
     99            stderr,
     100            "unable to open the input file; '%s'\n",
     101            state->params.in_filename);
     102        return 0;
     103    }
     104
     105    CObjectDeleter<FILE *> inDeleter(&(state->in), fclose_quietly);
     106
     107    if (state->params.out_filename != NULL)
     108        state->out = fopen(state->params.out_filename, "wb");
     109    else
     110        state->out = stdout;
     111
     112    if (state->out == NULL) {
     113        fprintf(
     114            stderr,
     115            "unable to open the output file; '%s'\n",
     116            state->params.out_filename);
     117        return 0;
     118    }
     119
     120    inDeleter.Detach();
     121
     122    return 1;
     123}
     124
     125
     126static int
     127h2p_write_png(BBitmap* bitmap, FILE* out)
     128{
     129    int result = 0;
     130
     131    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
     132
     133    if (png == NULL)
     134        fprintf(stderr, "unable to setup png write data structures\n");
     135    else {
     136
     137        png_init_io(png, out);
     138        png_infop info = png_create_info_struct(png);
     139
     140        if (info == NULL)
     141            fprintf(stderr, "unable to setup png info data structures\n");
     142        else {
     143            BRect rect = bitmap->Bounds();
     144            png_uint_32 width = (png_uint_32) rect.Width()+1;
     145            png_uint_32 height = (png_uint_32) rect.Height()+1;
     146
     147            png_set_IHDR(
     148                png, info, width, height,
     149                8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
     150                PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
     151
     152            png_set_bgr(png);
     153
     154            png_write_info(png, info);
     155
     156            uint8 *bitmapData = (uint8 *)bitmap->Bits();
     157            int32 bitmapBytesPerRow = bitmap->BytesPerRow();
     158
     159            for (png_uint_32 i = 0; i < height;i++) {
     160                png_write_row(
     161                    png,
     162                    (png_bytep)&bitmapData[i * bitmapBytesPerRow]);
     163            }
     164
     165            png_write_end(png, NULL);
     166
     167            result = 1;
     168        }
     169
     170        if (info != NULL)
     171            png_free_data(png, info, PNG_FREE_ALL, -1);
     172    }
     173
     174    if (png != NULL)
     175        png_destroy_write_struct(&png, (png_infopp)NULL);
     176
     177    return result;
     178}
     179
     180
     181/*! Reads the HVIF input data from the supplied input file.
     182    \return the quantity of bytes that were read from the
     183        HVIF file or 0 if there was a problem reading the HVIF data.
     184*/
     185
     186static size_t
     187h2p_read_hvif_input(h2p_hvif_buffer* result, FILE* in)
     188{
     189    result->buffer = (uint8 *)malloc(SIZE_HVIF_BUFFER_STEP);
     190    result->allocated = SIZE_HVIF_BUFFER_STEP;
     191    result->used = 0;
     192
     193    if (result->buffer == NULL) {
     194        fprintf(stderr,"out of memory\n");
     195        return 0;
     196    }
     197
     198    while (!feof(in)) {
     199        if (result->used == result->allocated) {
     200            result->buffer = (uint8 *)realloc(
     201                result->buffer,
     202                result->allocated + SIZE_HVIF_BUFFER_STEP);
     203
     204            if (result->buffer == NULL) {
     205                fprintf(stderr,"out of memory\n");
     206                return 0;
     207            }
     208        }
     209
     210        result->used += fread(
     211            &result->buffer[result->used],
     212            sizeof(uint8),
     213            result->allocated - result->used, in);
     214
     215        int err = ferror(in);
     216
     217        if (err != 0) {
     218            fprintf(stderr, "error reading input; %s\n", strerror(err));
     219            return 0;
     220        }
     221    }
     222
     223    return result->used;
     224}
     225
     226
     227/*! Parse the arguments to the conversion program from the command line.
     228        \return 0 if there was a problem reading the parameters and non-zero
     229        otherwise.
     230*/
     231
     232static int
     233h2p_parse_args(h2p_parameters* result, int argc, char* argv[])
     234{
     235    for (int i = 1;i < argc;) {
     236
     237        if (argv[i][0] != '-') {
     238            fprintf(stderr, "was expecting a switch; found '%s'\n",argv[i]);
     239            h2p_fprintsyntax(stderr);
     240            return 0;
     241        }
     242
     243        if (strlen(argv[i]) != 2) {
     244            fprintf(stderr, "illegal switch; '%s'\n",argv[i]);
     245            h2p_fprintsyntax(stderr);
     246            return 0;
     247        }
     248
     249        switch (argv[i][1]) {
     250
     251            case 's':
     252                if (i == argc - 1) {
     253                    fprintf(stderr,"the size has not been specified\n");
     254                    h2p_fprintsyntax(stderr);
     255                    return 0;
     256                } 
     257
     258                result->size = atoi(argv[i + 1]);
     259
     260                if (result->size <= 0 || result->size > 1024) {
     261                    fprintf(stderr,"bad size specified; '%s'\n", argv[i]);
     262                    h2p_fprintsyntax(stderr);
     263                    return 0;
     264                }
     265
     266                i+=2;
     267
     268                break;
     269
     270            case 'i':
     271                if (i == argc - 1) {
     272                    fprintf(stderr,"the input filename has not been specified\n");
     273                    h2p_fprintsyntax(stderr);
     274                    return 0;
     275                }
     276
     277                result->in_filename = argv[i + 1];
     278                i+=2;
     279                break;
     280
     281            case 'o':
     282
     283                if (i == argc - 1) {
     284                    fprintf(stderr,"the output filename has not been specified\n");
     285                    h2p_fprintsyntax(stderr);
     286                    return 0;
     287                }
     288
     289                result->out_filename = argv[i + 1];
     290                i += 2;
     291                break;
     292
     293            default:
     294                fprintf(stderr, "unrecognized switch; '%s'\n", argv[i]);
     295                h2p_fprintsyntax(stderr);
     296                return 0;
     297        }
     298
     299    }
     300
     301    if (result->size == 0) {
     302        fprintf(stderr, "size has not been specified\n");
     303        h2p_fprintsyntax(stderr);
     304        return 0;
     305    }
     306 
     307    return 1;
     308}
     309
     310
     311int
     312main(int argc, char* argv[])
     313{
     314    int exitResult = 1;
     315
     316    if (argc == 1)
     317        h2p_fprintsyntax(stderr);
     318    else {
     319
     320        h2p_state state;
     321        bzero(&state, sizeof(state));
     322
     323        if (h2p_parse_args(&(state.params), argc, argv)) {
     324
     325            if (h2p_open_streams(&state)) {
     326
     327                if (h2p_read_hvif_input(&(state.hvif_buffer), state.in) > 0) {
     328
     329                    // create the bitmap and then parse and render the HVIF icon data
     330                    // into the bitmap.
     331
     332                    state.bitmap = new BBitmap(
     333                        BRect(0.0, 0.0, state.params.size - 1, state.params.size - 1),
     334                        B_RGBA32); // actual storage is BGRA
     335
     336                    status_t gviStatus = BIconUtils::GetVectorIcon(
     337                        state.hvif_buffer.buffer,
     338                        state.hvif_buffer.used,
     339                        state.bitmap);
     340
     341                    if (gviStatus != B_OK) {
     342                        fprintf(
     343                            stderr,
     344                            "the hvif data (%zdB) was not able to be parsed / rendered\n",
     345                            state.hvif_buffer.used);
     346                    }
     347                    else {
     348                        // write the bitmap data out again as a PNG.
     349                        if (h2p_write_png(state.bitmap, state.out))
     350                            exitResult = 0;
     351                    }
     352                }
     353
     354            }
     355        }
     356
     357        // clean up
     358        h2p_close_state(&state);
     359    }
     360
     361    return exitResult;
     362
     363}