From a43fe96c89f932809810e74ee8806bbe4ba8a705 Mon Sep 17 00:00:00 2001 From: Benson Muite Date: Tue, 5 May 2026 16:36:39 +0300 Subject: [PATCH 1/2] Start creating webp module Add support for libwebp in libgd --- libraries/libgd/LIB_DEPENDS | 2 +- libraries/libgd/make.sh | 2 +- libraries/libsharpyuv/make.sh | 23 +++ libraries/libwebp/LIB_DEPENDS | 1 + libraries/libwebp/make.sh | 2 + modules/gd/LIBRARIES | 2 +- modules/gd/gd.scm | 2 + modules/webp/webp.scm | 292 ++++++++++++++++++++++++++++++++++ 8 files changed, 323 insertions(+), 3 deletions(-) create mode 100755 libraries/libsharpyuv/make.sh create mode 100644 libraries/libwebp/LIB_DEPENDS create mode 100755 libraries/libwebp/make.sh create mode 100644 modules/webp/webp.scm diff --git a/libraries/libgd/LIB_DEPENDS b/libraries/libgd/LIB_DEPENDS index 0675aab0..b9dba238 100644 --- a/libraries/libgd/LIB_DEPENDS +++ b/libraries/libgd/LIB_DEPENDS @@ -1 +1 @@ -libz libpng libjpeg libfreetype +libz libpng libsharpyuv libwebp libjpeg libfreetype diff --git a/libraries/libgd/make.sh b/libraries/libgd/make.sh index a05ada7b..bfaff435 100755 --- a/libraries/libgd/make.sh +++ b/libraries/libgd/make.sh @@ -23,7 +23,7 @@ if [ "$SYS_PLATFORM" = "win32" ]; then fi fi -package_configure $EXTRACONF --disable-shared --enable-static --with-png=$SYS_PREFIX --with-freetype=$SYS_PREFIX --with-jpeg=$SYS_PREFIX --without-avif --without-heif --without-tiff --without-webp --without-xpm --without-fontconfig --without-x +package_configure $EXTRACONF --disable-shared --enable-static --with-png=$SYS_PREFIX --with-freetype=$SYS_PREFIX --with-jpeg=$SYS_PREFIX --without-avif --without-heif --without-tiff --with-webp=$SYS_PREFIX --without-xpm --without-fontconfig --without-x cd src package_make libgd.la diff --git a/libraries/libsharpyuv/make.sh b/libraries/libsharpyuv/make.sh new file mode 100755 index 00000000..0ef3e741 --- /dev/null +++ b/libraries/libsharpyuv/make.sh @@ -0,0 +1,23 @@ +PKGURL=https://github.com/webmproject/libwebp/archive/refs/tags/v1.6.0.tar.gz +PKGHASH=6a5da51c23c8340e44a70421a5ef8bb1ae805ad2 + +package_download $PKGURL $PKGHASH + +veval "./autogen.sh" +asserterror $? "failed to generate configure script" + +rmifexists $SYS_PREFIX/include/webp + +if [ ! $SYS_PLATFORM = $SYS_HOSTPLATFORM ]; then + EXTRACONF=--host=$SYS_ARCH +fi + +package_configure $EXTRACONF --disable-shared --enable-static --enable-dependency-tracking --enable-pic --disable-libwebpmux --disable-libwebpdemux --disable-gl --disable-gif --disable-png --disable-tiff --disable-jpeg --disable-sdl --disable-wic --disable-threading + +package_make + +package_make install + +package_cleanup + +#eof diff --git a/libraries/libwebp/LIB_DEPENDS b/libraries/libwebp/LIB_DEPENDS new file mode 100644 index 00000000..1f0952cd --- /dev/null +++ b/libraries/libwebp/LIB_DEPENDS @@ -0,0 +1 @@ +libsharpyuv diff --git a/libraries/libwebp/make.sh b/libraries/libwebp/make.sh new file mode 100755 index 00000000..b81a5e72 --- /dev/null +++ b/libraries/libwebp/make.sh @@ -0,0 +1,2 @@ + +# this is just a dummy, the libwebp is built alongside libsharpyuv diff --git a/modules/gd/LIBRARIES b/modules/gd/LIBRARIES index 796c6931..e9347c50 100644 --- a/modules/gd/LIBRARIES +++ b/modules/gd/LIBRARIES @@ -1 +1 @@ -libz!android libpng libfreetype libjpeg libgd +libz!android libpng libsharpyuv libwebp libfreetype libjpeg libgd diff --git a/modules/gd/gd.scm b/modules/gd/gd.scm index 071c4851..511a97ae 100644 --- a/modules/gd/gd.scm +++ b/modules/gd/gd.scm @@ -170,11 +170,13 @@ end-of-c-declare (gd-function gdImageCreateTrueColor (int int) (pointer void)) (gd-function gdImageCreateFromGif ((pointer void)) (pointer void)) (gd-function gdImageCreateFromPng ((pointer void)) (pointer void)) +(gd-function gdImageCreateFromWebp ((pointer void)) (pointer void)) (gd-function gdImageCreateFromJpeg ((pointer void)) (pointer void)) (gd-function gdImageCreateFromGd ((pointer void)) (pointer void)) (gd-function gdImageCreateFromGd2 ((pointer void)) (pointer void)) (gd-function gdImageGif ((pointer void) (pointer void)) void) (gd-function gdImagePng ((pointer void) (pointer void)) void) +(gd-function gdImageWebp ((pointer void) (pointer void)) void) (gd-function gdImageJpeg ((pointer void) (pointer void) int) void) (gd-function gdImageGd ((pointer void) (pointer void)) void) (gd-function gdImageGd2 ((pointer void) (pointer void) int int) void) diff --git a/modules/webp/webp.scm b/modules/webp/webp.scm new file mode 100644 index 00000000..85d8fb52 --- /dev/null +++ b/modules/webp/webp.scm @@ -0,0 +1,292 @@ +#| +LambdaNative - a cross-platform Scheme framework +Copyright (c) 2009-2014, University of British Columbia +All rights reserved. + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials +provided with the distribution. + +* Neither the name of the University of British Columbia nor +the names of its contributors may be used to endorse or +promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +|# + +;; png - wrapper for libpng image library + +(define png:debuglevel 0) +(define (png:log level . x) + (if (>= png:debuglevel level) (apply log-system (append (list "png: ") x)))) + +(c-declare #< +#include +#include + +#include + +static int ln_png_info(char *fname, int infoarg) +{ + FILE *fd=0; + png_structp png_ptr = 0; + png_infop info_ptr = 0; + unsigned char header[8]; + int tmp,res=-1; + fd = fopen(fname, "rb"); + if (!fd) goto info_bail; + fread(header, 1, 8, fd); + if (png_sig_cmp(header, 0, 8)) goto info_bail; + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) goto info_bail; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) goto info_bail; + if (setjmp(png_jmpbuf(png_ptr))) { goto info_bail; } + png_init_io(png_ptr, fd); + png_set_sig_bytes(png_ptr, 8); + png_read_info(png_ptr, info_ptr); + switch (infoarg) { + case 1: res=png_get_image_width(png_ptr, info_ptr); break; + case 2: res=png_get_image_height(png_ptr, info_ptr); break; + case 3: res=png_get_bit_depth(png_ptr, info_ptr); break; + case 4: + tmp=png_get_color_type(png_ptr, info_ptr); + switch (tmp) { + case PNG_COLOR_TYPE_GRAY: res = 1; break; + case PNG_COLOR_TYPE_RGB: res = 3; break; + case PNG_COLOR_TYPE_RGBA : res = 4; break; + } + break; + } +info_bail: + if (info_ptr) png_destroy_info_struct(png_ptr, &info_ptr); + if (png_ptr) png_destroy_read_struct(&png_ptr, &info_ptr,0); + if (fd) fclose(fd); + return res; +} + +static int ln_png_from_u8vector(int w, int h, unsigned char *data, int datalen, const char *fname) +{ + FILE *fd=0; + png_structp png_ptr = 0; + png_infop info_ptr = 0; + int res=-1; + int color_types[] = { -1, PNG_COLOR_TYPE_GRAY, -1, PNG_COLOR_TYPE_RGB, PNG_COLOR_TYPE_RGBA}; + int stride = datalen/(w*h); + int color_type = (stride<5&&stride>0?color_types[stride]:-1); + if (color_type<0) goto writer_bail; + if (stride*w*h!=datalen) goto writer_bail; + png_byte ** row_pointers = NULL; + size_t x, y; + fd = fopen (fname, "wb"); + if (!fd) goto writer_bail; + png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) goto writer_bail; + info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) goto writer_bail; + if (setjmp (png_jmpbuf (png_ptr))) goto writer_bail; + png_set_IHDR (png_ptr, info_ptr, w, h, 8, // depth + color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + row_pointers = png_malloc (png_ptr, h * sizeof (png_byte *)); + for (y = 0; y < h; ++y) { + png_byte *row = png_malloc (png_ptr, sizeof (uint8_t) * w * stride); + row_pointers[y] = row; + for (x = 0; x < w; ++x) { + int i; + for (i=0;iw0) goto reader_bail; + if (height>h0) goto reader_bail; + png_set_interlace_handling(png_ptr); + png_read_update_info(png_ptr, info_ptr); + if (setjmp(png_jmpbuf(png_ptr))) goto reader_bail; + row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); + for (y=0; ypng data fname w h) + (png:log 1 "u8vector->png " w " " h " [] " fname) + (fx= ((c-lambda (int int scheme-object int char-string) int + "___result=ln_png_from_u8vector(___arg1,___arg2,___CAST(void*,___BODY_AS(___arg3,___tSUBTYPED)),___arg4,___arg5);") + w h data (u8vector-length data) fname) 0)) + +(define (png->u8vector fname . xargs) + (png:log 1 "png->u8vector " fname " " xargs) + (let* ((w (png-width fname)) + (h (png-height fname)) + (w0 (if (= (length xargs) 2) (car xargs) w)) + (h0 (if (= (length xargs) 2) (cadr xargs) h)) + (s (png-stride fname)) + (data (if (and w0 h0 s) (make-u8vector (* w0 h0 s) 0) #f))) + (if data (begin + (if (fx= ((c-lambda (int int scheme-object int char-string) int + "___result=ln_png_to_u8vector(___arg1,___arg2,___CAST(void*,___BODY_AS(___arg3,___tSUBTYPED)),___arg4,___arg5);") + w0 h0 data (u8vector-length data) fname) 0) data #f)) (begin + (log-error "png->u8vector failed on " fname) #f)))) + +;; ------ +;; opengl related functions +;; eval is used to delay resolving potentially unavailable calls + +(define (png:png->texture fname . xargs) + (png:log 1 "png->texture " fname " " xargs) + (let* ((w (png-width fname)) + (h (png-height fname)) + (w0 (if (= (length xargs) 2) (car xargs) w)) + (h0 (if (= (length xargs) 2) (cadr xargs) h)) + (data (png->u8vector fname w0 h0))) + (if data ((eval 'glCoreTextureCreate) w0 h0 data) + (begin (log-error "png:png->texture failed on " fname) #f)))) + +(define (png->img fname) + (png:log 1 "png->img " fname) + (let* ((w (png-width fname)) + (h (png-height fname)) + (w0 (fix (expt 2. (ceiling (/ (log w) (log 2.)))))) + (h0 (fix (expt 2. (ceiling (/ (log h) (log 2.)))))) + (t (png:png->texture fname w0 h0))) + (if (and w h t) + (list w h t 0. (- 1. (/ h h0 1.)) (/ w w0 1.) 1.) + (begin (log-error "png->img failed on " fname) #f)))) + +(define (png:texture->png t fname) + (png:log 1 "texture->png " t " " fname) + (let ((w ((eval 'glCoreTextureWidth) t)) + (h ((eval 'glCoreTextureHeight) t)) + (data ((eval 'glCoreTextureData) t))) + (u8vector->png data fname w h))) + +(define (img->png img fname) + (png:texture->png (caddr img) fname)) + +(define (screenshot->png fname) + (png:log 1 "screenshot->png " fname) + (let* ((w ((eval 'glgui-width-get))) + (h ((eval 'glgui-height-get))) + (data ((eval 'glCoreReadPixels) 0 0 w h))) + (u8vector->png data fname w h))) + +;; ------ +;; unit test + +(unit-test "png" "1000 random image encode-decode runs" + (lambda () + (let* ((fname (string-append (system-directory) (system-pathseparator) "unittest.png")) + (res (let loop ((n 1000)) + (if (fx= n 0) #t (if + (let* ((w (+ 1 (random-integer 200))) + (h (+ 1 (random-integer 200))) + (stride (list-ref '(1 3 4) (random-integer 3))) + (data (random-u8vector (* stride w h)))) + (u8vector->png data fname w h) + (not (and (= w (png-width fname)) + (= h (png-height fname)) + (= stride (png-stride fname)) + (equal? data (png->u8vector fname))))) #f (loop (fx- n 1))))))) + (if (file-exists? fname) (delete-file fname)) + res))) + +;; eof From 2c2d8d04fea2d088d4d44720b420e006ac61e573 Mon Sep 17 00:00:00 2001 From: Benson Muite Date: Sun, 17 May 2026 10:26:29 +0300 Subject: [PATCH 2/2] Initial WebP module and example --- apps/DemoCameraWebP/ANDROID_xml_services | 11 + apps/DemoCameraWebP/FONTS | 1 + apps/DemoCameraWebP/MODULES | 1 + apps/DemoCameraWebP/VERSION | 1 + apps/DemoCameraWebP/artwork.eps | 280 ++++++++++++++++++++ apps/DemoCameraWebP/artwork.obj | 39 +++ apps/DemoCameraWebP/artwork.png | Bin 0 -> 8017 bytes apps/DemoCameraWebP/main.scm | 110 ++++++++ apps/DemoCameraWebP/xml/file_paths.xml | 4 + modules/webp/LIBRARIES | 1 + modules/webp/webp.scm | 313 +++++++++++------------ 11 files changed, 593 insertions(+), 168 deletions(-) create mode 100644 apps/DemoCameraWebP/ANDROID_xml_services create mode 100644 apps/DemoCameraWebP/FONTS create mode 100644 apps/DemoCameraWebP/MODULES create mode 100644 apps/DemoCameraWebP/VERSION create mode 100644 apps/DemoCameraWebP/artwork.eps create mode 100644 apps/DemoCameraWebP/artwork.obj create mode 100644 apps/DemoCameraWebP/artwork.png create mode 100644 apps/DemoCameraWebP/main.scm create mode 100644 apps/DemoCameraWebP/xml/file_paths.xml create mode 100644 modules/webp/LIBRARIES diff --git a/apps/DemoCameraWebP/ANDROID_xml_services b/apps/DemoCameraWebP/ANDROID_xml_services new file mode 100644 index 00000000..3a31b7e4 --- /dev/null +++ b/apps/DemoCameraWebP/ANDROID_xml_services @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/apps/DemoCameraWebP/FONTS b/apps/DemoCameraWebP/FONTS new file mode 100644 index 00000000..d8784f55 --- /dev/null +++ b/apps/DemoCameraWebP/FONTS @@ -0,0 +1 @@ +cmss.ttf 7 18 ascii diff --git a/apps/DemoCameraWebP/MODULES b/apps/DemoCameraWebP/MODULES new file mode 100644 index 00000000..9efb9b10 --- /dev/null +++ b/apps/DemoCameraWebP/MODULES @@ -0,0 +1 @@ +config eventloop ln_core ln_glcore ln_glgui gd webp camera diff --git a/apps/DemoCameraWebP/VERSION b/apps/DemoCameraWebP/VERSION new file mode 100644 index 00000000..d3827e75 --- /dev/null +++ b/apps/DemoCameraWebP/VERSION @@ -0,0 +1 @@ +1.0 diff --git a/apps/DemoCameraWebP/artwork.eps b/apps/DemoCameraWebP/artwork.eps new file mode 100644 index 00000000..9b7f3429 --- /dev/null +++ b/apps/DemoCameraWebP/artwork.eps @@ -0,0 +1,280 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.18.4 (https://cairographics.org) +%%CreationDate: Sun May 17 10:11:54 2026 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%BoundingBox: 14 27 134 126 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 14 27 134 126 +%%EndPageSetup +q 14 27 120 99 rectclip +1 0 0 -1 0 147 cm q +0.254902 0.913725 0.117647 rg +56 23.5 m 49.25 37 l 43.527 37 l 43.527 31.18 l 30.027 31.18 l 30.027 37 + l 24.5 37 l 19.527 37 15.5 41.031 15.5 46 c 15.5 109 l 15.5 113.973 19.527 + 118 24.5 118 c 123.5 118 l 128.469 118 132.5 113.973 132.5 109 c 132.5 +46 l 132.5 41.031 128.469 37 123.5 37 c 98.75 37 l 92 23.5 l h +56 23.5 m f +0.470588 g +2.834646 w +0 J +1 j +[] 0.0 d +4 M q 1 0 0 -1 0 0 cm +56 -23.5 m 49.25 -37 l 43.527 -37 l 43.527 -31.18 l 30.027 -31.18 l 30.027 + -37 l 24.5 -37 l 19.527 -37 15.5 -41.031 15.5 -46 c 15.5 -109 l 15.5 -113.973 + 19.527 -118 24.5 -118 c 123.5 -118 l 128.469 -118 132.5 -113.973 132.5 +-109 c 132.5 -46 l 132.5 -41.031 128.469 -37 123.5 -37 c 98.75 -37 l 92 +-23.5 l h +56 -23.5 m S Q +1 g +105.5 77.5 m 105.5 94.898 91.398 109 74 109 c 56.602 109 42.5 94.898 42.5 + 77.5 c 42.5 60.102 56.602 46 74 46 c 91.398 46 105.5 60.102 105.5 77.5 +c f +0 g +0 j +q 1 0 0 -1 0 0 cm +105.5 -77.5 m 105.5 -94.898 91.398 -109 74 -109 c 56.602 -109 42.5 -94.898 + 42.5 -77.5 c 42.5 -60.102 56.602 -46 74 -46 c 91.398 -46 105.5 -60.102 +105.5 -77.5 c S Q +Q q +101 21 31 31 re W n +q +101 21 31 31 re W n +% Fallback Image: x=101 y=21 w=31 h=31 res=300ppi size=50700 +[ 31.2 0 0 -31.2 101 52.2 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 130 + /Height 130 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 130 0 0 -130 0 130 ] +>> +cairo_image + Gb"/kM0BZa[f?@?MYDSoY4\A^n+/;1au+\t.LHI(+>\VnK*#HsA/'95;.Q7#,S2)/T'(A?R + 2$EhFE^_4?1Y%q/q3-Q;cR*@^a)mW;670,3rXqjVX'c0n( + .EOB\G%ol^CkTBfGQts'*:t=oA:'MhCkWPVQ0ITpq7 + ;Udg7kZOD".[6^Atprl + :_XBVuBUmZULIaKt&;8Fgt^RePmb+%?s5p6-d%)"P8nGPh?",l.>!?hfNp1-2?!W4NVfJ(E$Bq#d<`h/H:sfD1bM0'I+"8oh-ZaQRZc0D!-n9 + redG!sS-*L&Mup`a2Nr.u8O>I2]4s^YeJi"p2R>@0f@*aR`_8g*;Ec71"_lIS4"SH4)sA7h + GF1c\Dp^,bK26WHDJPOWEB(g[b9E+RTl=?%TRbOEQL56P+I!dOp>o"j(3f1)rhVFHutpZ(X + e(M"A.bP.X-n[gUW-6/3fCgI,bF+E"Rg^Qln7[gV2=;;+=G#i[I&r"]Qm!/K^OitMPh]@Y= + '-d/),+7ctubkX2lKYIlB2hJQ9^%d1g;dZoP/GhF,3,)pJMcSt!n + `!"=`s,jP08MT4@3%#&LKMS)lgT,fpG_U$#5H;7-BTmW5YMrJ0"RrMIHU?OSkfVd_1.8\YN + `^38H-RnrlLVLR3rl,<3P?$[=YoS(Y8)M/Hc@WrO';JcG[*("V.L8$Rg>5TplBA#_\po?10 + NPKOTOZH@iX3XHV.`X8Zoi(]O]&9EAdKXaj=jc3p[uEA]DN_BH)AKp=Vcns[L3?4;U]>_@k + M1*PogYQ3H?7*-'1E'\UA6`,$KC:IKTPECVsK,P=_! + 5$ftd_5UC3Wh!.S5b>Qh8:XX^^*XT,*qOQ(oa%r6VCO)p6N$oq\9#n&bB60l>D>f[509KJ( + `*$?GX"\[+T24G4,uSXfq@.kgX?3)*W\qN&D)N7Xs1giQLQ_j?c!\= + HkA"_jFd],0V@C?i.NaCINAt"K"'_Ipjr7VAYH)c,ojZ6V"#aDe>UpUh5&HSfEt%9'S5bk1 + EAW1[Wb>u!_W]d#m/2&.05s8'iX(`H-McdtK5r>ST9Hp?@#=&D\%_CNE5DtVco7-',D>A&db-p&)?m$"^'+<`OjfiWrrnt + ahX.n` + u"G,J1-jZHZQcs$f&Rd?N/Hg;aXuai?uEamq5iDE>g6BDH6m5E4^$ + Z.r:g?F/EDQClIm1H6LDE3M_K\:Vs1=Y7(=i[^BO$kT3k_9BCu3esBP&X%O?,Cb!@W#7l4! + cd9Ad$,/)-5/ZF!QUZ^?qA(8ru>ACOF/kU/3fE]5%FE7=Dg_RnCu:IT1DZ9n:*2,KJNj$0c + +TS!n4ZGnV1VYJsM?PZ("EUCkjk]'W9NhT77B'-HQL`rnLOtJ3+t-NdsH,+Y]o-YlJ&/=hL + ,7_;[D:n)L;?\B-9dRH5dk\;@:=i9_d32i6WC"..=f$S7D(:on7JXs&/n(*YQB$E3#)f-!a)V3E#IVj"N^EebC7)7Vg=ko)scP(pt1XTS1X6b0e>97a,U5He+jQ2N!6&:B8mfe$-\!#-N`:KB + OVd>p(_bC^`[UBAi6_qM+p&a#?d(3)?j-CELOa^9*hb#7&C&kM`@Ib>lnSG^=eY&&E(3L$9 + 9(:lQ=QuNTJ+oU9n8sOU+CtkTYVo09hAMMNm5/U:>j;kEtNO$hB\cV/.@!#8CT)Z!VIe6J. + H)B'aQr'scEWQgAa3Z<<@OmrViaMCBf2pd+&UK,-eh4*=#"[)/>n(RRq]ChSU$=pVoh5DDk + kPd:2g8NnK]jBn(tAQc_uUT4Z+77rMtY0,scN%Q=h%8\5pBckMm#@3;YZ/^XC5T^/e^gk>7 + OPX5O&8#4bNN:Dm%c>'\j1HB0rqfJG"_[9W>HQ:R\=APE&7@_8)93](aL$Sf7QZ8Bd/\c1/ + :gT)rC8"F%G?c(;%-?3&W/qJ4:_95:.EhH\ctQs&LJ77MsI$lNOX-\i)8u]<(`?T[>ssP/DYR4A^a:B + nM`V5I:P05uj<2\0m;d`[PrG0Y;;)BOTcEc>Ur9^*A@:XS9?ba;:?7+6W#T^16@ZZPVf23+=.>f"Jiu)U + :;UDrs#-+TTpfDlss"\@,K(h_]k+JMVUS:bn:oR"S$9#i4MQQnqjdh1p,'>NtB7cGjps+$^ + _"j1>X2\LFp+QE3mQ'"[acT&NVN&bb^hG2#WYSq]=Yt'^KPQX,Gmrn> + SfR6Pe[!p#$_3i09sglC5r1JGXMNm'QjAi[^E]9!]IUhk)T&-@b'ob#BnL+X1Q!*:"&TOt6>^4Pr`U2 + &ei>+qs]7VENo>,ksM"]uR5-@eViS%&e^O#=8R/fA]f-G`5>`eQQn[qGf4(_e:O6A38:#PL + 13@;BP'-X'!%:Ao4]UCpKJh%B#"(u5dBF@W,mS\pWA#Ua-q('7-^n<"uG0B4o0K9UTa)aQM + !S:"H=AWZ_&9rlaMH;/2%[!G`Q;7.lRX&.=Z//D#u"K?+Q!\')trs%Qo[\pnMK[+\mQ^ + KWS[>]i--+@,#78dMc)eW_Jt/gpu<8E.TP3:iPaXTf*WrX2kqhX>B+b7Z]. + VbDeW1[8Cau-:>P(-d/hpSmd&@XL`L?[8=bBc"B(_jC1qL--gm]=@7b>XLf6Wd1NQ]#hjo3Ea?LD + heFaFn9h"+h>H#EJ"QY2VRT&HB@\il6?oL'5gM;'i36]^ca+1aW(H0A*hDPJUK9(E^"Ng"I + .:Icg;;$p:19Mqei_+dY9U\XBSrV-9iqjRPVVVTe0>H6DMWmuu)Ng(``jN/f;7ObV_-coFY + l(TSspGPb;0^j;NdI;/94S/cck7\@h),=e4S"Aa4b]\9o\igE`oO;afQTd;I2M&>n0K"C#* + M]:+)2(=9*,F-,Nf/DEWJF=eQ'aBX.J]O!e9=g>hG-]cSrklm.q_sZDHLf5^[_be()4Jc<; + ]4*acM[k6"Lc5b:hNW8rrtdNPGuK + ?>\K<`BR-WpX5"e$#XO:L-?VL)U4WoJ+@4VR\_8a'R`7G[hH!P#8'Me19g$5k(9#n+ + ->n#`n+t$m=sfb&rB;A@Y[(ncU\"j-*S'VRcMs[jco@:--)H6P984,n$Mc8%Uns,C9cKLjMC + HIkN$8t;84X_+;EFF$#A^q*9$$.I0ndE`NF)l[$R8kSaN"u%m1_#O'P`39m5lE:N1E:u+Cp + :+Slq(kW7oQ?"<&M0Jt>)%Fe/9m?HqB+CA0Fd>a3AWWDF/4GWs*BE1ZTkC34r,hpB!DY'5k + r6@")J!MPV,RR5.q-s2V#2X]_0AY#!=N2$B.HllOd,dkm5lhI[mmd*8F+jA!:F*-\F]A4"5A$4\ZIs*_4&&5F_@DU4$WX[? + "_tRXZ^mr87^mWCik+(9F=kg'\9DrIA^7clVq/mI8B<2CHrAR>B[$]!J6rgEn"Eng'!u304 + /gp;sbJ,'")iiSgFf?`7ZSmLPNoT)snW$;$i)SP#L3`'[ed,A7Q1rarZk>o2\WS^[__djqk + a7La``b/K7qq5-V\/5\1[PWjR7jl[%/in,;2'QS`d3gN9UOGDS2Y+l/AM"]B*?4/fVgok.: + :#OsUKi236u,?+t9a;;cg*g`W]TC6f!o**-\g-ZsqI1_PZ73s1@69hqIq`20F>JCALt3pFj + Q$#*tJ`.P;T:<;]3OiLBWH6Z_i-$CP&7dkZZUVS/O`qG'rZ3sgaLUd1I0_8CDt.&^lH.gkG + mN-A#)n&5A4ciU)+OZ=UACKPaT=AJ9g\TpQ9.(rJW4J]K/E+ul1-<8T`eprZVT>nlVN;&RG + l+AI#6s`Ct`%4d.QfMUY/jlQMTk]6qO]%*6%JBj&0$,E&;uj(AU_I.X&EFfC'hG8 + o67!6oPu4N6UKBnfU76$!S$-J^Hp.)@5LZh18od-]*X=hi + Y+@c$>lQsqI5A7VVNO4_H[e3V&nnEm8t@%WFIc-Ju2;je/=^4@&OGA'ua"9]KIo(e5_77`_ + c23.a^m8do7eaV))'d6fg"$Y*[<*;FM!o_GKu[Q&hboDYZ7DT4-g%-?Qd9?"6_UVke9(3j3 + )a9"(DR#YM7mjR>c"Y@MZG.]XijPdi&^`J^I(3PmA?Cm5DoP.kl(N@n\=!\]i%V/kPT1)ML + #Ti)^W&Pa[=Tjel($:A*N;n]tCk8?\S/%rr!E=A,J:e;'ln5:-1.LYg2n&;ge@]4>9W + t2"sNRAs``.]O[WrmF)(O=8E"/,RAWoHVSH=GIjY0CLKXH-udGH-_qHV,ZnN;\jjF'gqTN2aR3(nf\.%F + bN(='c3&NO5+1_iAVYr!1+'Ts=`eSE5LS&&5Wn5=rW7$$W1J\Oe6&J-#Z1aAXaU8TCQh1Vp + hUME%-lU,YOPdk=INTAuT/i)u$>!?^G3,i5,=2Om;#l*P-Z/Q08Gd.gC?noSSe28/:=>VRo + 85fn/5gC_ol55-WhWcjlr;=^6r1RBuEVoH!lfO3r@AJfB`&L6F&/6G;!d0s*c7i(ZBI\nZ. + ub7>=GD_);@-Ys%V]7>),cglTIpt*WFCU^Bcd+IgAP,7k`Ut:j\m:Zo8F[N72J6.d3QBgU0 + !A,r'u"mdr+u+UNH:9oYWh#Fh.73+tlpr'QUl(F=*s4&;%A[3JqG<8Qt3];ZIs\Kr*>f`?) + eo?dZE&FdBn4Z]hP!^YXi7R#B\YS/)NKJFbuspVbWJ;s.jEP,9k[7T$JPO@\F4RE8uu\mto + jUXK&90>aU,dXamPYY.1BQ;;hfe$OLgQ6R7B*$_)NjTo$Rl]FtijATsl\-ksfi$2t9*WCs0 + n,Fni6Bi"q2VX-UVgC]82#c]h&?Kn?irp)^)[Jtp3W_t?):s6+cDr\!,Zs]rMBj7f"?`-_6R'#ce>44S?;d*k+H!g2.J(%7m)KXU4ccE])l + 5nSkm63,mZpW+OH7$7@kR!oXT*p6V!idF2q9gI-t[d77qPEtJ=+i\<2`7<&`>JI6@b7^&)o + _S-\%Y`Nj`#Lg::bGIp=OPUOs8(ICgUa4T'sVISa%p:1:<#f$J<4ABEdCOTT<`9Uee.VM-G + 8!`;5,)QH_]djmAf.DLbp*_G6RQ4?$CIXE[eK_Y)BFPr;R_]rmq4^h?=o;H-eIhXW)T]H=m + Jon5LA.q6[S-*baJ.O8=L.aMcTal3iM+6"fNpT)!]70]N19&74`nDl#F..^Bd<7NT?jq782 + W\>s-,Ui2#]GXX'oR[[/-&2db2tks^(5+%;f?_un+-'gF)u6)'5O)p0)*(XbYTSb"f<:ZKn + pjZ$p-u]"E@,.26n2F+9\S)dsUuEEU)tmZ&-eqn"MFpZf^@,CY%,e%!,;'3D/6ADHVBo:QNC + XFpdb](-A*V:2ndKonnVIa&EBT2kJ3!`4Df[)t]R`D6@+ + mn??qfl(W'tf97PJ#@k?+-"n%@B*,Hf"G?FtC21FTp'U(0.A2-=lYik\](AT\d\b@;pj198/Y)Zpkn12/Y)+u1=;PS#,%!,D_nNHnBucW#/N=cp + -'^3cOOpEtA2GE_kd&a-_O3fZA(jL0/;'obHUd4,Zt`rlmof.l'W*ruPUr;9E2Bu:9'8-(+]l"J2G\jl:>Q6Ubb.>*E)gW/]EQmHWT*0\knfaT19S`s8J)&?pLK2E-S#-;tV\=es5SR!%gL3NAc1@lIkg.6Q5q6l.<)VsF'OT=V5P3E-\^F0/ri0:![co*N=^DRjfrmn2E + 4%SpF4:M2W'KTq@CR)0`_P+HQ`Y$oD;C1/F'olOP!i@Nkh.(Q\Zc9 + P8"_VT=e5&NaY@7j%[-I+7r"#bFL/bXJWANZ@Bfoa*Zeee'`Ve1]1g7ajdFMh!G(h1f%cJ. + `)BM=[1>c,u*2:\VX?9F"0$fs2q;+?N#80-CO\0oe87]H<(O0UM\h-O@Wp9Z23d + Tlf_/ge8n]a=qn$`quJj))@](\ML^YYJ%$F&?.n.0fq6Yc#N=>6fMt/5U!(F\?oX,&R$Jau + cj=/#(7V6iP1u5*WQuF:Y,_2=I*,1ku.<:#sf/n;Nb%2KpNtrVNU;.m$1.N/RNeaJVPrN>g + ?hF:-7/]O;hs"E9ki(\S%(7AP3iR!^9E$*=&GFH6^srNkY_-RFRbdof/e%1%-G66J#_^l2# + c^p?Cijj70F0OLH&'l3'N_@^3O=JTJu1\G4i2.&l+[Nc1g-M`F(Ia#HKG1[J`.V-L$GDh]7 + (AD-J.?&@Iqrf*WE2n[eV]Z/cdY1\u/0Y4S&Q$*@\"r/VDO#TIJ#j:D$+^MsA#6)G8k2tWl + 7@W3m4OK?(g]$$Y/Sd95'%>#jd![APA + (;Xb3_N@plq"b!4[L)u%Xt-CP9WCd4Q`%mB6=k;-R>0W4/qi&G87GTa[ikSA0je&-E=rd:Z + ip)m*.?[K3%MV2W,ko,7nl^'Yj-KGJO)aCdqMd"*DW,Z+?0W^Dj(?u;*6c=Rh+p`6ee#nYt + 1'QHE\Z#H[Qm,kDf][U\*0U-=(;'sWh>GDA8L1rh%u\YuLqQaCP^6W5(K.:^2eJ8aMZ?b/7,)bn$#eT:tO!e+t':$m + CD5cjKP,G$,]_4s7:q-NZ*#Oqmjc0K==)A3B&B)['mi`f2[]Jq/N89Obee/<W\.?Hbh + R=cT]$%6\Q'&Rs'^2`YJ&Ln,57_#BM4SYLaaRe2)*+GiU1qnMRlo]re!f:?Fp]9LnlK7=3# + #@:?FJ40u$kmGkQhR$MU@@`l?PHh"BLUn[!s_ntS,~> +Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/apps/DemoCameraWebP/artwork.obj b/apps/DemoCameraWebP/artwork.obj new file mode 100644 index 00000000..d10f1ce9 --- /dev/null +++ b/apps/DemoCameraWebP/artwork.obj @@ -0,0 +1,39 @@ +% TGIF +state(0,33,100,0,0,1,16,1,9,1,1,0,0,1,0,1,0,'Courier',0,17,0,0,1,5,0,0,1,1,0,16,1,0,1,1,1,0,1056,1497,0,0,2880). +unit("1 pixel/pixel"). +generated_by("pstoedit",0,"4.3"). +page(1,"",1). +polygon('#41e81d',37,[ + 99.5556,1278.05,87.5556,1302.05,77.3819,1302.05,77.3819,1291.71,53.3819,1291.71,53.3819,1302.05,43.5556,1302.05,41.9931,1302.05, + 37.3195,1303.31,32.2361,1306.74,28.8055,1311.83,27.5556,1316.49,27.5556,1318.05,27.5556,1430.05,27.5556,1431.61,28.8055,1436.28, + 32.2361,1441.37,37.3195,1444.8,41.9931,1446.05,43.5556,1446.05,219.556,1446.05,221.111,1446.05,225.778,1444.8,230.868,1441.37, + 234.292,1436.28,235.556,1431.61,235.556,1430.05,235.556,1318.05,235.556,1316.49,234.292,1311.83,230.868,1306.74,225.778,1303.31, + 221.111,1302.05,219.556,1302.05,175.556,1302.05,163.556,1278.05,99.5556,1278.05],1,0,1,0,1,0,0,0,0,0,'0', + "0000000000",[ +]). +polygon('#777777',37,[ + 99.5556,1278.05,87.5556,1302.05,77.3819,1302.05,77.3819,1291.71,53.3819,1291.71,53.3819,1302.05,43.5556,1302.05,41.9931,1302.05, + 37.3195,1303.31,32.2361,1306.74,28.8055,1311.83,27.5556,1316.49,27.5556,1318.05,27.5556,1430.05,27.5556,1431.61,28.8055,1436.28, + 32.2361,1441.37,37.3195,1444.8,41.9931,1446.05,43.5556,1446.05,219.556,1446.05,221.111,1446.05,225.778,1444.8,230.868,1441.37, + 234.292,1436.28,235.556,1431.61,235.556,1430.05,235.556,1318.05,235.556,1316.49,234.292,1311.83,230.868,1306.74,225.778,1303.31, + 221.111,1302.05,219.556,1302.05,175.556,1302.05,163.556,1278.05,99.5556,1278.05],0,5.03938,1,0,2,0,0,0,0,0,'5', + "0000000000",[ +]). +polygon('#ffffff',41,[ + 187.556,1374.05,187.556,1376.87,186.416,1385.34,183.152,1395.85,177.986,1405.36,171.153,1413.65,162.861,1420.48,153.354,1425.65, + 142.84,1428.92,134.375,1430.05,131.556,1430.05,128.729,1430.05,120.264,1428.92,109.75,1425.65,100.243,1420.48,91.9515,1413.65, + 85.118,1405.36,79.9515,1395.85,76.6875,1385.34,75.5556,1376.87,75.5556,1374.05,75.5556,1371.23,76.6875,1362.76,79.9515,1352.25, + 85.118,1342.74,91.9515,1334.45,100.243,1327.62,109.75,1322.45,120.264,1319.19,128.729,1318.05,131.556,1318.05,134.375,1318.05, + 142.84,1319.19,153.354,1322.45,162.861,1327.62,171.153,1334.45,177.986,1342.74,183.152,1352.25,186.416,1362.76,187.556,1371.23, + 187.556,1374.05],1,0,1,0,3,0,0,0,0,0,'0', + "00000000000",[ +]). +polygon('#000000',41,[ + 187.556,1374.05,187.556,1376.87,186.416,1385.34,183.152,1395.85,177.986,1405.36,171.153,1413.65,162.861,1420.48,153.354,1425.65, + 142.84,1428.92,134.375,1430.05,131.556,1430.05,128.729,1430.05,120.264,1428.92,109.75,1425.65,100.243,1420.48,91.9515,1413.65, + 85.118,1405.36,79.9515,1395.85,76.6875,1385.34,75.5556,1376.87,75.5556,1374.05,75.5556,1371.23,76.6875,1362.76,79.9515,1352.25, + 85.118,1342.74,91.9515,1334.45,100.243,1327.62,109.75,1322.45,120.264,1319.19,128.729,1318.05,131.556,1318.05,134.375,1318.05, + 142.84,1319.19,153.354,1322.45,162.861,1327.62,171.153,1334.45,177.986,1342.74,183.152,1352.25,186.416,1362.76,187.556,1371.23, + 187.556,1374.05],0,5.03938,1,0,4,0,0,0,0,0,'5', + "00000000000",[ +]). diff --git a/apps/DemoCameraWebP/artwork.png b/apps/DemoCameraWebP/artwork.png new file mode 100644 index 0000000000000000000000000000000000000000..8cff87ad09c353bbb9852f234c3fdff0d57508d9 GIT binary patch literal 8017 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 X=oc8P_&<=x;ef29qC|z5QQ-dr24eA* literal 0 HcmV?d00001 diff --git a/apps/DemoCameraWebP/main.scm b/apps/DemoCameraWebP/main.scm new file mode 100644 index 00000000..fe0d576c --- /dev/null +++ b/apps/DemoCameraWebP/main.scm @@ -0,0 +1,110 @@ +#| +LambdaNative - a cross-platform Scheme framework +Copyright (c) 2009-2014, University of British Columbia +Copyright (c) 2026, Benson Muite +All rights reserved. + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials +provided with the distribution. + +* Neither the name of the University of British Columbia nor +the names of its contributors may be used to endorse or +promote products derived from this software without specific +prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +|# + +;; WebP camera example +(define gui #f) + +(define background #f) +(define default:background (list 4 4 (glCoreTextureCreate 4 4 (make-u8vector 16 #xff)) 0.1 0.1 .9 .9)) + +(define camera-image (string-append (system-directory) (system-pathseparator) "vidcam.jpg")) +(define camera-image2 (string-append (system-directory) (system-pathseparator) "vidcam.webp")) + +(define lastmodtime 0.) + +;; look for a new jpeg from the camera, create a downsampled webp, and load that as a texture + +(define (autoload) + (let* ((fileinfo (if (file-exists? camera-image) (file-info camera-image) #f)) + (modtime (if fileinfo (time->seconds (file-info-last-modification-time fileinfo)) #f))) + (if (and gui background modtime (> modtime lastmodtime)) + (let* ((gdf (gdFileOpen camera-image "r")) + (gd (gdImageCreateFromJpeg gdf)) + (w (gdImageSX gd)) + (h (gdImageSY gd)) + (w2 256) + (h2 (fix (* w2 (/ h w)))) + (gdf2 (gdFileOpen camera-image2 "w")) + (gd2 (gdImageCreateTrueColor w2 h2))) + (gdImageCopyResampled gd2 gd 0 0 0 0 w2 h2 w h) + (gdImageWebp gd2 gdf2) + (gdImageDestroy gd) + (gdImageDestroy gd2) + (gdFileClose gdf) + (gdFileClose gdf2) + (let ((img (if (file-exists? camera-image2) (webp->img camera-image2) #f))) + (glgui-widget-set! gui background 'image (if img img default:background))) + (set! lastmodtime modtime) + )))) + +(main +;; initialization + (lambda (w h) + (make-window 320 480) + (glgui-orientation-set! GUI_PORTRAIT) + (set! gui (make-glgui)) + (let ((w (glgui-width-get)) + (h (glgui-height-get))) + (set! background (glgui-pixmap gui 0 0 default:background w h)) + (let* ((bw 150) (bh 50) + (bx (/ (- w bw) 2.)) + (by (/ (- h bh) 2.))) + (glgui-button-string gui bx (+ by (* bh 2)) bw bh "Take picture" ascii_18.fnt + (lambda (un . used) (camera-start camera-image))) + )) + (if (file-exists? camera-image) (delete-file camera-image)) + (if (file-exists? camera-image2) (delete-file camera-image2)) + (let ((logdir (string-append (system-directory) "/log"))) + (if (not (file-exists? logdir)) (create-directory logdir))) + ) +;; events + (lambda (t x y) + (autoload) + (if (= t EVENT_KEYPRESS) (begin + (if (= x EVENT_KEYESCAPE) (terminate)))) + (glgui-event gui t x y)) +;; termination + (lambda () #t) +;; suspend + (lambda () (glgui-suspend)) +;; resume + (lambda () (glgui-resume)) +) + +;; eof diff --git a/apps/DemoCameraWebP/xml/file_paths.xml b/apps/DemoCameraWebP/xml/file_paths.xml new file mode 100644 index 00000000..fa172d14 --- /dev/null +++ b/apps/DemoCameraWebP/xml/file_paths.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/modules/webp/LIBRARIES b/modules/webp/LIBRARIES new file mode 100644 index 00000000..d60dce48 --- /dev/null +++ b/modules/webp/LIBRARIES @@ -0,0 +1 @@ +libwebp diff --git a/modules/webp/webp.scm b/modules/webp/webp.scm index 85d8fb52..0db7d2fd 100644 --- a/modules/webp/webp.scm +++ b/modules/webp/webp.scm @@ -1,6 +1,7 @@ #| LambdaNative - a cross-platform Scheme framework Copyright (c) 2009-2014, University of British Columbia +Copyright (c) 2026, Benson Muite All rights reserved. Redistribution and use in source and binary forms, with or @@ -36,11 +37,11 @@ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |# -;; png - wrapper for libpng image library +;; webp - wrapper for libwebp image library -(define png:debuglevel 0) -(define (png:log level . x) - (if (>= png:debuglevel level) (apply log-system (append (list "png: ") x)))) +(define webp:debuglevel 0) +(define (webp:log level . x) + (if (>= webp:debuglevel level) (apply log-system (append (list "webp: ") x)))) (c-declare #< #include -#include +#include +#include +#include -static int ln_png_info(char *fname, int infoarg) +#define COLOR_GRAY 1 +#define COLOR_RGB 3 +#define COLOR_RGBA 4 + +static int ln_webp_info(const char *fname, int infoarg) { + FILE *fd=0; - png_structp png_ptr = 0; - png_infop info_ptr = 0; - unsigned char header[8]; - int tmp,res=-1; + int res=-1; + uint8_t *file_data; + uint8_t *width; + uint8_t *height; + WebPBitstreamFeatures data_features; + size_t file_size; fd = fopen(fname, "rb"); if (!fd) goto info_bail; - fread(header, 1, 8, fd); - if (png_sig_cmp(header, 0, 8)) goto info_bail; - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) goto info_bail; - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) goto info_bail; - if (setjmp(png_jmpbuf(png_ptr))) { goto info_bail; } - png_init_io(png_ptr, fd); - png_set_sig_bytes(png_ptr, 8); - png_read_info(png_ptr, info_ptr); + fseek(fd, 0, SEEK_END); + file_size = ftell(fd); + if (file_size == (size_t)-1) goto info_bail; + fseek(fd, 0, SEEK_SET); + // we allocate one extra byte for the \0 terminator + file_data = (uint8_t*)WebPMalloc(file_size + 1); + if (file_data == NULL) goto info_bail; + if (!(fread(file_data, file_size, 1, fd) == 1)) goto info_bail; + file_data[file_size] = '\0'; // convenient 0-terminator + if(WebPGetFeatures(file_data, file_size, &data_features) != VP8_STATUS_OK) goto info_bail; switch (infoarg) { - case 1: res=png_get_image_width(png_ptr, info_ptr); break; - case 2: res=png_get_image_height(png_ptr, info_ptr); break; - case 3: res=png_get_bit_depth(png_ptr, info_ptr); break; - case 4: - tmp=png_get_color_type(png_ptr, info_ptr); - switch (tmp) { - case PNG_COLOR_TYPE_GRAY: res = 1; break; - case PNG_COLOR_TYPE_RGB: res = 3; break; - case PNG_COLOR_TYPE_RGBA : res = 4; break; - } - break; + case 1: res=(int) data_features.width; break; + case 2: res=(int) data_features.height; break; + case 3: res=(int) file_size; break; + case 4: res=(int) data_features.has_alpha; break; + case 5: res=(int) data_features.has_animation; break; + case 6: res=(int) data_features.format; break; } info_bail: - if (info_ptr) png_destroy_info_struct(png_ptr, &info_ptr); - if (png_ptr) png_destroy_read_struct(&png_ptr, &info_ptr,0); + if (file_data) WebPFree(file_data); if (fd) fclose(fd); return res; } -static int ln_png_from_u8vector(int w, int h, unsigned char *data, int datalen, const char *fname) +static int ln_webp_from_u8vector(int w, int h, unsigned char *data, int datalen, const char *fname) { + FILE *fd=0; - png_structp png_ptr = 0; - png_infop info_ptr = 0; int res=-1; - int color_types[] = { -1, PNG_COLOR_TYPE_GRAY, -1, PNG_COLOR_TYPE_RGB, PNG_COLOR_TYPE_RGBA}; + int color_types[] = { -1, COLOR_GRAY, -1, COLOR_RGB, COLOR_RGBA}; int stride = datalen/(w*h); int color_type = (stride<5&&stride>0?color_types[stride]:-1); if (color_type<0) goto writer_bail; if (stride*w*h!=datalen) goto writer_bail; - png_byte ** row_pointers = NULL; - size_t x, y; + uint8_t ** output = NULL; + uint8_t * data_webp = NULL; + data_webp = (uint8_t*)malloc(4*datalen*sizeof(uint8_t)); + if (!data_webp) goto writer_bail; + size_t output_size=0; fd = fopen (fname, "wb"); if (!fd) goto writer_bail; - png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) goto writer_bail; - info_ptr = png_create_info_struct (png_ptr); - if (!info_ptr) goto writer_bail; - if (setjmp (png_jmpbuf (png_ptr))) goto writer_bail; - png_set_IHDR (png_ptr, info_ptr, w, h, 8, // depth - color_type, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - row_pointers = png_malloc (png_ptr, h * sizeof (png_byte *)); - for (y = 0; y < h; ++y) { - png_byte *row = png_malloc (png_ptr, sizeof (uint8_t) * w * stride); - row_pointers[y] = row; - for (x = 0; x < w; ++x) { - int i; - for (i=0;iw0) goto reader_bail; - if (height>h0) goto reader_bail; - png_set_interlace_handling(png_ptr); - png_read_update_info(png_ptr, info_ptr); - if (setjmp(png_jmpbuf(png_ptr))) goto reader_bail; - row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); - for (y=0; ypng data fname w h) - (png:log 1 "u8vector->png " w " " h " [] " fname) +(define (u8vector->webp data fname w h) + (webp:log 1 "u8vector->webp " w " " h " [] " fname) (fx= ((c-lambda (int int scheme-object int char-string) int - "___result=ln_png_from_u8vector(___arg1,___arg2,___CAST(void*,___BODY_AS(___arg3,___tSUBTYPED)),___arg4,___arg5);") + "___result=ln_webp_from_u8vector(___arg1,___arg2,___CAST(void*,___BODY_AS(___arg3,___tSUBTYPED)),___arg4,___arg5);") w h data (u8vector-length data) fname) 0)) -(define (png->u8vector fname . xargs) - (png:log 1 "png->u8vector " fname " " xargs) - (let* ((w (png-width fname)) - (h (png-height fname)) - (w0 (if (= (length xargs) 2) (car xargs) w)) +(define (webp->u8vector fname . xargs) + (webp:log 1 "webp->u8vector " fname " " xargs) + (let* ((w (webp-width fname)) + (h (webp-height fname)) + (a (webp-has_animation fname)) + (w0 (if (= (length xargs) 2) (car xargs) w)) (h0 (if (= (length xargs) 2) (cadr xargs) h)) - (s (png-stride fname)) - (data (if (and w0 h0 s) (make-u8vector (* w0 h0 s) 0) #f))) + (file_size (webp-file_size fname)) + (data (if (and w h file_size (equal? a 0)) (make-u8vector (* w h 4) 0) #f))) (if data (begin (if (fx= ((c-lambda (int int scheme-object int char-string) int - "___result=ln_png_to_u8vector(___arg1,___arg2,___CAST(void*,___BODY_AS(___arg3,___tSUBTYPED)),___arg4,___arg5);") - w0 h0 data (u8vector-length data) fname) 0) data #f)) (begin - (log-error "png->u8vector failed on " fname) #f)))) + "___result=ln_webp_to_u8vector(___arg1,___arg2,___CAST(void*,___BODY_AS(___arg3,___tSUBTYPED)),___arg4,___arg5);") + w0 h0 data file_size fname) 0) data #f)) + (begin + (log-error "webp->u8vector failed on " fname) #f)))) ;; ------ ;; opengl related functions ;; eval is used to delay resolving potentially unavailable calls -(define (png:png->texture fname . xargs) - (png:log 1 "png->texture " fname " " xargs) - (let* ((w (png-width fname)) - (h (png-height fname)) +(define (webp:webp->texture fname . xargs) + (webp:log 1 "webp->texture " fname " " xargs) + (let* ((w (webp-width fname)) + (h (webp-height fname)) + (a (webp-has_animation fname)) (w0 (if (= (length xargs) 2) (car xargs) w)) - (h0 (if (= (length xargs) 2) (cadr xargs) h)) - (data (png->u8vector fname w0 h0))) - (if data ((eval 'glCoreTextureCreate) w0 h0 data) - (begin (log-error "png:png->texture failed on " fname) #f)))) + (h0 (if (= (length xargs) 2) (cadr xargs) h)) + (data (webp->u8vector fname w0 h0))) + (if (and data (equal? a 0)) ((eval 'glCoreTextureCreate) w0 h0 data) + (begin (log-error "webp:webp->texture failed on " fname) #f)))) -(define (png->img fname) - (png:log 1 "png->img " fname) - (let* ((w (png-width fname)) - (h (png-height fname)) - (w0 (fix (expt 2. (ceiling (/ (log w) (log 2.)))))) - (h0 (fix (expt 2. (ceiling (/ (log h) (log 2.)))))) - (t (png:png->texture fname w0 h0))) - (if (and w h t) - (list w h t 0. (- 1. (/ h h0 1.)) (/ w w0 1.) 1.) - (begin (log-error "png->img failed on " fname) #f)))) +(define (webp->img fname) + (webp:log 1 "webp->img " fname) + (let* ((w (webp-width fname)) + (h (webp-height fname)) + (a (webp-has_animation fname)) + (w0 (fix (expt 2. (ceiling (/ (log w) (log 2.)))))) + (h0 (fix (expt 2. (ceiling (/ (log h) (log 2.)))))) + (t (webp:webp->texture fname))) + (if (and w h t (equal? a 0)) + (list w h t 0. (- 1. (/ h h0 1.)) (/ w w0 1.) 1.) + (begin (log-error "webp->img failed on " fname) #f)))) -(define (png:texture->png t fname) - (png:log 1 "texture->png " t " " fname) +(define (webp:texture->webp t fname) + (webp:log 1 "texture->webp " t " " fname) (let ((w ((eval 'glCoreTextureWidth) t)) (h ((eval 'glCoreTextureHeight) t)) (data ((eval 'glCoreTextureData) t))) - (u8vector->png data fname w h))) + (u8vector->webp data fname w h))) -(define (img->png img fname) - (png:texture->png (caddr img) fname)) +(define (img->webp img fname) + (webp:texture->webp (caddr img) fname)) -(define (screenshot->png fname) - (png:log 1 "screenshot->png " fname) +(define (screenshot->webp fname) + (webp:log 1 "screenshot->webp " fname) (let* ((w ((eval 'glgui-width-get))) (h ((eval 'glgui-height-get))) (data ((eval 'glCoreReadPixels) 0 0 w h))) - (u8vector->png data fname w h))) + (u8vector->webp data fname w h))) ;; ------ ;; unit test -(unit-test "png" "1000 random image encode-decode runs" +(unit-test "webp" "1000 random image encode-decode runs" (lambda () - (let* ((fname (string-append (system-directory) (system-pathseparator) "unittest.png")) + (let* ((fname (string-append (system-directory) (system-pathseparator) "unittest.webp")) (res (let loop ((n 1000)) (if (fx= n 0) #t (if (let* ((w (+ 1 (random-integer 200))) (h (+ 1 (random-integer 200))) - (stride (list-ref '(1 3 4) (random-integer 3))) - (data (random-u8vector (* stride w h)))) - (u8vector->png data fname w h) - (not (and (= w (png-width fname)) - (= h (png-height fname)) - (= stride (png-stride fname)) - (equal? data (png->u8vector fname))))) #f (loop (fx- n 1))))))) + (data (random-u8vector (* 4 w h)))) + (u8vector->webp data fname w h) + (not (and (= w (webp-width fname)) + (= h (webp-height fname)) + (equal? data (webp->u8vector fname))))) #f (loop (fx- n 1))))))) (if (file-exists? fname) (delete-file fname)) res)))