~fabrixxm/zint-vapi

057a0fafe013c4360a5db5d429ae0d2dd919d42f — fabrixxm 3 years ago
First commit
A  => .gitignore +3 -0
@@ 1,3 @@
work/
*~
docs/

A  => Makefile +6 -0
@@ 1,6 @@
docs: libzint.vapi
	rm -fr docs/
	valadoc --profile=posix --package-name=Zint  -o docs libzint.vapi

clean:
	rm -fr docs/

A  => README.md +22 -0
@@ 1,22 @@
# Zint vapi

(Simple) Vapi file for [Zint library](http://www.zint.org.uk/Default.aspx)

## Docs

Official docs at http://www.zint.org.uk/Manual.aspx?type=p&page=5

To build Vala docs run

    make docs

## Tests and examples

    cd test
    make

`example_1` and `example_2` are Vala port of official docs sample code.

`example_3` loads the symbol bitmap in a GdkPixBuf and save it as jpeg.

`barcodeui` is a simple Gtk3 interface to generate barcodes.

A  => libzint.vapi +174 -0
@@ 1,174 @@
/*
 * zint vapi
 */
[CCode (cprefix="zint_", cheader_filename="zint.h")]
namespace Zint {
    [Compact, CCode(cname="struct zint_symbol", free_function="ZBarcode_Delete")]
    public class Symbol {
        public int symbology;
        public int height;
        public int whitespace_width;
        public int border_width;
        public int output_options;
        [CCode (array_length = false)]
        public weak char fgcolour[10];
        public weak string fgcolor;
        [CCode (array_length = false)]
        public weak char bgcolour[10];
        public weak string bgcolor;
        [CCode (array_length = false)]
        public weak char outfile[256];
        public float scale;
        public int option_1;
        public int option_2;
        public int option_3;
        public int show_hrt;
        public int fontsize;
        public int input_mode;
        public int eci;
        [CCode (array_length = false)]
        public weak uint8 text[128];
        public int rows;
        public int width;
        [CCode (array_length = false)]
        public weak char primary[128];
        [CCode (array_length = false)]
        public weak uint8 encoded_data[28600];
        [CCode (array_length_cname="rows")]
        public weak int row_height[200];
        public weak char errtxt[100];


        [CCode (array_length=false)]
        private uint8[] bitmap;
        public int bitmap_width;
        public int bitmap_height;
        [CCode (array_length=false)]
        private uint8[] alphamap;
        public float dot_size;
        public int debug;

        [CCode (cname = "__zbarcode_get_bitmap")]
        public uint8[] get_bitmap () {
            int len = 3 * bitmap_width * bitmap_height;
            unowned uint8[] tmp = bitmap[0:len];
            return tmp;
        }

        [CCode(cname="ZBarcode_Create")]
        public Symbol();
        
        [CCode(cname="ZBarcode_Encode")]
        public int encode([CCode(type="unsigned char*", array_lenght_type="int")] char[] input);
        
        [CCode (cname="ZBarcode_Encode_File")]
        public int encode_file(string filename);
        
        [CCode(cname="ZBarcode_Print")]
        public int print(int rotate_angle);
        
        [CCode(cname="ZBarcode_Buffer")]
        public int buffer(int rotate_angle);
    // /Symbol
    }

    [CCode (cname="int", cprefix="BARCODE_", type_id="G_TYPE_ENUM")]
    public enum Barcode {
        CODE11=1,
        C25MATRIX=2,
        C25INTER=3,
        C25IATA=4,
        C25LOGIC=6,
        C25IND=7,
        CODE39=8,
        EXCODE39=9,
        EANX=13,
        EANX_CHK=14,
        EAN128=16,
        CODABAR=18,
        CODE128=20,
        DPLEIT=21,
        DPIDENT=22,
        CODE16K=23,
        CODE49=24,
        CODE93=25,
        FLAT=28,
        RSS14=29,
        RSS_LTD=30,
        RSS_EXP=31,
        TELEPEN=32,
        UPCA=34,
        UPCA_CHK=35,
        UPCE=37,
        UPCE_CHK=38,
        POSTNET=40,
        MSI_PLESSEY=47,
        FIM=49,
        LOGMARS=50,
        PHARMA=51,
        PZN=52,
        PHARMA_TWO=53,
        PDF417=55,
        PDF417TRUNC=56,
        MAXICODE=57,
        QRCODE=58,
        CODE128B=60,
        AUSPOST=63,
        AUSREPLY=66,
        AUSROUTE=67,
        AUSREDIRECT=68,
        ISBNX=69,
        RM4SCC=70,
        DATAMATRIX=71,
        EAN14=72,
        VIN=73,
        CODABLOCKF=74,
        NVE18=75,
        JAPANPOST=76,
        KOREAPOST=77,
        RSS14STACK=79,
        RSS14STACK_OMNI=80,
        RSS_EXPSTACK=81,
        PLANET=82,
        MICROPDF417=84,
        ONECODE=85,
        PLESSEY=86,
        TELEPEN_NUM=87,
        ITF14=89,
        KIX=90,
        AZTEC=92,
        DAFT=93,
        MICROQR=97,
        HIBC_128=98,
        HIBC_39=99,
        HIBC_DM=102,
        HIBC_QR=104,
        HIBC_PDF=106,
        HIBC_MICPDF=108,
        HIBC_AZTEC=112,
        DOTCODE=115,
        HANXIN=116,
        MAILMARK=121,
        AZRUNE=128,
        CODE32=129,
        EANX_CC=130,
        EAN128_CC=131,
        RSS14_CC=132,
        RSS_LTD_CC=133,
        RSS_EXP_CC=134,
        UPCA_CC=135,
        UPCE_CC=136,
        RSS14STACK_CC=137,
        RSS14_OMNI_CC=138,
        RSS_EXPSTACK_CC=139,
        CHANNEL=140,
        CODEONE=141,
        GRIDMATRIX=142,
        UPNQR=143,
        ULTRA=144,
        RMQR=145,
    // /Barcode
    }
    
//namespace
}

A  => test/Makefile +27 -0
@@ 1,27 @@
SOURCES := $(wildcard *.vala)
EXES := $(patsubst %.vala,%,${SOURCES})

ZINTOPTS=--vapidir=.. --Xcc=-lzint --pkg=libzint

.PHONY: all clean

all: ${EXES}

%: %.vala ../libzint.vapi
	valac ${ZINTOPTS} -o $@ $<

example_3: example_3.vala ../libzint.vapi
	valac ${ZINTOPTS} --pkg=gdk-3.0 -o $@ $<

barcodeui_res.c: barcodeui_res.xml barcodeui.ui
	glib-compile-resources --generate-source barcodeui_res.xml

barcodeui: barcodeui.vala barcodeui_res.c ../libzint.vapi 
	valac ${ZINTOPTS} --pkg=gtk+-3.0 --pkg gmodule-2.0  --gresources barcodeui_res.xml --gresourcesdir=. -o $@ barcodeui_res.c $<



clean:
	rm -f ${EXES}
	rm -f out.png out.jpg
	rm -f barcodeui_res.c

A  => test/barcodeui.ui +462 -0
@@ 1,462 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
  <requires lib="gtk+" version="3.24"/>
  <object class="GtkListStore" id="barcodetypes">
    <columns>
      <!-- column-name id -->
      <column type="gchararray"/>
      <!-- column-name label -->
      <column type="gchararray"/>
    </columns>
    <data>
      <row>
        <col id="0">1</col>
        <col id="1">Code 11</col>
      </row>
      <row>
        <col id="0">2</col>
        <col id="1">Standard Code 2 of 5</col>
      </row>
      <row>
        <col id="0">3</col>
        <col id="1">Interleaved 2 of 5</col>
      </row>
      <row>
        <col id="0">4</col>
        <col id="1">Code 2 of 5 IATA</col>
      </row>
      <row>
        <col id="0">6</col>
        <col id="1">Code 2 of 5 Data Logic</col>
      </row>
      <row>
        <col id="0">7</col>
        <col id="1">Code 2 of 5 Industrial</col>
      </row>
      <row>
        <col id="0">8</col>
        <col id="1">Code 3 of 9 (Code 39)</col>
      </row>
      <row>
        <col id="0">9</col>
        <col id="1">Extended Code 3 of 9 (Code 39+)</col>
      </row>
      <row>
        <col id="0">13</col>
        <col id="1">EAN</col>
      </row>
      <row>
        <col id="0">14</col>
        <col id="1">EAN + Check Digit</col>
      </row>
      <row>
        <col id="0">16</col>
        <col id="1">GS1-128 (UCC.EAN-128)</col>
      </row>
      <row>
        <col id="0">18</col>
        <col id="1">Codabar</col>
      </row>
      <row>
        <col id="0">20</col>
        <col id="1">Code 128 (automatic subset switching)</col>
      </row>
      <row>
        <col id="0">21</col>
        <col id="1">Deutshe Post Leitcode</col>
      </row>
      <row>
        <col id="0">22</col>
        <col id="1">Deutshe Post Identcode</col>
      </row>
      <row>
        <col id="0">23</col>
        <col id="1">Code 16K</col>
      </row>
      <row>
        <col id="0">24</col>
        <col id="1">Code 49</col>
      </row>
      <row>
        <col id="0">25</col>
        <col id="1">Code 93</col>
      </row>
      <row>
        <col id="0">28</col>
        <col id="1">Flattermarken</col>
      </row>
      <row>
        <col id="0">29</col>
        <col id="1">GS1 DataBar-14</col>
      </row>
      <row>
        <col id="0">30</col>
        <col id="1">GS1 DataBar Limited</col>
      </row>
      <row>
        <col id="0">31</col>
        <col id="1">GS1 DataBar Extended</col>
      </row>
      <row>
        <col id="0">32</col>
        <col id="1">Telepen Alpha</col>
      </row>
      <row>
        <col id="0">34</col>
        <col id="1">UPC A</col>
      </row>
      <row>
        <col id="0">35</col>
        <col id="1">UPC A + Check Digit</col>
      </row>
      <row>
        <col id="0">37</col>
        <col id="1">UPC E</col>
      </row>
      <row>
        <col id="0">38</col>
        <col id="1">UPC E + Check Digit</col>
      </row>
      <row>
        <col id="0">40</col>
        <col id="1">PostNet</col>
      </row>
      <row>
        <col id="0">47</col>
        <col id="1">MSI Plessey</col>
      </row>
      <row>
        <col id="0">49</col>
        <col id="1">FIM</col>
      </row>
      <row>
        <col id="0">50</col>
        <col id="1">LOGMARS</col>
      </row>
      <row>
        <col id="0">51</col>
        <col id="1">Pharmacode One-Track</col>
      </row>
      <row>
        <col id="0">52</col>
        <col id="1">PZN</col>
      </row>
      <row>
        <col id="0">53</col>
        <col id="1">Pharmacode Two-Track</col>
      </row>
      <row>
        <col id="0">55</col>
        <col id="1">PDF417</col>
      </row>
      <row>
        <col id="0">56</col>
        <col id="1">PDF417 Truncated</col>
      </row>
      <row>
        <col id="0">57</col>
        <col id="1">Maxicode</col>
      </row>
      <row>
        <col id="0">58</col>
        <col id="1">QR Code</col>
      </row>
      <row>
        <col id="0">60</col>
        <col id="1">Code 128 (Subset B)</col>
      </row>
      <row>
        <col id="0">63</col>
        <col id="1">Australia Post Standard Customer</col>
      </row>
      <row>
        <col id="0">66</col>
        <col id="1">Australia Post Reply Paid</col>
      </row>
      <row>
        <col id="0">67</col>
        <col id="1">Australia Post Routing</col>
      </row>
      <row>
        <col id="0">68</col>
        <col id="1">Australia Post Redirection</col>
      </row>
      <row>
        <col id="0">69</col>
        <col id="1">ISBN (EAN-13 with verification stage)</col>
      </row>
      <row>
        <col id="0">70</col>
        <col id="1">Royal Mail 4 State (RM4SCC)</col>
      </row>
      <row>
        <col id="0">71</col>
        <col id="1">Data Matrix ECC200</col>
      </row>
      <row>
        <col id="0">72</col>
        <col id="1">EAN-14</col>
      </row>
      <row>
        <col id="0">73</col>
        <col id="1">Vehincle Identification Number (America)</col>
      </row>
      <row>
        <col id="0">74</col>
        <col id="1">Codablock-F</col>
      </row>
      <row>
        <col id="0">75</col>
        <col id="1">NVE-18</col>
      </row>
      <row>
        <col id="0">76</col>
        <col id="1">Japanese Postal Code</col>
      </row>
      <row>
        <col id="0">77</col>
        <col id="1">Korea Post</col>
      </row>
      <row>
        <col id="0">79</col>
        <col id="1">GS1 DataBar-14 Stacked</col>
      </row>
      <row>
        <col id="0">80</col>
        <col id="1">GS1 DataBar-14 Stacked Omnidirectional</col>
      </row>
      <row>
        <col id="0">81</col>
        <col id="1">GS1 DataBar Expanded Stacked</col>
      </row>
      <row>
        <col id="0">82</col>
        <col id="1">PLANET</col>
      </row>
      <row>
        <col id="0">84</col>
        <col id="1">MicroPDF417</col>
      </row>
      <row>
        <col id="0">85</col>
        <col id="1">USPS OneCode</col>
      </row>
      <row>
        <col id="0">86</col>
        <col id="1">Plessey Code</col>
      </row>
      <row>
        <col id="0">87</col>
        <col id="1">Telepen Numeric</col>
      </row>
      <row>
        <col id="0">89</col>
        <col id="1">ITF-14</col>
      </row>
      <row>
        <col id="0">90</col>
        <col id="1">Dutch Post KIX Code</col>
      </row>
      <row>
        <col id="0">92</col>
        <col id="1">Aztec Code</col>
      </row>
      <row>
        <col id="0">93</col>
        <col id="1">DAFT Code</col>
      </row>
      <row>
        <col id="0">97</col>
        <col id="1">Micro QR Code</col>
      </row>
      <row>
        <col id="0">98</col>
        <col id="1">HIBC Code 128</col>
      </row>
      <row>
        <col id="0">99</col>
        <col id="1">HIBC Code 39</col>
      </row>
      <row>
        <col id="0">102</col>
        <col id="1">HIBC Data Matrix ECC200</col>
      </row>
      <row>
        <col id="0">104</col>
        <col id="1">HIBC QR Code</col>
      </row>
      <row>
        <col id="0">106</col>
        <col id="1">HIBC PDF417</col>
      </row>
      <row>
        <col id="0">108</col>
        <col id="1">HIBC MicroPDF417</col>
      </row>
      <row>
        <col id="0">112</col>
        <col id="1">HIBC Aztec Code</col>
      </row>
      <row>
        <col id="0">115</col>
        <col id="1">DotCode</col>
      </row>
      <row>
        <col id="0">116</col>
        <col id="1">Han Xin (Chinese Sensible) Code</col>
      </row>
      <row>
        <col id="0">121</col>
        <col id="1">Royal Mail 4-State Mailmark</col>
      </row>
      <row>
        <col id="0">128</col>
        <col id="1">Aztec Runes</col>
      </row>
      <row>
        <col id="0">129</col>
        <col id="1">Code 32</col>
      </row>
      <row>
        <col id="0">130</col>
        <col id="1">Composite Symbol with EAN linear component</col>
      </row>
      <row>
        <col id="0">131</col>
        <col id="1">Composite Symbol with GS1-128 linear component</col>
      </row>
      <row>
        <col id="0">132</col>
        <col id="1">Composite Symbol with GS1 DataBar-14 linear component</col>
      </row>
      <row>
        <col id="0">133</col>
        <col id="1">Composite Symbol with GS1 DataBar Limited component</col>
      </row>
      <row>
        <col id="0">134</col>
        <col id="1">Composite Symbol with GS1 DataBar Extended component</col>
      </row>
      <row>
        <col id="0">135</col>
        <col id="1">Composite Symbol with UPC A linear component</col>
      </row>
      <row>
        <col id="0">136</col>
        <col id="1">Composite Symbol with UPC E linear component</col>
      </row>
      <row>
        <col id="0">137</col>
        <col id="1">Composite Symbol with GS1 DataBar-14 Stacked component</col>
      </row>
      <row>
        <col id="0">138</col>
        <col id="1">Composite Symbol with GS1 DataBar-14 Stacked Omnidirectional component</col>
      </row>
      <row>
        <col id="0">139</col>
        <col id="1">Composite Symbol with GS1 DataBar Expanded Stacked component</col>
      </row>
      <row>
        <col id="0">140</col>
        <col id="1">Channel Code</col>
      </row>
      <row>
        <col id="0">141</col>
        <col id="1">Code One</col>
      </row>
      <row>
        <col id="0">142</col>
        <col id="1">Grid Matrix</col>
      </row>
      <row>
        <col id="0">143</col>
        <col id="1">UPNQR (Univerzalni Plačilni Nalog QR)</col>
      </row>
      <row>
        <col id="0">144</col>
        <col id="1">Ultracode</col>
      </row>
      <row>
        <col id="0">145</col>
        <col id="1">Rectangular Micro QR Code (rMQR)</col>
      </row>
    </data>
  </object>
  <template class="BarcodeUI" parent="GtkWindow">
    <property name="can-focus">False</property>
    <property name="title" translatable="yes">Barcode UI</property>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can-focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkEntry" id="entry">
            <property name="visible">True</property>
            <property name="can-focus">True</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkComboBox" id="barcodeselect">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="model">barcodetypes</property>
            <property name="active">0</property>
            <property name="id-column">0</property>
            <child>
              <object class="GtkCellRendererText"/>
              <attributes>
                <attribute name="text">1</attribute>
              </attributes>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkDrawingArea" id="image">
            <property name="height-request">200</property>
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="margin-start">4</property>
            <property name="margin-end">4</property>
            <property name="margin-top">4</property>
            <property name="margin-bottom">4</property>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkStatusbar" id="statusbar">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="margin-start">10</property>
            <property name="margin-end">10</property>
            <property name="margin-top">6</property>
            <property name="margin-bottom">6</property>
            <property name="orientation">vertical</property>
            <property name="spacing">2</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">3</property>
          </packing>
        </child>
      </object>
    </child>
  </template>
</interface>

A  => test/barcodeui.vala +139 -0
@@ 1,139 @@
using Gtk;

[GtkTemplate (ui="/com/example/barcodeui/barcodeui.ui")]
class BarcodeUI : Window {
    [GtkChild]
    unowned Entry entry;

    [GtkChild]
    unowned DrawingArea image;
    
    [GtkChild]
    unowned ComboBox barcodeselect;
    
    [GtkChild]
    unowned Statusbar statusbar;


    private Gdk.Pixbuf pixbuf;
    private uint sbctx;

    public BarcodeUI() {
        sbctx = statusbar.get_context_id("status");
        
        entry.changed.connect( on_entry_changed );
        barcodeselect.changed.connect( on_barcode_changed );
        image.draw.connect( on_image_redraw );
    }

    private void on_barcode_changed (ComboBox source) {
        update_pixbuf();
    }

    private void on_entry_changed (Editable source) {
        update_pixbuf();
    }
    
    private void message(string text) {
        statusbar.push(sbctx, text);
    }
    
    private void update_pixbuf() {
        string symbology_id_str = barcodeselect.get_active_id();
        int symbology_id = int.parse(symbology_id_str);
        
        debug("new symbol #%d for '%s'", symbology_id, entry.text);

        if (entry.text == "") {
            pixbuf = null;
            statusbar.remove_all(sbctx);
            image.queue_draw();
            return;
        }

        var my_symbol = new Zint.Symbol();

        my_symbol.scale = 4;
        my_symbol.symbology = symbology_id;

        int err;
        err = my_symbol.encode(entry.text.to_utf8());
        if (err != 0) {
            message((string) my_symbol.errtxt);
            pixbuf = null;
            image.queue_draw();
            return;
        }
        err = my_symbol.buffer(0);
        if (err != 0) {
            message("Error saving to buffer");
            pixbuf = null;
            image.queue_draw();
            return;
        }

        var bitmap = my_symbol.get_bitmap();

        pixbuf = new Gdk.Pixbuf.from_data(
            bitmap,
            Gdk.Colorspace.RGB,
            false,
            8,
            my_symbol.bitmap_width,
            my_symbol.bitmap_height,
            my_symbol.bitmap_width*3
        );
         
        if (pixbuf == null) {
            message("Error creating pixbuf");
            image.queue_draw();
            return;
        }
        
        statusbar.remove_all(sbctx);
        debug("queue draw");
        image.queue_draw();
    }
    
    private bool on_image_redraw(Widget source, Cairo.Context cr) {
        debug("draw (pixbuf null: %i)", (int)(pixbuf == null));
        if (pixbuf == null) {
            return false;
        }
        
        int width = image.get_allocated_width();
        int height = image.get_allocated_height();
        debug("draw into %ix%i", width, height);
        
        if (width < 2 || height < 2) return false;
        
        // keep ratio
        var pbr = (double)pixbuf.get_height() / (double)pixbuf.get_width();
        var dar = (double)height / (double) width;
        if (pbr < dar) {
            height = (int)(width * pbr);
        } else if (pbr > dar) {
            width = (int)(height / pbr);
        }
        // center
        var x = (image.get_allocated_width() - width) / 2.0;
        var y = (image.get_allocated_height() - height) / 2.0;
        
        var temp = pixbuf.scale_simple(width, height, Gdk.InterpType.BILINEAR);
        Gdk.cairo_set_source_pixbuf(cr, temp, x, y);
        cr.paint();
        return false;
    }


    public static int main (string[] args) {
        Gtk.init (ref args);

        var window = new BarcodeUI ();
        window.show_all ();
        window.destroy.connect (Gtk.main_quit);

        Gtk.main ();
        return 0;
    }
}

A  => test/barcodeui_res.xml +6 -0
@@ 1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
  <gresource prefix="/com/example/barcodeui">
    <file>barcodeui.ui</file>
  </gresource>
</gresources>

A  => test/example_1.vala +8 -0
@@ 1,8 @@
// Creating and Deleting Symbols

void main(string[] args) {
    Zint.Symbol my_symbol = new Zint.Symbol();
    if (my_symbol != null) {
        stdout.printf("Symbol successfully created!\n");
    }
}

A  => test/example_2.vala +12 -0
@@ 1,12 @@
// Encoding and Saving to File

void main(string[] args) {
    if (args.length != 2) {
        stderr.printf("Missing value param.\n");
        return;
    }

    Zint.Symbol my_symbol = new Zint.Symbol();
    my_symbol.encode(args[1].to_utf8());
    my_symbol.print(0);
}

A  => test/example_3.vala +54 -0
@@ 1,54 @@
// Encoding and Saving to Buffer

void main(string[] args) {
    if (args.length != 2) {
        error("Missing 'value' param.\n");
    }

    var my_symbol = new Zint.Symbol();

    int err;
    err = my_symbol.encode(args[1].to_utf8());
    err = my_symbol.buffer(0);
    if (err != 0) {
        error("Error saving to buffer");
    }

    var bitmap = my_symbol.get_bitmap();

    print("bitmap: %u bytes, %dx%d\n",
        bitmap.length,
        my_symbol.bitmap_width,
        my_symbol.bitmap_height
    );
    
    if (bitmap.length == 0) return;
    
    var pixbuf = new Gdk.Pixbuf.from_data(
        bitmap,
        Gdk.Colorspace.RGB,
        false,
        8,
        my_symbol.bitmap_width,
        my_symbol.bitmap_height,
        my_symbol.bitmap_width*3
    );
     
    if (pixbuf == null) {
        error("Error creating pixbuf\n");
    }
    
    print("pixbuf\n");
    print("\tbits_per_sample: %i\n", pixbuf.get_bits_per_sample());
    print("\tchannels: %i\n", pixbuf.get_n_channels());
    print("\tbyte_length: %u\n", (uint)pixbuf.get_byte_length());
    print("\tpix size: %ix%i\n", pixbuf.get_width(), pixbuf.get_height());
    
    File file = File.new_for_path("out.jpg");
    try {
        FileOutputStream os = file.create(FileCreateFlags.REPLACE_DESTINATION);
        pixbuf.save_to_stream(os, "jpeg");
    } catch(Error e) {
        error("Error: %s\n", e.message);
    }
}