svn commit: r468805 - in head/graphics: . openfx-arena openfx-arena/files

Olivier Cochard olivier at FreeBSD.org
Tue May 1 23:59:25 UTC 2018


Author: olivier
Date: Tue May  1 23:59:23 2018
New Revision: 468805
URL: https://svnweb.freebsd.org/changeset/ports/468805

Log:
  New port: graphics/openfx-arena
  Extra set of OpenFX plugins designed for Natron but also compatible with other
  hosts.

Added:
  head/graphics/openfx-arena/
  head/graphics/openfx-arena/Makefile   (contents, props changed)
  head/graphics/openfx-arena/distinfo   (contents, props changed)
  head/graphics/openfx-arena/files/
  head/graphics/openfx-arena/files/patch-Bundle_Makefile   (contents, props changed)
  head/graphics/openfx-arena/files/patch-Bundle_lodepng.cpp   (contents, props changed)
  head/graphics/openfx-arena/files/patch-Bundle_lodepng.h   (contents, props changed)
  head/graphics/openfx-arena/files/patch-Makefile.master   (contents, props changed)
  head/graphics/openfx-arena/pkg-descr   (contents, props changed)
  head/graphics/openfx-arena/pkg-plist   (contents, props changed)
Modified:
  head/graphics/Makefile

Modified: head/graphics/Makefile
==============================================================================
--- head/graphics/Makefile	Tue May  1 23:51:34 2018	(r468804)
+++ head/graphics/Makefile	Tue May  1 23:59:23 2018	(r468805)
@@ -658,6 +658,7 @@
     SUBDIR += opencv-core
     SUBDIR += opencv-java
     SUBDIR += opendx
+    SUBDIR += openfx-arena
     SUBDIR += openfx-io
     SUBDIR += openfx-misc
     SUBDIR += opengl-man

Added: head/graphics/openfx-arena/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/graphics/openfx-arena/Makefile	Tue May  1 23:59:23 2018	(r468805)
@@ -0,0 +1,67 @@
+# $FreeBSD$
+
+PORTNAME=	openfx-arena
+PORTVERSION=	2.2.1
+CATEGORIES=	graphics
+
+MAINTAINER=	olivier at FreeBSD.org
+COMMENT=	Extra OpenFX plugins for Natron
+
+LICENSE=	GPLv2
+
+ONLY_FOR_ARCHS=	amd64
+BUILD_DEPENDS=	opencl>=0:devel/opencl
+LIB_DEPENDS=	libOpenColorIO.so:graphics/opencolorio \
+		libfontconfig.so:x11-fonts/fontconfig \
+		libcdr-0.1.so:graphics/libcdr01 \
+		librevenge-0.0.so:textproc/librevenge \
+		libpoppler-glib.so:graphics/poppler-glib \
+		liblcms2.so:graphics/lcms2 \
+		libMagick++-6.so:graphics/ImageMagick \
+		libzip.so:archivers/libzip \
+		libexpat.so:textproc/expat2 \
+		libfreetype.so:print/freetype2 \
+		libpcre.so:devel/pcre \
+		libffi.so:devel/libffi \
+		libdrm.so:graphics/libdrm \
+		libpng16.so:graphics/png \
+		libharfbuzz.so:print/harfbuzz \
+		libgraphite2.so:graphics/graphite2 \
+		libicui18n.so:devel/icu \
+		liblqr-1.so:graphics/liblqr-1 \
+		libfftw3.so:math/fftw3 \
+		libltdl.so:devel/libltdl \
+		libpoppler.so:graphics/poppler
+
+USES=		gmake iconv
+USE_GITHUB=	yes
+GH_ACCOUNT=	olear
+GH_PROJECT=	openfx-arena
+GH_TAGNAME=	95caed1
+GH_TUPLE=	devernay:openfx-supportext:90093f7:openfx_supportext/SupportExt \
+		devernay:openfx:42463b8:openfx/OpenFX \
+		MrKepzie:openfx-io:1148523:OpenFX_IO/OpenFX-IO \
+		MrKepzie:SequenceParsing:25112f0:SequenceParsing/OpenFX-IO/IOSupport/SequenceParsing \
+		MrKepzie:tinydir:60f0905:tinydir/OpenFX-IO/IOSupport/SequenceParsing/tinydir
+
+MAKE_ENV+=	CONFIG=release
+USE_GL=	gl
+USE_GNOME=	libxml2 pango cairo librsvg2
+USE_XORG+=	x11 xcb xau xdamage xfixes xxf86vm xrender xext xdmcp pixman sm ice xt
+MAKE_ENV+=	CONFIG=release
+
+post-extract:
+	@${RMDIR} ${WRKSRC}/OpenFX-IO/openfx
+	${LN} -s ../OpenFX ${WRKSRC}/OpenFX-IO/openfx
+
+post-patch:
+	@${REINPLACE_CMD} -e 's|/usr/OFX/Plugins|${PREFIX}/OFX/Plugins|g' \
+		${WRKSRC}/OpenFX/Examples/Makefile.master \
+		${WRKSRC}/OpenFX/Support/Plugins/Makefile.master \
+		${WRKSRC}/OpenFX/HostSupport/src/ofxhPluginCache.cpp
+	@${REINPLACE_CMD} -e 's|/Contents/$$(ARCH)|/Contents/FreeBSD-x86-64/|g' \
+		${WRKSRC}/OpenFX/Support/Plugins/Makefile.master
+post-install:
+	${STRIP_CMD} ${STAGEDIR}${LOCALBASE}/OFX/Plugins/Arena.ofx.bundle/Contents/FreeBSD-x86-64/Arena.ofx
+
+.include <bsd.port.mk>

Added: head/graphics/openfx-arena/distinfo
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/graphics/openfx-arena/distinfo	Tue May  1 23:59:23 2018	(r468805)
@@ -0,0 +1,13 @@
+TIMESTAMP = 1525130623
+SHA256 (olear-openfx-arena-2.2.1-95caed1_GH0.tar.gz) = 6b945a8fdb93e83af89ef2f2f8b6a69610265ec32257fa5aa5035a84630977c2
+SIZE (olear-openfx-arena-2.2.1-95caed1_GH0.tar.gz) = 564650
+SHA256 (devernay-openfx-supportext-90093f7_GH0.tar.gz) = 3dedf570b60d17e1d6f1c9e0bb2dcb20d3a76f4323f053b20cc35b15efa4956a
+SIZE (devernay-openfx-supportext-90093f7_GH0.tar.gz) = 260067
+SHA256 (devernay-openfx-42463b8_GH0.tar.gz) = e914c87aa8902c3f092b432e744e4c9070348efbe5e58c926a05a3664dc7a62b
+SIZE (devernay-openfx-42463b8_GH0.tar.gz) = 10319112
+SHA256 (MrKepzie-openfx-io-1148523_GH0.tar.gz) = 5acc203e9de1a24ef18727608abdc2971704906611ee000f8fe604adc2c28a7a
+SIZE (MrKepzie-openfx-io-1148523_GH0.tar.gz) = 425189
+SHA256 (MrKepzie-SequenceParsing-25112f0_GH0.tar.gz) = cfc3e6ffff89f978a66e1324e7ec2270618eb8d1133c5281ee8b4507cf1503ec
+SIZE (MrKepzie-SequenceParsing-25112f0_GH0.tar.gz) = 15770
+SHA256 (MrKepzie-tinydir-60f0905_GH0.tar.gz) = 9cdedea9e02a97d4539881c06019a2317fa789d8132d914ca9909cba56c3517d
+SIZE (MrKepzie-tinydir-60f0905_GH0.tar.gz) = 4479

Added: head/graphics/openfx-arena/files/patch-Bundle_Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/graphics/openfx-arena/files/patch-Bundle_Makefile	Tue May  1 23:59:23 2018	(r468805)
@@ -0,0 +1,18 @@
+--- Bundle/Makefile.orig	2017-01-03 14:53:38 UTC
++++ Bundle/Makefile
+@@ -168,11 +168,11 @@ endif
+ 
+ PNGVERSION = a70c086077c0eaecbae3845e4da4424de5f43361
+ 
+-lodepng.cpp:
+-	curl -o $@ https://raw.githubusercontent.com/lvandeve/lodepng/$(PNGVERSION)/lodepng.cpp
++#lodepng.cpp:
++	#curl -o $@ https://raw.githubusercontent.com/lvandeve/lodepng/$(PNGVERSION)/lodepng.cpp
+ 
+-lodepng.h:
+-	curl -o $@ https://raw.githubusercontent.com/lvandeve/lodepng/$(PNGVERSION)/lodepng.h
++#lodepng.h:
++	#curl -o $@ https://raw.githubusercontent.com/lvandeve/lodepng/$(PNGVERSION)/lodepng.h
+ 
+ $(OBJECTPATH)/lodepng.o: lodepng.cpp lodepng.h
+ $(OBJECTPATH)/ReadKrita.o: ReadKrita.cpp lodepng.h

Added: head/graphics/openfx-arena/files/patch-Bundle_lodepng.cpp
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/graphics/openfx-arena/files/patch-Bundle_lodepng.cpp	Tue May  1 23:59:23 2018	(r468805)
@@ -0,0 +1,6226 @@
+--- Bundle/lodepng.cpp.orig	2017-10-04 17:18:33 UTC
++++ Bundle/lodepng.cpp
+@@ -0,0 +1,6223 @@
++/*
++LodePNG version 20160418
++
++Copyright (c) 2005-2016 Lode Vandevenne
++
++This software is provided 'as-is', without any express or implied
++warranty. In no event will the authors be held liable for any damages
++arising from the use of this software.
++
++Permission is granted to anyone to use this software for any purpose,
++including commercial applications, and to alter it and redistribute it
++freely, subject to the following restrictions:
++
++    1. The origin of this software must not be misrepresented; you must not
++    claim that you wrote the original software. If you use this software
++    in a product, an acknowledgment in the product documentation would be
++    appreciated but is not required.
++
++    2. Altered source versions must be plainly marked as such, and must not be
++    misrepresented as being the original software.
++
++    3. This notice may not be removed or altered from any source
++    distribution.
++*/
++
++/*
++The manual and changelog are in the header file "lodepng.h"
++Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C.
++*/
++
++#include "lodepng.h"
++
++#include <limits.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/
++#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/
++#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/
++#endif /*_MSC_VER */
++
++const char* LODEPNG_VERSION_STRING = "20160418";
++
++/*
++This source file is built up in the following large parts. The code sections
++with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way.
++-Tools for C and common code for PNG and Zlib
++-C Code for Zlib (huffman, deflate, ...)
++-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...)
++-The C++ wrapper around all of the above
++*/
++
++/*The malloc, realloc and free functions defined here with "lodepng_" in front
++of the name, so that you can easily change them to others related to your
++platform if needed. Everything else in the code calls these. Pass
++-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out
++#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and
++define them in your own project's source files without needing to change
++lodepng source code. Don't forget to remove "static" if you copypaste them
++from here.*/
++
++#ifdef LODEPNG_COMPILE_ALLOCATORS
++static void* lodepng_malloc(size_t size)
++{
++  return malloc(size);
++}
++
++static void* lodepng_realloc(void* ptr, size_t new_size)
++{
++  return realloc(ptr, new_size);
++}
++
++static void lodepng_free(void* ptr)
++{
++  free(ptr);
++}
++#else /*LODEPNG_COMPILE_ALLOCATORS*/
++void* lodepng_malloc(size_t size);
++void* lodepng_realloc(void* ptr, size_t new_size);
++void lodepng_free(void* ptr);
++#endif /*LODEPNG_COMPILE_ALLOCATORS*/
++
++/* ////////////////////////////////////////////////////////////////////////// */
++/* ////////////////////////////////////////////////////////////////////////// */
++/* // Tools for C, and common code for PNG and Zlib.                       // */
++/* ////////////////////////////////////////////////////////////////////////// */
++/* ////////////////////////////////////////////////////////////////////////// */
++
++/*
++Often in case of an error a value is assigned to a variable and then it breaks
++out of a loop (to go to the cleanup phase of a function). This macro does that.
++It makes the error handling code shorter and more readable.
++
++Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83);
++*/
++#define CERROR_BREAK(errorvar, code)\
++{\
++  errorvar = code;\
++  break;\
++}
++
++/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/
++#define ERROR_BREAK(code) CERROR_BREAK(error, code)
++
++/*Set error var to the error code, and return it.*/
++#define CERROR_RETURN_ERROR(errorvar, code)\
++{\
++  errorvar = code;\
++  return code;\
++}
++
++/*Try the code, if it returns error, also return the error.*/
++#define CERROR_TRY_RETURN(call)\
++{\
++  unsigned error = call;\
++  if(error) return error;\
++}
++
++/*Set error var to the error code, and return from the void function.*/
++#define CERROR_RETURN(errorvar, code)\
++{\
++  errorvar = code;\
++  return;\
++}
++
++/*
++About uivector, ucvector and string:
++-All of them wrap dynamic arrays or text strings in a similar way.
++-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version.
++-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated.
++-They're not used in the interface, only internally in this file as static functions.
++-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor.
++*/
++
++#ifdef LODEPNG_COMPILE_ZLIB
++/*dynamic vector of unsigned ints*/
++typedef struct uivector
++{
++  unsigned* data;
++  size_t size; /*size in number of unsigned longs*/
++  size_t allocsize; /*allocated size in bytes*/
++} uivector;
++
++static void uivector_cleanup(void* p)
++{
++  ((uivector*)p)->size = ((uivector*)p)->allocsize = 0;
++  lodepng_free(((uivector*)p)->data);
++  ((uivector*)p)->data = NULL;
++}
++
++/*returns 1 if success, 0 if failure ==> nothing done*/
++static unsigned uivector_reserve(uivector* p, size_t allocsize)
++{
++  if(allocsize > p->allocsize)
++  {
++    size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2);
++    void* data = lodepng_realloc(p->data, newsize);
++    if(data)
++    {
++      p->allocsize = newsize;
++      p->data = (unsigned*)data;
++    }
++    else return 0; /*error: not enough memory*/
++  }
++  return 1;
++}
++
++/*returns 1 if success, 0 if failure ==> nothing done*/
++static unsigned uivector_resize(uivector* p, size_t size)
++{
++  if(!uivector_reserve(p, size * sizeof(unsigned))) return 0;
++  p->size = size;
++  return 1; /*success*/
++}
++
++/*resize and give all new elements the value*/
++static unsigned uivector_resizev(uivector* p, size_t size, unsigned value)
++{
++  size_t oldsize = p->size, i;
++  if(!uivector_resize(p, size)) return 0;
++  for(i = oldsize; i < size; ++i) p->data[i] = value;
++  return 1;
++}
++
++static void uivector_init(uivector* p)
++{
++  p->data = NULL;
++  p->size = p->allocsize = 0;
++}
++
++#ifdef LODEPNG_COMPILE_ENCODER
++/*returns 1 if success, 0 if failure ==> nothing done*/
++static unsigned uivector_push_back(uivector* p, unsigned c)
++{
++  if(!uivector_resize(p, p->size + 1)) return 0;
++  p->data[p->size - 1] = c;
++  return 1;
++}
++#endif /*LODEPNG_COMPILE_ENCODER*/
++#endif /*LODEPNG_COMPILE_ZLIB*/
++
++/* /////////////////////////////////////////////////////////////////////////// */
++
++/*dynamic vector of unsigned chars*/
++typedef struct ucvector
++{
++  unsigned char* data;
++  size_t size; /*used size*/
++  size_t allocsize; /*allocated size*/
++} ucvector;
++
++/*returns 1 if success, 0 if failure ==> nothing done*/
++static unsigned ucvector_reserve(ucvector* p, size_t allocsize)
++{
++  if(allocsize > p->allocsize)
++  {
++    size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2);
++    void* data = lodepng_realloc(p->data, newsize);
++    if(data)
++    {
++      p->allocsize = newsize;
++      p->data = (unsigned char*)data;
++    }
++    else return 0; /*error: not enough memory*/
++  }
++  return 1;
++}
++
++/*returns 1 if success, 0 if failure ==> nothing done*/
++static unsigned ucvector_resize(ucvector* p, size_t size)
++{
++  if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0;
++  p->size = size;
++  return 1; /*success*/
++}
++
++#ifdef LODEPNG_COMPILE_PNG
++
++static void ucvector_cleanup(void* p)
++{
++  ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0;
++  lodepng_free(((ucvector*)p)->data);
++  ((ucvector*)p)->data = NULL;
++}
++
++static void ucvector_init(ucvector* p)
++{
++  p->data = NULL;
++  p->size = p->allocsize = 0;
++}
++#endif /*LODEPNG_COMPILE_PNG*/
++
++#ifdef LODEPNG_COMPILE_ZLIB
++/*you can both convert from vector to buffer&size and vica versa. If you use
++init_buffer to take over a buffer and size, it is not needed to use cleanup*/
++static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size)
++{
++  p->data = buffer;
++  p->allocsize = p->size = size;
++}
++#endif /*LODEPNG_COMPILE_ZLIB*/
++
++#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER)
++/*returns 1 if success, 0 if failure ==> nothing done*/
++static unsigned ucvector_push_back(ucvector* p, unsigned char c)
++{
++  if(!ucvector_resize(p, p->size + 1)) return 0;
++  p->data[p->size - 1] = c;
++  return 1;
++}
++#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/
++
++
++/* ////////////////////////////////////////////////////////////////////////// */
++
++#ifdef LODEPNG_COMPILE_PNG
++#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
++/*returns 1 if success, 0 if failure ==> nothing done*/
++static unsigned string_resize(char** out, size_t size)
++{
++  char* data = (char*)lodepng_realloc(*out, size + 1);
++  if(data)
++  {
++    data[size] = 0; /*null termination char*/
++    *out = data;
++  }
++  return data != 0;
++}
++
++/*init a {char*, size_t} pair for use as string*/
++static void string_init(char** out)
++{
++  *out = NULL;
++  string_resize(out, 0);
++}
++
++/*free the above pair again*/
++static void string_cleanup(char** out)
++{
++  lodepng_free(*out);
++  *out = NULL;
++}
++
++static void string_set(char** out, const char* in)
++{
++  size_t insize = strlen(in), i;
++  if(string_resize(out, insize))
++  {
++    for(i = 0; i != insize; ++i)
++    {
++      (*out)[i] = in[i];
++    }
++  }
++}
++#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
++#endif /*LODEPNG_COMPILE_PNG*/
++
++/* ////////////////////////////////////////////////////////////////////////// */
++
++unsigned lodepng_read32bitInt(const unsigned char* buffer)
++{
++  return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]);
++}
++
++#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)
++/*buffer must have at least 4 allocated bytes available*/
++static void lodepng_set32bitInt(unsigned char* buffer, unsigned value)
++{
++  buffer[0] = (unsigned char)((value >> 24) & 0xff);
++  buffer[1] = (unsigned char)((value >> 16) & 0xff);
++  buffer[2] = (unsigned char)((value >>  8) & 0xff);
++  buffer[3] = (unsigned char)((value      ) & 0xff);
++}
++#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/
++
++#ifdef LODEPNG_COMPILE_ENCODER
++static void lodepng_add32bitInt(ucvector* buffer, unsigned value)
++{
++  ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/
++  lodepng_set32bitInt(&buffer->data[buffer->size - 4], value);
++}
++#endif /*LODEPNG_COMPILE_ENCODER*/
++
++/* ////////////////////////////////////////////////////////////////////////// */
++/* / File IO                                                                / */
++/* ////////////////////////////////////////////////////////////////////////// */
++
++#ifdef LODEPNG_COMPILE_DISK
++
++/* returns negative value on error. This should be pure C compatible, so no fstat. */
++static long lodepng_filesize(const char* filename)
++{
++  FILE* file;
++  long size;
++  file = fopen(filename, "rb");
++  if(!file) return -1;
++
++  if(fseek(file, 0, SEEK_END) != 0)
++  {
++    fclose(file);
++    return -1;
++  }
++
++  size = ftell(file);
++  /* It may give LONG_MAX as directory size, this is invalid for us. */
++  if(size == LONG_MAX) size = -1;
++
++  fclose(file);
++  return size;
++}
++
++/* load file into buffer that already has the correct allocated size. Returns error code.*/
++static unsigned lodepng_buffer_file(unsigned char* out, size_t size, const char* filename)
++{
++  FILE* file;
++  size_t readsize;
++  file = fopen(filename, "rb");
++  if(!file) return 78;
++
++  readsize = fread(out, 1, size, file);
++  fclose(file);
++
++  if (readsize != size) return 78;
++  return 0;
++}
++
++unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename)
++{
++  long size = lodepng_filesize(filename);
++  if (size < 0) return 78;
++  *outsize = (size_t)size;
++
++  *out = (unsigned char*)lodepng_malloc((size_t)size);
++  if(!(*out) && size > 0) return 83; /*the above malloc failed*/
++
++  return lodepng_buffer_file(*out, (size_t)size, filename);
++}
++
++/*write given buffer to the file, overwriting the file, it doesn't append to it.*/
++unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename)
++{
++  FILE* file;
++  file = fopen(filename, "wb" );
++  if(!file) return 79;
++  fwrite((char*)buffer , 1 , buffersize, file);
++  fclose(file);
++  return 0;
++}
++
++#endif /*LODEPNG_COMPILE_DISK*/
++
++/* ////////////////////////////////////////////////////////////////////////// */
++/* ////////////////////////////////////////////////////////////////////////// */
++/* // End of common code and tools. Begin of Zlib related code.            // */
++/* ////////////////////////////////////////////////////////////////////////// */
++/* ////////////////////////////////////////////////////////////////////////// */
++
++#ifdef LODEPNG_COMPILE_ZLIB
++#ifdef LODEPNG_COMPILE_ENCODER
++/*TODO: this ignores potential out of memory errors*/
++#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\
++{\
++  /*add a new byte at the end*/\
++  if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\
++  /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\
++  (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\
++  ++(*bitpointer);\
++}
++
++static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits)
++{
++  size_t i;
++  for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1));
++}
++
++static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits)
++{
++  size_t i;
++  for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1));
++}
++#endif /*LODEPNG_COMPILE_ENCODER*/
++
++#ifdef LODEPNG_COMPILE_DECODER
++
++#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1)
++
++static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream)
++{
++  unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream));
++  ++(*bitpointer);
++  return result;
++}
++
++static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
++{
++  unsigned result = 0, i;
++  for(i = 0; i != nbits; ++i)
++  {
++    result += ((unsigned)READBIT(*bitpointer, bitstream)) << i;
++    ++(*bitpointer);
++  }
++  return result;
++}
++#endif /*LODEPNG_COMPILE_DECODER*/
++
++/* ////////////////////////////////////////////////////////////////////////// */
++/* / Deflate - Huffman                                                      / */
++/* ////////////////////////////////////////////////////////////////////////// */
++
++#define FIRST_LENGTH_CODE_INDEX 257
++#define LAST_LENGTH_CODE_INDEX 285
++/*256 literals, the end code, some length codes, and 2 unused codes*/
++#define NUM_DEFLATE_CODE_SYMBOLS 288
++/*the distance codes have their own symbols, 30 used, 2 unused*/
++#define NUM_DISTANCE_SYMBOLS 32
++/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/
++#define NUM_CODE_LENGTH_CODES 19
++
++/*the base lengths represented by codes 257-285*/
++static const unsigned LENGTHBASE[29]
++  = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
++     67, 83, 99, 115, 131, 163, 195, 227, 258};
++
++/*the extra bits used by codes 257-285 (added to base length)*/
++static const unsigned LENGTHEXTRA[29]
++  = {0, 0, 0, 0, 0, 0, 0,  0,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,
++      4,  4,  4,   4,   5,   5,   5,   5,   0};
++
++/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/
++static const unsigned DISTANCEBASE[30]
++  = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
++     769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
++
++/*the extra bits of backwards distances (added to base)*/
++static const unsigned DISTANCEEXTRA[30]
++  = {0, 0, 0, 0, 1, 1, 2,  2,  3,  3,  4,  4,  5,  5,   6,   6,   7,   7,   8,
++       8,    9,    9,   10,   10,   11,   11,   12,    12,    13,    13};
++
++/*the order in which "code length alphabet code lengths" are stored, out of this
++the huffman tree of the dynamic huffman tree lengths is generated*/
++static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES]
++  = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
++
++/* ////////////////////////////////////////////////////////////////////////// */
++
++/*
++Huffman tree struct, containing multiple representations of the tree
++*/
++typedef struct HuffmanTree
++{
++  unsigned* tree2d;
++  unsigned* tree1d;
++  unsigned* lengths; /*the lengths of the codes of the 1d-tree*/
++  unsigned maxbitlen; /*maximum number of bits a single code can get*/
++  unsigned numcodes; /*number of symbols in the alphabet = number of codes*/
++} HuffmanTree;
++
++/*function used for debug purposes to draw the tree in ascii art with C++*/
++/*
++static void HuffmanTree_draw(HuffmanTree* tree)
++{
++  std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl;
++  for(size_t i = 0; i != tree->tree1d.size; ++i)
++  {
++    if(tree->lengths.data[i])
++      std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl;
++  }
++  std::cout << std::endl;
++}*/
++
++static void HuffmanTree_init(HuffmanTree* tree)
++{
++  tree->tree2d = 0;
++  tree->tree1d = 0;
++  tree->lengths = 0;
++}
++
++static void HuffmanTree_cleanup(HuffmanTree* tree)
++{
++  lodepng_free(tree->tree2d);
++  lodepng_free(tree->tree1d);
++  lodepng_free(tree->lengths);
++}
++
++/*the tree representation used by the decoder. return value is error*/
++static unsigned HuffmanTree_make2DTree(HuffmanTree* tree)
++{
++  unsigned nodefilled = 0; /*up to which node it is filled*/
++  unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/
++  unsigned n, i;
++
++  tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned));
++  if(!tree->tree2d) return 83; /*alloc fail*/
++
++  /*
++  convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means
++  uninited, a value >= numcodes is an address to another bit, a value < numcodes
++  is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as
++  many columns as codes - 1.
++  A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes.
++  Here, the internal nodes are stored (what their 0 and 1 option point to).
++  There is only memory for such good tree currently, if there are more nodes
++  (due to too long length codes), error 55 will happen
++  */
++  for(n = 0; n < tree->numcodes * 2; ++n)
++  {
++    tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/
++  }
++
++  for(n = 0; n < tree->numcodes; ++n) /*the codes*/
++  {
++    for(i = 0; i != tree->lengths[n]; ++i) /*the bits for this code*/
++    {
++      unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1);
++      /*oversubscribed, see comment in lodepng_error_text*/
++      if(treepos > 2147483647 || treepos + 2 > tree->numcodes) return 55;
++      if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/
++      {
++        if(i + 1 == tree->lengths[n]) /*last bit*/
++        {
++          tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/
++          treepos = 0;
++        }
++        else
++        {
++          /*put address of the next step in here, first that address has to be found of course
++          (it's just nodefilled + 1)...*/
++          ++nodefilled;
++          /*addresses encoded with numcodes added to it*/
++          tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes;
++          treepos = nodefilled;
++        }
++      }
++      else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes;
++    }
++  }
++
++  for(n = 0; n < tree->numcodes * 2; ++n)
++  {
++    if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/
++  }
++
++  return 0;
++}
++
++/*
++Second step for the ...makeFromLengths and ...makeFromFrequencies functions.
++numcodes, lengths and maxbitlen must already be filled in correctly. return
++value is error.
++*/
++static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree)
++{
++  uivector blcount;
++  uivector nextcode;
++  unsigned error = 0;
++  unsigned bits, n;
++
++  uivector_init(&blcount);
++  uivector_init(&nextcode);
++
++  tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned));
++  if(!tree->tree1d) error = 83; /*alloc fail*/
++
++  if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0)
++  || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0))
++    error = 83; /*alloc fail*/
++
++  if(!error)
++  {
++    /*step 1: count number of instances of each code length*/
++    for(bits = 0; bits != tree->numcodes; ++bits) ++blcount.data[tree->lengths[bits]];
++    /*step 2: generate the nextcode values*/
++    for(bits = 1; bits <= tree->maxbitlen; ++bits)
++    {
++      nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1;
++    }
++    /*step 3: generate all the codes*/
++    for(n = 0; n != tree->numcodes; ++n)
++    {
++      if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++;
++    }
++  }
++
++  uivector_cleanup(&blcount);
++  uivector_cleanup(&nextcode);
++
++  if(!error) return HuffmanTree_make2DTree(tree);
++  else return error;
++}
++
++/*
++given the code lengths (as stored in the PNG file), generate the tree as defined
++by Deflate. maxbitlen is the maximum bits that a code in the tree can have.
++return value is error.
++*/
++static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen,
++                                            size_t numcodes, unsigned maxbitlen)
++{
++  unsigned i;
++  tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned));
++  if(!tree->lengths) return 83; /*alloc fail*/
++  for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i];
++  tree->numcodes = (unsigned)numcodes; /*number of symbols*/
++  tree->maxbitlen = maxbitlen;
++  return HuffmanTree_makeFromLengths2(tree);
++}
++
++#ifdef LODEPNG_COMPILE_ENCODER
++
++/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding",
++Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/
++
++/*chain node for boundary package merge*/
++typedef struct BPMNode
++{
++  int weight; /*the sum of all weights in this chain*/
++  unsigned index; /*index of this leaf node (called "count" in the paper)*/
++  struct BPMNode* tail; /*the next nodes in this chain (null if last)*/
++  int in_use;
++} BPMNode;
++
++/*lists of chains*/
++typedef struct BPMLists
++{
++  /*memory pool*/
++  unsigned memsize;
++  BPMNode* memory;
++  unsigned numfree;
++  unsigned nextfree;
++  BPMNode** freelist;
++  /*two heads of lookahead chains per list*/
++  unsigned listsize;
++  BPMNode** chains0;
++  BPMNode** chains1;
++} BPMLists;
++
++/*creates a new chain node with the given parameters, from the memory in the lists */
++static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail)
++{
++  unsigned i;
++  BPMNode* result;
++
++  /*memory full, so garbage collect*/
++  if(lists->nextfree >= lists->numfree)
++  {
++    /*mark only those that are in use*/
++    for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0;
++    for(i = 0; i != lists->listsize; ++i)
++    {
++      BPMNode* node;
++      for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1;
++      for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1;
++    }
++    /*collect those that are free*/
++    lists->numfree = 0;
++    for(i = 0; i != lists->memsize; ++i)
++    {
++      if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i];
++    }
++    lists->nextfree = 0;
++  }
++
++  result = lists->freelist[lists->nextfree++];
++  result->weight = weight;
++  result->index = index;
++  result->tail = tail;
++  return result;
++}
++
++/*sort the leaves with stable mergesort*/
++static void bpmnode_sort(BPMNode* leaves, size_t num)
++{
++  BPMNode* mem = (BPMNode*)lodepng_malloc(sizeof(*leaves) * num);
++  size_t width, counter = 0;
++  for(width = 1; width < num; width *= 2)
++  {
++    BPMNode* a = (counter & 1) ? mem : leaves;
++    BPMNode* b = (counter & 1) ? leaves : mem;
++    size_t p;
++    for(p = 0; p < num; p += 2 * width)
++    {
++      size_t q = (p + width > num) ? num : (p + width);
++      size_t r = (p + 2 * width > num) ? num : (p + 2 * width);
++      size_t i = p, j = q, k;
++      for(k = p; k < r; k++)
++      {
++        if(i < q && (j >= r || a[i].weight <= a[j].weight)) b[k] = a[i++];
++        else b[k] = a[j++];
++      }
++    }
++    counter++;
++  }
++  if(counter & 1) memcpy(leaves, mem, sizeof(*leaves) * num);
++  lodepng_free(mem);
++}
++
++/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/
++static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num)
++{
++  unsigned lastindex = lists->chains1[c]->index;
++
++  if(c == 0)
++  {
++    if(lastindex >= numpresent) return;
++    lists->chains0[c] = lists->chains1[c];
++    lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0);
++  }
++  else
++  {
++    /*sum of the weights of the head nodes of the previous lookahead chains.*/
++    int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight;
++    lists->chains0[c] = lists->chains1[c];
++    if(lastindex < numpresent && sum > leaves[lastindex].weight)
++    {
++      lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail);
++      return;
++    }
++    lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]);
++    /*in the end we are only interested in the chain of the last list, so no
++    need to recurse if we're at the last one (this gives measurable speedup)*/
++    if(num + 1 < (int)(2 * numpresent - 2))
++    {
++      boundaryPM(lists, leaves, numpresent, c - 1, num);
++      boundaryPM(lists, leaves, numpresent, c - 1, num);
++    }
++  }
++}
++
++unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies,
++                                      size_t numcodes, unsigned maxbitlen)
++{
++  unsigned error = 0;
++  unsigned i;
++  size_t numpresent = 0; /*number of symbols with non-zero frequency*/
++  BPMNode* leaves; /*the symbols, only those with > 0 frequency*/
++
++  if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/
++  if((1u << maxbitlen) < numcodes) return 80; /*error: represent all symbols*/
++
++  leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves));
++  if(!leaves) return 83; /*alloc fail*/
++
++  for(i = 0; i != numcodes; ++i)
++  {
++    if(frequencies[i] > 0)
++    {
++      leaves[numpresent].weight = (int)frequencies[i];
++      leaves[numpresent].index = i;
++      ++numpresent;
++    }
++  }
++
++  for(i = 0; i != numcodes; ++i) lengths[i] = 0;
++
++  /*ensure at least two present symbols. There should be at least one symbol
++  according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To
++  make these work as well ensure there are at least two symbols. The
++  Package-Merge code below also doesn't work correctly if there's only one
++  symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/
++  if(numpresent == 0)
++  {
++    lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/
++  }
++  else if(numpresent == 1)
++  {
++    lengths[leaves[0].index] = 1;
++    lengths[leaves[0].index == 0 ? 1 : 0] = 1;
++  }
++  else
++  {
++    BPMLists lists;
++    BPMNode* node;
++
++    bpmnode_sort(leaves, numpresent);
++
++    lists.listsize = maxbitlen;
++    lists.memsize = 2 * maxbitlen * (maxbitlen + 1);
++    lists.nextfree = 0;
++    lists.numfree = lists.memsize;
++    lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory));
++    lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*));
++    lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*));
++    lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*));
++    if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/
++
++    if(!error)
++    {
++      for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i];
++
++      bpmnode_create(&lists, leaves[0].weight, 1, 0);
++      bpmnode_create(&lists, leaves[1].weight, 2, 0);
++
++      for(i = 0; i != lists.listsize; ++i)
++      {
++        lists.chains0[i] = &lists.memory[0];
++        lists.chains1[i] = &lists.memory[1];
++      }
++
++      /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/
++      for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i);
++
++      for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail)
++      {
++        for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index];
++      }
++    }
++
++    lodepng_free(lists.memory);
++    lodepng_free(lists.freelist);
++    lodepng_free(lists.chains0);
++    lodepng_free(lists.chains1);
++  }
++
++  lodepng_free(leaves);
++  return error;
++}
++

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-ports-all mailing list