mirror of
https://gitlab.com/citizensixtynine/orbit.git
synced 2026-05-26 14:58:15 +00:00
Add Comm Build System
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import imp, os, sys
|
||||
|
||||
old_bytecode = sys.dont_write_bytecode
|
||||
sys.dont_write_bytecode = True
|
||||
|
||||
ycm_module = imp.load_source("_ycm_extra_conf", os.path.join("mozilla", ".ycm_extra_conf.py"))
|
||||
|
||||
sys.dont_write_bytecode = old_bytecode
|
||||
|
||||
# Expose the FlagsForFile function from mozilla/.ycm_extra_conf.py
|
||||
FlagsForFile = ycm_module.FlagsForFile
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
dnl
|
||||
dnl Local autoconf macros used with UXP
|
||||
dnl The contents of this file are under the Public Domain.
|
||||
dnl
|
||||
|
||||
builtin(include, platform/build/autoconf/toolchain.m4)dnl
|
||||
builtin(include, platform/build/autoconf/config.status.m4)dnl
|
||||
builtin(include, platform/build/autoconf/nspr.m4)dnl
|
||||
builtin(include, platform/build/autoconf/nss.m4)dnl
|
||||
builtin(include, platform/build/autoconf/pkg.m4)dnl
|
||||
builtin(include, platform/build/autoconf/codeset.m4)dnl
|
||||
builtin(include, platform/build/autoconf/altoptions.m4)dnl
|
||||
builtin(include, platform/build/autoconf/mozprog.m4)dnl
|
||||
builtin(include, platform/build/autoconf/acwinpaths.m4)dnl
|
||||
builtin(include, platform/build/autoconf/lto.m4)dnl
|
||||
builtin(include, platform/build/autoconf/frameptr.m4)dnl
|
||||
builtin(include, platform/build/autoconf/compiler-opts.m4)dnl
|
||||
builtin(include, platform/build/autoconf/zlib.m4)dnl
|
||||
builtin(include, platform/build/autoconf/expandlibs.m4)dnl
|
||||
|
||||
MOZ_PROG_CHECKMSYS()
|
||||
|
||||
# Read the user's .mozconfig script. We can't do this in
|
||||
# configure.in: autoconf puts the argument parsing code above anything
|
||||
# expanded from configure.in, and we need to get the configure options
|
||||
# from .mozconfig in place before that argument parsing code.
|
||||
dnl MOZ_READ_MOZCONFIG(platform)
|
||||
Vendored
+1454
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# mozconfigfind - Loads options from .mozconfig onto configure's
|
||||
# command-line. The .mozconfig file is searched for in the
|
||||
# order:
|
||||
# If $MOZCONFIG is set, use that.
|
||||
# If one of $TOPSRCDIR/.mozconfig or $TOPSRCDIR/mozconfig exists, use it.
|
||||
# If both exist, or if various legacy locations contain a mozconfig, error.
|
||||
# Otherwise, use the default build options.
|
||||
#
|
||||
topsrcdir=$1
|
||||
|
||||
abspath() {
|
||||
if uname -s | grep -q MINGW; then
|
||||
# We have no way to figure out whether we're in gmake or pymake right
|
||||
# now. gmake gives us Unix-style paths while pymake gives us Windows-style
|
||||
# paths, so attempt to handle both.
|
||||
regexes='^\([A-Za-z]:\|\\\\\|\/\) ^\/'
|
||||
else
|
||||
regexes='^\/'
|
||||
fi
|
||||
|
||||
for regex in $regexes; do
|
||||
if echo $1 | grep -q $regex; then
|
||||
echo $1
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
# If we're at this point, we have a relative path
|
||||
echo `pwd`/$1
|
||||
}
|
||||
|
||||
if [ -n "$MOZCONFIG" ] && ! [ -f "$MOZCONFIG" ]; then
|
||||
echo "Specified MOZCONFIG \"$MOZCONFIG\" does not exist!" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$MOZ_MYCONFIG" ]; then
|
||||
echo "Your environment currently has the MOZ_MYCONFIG variable set to \"$MOZ_MYCONFIG\". MOZ_MYCONFIG is no longer supported. Please use MOZCONFIG instead." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$MOZCONFIG" ] && [ -f "$topsrcdir/.mozconfig" ] && [ -f "$topsrcdir/mozconfig" ]; then
|
||||
echo "Both \$topsrcdir/.mozconfig and \$topsrcdir/mozconfig are supported, but you must choose only one. Please remove the other." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for _config in "$MOZCONFIG" \
|
||||
"$topsrcdir/.mozconfig" \
|
||||
"$topsrcdir/mozconfig"
|
||||
do
|
||||
if test -f "$_config"; then
|
||||
abspath $_config
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
# We used to support a number of other implicit .mozconfig locations. We now
|
||||
# detect if we were about to use any of these locations and issue an error if we
|
||||
# find any.
|
||||
for _config in "$topsrcdir/mozconfig.sh" \
|
||||
"$topsrcdir/myconfig.sh" \
|
||||
"$HOME/.mozconfig" \
|
||||
"$HOME/.mozconfig.sh" \
|
||||
"$HOME/.mozmyconfig.sh"
|
||||
do
|
||||
if test -f "$_config"; then
|
||||
echo "You currently have a mozconfig at \"$_config\". This implicit location is no longer supported. Please move it to $topsrcdir/.mozconfig or specify it explicitly via \$MOZCONFIG." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,76 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# mozconfig2client-mk - Translates .mozconfig into options for client.mk.
|
||||
# Prints defines to stdout.
|
||||
#
|
||||
# See mozconfig2configure for more details
|
||||
|
||||
print_header() {
|
||||
cat <<EOF
|
||||
# gmake
|
||||
# This file is automatically generated for client.mk.
|
||||
# Do not edit. Edit $FOUND_MOZCONFIG instead.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
ac_add_options() {
|
||||
for _opt
|
||||
do
|
||||
case "$_opt" in
|
||||
--target=*)
|
||||
echo $_opt | sed s/--target/CONFIG_GUESS/
|
||||
;;
|
||||
*)
|
||||
echo "# $_opt is used by configure (not client.mk)"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
ac_add_app_options() {
|
||||
echo "# $* is used by configure (not client.mk)"
|
||||
}
|
||||
|
||||
mk_add_options() {
|
||||
for _opt
|
||||
do
|
||||
# Escape shell characters, space, tab, dollar, quote, backslash,
|
||||
# and substitute '@<word>@' with '$(<word>)'.
|
||||
_opt=`echo "$_opt" | sed -e 's/\([\"\\]\)/\\\\\1/g; s/@\([^@]*\)@/\$(\1)/g;'`
|
||||
echo $_opt;
|
||||
done
|
||||
}
|
||||
|
||||
# Main
|
||||
#--------------------------------------------------
|
||||
|
||||
scriptdir=`dirname $0`
|
||||
topsrcdir=$1
|
||||
|
||||
# If the path changes, configure should be rerun
|
||||
echo "# PATH=$PATH"
|
||||
|
||||
# If FOUND_MOZCONFIG isn't set, look for it and make sure the script doesn't error out
|
||||
isfoundset=${FOUND_MOZCONFIG+yes}
|
||||
if [ -z $isfoundset ]; then
|
||||
FOUND_MOZCONFIG=`$scriptdir/mozconfig-find $topsrcdir`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo '$(error Fix above errors before continuing.)'
|
||||
else
|
||||
isfoundset=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n $isfoundset ]; then
|
||||
if [ "$FOUND_MOZCONFIG" ]
|
||||
then
|
||||
print_header
|
||||
. "$FOUND_MOZCONFIG"
|
||||
echo "FOUND_MOZCONFIG := $FOUND_MOZCONFIG"
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,14 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os, sys
|
||||
|
||||
def bootstrap(topsrcdir, mozilla_dir=None):
|
||||
if mozilla_dir is None:
|
||||
mozilla_dir = os.path.join(topsrcdir, 'platform')
|
||||
sys.path[0:0] = [mozilla_dir]
|
||||
import build.mach_bootstrap
|
||||
return build.mach_bootstrap.bootstrap(topsrcdir, mozilla_dir)
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# This is a wrapper around mozilla-central's pymake. If that isn't found then
|
||||
# this uses client.py to pull it in.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import shlex
|
||||
|
||||
def getpath(relpath):
|
||||
thisdir = os.path.dirname(__file__)
|
||||
return os.path.abspath(os.path.join(thisdir, *relpath))
|
||||
|
||||
PYMAKE = getpath(["..", "..", "platform", "build", "pymake", "make.py"])
|
||||
|
||||
def main(args):
|
||||
if 'TINDERBOX_OUTPUT' in os.environ:
|
||||
# When building on mozilla build slaves, execute mozmake instead. Until bug
|
||||
# 978211, this is the easiest, albeit hackish, way to do this.
|
||||
mozmake = os.path.join(os.path.dirname(__file__), '..', '..',
|
||||
'mozmake.exe')
|
||||
if os.path.exists(mozmake):
|
||||
cmd = [mozmake]
|
||||
cmd.extend(sys.argv[1:])
|
||||
shell = os.environ.get('SHELL')
|
||||
if shell and not shell.lower().endswith('.exe'):
|
||||
cmd += ['SHELL=%s.exe' % shell]
|
||||
sys.exit(subprocess.call(cmd))
|
||||
|
||||
if not os.path.exists(PYMAKE):
|
||||
raise Exception("Pymake not found")
|
||||
|
||||
subprocess.check_call([sys.executable, PYMAKE] + args)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
||||
@@ -0,0 +1,3 @@
|
||||
# Nothing in this directory needs to be in sync with mozilla
|
||||
# The contents are used only in c-c
|
||||
*
|
||||
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/exnumpy.py $
|
||||
# $Rev: 126 $
|
||||
|
||||
# Numpy example.
|
||||
# Original code created by Mel Raab, modified by David Jones.
|
||||
|
||||
'''
|
||||
Example code integrating RGB PNG files, PyPNG and NumPy
|
||||
(abstracted from Mel Raab's functioning code)
|
||||
'''
|
||||
|
||||
# http://www.python.org/doc/2.4.4/lib/module-itertools.html
|
||||
import itertools
|
||||
|
||||
import numpy
|
||||
import png
|
||||
|
||||
|
||||
''' If you have a PNG file for an RGB image,
|
||||
and want to create a numpy array of data from it.
|
||||
'''
|
||||
# Read the file "picture.png" from the current directory. The `Reader`
|
||||
# class can take a filename, a file-like object, or the byte data
|
||||
# directly; this suggests alternatives such as using urllib to read
|
||||
# an image from the internet:
|
||||
# png.Reader(file=urllib.urlopen('http://www.libpng.org/pub/png/PngSuite/basn2c16.png'))
|
||||
pngReader=png.Reader(filename='picture.png')
|
||||
# Tuple unpacking, using multiple assignment, is very useful for the
|
||||
# result of asDirect (and other methods).
|
||||
# See
|
||||
# http://docs.python.org/tutorial/introduction.html#first-steps-towards-programming
|
||||
row_count, column_count, pngdata, meta = pngReader.asDirect()
|
||||
bitdepth=meta['bitdepth']
|
||||
plane_count=meta['planes']
|
||||
|
||||
# Make sure we're dealing with RGB files
|
||||
assert plane_count == 3
|
||||
|
||||
''' Boxed row flat pixel:
|
||||
list([R,G,B, R,G,B, R,G,B],
|
||||
[R,G,B, R,G,B, R,G,B])
|
||||
Array dimensions for this example: (2,9)
|
||||
|
||||
Create `image_2d` as a two-dimensional NumPy array by stacking a
|
||||
sequence of 1-dimensional arrays (rows).
|
||||
The NumPy array mimics PyPNG's (boxed row flat pixel) representation;
|
||||
it will have dimensions ``(row_count,column_count*plane_count)``.
|
||||
'''
|
||||
# The use of ``numpy.uint16``, below, is to convert each row to a NumPy
|
||||
# array with data type ``numpy.uint16``. This is a feature of NumPy,
|
||||
# discussed further in
|
||||
# http://docs.scipy.org/doc/numpy/user/basics.types.html .
|
||||
# You can use avoid the explicit conversion with
|
||||
# ``numpy.vstack(pngdata)``, but then NumPy will pick the array's data
|
||||
# type; in practice it seems to pick ``numpy.int32``, which is large enough
|
||||
# to hold any pixel value for any PNG image but uses 4 bytes per value when
|
||||
# 1 or 2 would be enough.
|
||||
# --- extract 001 start
|
||||
image_2d = numpy.vstack(itertools.imap(numpy.uint16, pngdata))
|
||||
# --- extract 001 end
|
||||
# Do not be tempted to use ``numpy.asarray``; when passed an iterator
|
||||
# (`pngdata` is often an iterator) it will attempt to create a size 1
|
||||
# array with the iterator as its only element.
|
||||
# An alternative to the above is to create the target array of the right
|
||||
# shape, then populate it row by row:
|
||||
if 0:
|
||||
image_2d = numpy.zeros((row_count,plane_count*column_count),
|
||||
dtype=numpy.uint16)
|
||||
for row_index, one_boxed_row_flat_pixels in enumerate(pngdata):
|
||||
image_2d[row_index,:]=one_boxed_row_flat_pixels
|
||||
|
||||
del pngReader
|
||||
del pngdata
|
||||
|
||||
|
||||
''' Reconfigure for easier referencing, similar to
|
||||
Boxed row boxed pixel:
|
||||
list([ (R,G,B), (R,G,B), (R,G,B) ],
|
||||
[ (R,G,B), (R,G,B), (R,G,B) ])
|
||||
Array dimensions for this example: (2,3,3)
|
||||
|
||||
``image_3d`` will contain the image as a three-dimensional numpy
|
||||
array, having dimensions ``(row_count,column_count,plane_count)``.
|
||||
'''
|
||||
# --- extract 002 start
|
||||
image_3d = numpy.reshape(image_2d,
|
||||
(row_count,column_count,plane_count))
|
||||
# --- extract 002 end
|
||||
|
||||
|
||||
''' ============= '''
|
||||
|
||||
''' Convert NumPy image_3d array to PNG image file.
|
||||
|
||||
If the data is three-dimensional, as it is above, the best thing
|
||||
to do is reshape it into a two-dimensional array with a shape of
|
||||
``(row_count, column_count*plane_count)``. Because a
|
||||
two-dimensional numpy array is an iterator, it can be passed
|
||||
directly to the ``png.Writer.write`` method.
|
||||
'''
|
||||
|
||||
row_count, column_count, plane_count = image_3d.shape
|
||||
assert plane_count==3
|
||||
|
||||
pngfile = open('picture_out.png', 'wb')
|
||||
try:
|
||||
# This example assumes that you have 16-bit pixel values in the data
|
||||
# array (that's what the ``bitdepth=16`` argument is for).
|
||||
# If you don't, then the resulting PNG file will likely be
|
||||
# very dark. Hey, it's only an example.
|
||||
pngWriter = png.Writer(column_count, row_count,
|
||||
greyscale=False,
|
||||
alpha=False,
|
||||
bitdepth=16)
|
||||
# As of 2009-04-13 passing a numpy array that has an element type
|
||||
# that is a numpy integer type (for example, the `image_3d` array has an
|
||||
# element type of ``numpy.uint16``) generates a deprecation warning.
|
||||
# This is probably a bug in numpy; it may go away in the future.
|
||||
# The code still works despite the warning.
|
||||
# See http://code.google.com/p/pypng/issues/detail?id=44
|
||||
# --- extract 003 start
|
||||
pngWriter.write(pngfile,
|
||||
numpy.reshape(image_3d, (-1, column_count*plane_count)))
|
||||
# --- extract 003 end
|
||||
finally:
|
||||
pngfile.close()
|
||||
|
||||
@@ -0,0 +1,537 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/iccp.py $
|
||||
# $Rev: 182 $
|
||||
|
||||
# iccp
|
||||
#
|
||||
# International Color Consortium Profile
|
||||
#
|
||||
# Tools for manipulating ICC profiles.
|
||||
#
|
||||
# An ICC profile can be extracted from a PNG image (iCCP chunk).
|
||||
#
|
||||
#
|
||||
# Non-standard ICCP tags.
|
||||
#
|
||||
# Apple use some (widespread but) non-standard tags. These can be
|
||||
# displayed in Apple's ColorSync Utility.
|
||||
# - 'vcgt' (Video Card Gamma Tag). Table to load into video
|
||||
# card LUT to apply gamma.
|
||||
# - 'ndin' Apple display native information.
|
||||
# - 'dscm' Apple multi-localized description strings.
|
||||
# - 'mmod' Apple display make and model information.
|
||||
#
|
||||
|
||||
# References
|
||||
#
|
||||
# [ICC 2001] ICC Specification ICC.1:2001-04 (Profile version 2.4.0)
|
||||
# [ICC 2004] ICC Specification ICC.1:2004-10 (Profile version 4.2.0.0)
|
||||
|
||||
import struct
|
||||
|
||||
import png
|
||||
|
||||
class FormatError(Exception):
|
||||
pass
|
||||
|
||||
class Profile:
|
||||
"""An International Color Consortium Profile (ICC Profile)."""
|
||||
|
||||
def __init__(self):
|
||||
self.rawtagtable = None
|
||||
self.rawtagdict = {}
|
||||
self.d = dict()
|
||||
|
||||
def fromFile(self, inp, name='<unknown>'):
|
||||
|
||||
# See [ICC 2004]
|
||||
profile = inp.read(128)
|
||||
if len(profile) < 128:
|
||||
raise FormatError("ICC Profile is too short.")
|
||||
size, = struct.unpack('>L', profile[:4])
|
||||
profile += inp.read(d['size'] - len(profile))
|
||||
return self.fromString(profile, name)
|
||||
|
||||
def fromString(self, profile, name='<unknown>'):
|
||||
self.d = dict()
|
||||
d = self.d
|
||||
if len(profile) < 128:
|
||||
raise FormatError("ICC Profile is too short.")
|
||||
d.update(
|
||||
zip(['size', 'preferredCMM', 'version',
|
||||
'profileclass', 'colourspace', 'pcs'],
|
||||
struct.unpack('>L4sL4s4s4s', profile[:24])))
|
||||
if len(profile) < d['size']:
|
||||
warnings.warn(
|
||||
'Profile size declared to be %d, but only got %d bytes' %
|
||||
(d['size'], len(profile)))
|
||||
d['version'] = '%08x' % d['version']
|
||||
d['created'] = readICCdatetime(profile[24:36])
|
||||
d.update(
|
||||
zip(['acsp', 'platform', 'flag', 'manufacturer', 'model'],
|
||||
struct.unpack('>4s4s3L', profile[36:56])))
|
||||
if d['acsp'] != 'acsp':
|
||||
warnings.warn('acsp field not present (not an ICC Profile?).')
|
||||
d['deviceattributes'] = profile[56:64]
|
||||
d['intent'], = struct.unpack('>L', profile[64:68])
|
||||
d['pcsilluminant'] = readICCXYZNumber(profile[68:80])
|
||||
d['creator'] = profile[80:84]
|
||||
d['id'] = profile[84:100]
|
||||
ntags, = struct.unpack('>L', profile[128:132])
|
||||
d['ntags'] = ntags
|
||||
fmt = '4s2L' * ntags
|
||||
# tag table
|
||||
tt = struct.unpack('>' + fmt, profile[132:132+12*ntags])
|
||||
tt = group(tt, 3)
|
||||
|
||||
# Could (should) detect 2 or more tags having the same sig. But
|
||||
# we don't. Two or more tags with the same sig is illegal per
|
||||
# the ICC spec.
|
||||
|
||||
# Convert (sig,offset,size) triples into (sig,value) pairs.
|
||||
rawtag = map(lambda x: (x[0], profile[x[1]:x[1]+x[2]]), tt)
|
||||
self.rawtagtable = rawtag
|
||||
self.rawtagdict = dict(rawtag)
|
||||
tag = dict()
|
||||
# Interpret the tags whose types we know about
|
||||
for sig, v in rawtag:
|
||||
if sig in tag:
|
||||
warnings.warn("Duplicate tag %r found. Ignoring." % sig)
|
||||
continue
|
||||
v = ICCdecode(v)
|
||||
if v is not None:
|
||||
tag[sig] = v
|
||||
self.tag = tag
|
||||
return self
|
||||
|
||||
def greyInput(self):
|
||||
"""Adjust ``self.d`` dictionary for greyscale input device.
|
||||
``profileclass`` is 'scnr', ``colourspace`` is 'GRAY', ``pcs``
|
||||
is 'XYZ '.
|
||||
"""
|
||||
|
||||
self.d.update(dict(profileclass='scnr',
|
||||
colourspace='GRAY', pcs='XYZ '))
|
||||
return self
|
||||
|
||||
def maybeAddDefaults(self):
|
||||
if self.rawtagdict:
|
||||
return
|
||||
self._addTags(
|
||||
cprt='Copyright unknown.',
|
||||
desc='created by $URL: http://pypng.googlecode.com/svn/trunk/code/iccp.py $ $Rev: 182 $',
|
||||
wtpt=D50(),
|
||||
)
|
||||
|
||||
def addTags(self, **k):
|
||||
self.maybeAddDefaults()
|
||||
self._addTags(**k)
|
||||
|
||||
def _addTags(self, **k):
|
||||
"""Helper for :meth:`addTags`."""
|
||||
|
||||
for tag, thing in k.items():
|
||||
if not isinstance(thing, (tuple, list)):
|
||||
thing = (thing,)
|
||||
typetag = defaulttagtype[tag]
|
||||
self.rawtagdict[tag] = encode(typetag, *thing)
|
||||
return self
|
||||
|
||||
def write(self, out):
|
||||
"""Write ICC Profile to the file."""
|
||||
|
||||
if not self.rawtagtable:
|
||||
self.rawtagtable = self.rawtagdict.items()
|
||||
tags = tagblock(self.rawtagtable)
|
||||
self.writeHeader(out, 128 + len(tags))
|
||||
out.write(tags)
|
||||
out.flush()
|
||||
|
||||
return self
|
||||
|
||||
def writeHeader(self, out, size=999):
|
||||
"""Add default values to the instance's `d` dictionary, then
|
||||
write a header out onto the file stream. The size of the
|
||||
profile must be specified using the `size` argument.
|
||||
"""
|
||||
|
||||
def defaultkey(d, key, value):
|
||||
"""Add ``[key]==value`` to the dictionary `d`, but only if
|
||||
it does not have that key already.
|
||||
"""
|
||||
|
||||
if key in d:
|
||||
return
|
||||
d[key] = value
|
||||
|
||||
z = '\x00' * 4
|
||||
defaults = dict(preferredCMM=z,
|
||||
version='02000000',
|
||||
profileclass=z,
|
||||
colourspace=z,
|
||||
pcs='XYZ ',
|
||||
created=writeICCdatetime(),
|
||||
acsp='acsp',
|
||||
platform=z,
|
||||
flag=0,
|
||||
manufacturer=z,
|
||||
model=0,
|
||||
deviceattributes=0,
|
||||
intent=0,
|
||||
pcsilluminant=encodefuns()['XYZ'](*D50()),
|
||||
creator=z,
|
||||
)
|
||||
for k,v in defaults.items():
|
||||
defaultkey(self.d, k, v)
|
||||
|
||||
hl = map(self.d.__getitem__,
|
||||
['preferredCMM', 'version', 'profileclass', 'colourspace',
|
||||
'pcs', 'created', 'acsp', 'platform', 'flag',
|
||||
'manufacturer', 'model', 'deviceattributes', 'intent',
|
||||
'pcsilluminant', 'creator'])
|
||||
# Convert to struct.pack input
|
||||
hl[1] = int(hl[1], 16)
|
||||
|
||||
out.write(struct.pack('>L4sL4s4s4s12s4s4sL4sLQL12s4s', size, *hl))
|
||||
out.write('\x00' * 44)
|
||||
return self
|
||||
|
||||
def encodefuns():
|
||||
"""Returns a dictionary mapping ICC type signature sig to encoding
|
||||
function. Each function returns a string comprising the content of
|
||||
the encoded value. To form the full value, the type sig and the 4
|
||||
zero bytes should be prefixed (8 bytes).
|
||||
"""
|
||||
|
||||
def desc(ascii):
|
||||
"""Return textDescription type [ICC 2001] 6.5.17. The ASCII part is
|
||||
filled in with the string `ascii`, the Unicode and ScriptCode parts
|
||||
are empty."""
|
||||
|
||||
ascii += '\x00'
|
||||
l = len(ascii)
|
||||
|
||||
return struct.pack('>L%ds2LHB67s' % l,
|
||||
l, ascii, 0, 0, 0, 0, '')
|
||||
|
||||
def text(ascii):
|
||||
"""Return textType [ICC 2001] 6.5.18."""
|
||||
|
||||
return ascii + '\x00'
|
||||
|
||||
def curv(f=None, n=256):
|
||||
"""Return a curveType, [ICC 2001] 6.5.3. If no arguments are
|
||||
supplied then a TRC for a linear response is generated (no entries).
|
||||
If an argument is supplied and it is a number (for *f* to be a
|
||||
number it means that ``float(f)==f``) then a TRC for that
|
||||
gamma value is generated.
|
||||
Otherwise `f` is assumed to be a function that maps [0.0, 1.0] to
|
||||
[0.0, 1.0]; an `n` element table is generated for it.
|
||||
"""
|
||||
|
||||
if f is None:
|
||||
return struct.pack('>L', 0)
|
||||
try:
|
||||
if float(f) == f:
|
||||
return struct.pack('>LH', 1, int(round(f*2**8)))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
assert n >= 2
|
||||
table = []
|
||||
M = float(n-1)
|
||||
for i in range(n):
|
||||
x = i/M
|
||||
table.append(int(round(f(x) * 65535)))
|
||||
return struct.pack('>L%dH' % n, n, *table)
|
||||
|
||||
def XYZ(*l):
|
||||
return struct.pack('>3l', *map(fs15f16, l))
|
||||
|
||||
return locals()
|
||||
|
||||
# Tag type defaults.
|
||||
# Most tags can only have one or a few tag types.
|
||||
# When encoding, we associate a default tag type with each tag so that
|
||||
# the encoding is implicit.
|
||||
defaulttagtype=dict(
|
||||
A2B0='mft1',
|
||||
A2B1='mft1',
|
||||
A2B2='mft1',
|
||||
bXYZ='XYZ',
|
||||
bTRC='curv',
|
||||
B2A0='mft1',
|
||||
B2A1='mft1',
|
||||
B2A2='mft1',
|
||||
calt='dtim',
|
||||
targ='text',
|
||||
chad='sf32',
|
||||
chrm='chrm',
|
||||
cprt='desc',
|
||||
crdi='crdi',
|
||||
dmnd='desc',
|
||||
dmdd='desc',
|
||||
devs='',
|
||||
gamt='mft1',
|
||||
kTRC='curv',
|
||||
gXYZ='XYZ',
|
||||
gTRC='curv',
|
||||
lumi='XYZ',
|
||||
meas='',
|
||||
bkpt='XYZ',
|
||||
wtpt='XYZ',
|
||||
ncol='',
|
||||
ncl2='',
|
||||
resp='',
|
||||
pre0='mft1',
|
||||
pre1='mft1',
|
||||
pre2='mft1',
|
||||
desc='desc',
|
||||
pseq='',
|
||||
psd0='data',
|
||||
psd1='data',
|
||||
psd2='data',
|
||||
psd3='data',
|
||||
ps2s='data',
|
||||
ps2i='data',
|
||||
rXYZ='XYZ',
|
||||
rTRC='curv',
|
||||
scrd='desc',
|
||||
scrn='',
|
||||
tech='sig',
|
||||
bfd='',
|
||||
vued='desc',
|
||||
view='view',
|
||||
)
|
||||
|
||||
def encode(tsig, *l):
|
||||
"""Encode a Python value as an ICC type. `tsig` is the type
|
||||
signature to (the first 4 bytes of the encoded value, see [ICC 2004]
|
||||
section 10.
|
||||
"""
|
||||
|
||||
fun = encodefuns()
|
||||
if tsig not in fun:
|
||||
raise "No encoder for type %r." % tsig
|
||||
v = fun[tsig](*l)
|
||||
# Padd tsig out with spaces.
|
||||
tsig = (tsig + ' ')[:4]
|
||||
return tsig + '\x00'*4 + v
|
||||
|
||||
def tagblock(tag):
|
||||
"""`tag` should be a list of (*signature*, *element*) pairs, where
|
||||
*signature* (the key) is a length 4 string, and *element* is the
|
||||
content of the tag element (another string).
|
||||
|
||||
The entire tag block (consisting of first a table and then the
|
||||
element data) is constructed and returned as a string.
|
||||
"""
|
||||
|
||||
n = len(tag)
|
||||
tablelen = 12*n
|
||||
|
||||
# Build the tag table in two parts. A list of 12-byte tags, and a
|
||||
# string of element data. Offset is the offset from the start of
|
||||
# the profile to the start of the element data (so the offset for
|
||||
# the next element is this offset plus the length of the element
|
||||
# string so far).
|
||||
offset = 128 + tablelen + 4
|
||||
# The table. As a string.
|
||||
table = ''
|
||||
# The element data
|
||||
element = ''
|
||||
for k,v in tag:
|
||||
table += struct.pack('>4s2L', k, offset + len(element), len(v))
|
||||
element += v
|
||||
return struct.pack('>L', n) + table + element
|
||||
|
||||
def iccp(out, inp):
|
||||
profile = Profile().fromString(*profileFromPNG(inp))
|
||||
print >>out, profile.d
|
||||
print >>out, map(lambda x: x[0], profile.rawtagtable)
|
||||
print >>out, profile.tag
|
||||
|
||||
def profileFromPNG(inp):
|
||||
"""Extract profile from PNG file. Return (*profile*, *name*)
|
||||
pair."""
|
||||
r = png.Reader(file=inp)
|
||||
_,chunk = r.chunk('iCCP')
|
||||
i = chunk.index('\x00')
|
||||
name = chunk[:i]
|
||||
compression = chunk[i+1]
|
||||
assert compression == chr(0)
|
||||
profile = chunk[i+2:].decode('zlib')
|
||||
return profile, name
|
||||
|
||||
def iccpout(out, inp):
|
||||
"""Extract ICC Profile from PNG file `inp` and write it to
|
||||
the file `out`."""
|
||||
|
||||
out.write(profileFromPNG(inp)[0])
|
||||
|
||||
def fs15f16(x):
|
||||
"""Convert float to ICC s15Fixed16Number (as a Python ``int``)."""
|
||||
|
||||
return int(round(x * 2**16))
|
||||
|
||||
def D50():
|
||||
"""Return D50 illuminant as an (X,Y,Z) triple."""
|
||||
|
||||
# See [ICC 2001] A.1
|
||||
return (0.9642, 1.0000, 0.8249)
|
||||
|
||||
|
||||
def writeICCdatetime(t=None):
|
||||
"""`t` should be a gmtime tuple (as returned from
|
||||
``time.gmtime()``). If not supplied, the current time will be used.
|
||||
Return an ICC dateTimeNumber in a 12 byte string.
|
||||
"""
|
||||
|
||||
import time
|
||||
if t is None:
|
||||
t = time.gmtime()
|
||||
return struct.pack('>6H', *t[:6])
|
||||
|
||||
def readICCdatetime(s):
|
||||
"""Convert from 12 byte ICC representation of dateTimeNumber to
|
||||
ISO8601 string. See [ICC 2004] 5.1.1"""
|
||||
|
||||
return '%04d-%02d-%02dT%02d:%02d:%02dZ' % struct.unpack('>6H', s)
|
||||
|
||||
def readICCXYZNumber(s):
|
||||
"""Convert from 12 byte ICC representation of XYZNumber to (x,y,z)
|
||||
triple of floats. See [ICC 2004] 5.1.11"""
|
||||
|
||||
return s15f16l(s)
|
||||
|
||||
def s15f16l(s):
|
||||
"""Convert sequence of ICC s15Fixed16 to list of float."""
|
||||
# Note: As long as float has at least 32 bits of mantissa, all
|
||||
# values are preserved.
|
||||
n = len(s)//4
|
||||
t = struct.unpack('>%dl' % n, s)
|
||||
return map((2**-16).__mul__, t)
|
||||
|
||||
# Several types and their byte encodings are defined by [ICC 2004]
|
||||
# section 10. When encoded, a value begins with a 4 byte type
|
||||
# signature. We use the same 4 byte type signature in the names of the
|
||||
# Python functions that decode the type into a Pythonic representation.
|
||||
|
||||
def ICCdecode(s):
|
||||
"""Take an ICC encoded tag, and dispatch on its type signature
|
||||
(first 4 bytes) to decode it into a Python value. Pair (*sig*,
|
||||
*value*) is returned, where *sig* is a 4 byte string, and *value* is
|
||||
some Python value determined by the content and type.
|
||||
"""
|
||||
|
||||
sig = s[0:4].strip()
|
||||
f=dict(text=RDtext,
|
||||
XYZ=RDXYZ,
|
||||
curv=RDcurv,
|
||||
vcgt=RDvcgt,
|
||||
sf32=RDsf32,
|
||||
)
|
||||
if sig not in f:
|
||||
return None
|
||||
return (sig, f[sig](s))
|
||||
|
||||
def RDXYZ(s):
|
||||
"""Convert ICC XYZType to rank 1 array of trimulus values."""
|
||||
|
||||
# See [ICC 2001] 6.5.26
|
||||
assert s[0:4] == 'XYZ '
|
||||
return readICCXYZNumber(s[8:])
|
||||
|
||||
def RDsf32(s):
|
||||
"""Convert ICC s15Fixed16ArrayType to list of float."""
|
||||
# See [ICC 2004] 10.18
|
||||
assert s[0:4] == 'sf32'
|
||||
return s15f16l(s[8:])
|
||||
|
||||
def RDmluc(s):
|
||||
"""Convert ICC multiLocalizedUnicodeType. This types encodes
|
||||
several strings together with a language/country code for each
|
||||
string. A list of (*lc*, *string*) pairs is returned where *lc* is
|
||||
the 4 byte language/country code, and *string* is the string
|
||||
corresponding to that code. It seems unlikely that the same
|
||||
language/country code will appear more than once with different
|
||||
strings, but the ICC standard does not prohibit it."""
|
||||
# See [ICC 2004] 10.13
|
||||
assert s[0:4] == 'mluc'
|
||||
n,sz = struct.unpack('>2L', s[8:16])
|
||||
assert sz == 12
|
||||
record = []
|
||||
for i in range(n):
|
||||
lc,l,o = struct.unpack('4s2L', s[16+12*n:28+12*n])
|
||||
record.append(lc, s[o:o+l])
|
||||
# How are strings encoded?
|
||||
return record
|
||||
|
||||
def RDtext(s):
|
||||
"""Convert ICC textType to Python string."""
|
||||
# Note: type not specified or used in [ICC 2004], only in older
|
||||
# [ICC 2001].
|
||||
# See [ICC 2001] 6.5.18
|
||||
assert s[0:4] == 'text'
|
||||
return s[8:-1]
|
||||
|
||||
def RDcurv(s):
|
||||
"""Convert ICC curveType."""
|
||||
# See [ICC 2001] 6.5.3
|
||||
assert s[0:4] == 'curv'
|
||||
count, = struct.unpack('>L', s[8:12])
|
||||
if count == 0:
|
||||
return dict(gamma=1)
|
||||
table = struct.unpack('>%dH' % count, s[12:])
|
||||
if count == 1:
|
||||
return dict(gamma=table[0]*2**-8)
|
||||
return table
|
||||
|
||||
def RDvcgt(s):
|
||||
"""Convert Apple CMVideoCardGammaType."""
|
||||
# See
|
||||
# http://developer.apple.com/documentation/GraphicsImaging/Reference/ColorSync_Manager/Reference/reference.html#//apple_ref/c/tdef/CMVideoCardGammaType
|
||||
assert s[0:4] == 'vcgt'
|
||||
tagtype, = struct.unpack('>L', s[8:12])
|
||||
if tagtype != 0:
|
||||
return s[8:]
|
||||
if tagtype == 0:
|
||||
# Table.
|
||||
channels,count,size = struct.unpack('>3H', s[12:18])
|
||||
if size == 1:
|
||||
fmt = 'B'
|
||||
elif size == 2:
|
||||
fmt = 'H'
|
||||
else:
|
||||
return s[8:]
|
||||
l = len(s[18:])//size
|
||||
t = struct.unpack('>%d%s' % (l, fmt), s[18:])
|
||||
t = group(t, count)
|
||||
return size, t
|
||||
return s[8:]
|
||||
|
||||
|
||||
def group(s, n):
|
||||
# See
|
||||
# http://www.python.org/doc/2.6/library/functions.html#zip
|
||||
return zip(*[iter(s)]*n)
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
from getopt import getopt
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
argv = argv[1:]
|
||||
opt,arg = getopt(argv, 'o:')
|
||||
if len(arg) > 0:
|
||||
inp = open(arg[0], 'rb')
|
||||
else:
|
||||
inp = sys.stdin
|
||||
for o,v in opt:
|
||||
if o == '-o':
|
||||
f = open(v, 'wb')
|
||||
return iccpout(f, inp)
|
||||
return iccp(sys.stdout, inp)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/mkiccp.py $
|
||||
# $Rev: 182 $
|
||||
# Make ICC Profile
|
||||
|
||||
# References
|
||||
#
|
||||
# [ICC 2001] ICC Specification ICC.1:2001-04 (Profile version 2.4.0)
|
||||
# [ICC 2004] ICC Specification ICC.1:2004-10 (Profile version 4.2.0.0)
|
||||
|
||||
import struct
|
||||
|
||||
# Local module.
|
||||
import iccp
|
||||
|
||||
def black(m):
|
||||
"""Return a function that maps all values from [0.0,m] to 0, and maps
|
||||
the range [m,1.0] into [0.0, 1.0] linearly.
|
||||
"""
|
||||
|
||||
m = float(m)
|
||||
|
||||
def f(x):
|
||||
if x <= m:
|
||||
return 0.0
|
||||
return (x-m)/(1.0-m)
|
||||
return f
|
||||
|
||||
# For monochrome input the required tags are (See [ICC 2001] 6.3.1.1):
|
||||
# profileDescription [ICC 2001] 6.4.32
|
||||
# grayTRC [ICC 2001] 6.4.19
|
||||
# mediaWhitePoint [ICC 2001] 6.4.25
|
||||
# copyright [ICC 2001] 6.4.13
|
||||
|
||||
def agreyprofile(out):
|
||||
it = iccp.Profile().greyInput()
|
||||
it.addTags(kTRC=black(0.07))
|
||||
it.write(out)
|
||||
|
||||
def main():
|
||||
import sys
|
||||
agreyprofile(sys.stdout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pdsimgtopng $
|
||||
# $Rev: 154 $
|
||||
# PDS Image to PNG
|
||||
|
||||
import re
|
||||
import struct
|
||||
|
||||
import png
|
||||
|
||||
class FormatError(Exception):
|
||||
pass
|
||||
|
||||
def pdskey(s, k):
|
||||
"""Lookup key `k` in string `s`. Returns value (as a string), or
|
||||
raises exception if not found.
|
||||
"""
|
||||
|
||||
assert re.match(r' *\^?[:\w]+$', k)
|
||||
safere = '^' + re.escape(k) +r' *= *(\w+)'
|
||||
m = re.search(safere, s, re.MULTILINE)
|
||||
if not m:
|
||||
raise FormatError("Can't find %s." % k)
|
||||
return m.group(1)
|
||||
|
||||
def img(inp):
|
||||
"""Open the PDS IMG file `inp` and return (*pixels*, *info*).
|
||||
*pixels* is an iterator over the rows, *info* is the information
|
||||
dictionary.
|
||||
"""
|
||||
|
||||
err = __import__('sys').stderr
|
||||
|
||||
consumed = 1024
|
||||
|
||||
s = inp.read(consumed)
|
||||
record_type = pdskey(s, 'RECORD_TYPE')
|
||||
if record_type != 'FIXED_LENGTH':
|
||||
raise FormatError(
|
||||
"Can only deal with FIXED_LENGTH record type (found %s)" %
|
||||
record_type)
|
||||
record_bytes = int(pdskey(s,'RECORD_BYTES'))
|
||||
file_records = int(pdskey(s, 'FILE_RECORDS'))
|
||||
label_records = int(pdskey(s, 'LABEL_RECORDS'))
|
||||
remaining = label_records * record_bytes - consumed
|
||||
s += inp.read(remaining)
|
||||
consumed += remaining
|
||||
|
||||
image_pointer = int(pdskey(s, '^IMAGE'))
|
||||
# "^IMAGE" locates a record. Records are numbered starting from 1.
|
||||
image_index = image_pointer - 1
|
||||
image_offset = image_index * record_bytes
|
||||
gap = image_offset - consumed
|
||||
assert gap >= 0
|
||||
if gap:
|
||||
inp.read(gap)
|
||||
# This assumes there is only one OBJECT in the file, and it is the
|
||||
# IMAGE.
|
||||
height = int(pdskey(s, ' LINES'))
|
||||
width = int(pdskey(s, ' LINE_SAMPLES'))
|
||||
sample_type = pdskey(s, ' SAMPLE_TYPE')
|
||||
sample_bits = int(pdskey(s, ' SAMPLE_BITS'))
|
||||
# For Messenger MDIS, SAMPLE_BITS is reported as 16, but only values
|
||||
# from 0 ot 4095 are used.
|
||||
bitdepth = 12
|
||||
if sample_type == 'MSB_UNSIGNED_INTEGER':
|
||||
fmt = '>H'
|
||||
else:
|
||||
raise 'Unknown sample type: %s.' % sample_type
|
||||
sample_bytes = (1,2)[bitdepth > 8]
|
||||
row_bytes = sample_bytes * width
|
||||
fmt = fmt[:1] + str(width) + fmt[1:]
|
||||
def rowiter():
|
||||
for y in range(height):
|
||||
yield struct.unpack(fmt, inp.read(row_bytes))
|
||||
info = dict(greyscale=True, alpha=False, bitdepth=bitdepth,
|
||||
size=(width,height), gamma=1.0)
|
||||
return rowiter(), info
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
argv = argv[1:]
|
||||
arg = argv
|
||||
if len(arg) >= 1:
|
||||
f = open(arg[0], 'rb')
|
||||
else:
|
||||
f = sys.stdin
|
||||
pixels,info = img(f)
|
||||
w = png.Writer(**info)
|
||||
w.write(sys.stdout, pixels)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pipasgrey $
|
||||
# $Rev: 187 $
|
||||
|
||||
# pipasgrey
|
||||
|
||||
# Convert image to grey (L, or LA), but only if that involves no colour
|
||||
# change.
|
||||
|
||||
def asgrey(out, inp, quiet=False):
|
||||
"""Convert image to greyscale, but only when no colour change. This
|
||||
works by using the input G channel (green) as the output L channel
|
||||
(luminance) and checking that every pixel is grey as we go. A non-grey
|
||||
pixel will raise an error, but if `quiet` is true then the grey pixel
|
||||
check is suppressed.
|
||||
"""
|
||||
|
||||
from array import array
|
||||
|
||||
import png
|
||||
|
||||
r = png.Reader(file=inp)
|
||||
_,_,pixels,info = r.asDirect()
|
||||
if info['greyscale']:
|
||||
w = png.Writer(**info)
|
||||
return w.write(out, pixels)
|
||||
planes = info['planes']
|
||||
targetplanes = planes - 2
|
||||
alpha = info['alpha']
|
||||
width = info['size'][0]
|
||||
typecode = 'BH'[info['bitdepth'] > 8]
|
||||
# Values per target row
|
||||
vpr = width * (targetplanes)
|
||||
def iterasgrey():
|
||||
for i,row in enumerate(pixels):
|
||||
row = array(typecode, row)
|
||||
targetrow = array(typecode, [0]*vpr)
|
||||
# Copy G (and possibly A) channel.
|
||||
green = row[0::planes]
|
||||
if alpha:
|
||||
targetrow[0::2] = green
|
||||
targetrow[1::2] = row[3::4]
|
||||
else:
|
||||
targetrow = green
|
||||
# Check R and B channel match.
|
||||
if not quiet and (
|
||||
green != row[0::planes] or green != row[2::planes]):
|
||||
raise ValueError('Row %i contains non-grey pixel.' % i)
|
||||
yield targetrow
|
||||
info['greyscale'] = True
|
||||
del info['planes']
|
||||
w = png.Writer(**info)
|
||||
w.write(out, iterasgrey())
|
||||
|
||||
def main(argv=None):
|
||||
from getopt import getopt
|
||||
import sys
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
argv = argv[1:]
|
||||
opt,argv = getopt(argv, 'q')
|
||||
quiet = False
|
||||
for o,v in opt:
|
||||
if o == '-q':
|
||||
quiet = True
|
||||
if len(argv) > 0:
|
||||
f = open(argv[0], 'rb')
|
||||
else:
|
||||
f = sys.stdin
|
||||
return asgrey(sys.stdout, f, quiet)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pipcat $
|
||||
# $Rev: 77 $
|
||||
|
||||
# http://www.python.org/doc/2.4.4/lib/module-itertools.html
|
||||
import itertools
|
||||
import sys
|
||||
|
||||
import png
|
||||
|
||||
def cat(out, l):
|
||||
"""Concatenate the list of images. All input images must be same
|
||||
height and have the same number of channels. They are concatenated
|
||||
left-to-right. `out` is the (open file) destination for the
|
||||
output image. `l` should be a list of open files (the input
|
||||
image files).
|
||||
"""
|
||||
|
||||
l = map(lambda f: png.Reader(file=f), l)
|
||||
# Ewgh, side effects.
|
||||
map(lambda r: r.preamble(), l)
|
||||
# The reference height; from the first image.
|
||||
height = l[0].height
|
||||
# The total target width
|
||||
width = 0
|
||||
for i,r in enumerate(l):
|
||||
if r.height != height:
|
||||
raise Error('Image %d, height %d, does not match %d.' %
|
||||
(i, r.height, height))
|
||||
width += r.width
|
||||
pixel,info = zip(*map(lambda r: r.asDirect()[2:4], l))
|
||||
tinfo = dict(info[0])
|
||||
del tinfo['size']
|
||||
w = png.Writer(width, height, **tinfo)
|
||||
def itercat():
|
||||
for row in itertools.izip(*pixel):
|
||||
yield itertools.chain(*row)
|
||||
w.write(out, itercat())
|
||||
|
||||
def main(argv):
|
||||
return cat(sys.stdout, map(lambda n: open(n, 'rb'), argv[1:]))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pipcolours $
|
||||
# $Rev: 96 $
|
||||
|
||||
# pipcolours - extract all colours present in source image.
|
||||
|
||||
def colours(out, inp):
|
||||
import itertools
|
||||
import png
|
||||
|
||||
r = png.Reader(file=inp)
|
||||
_,_,pixels,info = r.asDirect()
|
||||
planes = info['planes']
|
||||
col = set()
|
||||
for row in pixels:
|
||||
# Ewgh, side effects on col
|
||||
map(col.add, png.group(row, planes))
|
||||
col,planes = channel_reduce(col, planes)
|
||||
col = list(col)
|
||||
col.sort()
|
||||
col = list(itertools.chain(*col))
|
||||
width = len(col)//planes
|
||||
greyscale = planes in (1,2)
|
||||
alpha = planes in (2,4)
|
||||
bitdepth = info['bitdepth']
|
||||
w = png.Writer(width, 1,
|
||||
bitdepth=bitdepth, greyscale=greyscale, alpha=alpha)
|
||||
w.write(out, [col])
|
||||
|
||||
def channel_reduce(col, planes):
|
||||
"""Attempt to reduce the number of channels in the set of
|
||||
colours."""
|
||||
if planes >= 3:
|
||||
def isgrey(c):
|
||||
return c[0] == c[1] == c[2]
|
||||
if min(map(isgrey, col)) == True:
|
||||
# Every colour is grey.
|
||||
col = set(map(lambda x: x[0::3], col))
|
||||
planes -= 2
|
||||
return col,planes
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
|
||||
argv = argv[1:]
|
||||
if len(argv) > 0:
|
||||
f = open(argv[0], 'rb')
|
||||
else:
|
||||
f = sys.stdin
|
||||
return colours(sys.stdout, f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pipcomposite $
|
||||
# $Rev: 208 $
|
||||
# pipcomposite
|
||||
# Image alpha compositing.
|
||||
|
||||
"""
|
||||
pipcomposite [--background #rrggbb] file.png
|
||||
|
||||
Composite an image onto a background and output the result. The
|
||||
background colour is specified with an HTML-style triple (3, 6, or 12
|
||||
hex digits), and defaults to black (#000).
|
||||
|
||||
The output PNG has no alpha channel.
|
||||
|
||||
It is valid for the input to have no alpha channel, but it doesn't
|
||||
make much sense: the output will equal the input.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
def composite(out, inp, background):
|
||||
import png
|
||||
|
||||
p = png.Reader(file=inp)
|
||||
w,h,pixel,info = p.asRGBA()
|
||||
|
||||
outinfo = dict(info)
|
||||
outinfo['alpha'] = False
|
||||
outinfo['planes'] -= 1
|
||||
outinfo['interlace'] = 0
|
||||
|
||||
# Convert to tuple and normalise to same range as source.
|
||||
background = rgbhex(background)
|
||||
maxval = float(2**info['bitdepth'] - 1)
|
||||
background = map(lambda x: int(0.5 + x*maxval/65535.0),
|
||||
background)
|
||||
# Repeat background so that it's a whole row of sample values.
|
||||
background *= w
|
||||
|
||||
def iterrow():
|
||||
for row in pixel:
|
||||
# Remove alpha from row, then create a list with one alpha
|
||||
# entry _per channel value_.
|
||||
# Squirrel the alpha channel away (and normalise it).
|
||||
t = map(lambda x: x/maxval, row[3::4])
|
||||
row = list(row)
|
||||
del row[3::4]
|
||||
alpha = row[:]
|
||||
for i in range(3):
|
||||
alpha[i::3] = t
|
||||
assert len(alpha) == len(row) == len(background)
|
||||
yield map(lambda a,v,b: int(0.5 + a*v + (1.0-a)*b),
|
||||
alpha, row, background)
|
||||
|
||||
w = png.Writer(**outinfo)
|
||||
w.write(out, iterrow())
|
||||
|
||||
def rgbhex(s):
|
||||
"""Take an HTML style string of the form "#rrggbb" and return a
|
||||
colour (R,G,B) triple. Following the initial '#' there can be 3, 6,
|
||||
or 12 digits (for 4-, 8- or 16- bits per channel). In all cases the
|
||||
values are expanded to a full 16-bit range, so the returned values
|
||||
are all in range(65536).
|
||||
"""
|
||||
|
||||
assert s[0] == '#'
|
||||
s = s[1:]
|
||||
assert len(s) in (3,6,12)
|
||||
|
||||
# Create a target list of length 12, and expand the string s to make
|
||||
# it length 12.
|
||||
l = ['z']*12
|
||||
if len(s) == 3:
|
||||
for i in range(4):
|
||||
l[i::4] = s
|
||||
if len(s) == 6:
|
||||
for i in range(2):
|
||||
l[i::4] = s[i::2]
|
||||
l[i+2::4] = s[i::2]
|
||||
if len(s) == 12:
|
||||
l[:] = s
|
||||
s = ''.join(l)
|
||||
return map(lambda x: int(x, 16), (s[:4], s[4:8], s[8:]))
|
||||
|
||||
class Usage(Exception):
|
||||
pass
|
||||
|
||||
def main(argv=None):
|
||||
import getopt
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
|
||||
argv = argv[1:]
|
||||
|
||||
try:
|
||||
try:
|
||||
opt,arg = getopt.getopt(argv, '',
|
||||
['background='])
|
||||
except getopt.error, msg:
|
||||
raise Usage(msg)
|
||||
background = '#000'
|
||||
for o,v in opt:
|
||||
if o in ['--background']:
|
||||
background = v
|
||||
except Usage, err:
|
||||
print >>sys.stderr, __doc__
|
||||
print >>sys.stderr, str(err)
|
||||
return 2
|
||||
|
||||
if len(arg) > 0:
|
||||
f = open(arg[0], 'rb')
|
||||
else:
|
||||
f = sys.stdin
|
||||
return composite(sys.stdout, f, background)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pipdither $
|
||||
# $Rev: 150 $
|
||||
|
||||
# pipdither
|
||||
# Error Diffusing image dithering.
|
||||
# Now with serpentine scanning.
|
||||
|
||||
# See http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT
|
||||
|
||||
# http://www.python.org/doc/2.4.4/lib/module-bisect.html
|
||||
from bisect import bisect_left
|
||||
|
||||
import png
|
||||
|
||||
def dither(out, inp,
|
||||
bitdepth=1, linear=False, defaultgamma=1.0, targetgamma=None,
|
||||
cutoff=0.75):
|
||||
"""Dither the input PNG `inp` into an image with a smaller bit depth
|
||||
and write the result image onto `out`. `bitdepth` specifies the bit
|
||||
depth of the new image.
|
||||
|
||||
Normally the source image gamma is honoured (the image is
|
||||
converted into a linear light space before being dithered), but
|
||||
if the `linear` argument is true then the image is treated as
|
||||
being linear already: no gamma conversion is done (this is
|
||||
quicker, and if you don't care much about accuracy, it won't
|
||||
matter much).
|
||||
|
||||
Images with no gamma indication (no ``gAMA`` chunk) are normally
|
||||
treated as linear (gamma = 1.0), but often it can be better
|
||||
to assume a different gamma value: For example continuous tone
|
||||
photographs intended for presentation on the web often carry
|
||||
an implicit assumption of being encoded with a gamma of about
|
||||
0.45 (because that's what you get if you just "blat the pixels"
|
||||
onto a PC framebuffer), so ``defaultgamma=0.45`` might be a
|
||||
good idea. `defaultgamma` does not override a gamma value
|
||||
specified in the file itself: It is only used when the file
|
||||
does not specify a gamma.
|
||||
|
||||
If you (pointlessly) specify both `linear` and `defaultgamma`,
|
||||
`linear` wins.
|
||||
|
||||
The gamma of the output image is, by default, the same as the input
|
||||
image. The `targetgamma` argument can be used to specify a
|
||||
different gamma for the output image. This effectively recodes the
|
||||
image to a different gamma, dithering as we go. The gamma specified
|
||||
is the exponent used to encode the output file (and appears in the
|
||||
output PNG's ``gAMA`` chunk); it is usually less than 1.
|
||||
|
||||
"""
|
||||
|
||||
# Encoding is what happened when the PNG was made (and also what
|
||||
# happens when we output the PNG). Decoding is what we do to the
|
||||
# source PNG in order to process it.
|
||||
|
||||
# The dithering algorithm is not completely general; it
|
||||
# can only do bit depth reduction, not arbitrary palette changes.
|
||||
import operator
|
||||
maxval = 2**bitdepth - 1
|
||||
r = png.Reader(file=inp)
|
||||
# If image gamma is 1 or gamma is not present and we are assuming a
|
||||
# value of 1, then it is faster to pass a maxval parameter to
|
||||
# asFloat (the multiplications get combined). With gamma, we have
|
||||
# to have the pixel values from 0.0 to 1.0 (as long as we are doing
|
||||
# gamma correction here).
|
||||
# Slightly annoyingly, we don't know the image gamma until we've
|
||||
# called asFloat().
|
||||
_,_,pixels,info = r.asDirect()
|
||||
planes = info['planes']
|
||||
assert planes == 1
|
||||
width = info['size'][0]
|
||||
sourcemaxval = 2**info['bitdepth'] - 1
|
||||
if linear:
|
||||
gamma = 1
|
||||
else:
|
||||
gamma = info.get('gamma') or defaultgamma
|
||||
# Convert gamma from encoding gamma to the required power for
|
||||
# decoding.
|
||||
decode = 1.0/gamma
|
||||
# Build a lookup table for decoding; convert from pixel values to linear
|
||||
# space:
|
||||
sourcef = 1.0/sourcemaxval
|
||||
incode = map(sourcef.__mul__, range(sourcemaxval+1))
|
||||
if decode != 1.0:
|
||||
incode = map(decode.__rpow__, incode)
|
||||
# Could be different, later on. targetdecode is the assumed gamma
|
||||
# that is going to be used to decoding the target PNG. It is the
|
||||
# reciprocal of the exponent that we use to encode the target PNG.
|
||||
# This is the value that we need to build our table that we use for
|
||||
# converting from linear to target colour space.
|
||||
if targetgamma is None:
|
||||
targetdecode = decode
|
||||
else:
|
||||
targetdecode = 1.0/targetgamma
|
||||
# The table we use for encoding (creating the target PNG), still
|
||||
# maps from pixel value to linear space, but we use it inverted, by
|
||||
# searching through it with bisect.
|
||||
targetf = 1.0/maxval
|
||||
outcode = map(targetf.__mul__, range(maxval+1))
|
||||
if targetdecode != 1.0:
|
||||
outcode = map(targetdecode.__rpow__, outcode)
|
||||
# The table used for choosing output codes. These values represent
|
||||
# the cutoff points between two adjacent output codes.
|
||||
choosecode = zip(outcode[1:], outcode)
|
||||
p = cutoff
|
||||
choosecode = map(lambda x: x[0]*p+x[1]*(1.0-p), choosecode)
|
||||
def iterdither():
|
||||
# Errors diffused downwards (into next row)
|
||||
ed = [0.0]*width
|
||||
flipped = False
|
||||
for row in pixels:
|
||||
row = map(incode.__getitem__, row)
|
||||
row = map(operator.add, ed, row)
|
||||
if flipped:
|
||||
row = row[::-1]
|
||||
targetrow = [0] * width
|
||||
for i,v in enumerate(row):
|
||||
# Clamp. Necessary because previously added errors may take
|
||||
# v out of range.
|
||||
v = max(0.0, min(v, 1.0))
|
||||
# `it` will be the index of the chosen target colour;
|
||||
it = bisect_left(choosecode, v)
|
||||
t = outcode[it]
|
||||
targetrow[i] = it
|
||||
# err is the error that needs distributing.
|
||||
err = v - t
|
||||
# Sierra "Filter Lite" distributes * 2
|
||||
# as per this diagram. 1 1
|
||||
ef = err/2.0
|
||||
# :todo: consider making rows one wider at each end and
|
||||
# removing "if"s
|
||||
if i+1 < width:
|
||||
row[i+1] += ef
|
||||
ef /= 2.0
|
||||
ed[i] = ef
|
||||
if i:
|
||||
ed[i-1] += ef
|
||||
if flipped:
|
||||
ed = ed[::-1]
|
||||
targetrow = targetrow[::-1]
|
||||
yield targetrow
|
||||
flipped = not flipped
|
||||
info['bitdepth'] = bitdepth
|
||||
info['gamma'] = 1.0/targetdecode
|
||||
w = png.Writer(**info)
|
||||
w.write(out, iterdither())
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
# http://www.python.org/doc/2.4.4/lib/module-getopt.html
|
||||
from getopt import getopt
|
||||
import sys
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
opt,argv = getopt(argv[1:], 'b:c:g:lo:')
|
||||
k = {}
|
||||
for o,v in opt:
|
||||
if o == '-b':
|
||||
k['bitdepth'] = int(v)
|
||||
if o == '-c':
|
||||
k['cutoff'] = float(v)
|
||||
if o == '-g':
|
||||
k['defaultgamma'] = float(v)
|
||||
if o == '-l':
|
||||
k['linear'] = True
|
||||
if o == '-o':
|
||||
k['targetgamma'] = float(v)
|
||||
if o == '-?':
|
||||
print >>sys.stderr, "pipdither [-b bits] [-c cutoff] [-g assumed-gamma] [-l] [in.png]"
|
||||
|
||||
if len(argv) > 0:
|
||||
f = open(argv[0], 'rb')
|
||||
else:
|
||||
f = sys.stdin
|
||||
|
||||
return dither(sys.stdout, f, **k)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/piprgb $
|
||||
# $Rev: 131 $
|
||||
# piprgb
|
||||
#
|
||||
# Convert input image to RGB or RGBA format. Output will be colour type
|
||||
# 2 or 6, and will not have a tRNS chunk.
|
||||
|
||||
import png
|
||||
|
||||
def rgb(out, inp):
|
||||
"""Convert to RGB/RGBA."""
|
||||
|
||||
r = png.Reader(file=inp)
|
||||
r.preamble()
|
||||
if r.alpha or r.trns:
|
||||
get = r.asRGBA
|
||||
else:
|
||||
get = r.asRGB
|
||||
pixels,info = get()[2:4]
|
||||
w = png.Writer(**info)
|
||||
w.write(out, pixels)
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
if len(argv) > 1:
|
||||
f = open(argv[1], 'rb')
|
||||
else:
|
||||
f = sys.stdin
|
||||
return rgb(sys.stdout, f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pipscalez $
|
||||
# $Rev: 131 $
|
||||
|
||||
# pipscalez
|
||||
# Enlarge an image by an integer factor horizontally and vertically.
|
||||
|
||||
def rescale(inp, out, xf, yf):
|
||||
from array import array
|
||||
import png
|
||||
|
||||
r = png.Reader(file=inp)
|
||||
_,_,pixels,meta = r.asDirect()
|
||||
typecode = 'BH'[meta['bitdepth'] > 8]
|
||||
planes = meta['planes']
|
||||
# We are going to use meta in the call to Writer, so expand the
|
||||
# size.
|
||||
x,y = meta['size']
|
||||
x *= xf
|
||||
y *= yf
|
||||
meta['size'] = (x,y)
|
||||
del x
|
||||
del y
|
||||
# Values per row, target row.
|
||||
vpr = meta['size'][0] * planes
|
||||
def iterscale():
|
||||
for row in pixels:
|
||||
bigrow = array(typecode, [0]*vpr)
|
||||
row = array(typecode, row)
|
||||
for c in range(planes):
|
||||
channel = row[c::planes]
|
||||
for i in range(xf):
|
||||
bigrow[i*planes+c::xf*planes] = channel
|
||||
for _ in range(yf):
|
||||
yield bigrow
|
||||
w = png.Writer(**meta)
|
||||
w.write(out, iterscale())
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
xf = int(argv[1])
|
||||
if len(argv) > 2:
|
||||
yf = int(argv[2])
|
||||
else:
|
||||
yf = xf
|
||||
return rescale(sys.stdin, sys.stdout, xf, yf)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pipstack $
|
||||
# $Rev: 190 $
|
||||
|
||||
# pipstack
|
||||
# Combine input PNG files into a multi-channel output PNG.
|
||||
|
||||
"""
|
||||
pipstack file1.png [file2.png ...]
|
||||
|
||||
pipstack can be used to combine 3 greyscale PNG files into a colour, RGB,
|
||||
PNG file. In fact it is slightly more general than that. The number of
|
||||
channels in the output PNG is equal to the sum of the numbers of
|
||||
channels in the input images. It is an error if this sum exceeds 4 (the
|
||||
maximum number of channels in a PNG image is 4, for an RGBA image). The
|
||||
output colour model corresponds to the number of channels: 1 -
|
||||
greyscale; 2 - greyscale+alpha; 3 - RGB; 4 - RGB+alpha.
|
||||
|
||||
In this way it is possible to combine 3 greyscale PNG files into an RGB
|
||||
PNG (a common expected use) as well as more esoteric options: rgb.png +
|
||||
grey.png = rgba.png; grey.png + grey.png = greyalpha.png.
|
||||
|
||||
Color Profile, Gamma, and so on.
|
||||
|
||||
[This is not implemented yet]
|
||||
|
||||
If an input has an ICC Profile (``iCCP`` chunk) then the output will
|
||||
have an ICC Profile, but only if it is possible to combine all the input
|
||||
ICC Profiles. It is possible to combine all the input ICC Profiles
|
||||
only when: they all use the same Profile Connection Space; the PCS white
|
||||
point is the same (specified in the header; should always be D50);
|
||||
possibly some other things I haven't thought of yet.
|
||||
|
||||
If some of the inputs have a ``gAMA`` chunk (specifying gamma) and
|
||||
an output ICC Profile is being generated, then the gamma information
|
||||
will be incorporated into the ICC Profile.
|
||||
|
||||
When the output is an RGB colour type and the output ICC Profile is
|
||||
synthesized, it is necessary to supply colorant tags (``rXYZ`` and so
|
||||
on). These are taken from ``sRGB``.
|
||||
|
||||
If the input images have ``gAMA`` chunks and no input image has an ICC
|
||||
Profile then the output image will have a ``gAMA`` chunk, but only if
|
||||
all the ``gAMA`` chunks specify the same value. Otherwise a warning
|
||||
will be emitted and no ``gAMA`` chunk. It is possible to add or replace
|
||||
a ``gAMA`` chunk using the ``pipchunk`` tool.
|
||||
|
||||
gAMA, pHYs, iCCP, sRGB, tIME, any other chunks.
|
||||
"""
|
||||
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
def stack(out, inp):
|
||||
"""Stack the input PNG files into a single output PNG."""
|
||||
|
||||
from array import array
|
||||
import itertools
|
||||
# Local module
|
||||
import png
|
||||
|
||||
if len(inp) < 1:
|
||||
raise Error("Required input is missing.")
|
||||
|
||||
l = map(png.Reader, inp)
|
||||
# Let data be a list of (pixel,info) pairs.
|
||||
data = map(lambda p: p.asDirect()[2:], l)
|
||||
totalchannels = sum(map(lambda x: x[1]['planes'], data))
|
||||
|
||||
if not (0 < totalchannels <= 4):
|
||||
raise Error("Too many channels in input.")
|
||||
alpha = totalchannels in (2,4)
|
||||
greyscale = totalchannels in (1,2)
|
||||
bitdepth = []
|
||||
for b in map(lambda x: x[1]['bitdepth'], data):
|
||||
try:
|
||||
if b == int(b):
|
||||
bitdepth.append(b)
|
||||
continue
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
# Assume a tuple.
|
||||
bitdepth += b
|
||||
# Currently, fail unless all bitdepths equal.
|
||||
if len(set(bitdepth)) > 1:
|
||||
raise NotImplemented("Cannot cope when bitdepths differ - sorry!")
|
||||
bitdepth = bitdepth[0]
|
||||
arraytype = 'BH'[bitdepth > 8]
|
||||
size = map(lambda x: x[1]['size'], data)
|
||||
# Currently, fail unless all images same size.
|
||||
if len(set(size)) > 1:
|
||||
raise NotImplemented("Cannot cope when sizes differ - sorry!")
|
||||
size = size[0]
|
||||
# Values per row
|
||||
vpr = totalchannels * size[0]
|
||||
def iterstack():
|
||||
# the izip call creates an iterator that yields the next row
|
||||
# from all the input images combined into a tuple.
|
||||
for irow in itertools.izip(*map(lambda x: x[0], data)):
|
||||
row = array(arraytype, [0]*vpr)
|
||||
# output channel
|
||||
och = 0
|
||||
for i,arow in enumerate(irow):
|
||||
# ensure incoming row is an array
|
||||
arow = array(arraytype, arow)
|
||||
n = data[i][1]['planes']
|
||||
for j in range(n):
|
||||
row[och::totalchannels] = arow[j::n]
|
||||
och += 1
|
||||
yield row
|
||||
w = png.Writer(size[0], size[1],
|
||||
greyscale=greyscale, alpha=alpha, bitdepth=bitdepth)
|
||||
w.write(out, iterstack())
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
argv = argv[1:]
|
||||
arg = argv[:]
|
||||
return stack(sys.stdout, arg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pipwindow $
|
||||
# $Rev: 173 $
|
||||
|
||||
# pipwindow
|
||||
# Tool to crop/expand an image to a rectangular window. Come the
|
||||
# revolution this tool will allow the image and the window to be placed
|
||||
# arbitrarily (in particular the window can be bigger than the picture
|
||||
# and/or overlap it only partially) and the image can be OpenGL style
|
||||
# border/repeat effects (repeat, mirrored repeat, clamp, fixed
|
||||
# background colour, background colour from source file). For now it
|
||||
# only acts as crop. The window must be no greater than the image in
|
||||
# both x and y.
|
||||
|
||||
def window(tl, br, inp, out):
|
||||
"""Place a window onto the image and cut-out the resulting
|
||||
rectangle. The window is an axis aligned rectangle opposite corners
|
||||
at *tl* and *br* (each being an (x,y) pair). *inp* specifies the
|
||||
input file which should be a PNG image.
|
||||
"""
|
||||
|
||||
import png
|
||||
|
||||
r = png.Reader(file=inp)
|
||||
x,y,pixels,meta = r.asDirect()
|
||||
if not (0 <= tl[0] < br[0] <= x):
|
||||
raise NotImplementedError()
|
||||
if not (0 <= tl[1] < br[1] <= y):
|
||||
raise NotImplementedError()
|
||||
# Compute left and right bounds for each row
|
||||
l = tl[0] * meta['planes']
|
||||
r = br[0] * meta['planes']
|
||||
def itercrop():
|
||||
"""An iterator to perform the crop."""
|
||||
|
||||
for i,row in enumerate(pixels):
|
||||
if i < tl[1]:
|
||||
continue
|
||||
if i >= br[1]:
|
||||
# Same as "raise StopIteration"
|
||||
return
|
||||
yield row[l:r]
|
||||
meta['size'] = (br[0]-tl[0], br[1]-tl[1])
|
||||
w = png.Writer(**meta)
|
||||
w.write(out, itercrop())
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
argv = argv[1:]
|
||||
|
||||
tl = (0,0)
|
||||
br = tuple(map(int, argv[:2]))
|
||||
if len(argv) >= 4:
|
||||
tl = br
|
||||
br = tuple(map(int, argv[2:4]))
|
||||
if len(argv) in (2, 4):
|
||||
f = sys.stdin
|
||||
else:
|
||||
f = open(argv[-1], 'rb')
|
||||
|
||||
return window(tl, br, f, sys.stdout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,293 @@
|
||||
#!/usr/bin/env python
|
||||
# $Rev: 184 $
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/plan9topng.py $
|
||||
|
||||
# Imported from //depot/prj/plan9topam/master/code/plan9topam.py#4 on
|
||||
# 2009-06-15.
|
||||
|
||||
"""Command line tool to convert from Plan 9 image format to PNG format.
|
||||
|
||||
Plan 9 image format description:
|
||||
http://plan9.bell-labs.com/magic/man2html/6/image
|
||||
"""
|
||||
|
||||
# http://www.python.org/doc/2.3.5/lib/module-itertools.html
|
||||
import itertools
|
||||
# http://www.python.org/doc/2.3.5/lib/module-re.html
|
||||
import re
|
||||
# http://www.python.org/doc/2.3.5/lib/module-sys.html
|
||||
import sys
|
||||
|
||||
def block(s, n):
|
||||
# See http://www.python.org/doc/2.6.2/library/functions.html#zip
|
||||
return zip(*[iter(s)]*n)
|
||||
|
||||
def convert(f, output=sys.stdout) :
|
||||
"""Convert Plan 9 file to PNG format. Works with either uncompressed
|
||||
or compressed files.
|
||||
"""
|
||||
|
||||
r = f.read(11)
|
||||
if r == 'compressed\n' :
|
||||
png(output, *decompress(f))
|
||||
else :
|
||||
png(output, *glue(f, r))
|
||||
|
||||
|
||||
def glue(f, r) :
|
||||
"""Return (metadata, stream) pair where `r` is the initial portion of
|
||||
the metadata that has already been read from the stream `f`.
|
||||
"""
|
||||
|
||||
r = r + f.read(60-len(r))
|
||||
return (r, f)
|
||||
|
||||
def meta(r) :
|
||||
"""Convert 60 character string `r`, the metadata from an image file.
|
||||
Returns a 5-tuple (*chan*,*minx*,*miny*,*limx*,*limy*). 5-tuples may
|
||||
settle into lists in transit.
|
||||
|
||||
As per http://plan9.bell-labs.com/magic/man2html/6/image the metadata
|
||||
comprises 5 words separated by blanks. As it happens each word starts
|
||||
at an index that is a multiple of 12, but this routine does not care
|
||||
about that."""
|
||||
|
||||
r = r.split()
|
||||
# :todo: raise FormatError
|
||||
assert len(r) == 5
|
||||
r = [r[0]] + map(int, r[1:])
|
||||
return r
|
||||
|
||||
def bitdepthof(pixel) :
|
||||
"""Return the bitdepth for a Plan9 pixel format string."""
|
||||
|
||||
maxd = 0
|
||||
for c in re.findall(r'[a-z]\d*', pixel) :
|
||||
if c[0] != 'x':
|
||||
maxd = max(maxd, int(c[1:]))
|
||||
return maxd
|
||||
|
||||
def maxvalof(pixel):
|
||||
"""Return the netpbm MAXVAL for a Plan9 pixel format string."""
|
||||
|
||||
bitdepth = bitdepthof(pixel)
|
||||
return (2**bitdepth)-1
|
||||
|
||||
def pixmeta(metadata, f) :
|
||||
"""Convert (uncompressed) Plan 9 image file to pair of (*metadata*,
|
||||
*pixels*). This is intended to be used by PyPNG format. *metadata*
|
||||
is the metadata returned in a dictionary, *pixels* is an iterator that
|
||||
yields each row in boxed row flat pixel format.
|
||||
|
||||
`f`, the input file, should be cued up to the start of the image data.
|
||||
"""
|
||||
|
||||
chan,minx,miny,limx,limy = metadata
|
||||
rows = limy - miny
|
||||
width = limx - minx
|
||||
nchans = len(re.findall('[a-wyz]', chan))
|
||||
alpha = 'a' in chan
|
||||
# Iverson's convention for the win!
|
||||
ncolour = nchans - alpha
|
||||
greyscale = ncolour == 1
|
||||
bitdepth = bitdepthof(chan)
|
||||
maxval = 2**bitdepth - 1
|
||||
# PNG style metadata
|
||||
meta=dict(size=(width,rows), bitdepth=bitdepthof(chan),
|
||||
greyscale=greyscale, alpha=alpha, planes=nchans)
|
||||
|
||||
return itertools.imap(lambda x: itertools.chain(*x),
|
||||
block(unpack(f, rows, width, chan, maxval), width)), meta
|
||||
|
||||
def png(out, metadata, f):
|
||||
"""Convert to PNG format. `metadata` should be a Plan9 5-tuple; `f`
|
||||
the input file (see :meth:`pixmeta`).
|
||||
"""
|
||||
|
||||
import png
|
||||
|
||||
pixels,meta = pixmeta(metadata, f)
|
||||
p = png.Writer(**meta)
|
||||
p.write(out, pixels)
|
||||
|
||||
def spam():
|
||||
"""Not really spam, but old PAM code, which is in limbo."""
|
||||
|
||||
if nchans == 3 or nchans == 1 :
|
||||
# PGM (P5) or PPM (P6) format.
|
||||
output.write('P%d\n%d %d %d\n' % (5+(nchans==3), width, rows, maxval))
|
||||
else :
|
||||
# PAM format.
|
||||
output.write("""P7
|
||||
WIDTH %d
|
||||
HEIGHT %d
|
||||
DEPTH %d
|
||||
MAXVAL %d
|
||||
""" % (width, rows, nchans, maxval))
|
||||
|
||||
def unpack(f, rows, width, pixel, maxval) :
|
||||
"""Unpack `f` into pixels. Assumes the pixel format is such that the depth
|
||||
is either a multiple or a divisor of 8.
|
||||
`f` is assumed to be an iterator that returns blocks of input such
|
||||
that each block contains a whole number of pixels. An iterator is
|
||||
returned that yields each pixel as an n-tuple. `pixel` describes the
|
||||
pixel format using the Plan9 syntax ("k8", "r8g8b8", and so on).
|
||||
"""
|
||||
|
||||
def mask(w) :
|
||||
"""An integer, to be used as a mask, with bottom `w` bits set to 1."""
|
||||
|
||||
return (1 << w)-1
|
||||
|
||||
def deblock(f, depth, width) :
|
||||
"""A "packer" used to convert multiple bytes into single pixels.
|
||||
`depth` is the pixel depth in bits (>= 8), `width` is the row width in
|
||||
pixels.
|
||||
"""
|
||||
|
||||
w = depth // 8
|
||||
i = 0
|
||||
for block in f :
|
||||
for i in range(len(block)//w) :
|
||||
p = block[w*i:w*(i+1)]
|
||||
i += w
|
||||
# Convert p to little-endian integer, x
|
||||
x = 0
|
||||
s = 1 # scale
|
||||
for j in p :
|
||||
x += s * ord(j)
|
||||
s <<= 8
|
||||
yield x
|
||||
|
||||
def bitfunge(f, depth, width) :
|
||||
"""A "packer" used to convert single bytes into multiple pixels.
|
||||
Depth is the pixel depth (< 8), width is the row width in pixels.
|
||||
"""
|
||||
|
||||
for block in f :
|
||||
col = 0
|
||||
for i in block :
|
||||
x = ord(i)
|
||||
for j in range(8/depth) :
|
||||
yield x >> (8 - depth)
|
||||
col += 1
|
||||
if col == width :
|
||||
# A row-end forces a new byte even if we haven't consumed
|
||||
# all of the current byte. Effectively rows are bit-padded
|
||||
# to make a whole number of bytes.
|
||||
col = 0
|
||||
break
|
||||
x <<= depth
|
||||
|
||||
# number of bits in each channel
|
||||
chan = map(int, re.findall(r'\d+', pixel))
|
||||
# type of each channel
|
||||
type = re.findall('[a-z]', pixel)
|
||||
|
||||
depth = sum(chan)
|
||||
|
||||
# According to the value of depth pick a "packer" that either gathers
|
||||
# multiple bytes into a single pixel (for depth >= 8) or split bytes
|
||||
# into several pixels (for depth < 8)
|
||||
if depth >= 8 :
|
||||
#
|
||||
assert depth % 8 == 0
|
||||
packer = deblock
|
||||
else :
|
||||
assert 8 % depth == 0
|
||||
packer = bitfunge
|
||||
|
||||
for x in packer(f, depth, width) :
|
||||
# x is the pixel as an unsigned integer
|
||||
o = []
|
||||
# This is a bit yucky. Extract each channel from the _most_
|
||||
# significant part of x.
|
||||
for j in range(len(chan)) :
|
||||
v = (x >> (depth - chan[j])) & mask(chan[j])
|
||||
x <<= chan[j]
|
||||
if type[j] != 'x' :
|
||||
# scale to maxval
|
||||
v = v * float(maxval) / mask(chan[j])
|
||||
v = int(v+0.5)
|
||||
o.append(v)
|
||||
yield o
|
||||
|
||||
|
||||
def decompress(f) :
|
||||
"""Decompress a Plan 9 image file. Assumes f is already cued past the
|
||||
initial 'compressed\n' string.
|
||||
"""
|
||||
|
||||
r = meta(f.read(60))
|
||||
return r, decomprest(f, r[4])
|
||||
|
||||
|
||||
def decomprest(f, rows) :
|
||||
"""Iterator that decompresses the rest of a file once the metadata
|
||||
have been consumed."""
|
||||
|
||||
row = 0
|
||||
while row < rows :
|
||||
row,o = deblock(f)
|
||||
yield o
|
||||
|
||||
|
||||
def deblock(f) :
|
||||
"""Decompress a single block from a compressed Plan 9 image file.
|
||||
Each block starts with 2 decimal strings of 12 bytes each. Yields a
|
||||
sequence of (row, data) pairs where row is the total number of rows
|
||||
processed according to the file format and data is the decompressed
|
||||
data for a set of rows."""
|
||||
|
||||
row = int(f.read(12))
|
||||
size = int(f.read(12))
|
||||
if not (0 <= size <= 6000) :
|
||||
raise 'block has invalid size; not a Plan 9 image file?'
|
||||
|
||||
# Since each block is at most 6000 bytes we may as well read it all in
|
||||
# one go.
|
||||
d = f.read(size)
|
||||
i = 0
|
||||
o = []
|
||||
|
||||
while i < size :
|
||||
x = ord(d[i])
|
||||
i += 1
|
||||
if x & 0x80 :
|
||||
x = (x & 0x7f) + 1
|
||||
lit = d[i:i+x]
|
||||
i += x
|
||||
o.extend(lit)
|
||||
continue
|
||||
# x's high-order bit is 0
|
||||
l = (x >> 2) + 3
|
||||
# Offset is made from bottom 2 bits of x and all 8 bits of next
|
||||
# byte. http://plan9.bell-labs.com/magic/man2html/6/image doesn't
|
||||
# say whether x's 2 bits are most signiificant or least significant.
|
||||
# But it is clear from inspecting a random file,
|
||||
# http://plan9.bell-labs.com/sources/plan9/sys/games/lib/sokoban/images/cargo.bit
|
||||
# that x's 2 bit are most significant.
|
||||
#
|
||||
offset = (x & 3) << 8
|
||||
offset |= ord(d[i])
|
||||
i += 1
|
||||
# Note: complement operator neatly maps (0 to 1023) to (-1 to
|
||||
# -1024). Adding len(o) gives a (non-negative) offset into o from
|
||||
# which to start indexing.
|
||||
offset = ~offset + len(o)
|
||||
if offset < 0 :
|
||||
raise 'byte offset indexes off the begininning of the output buffer; not a Plan 9 image file?'
|
||||
for j in range(l) :
|
||||
o.append(o[offset+j])
|
||||
return row,''.join(o)
|
||||
|
||||
def main(argv=None) :
|
||||
if argv is None :
|
||||
argv = sys.argv
|
||||
if len(sys.argv) <= 1 :
|
||||
return convert(sys.stdin)
|
||||
else :
|
||||
return convert(open(argv[1], 'rb'))
|
||||
|
||||
if __name__ == '__main__' :
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pngchunk $
|
||||
# $Rev: 156 $
|
||||
# pngchunk
|
||||
# Chunk editing/extraction tool.
|
||||
|
||||
import struct
|
||||
import warnings
|
||||
|
||||
# Local module.
|
||||
import png
|
||||
|
||||
"""
|
||||
pngchunk [--gamma g] [--iccprofile file] [--sigbit b] [-c cHNK!] [-c cHNK:foo] [-c cHNK<file]
|
||||
|
||||
The ``-c`` option is used to add or remove chunks. A chunk is specified
|
||||
by its 4 byte chunk type. If this is followed by a ``!`` then that
|
||||
chunk is removed from the PNG file. If the chunk type is followed by a
|
||||
``:`` then the chunk is replaced with the contents of the rest of the
|
||||
argument (this is probably only useful if the content is mostly ASCII,
|
||||
otherwise it's a pain to quote the contents, otherwise see...). A ``<``
|
||||
can be used to take the contents of the chunk from the named file.
|
||||
"""
|
||||
|
||||
|
||||
def chunk(out, inp, l):
|
||||
"""Process the input PNG file to the output, chunk by chunk. Chunks
|
||||
can be inserted, removed, replaced, or sometimes edited. Generally,
|
||||
chunks are not inspected, so pixel data (in the ``IDAT`` chunks)
|
||||
cannot be modified. `l` should be a list of (*chunktype*,
|
||||
*content*) pairs. *chunktype* is usually the type of the PNG chunk,
|
||||
specified as a 4-byte Python string, and *content* is the chunk's
|
||||
content, also as a string; if *content* is ``None`` then *all*
|
||||
chunks of that type will be removed.
|
||||
|
||||
This function *knows* about certain chunk types and will
|
||||
automatically convert from Python friendly representations to
|
||||
string-of-bytes.
|
||||
|
||||
chunktype
|
||||
'gamma' 'gAMA' float
|
||||
'sigbit' 'sBIT' int, or tuple of length 1,2 or 3
|
||||
|
||||
Note that the length of the strings used to identify *friendly*
|
||||
chunk types is greater than 4, hence they cannot be confused with
|
||||
canonical chunk types.
|
||||
|
||||
Chunk types, if specified using the 4-byte syntax, need not be
|
||||
official PNG chunks at all. Non-standard chunks can be created.
|
||||
"""
|
||||
|
||||
def canonical(p):
|
||||
"""Take a pair (*chunktype*, *content*), and return canonical
|
||||
representation (*chunktype*, *content*) where `chunktype` is the
|
||||
4-byte PNG chunk type and `content` is a string.
|
||||
"""
|
||||
|
||||
t,v = p
|
||||
if len(t) == 4:
|
||||
return t,v
|
||||
if t == 'gamma':
|
||||
t = 'gAMA'
|
||||
v = int(round(1e5*v))
|
||||
v = struct.pack('>I', v)
|
||||
elif t == 'sigbit':
|
||||
t = 'sBIT'
|
||||
try:
|
||||
v[0]
|
||||
except TypeError:
|
||||
v = (v,)
|
||||
v = struct.pack('%dB' % len(v), *v)
|
||||
elif t == 'iccprofile':
|
||||
t = 'iCCP'
|
||||
# http://www.w3.org/TR/PNG/#11iCCP
|
||||
v = 'a color profile\x00\x00' + v.encode('zip')
|
||||
else:
|
||||
warnings.warn('Unknown chunk type %r' % t)
|
||||
return t[:4],v
|
||||
|
||||
l = map(canonical, l)
|
||||
# Some chunks automagically replace ones that are present in the
|
||||
# source PNG. There can only be one of each of these chunk types.
|
||||
# Create a 'replace' dictionary to record these chunks.
|
||||
add = []
|
||||
delete = set()
|
||||
replacing = set(['gAMA', 'sBIT', 'PLTE', 'tRNS', 'sPLT', 'IHDR'])
|
||||
replace = dict()
|
||||
for t,v in l:
|
||||
if v is None:
|
||||
delete.add(t)
|
||||
elif t in replacing:
|
||||
replace[t] = v
|
||||
else:
|
||||
add.append((t,v))
|
||||
del l
|
||||
r = png.Reader(file=inp)
|
||||
chunks = r.chunks()
|
||||
def iterchunks():
|
||||
for t,v in chunks:
|
||||
if t in delete:
|
||||
continue
|
||||
if t in replace:
|
||||
yield t,replace[t]
|
||||
del replace[t]
|
||||
continue
|
||||
if t == 'IDAT' and replace:
|
||||
# Insert into the output any chunks that are on the
|
||||
# replace list. We haven't output them yet, because we
|
||||
# didn't see an original chunk of the same type to
|
||||
# replace. Thus the "replace" is actually an "insert".
|
||||
for u,w in replace.items():
|
||||
yield u,w
|
||||
del replace[u]
|
||||
if t == 'IDAT' and add:
|
||||
for item in add:
|
||||
yield item
|
||||
del add[:]
|
||||
yield t,v
|
||||
return png.write_chunks(out, iterchunks())
|
||||
|
||||
class Usage(Exception):
|
||||
pass
|
||||
|
||||
def main(argv=None):
|
||||
import getopt
|
||||
import re
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
|
||||
argv = argv[1:]
|
||||
|
||||
try:
|
||||
try:
|
||||
opt,arg = getopt.getopt(argv, 'c:',
|
||||
['gamma=', 'iccprofile=', 'sigbit='])
|
||||
except getopt.error, msg:
|
||||
raise Usage(msg)
|
||||
k = []
|
||||
for o,v in opt:
|
||||
if o in ['--gamma']:
|
||||
k.append(('gamma', float(v)))
|
||||
if o in ['--sigbit']:
|
||||
k.append(('sigbit', int(v)))
|
||||
if o in ['--iccprofile']:
|
||||
k.append(('iccprofile', open(v, 'rb').read()))
|
||||
if o in ['-c']:
|
||||
type = v[:4]
|
||||
if not re.match('[a-zA-Z]{4}', type):
|
||||
raise Usage('Chunk type must consist of 4 letters.')
|
||||
if v[4] == '!':
|
||||
k.append((type, None))
|
||||
if v[4] == ':':
|
||||
k.append((type, v[5:]))
|
||||
if v[4] == '<':
|
||||
k.append((type, open(v[5:], 'rb').read()))
|
||||
except Usage, err:
|
||||
print >>sys.stderr, (
|
||||
"usage: pngchunk [--gamma d.dd] [--sigbit b] [-c cHNK! | -c cHNK:text-string]")
|
||||
print >>sys.stderr, err.message
|
||||
return 2
|
||||
|
||||
if len(arg) > 0:
|
||||
f = open(arg[0], 'rb')
|
||||
else:
|
||||
f = sys.stdin
|
||||
return chunk(sys.stdout, f, k)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pnghist $
|
||||
# $Rev: 153 $
|
||||
# PNG Histogram
|
||||
# Only really works on grayscale images.
|
||||
|
||||
from array import array
|
||||
import getopt
|
||||
|
||||
import png
|
||||
|
||||
def decidemax(level):
|
||||
"""Given an array of levels, decide the maximum value to use for the
|
||||
histogram. This is normally chosen to be a bit bigger than the 99th
|
||||
percentile, but if the 100th percentile is not much more (within a
|
||||
factor of 2) then the 100th percentile is chosen.
|
||||
"""
|
||||
|
||||
truemax = max(level)
|
||||
sl = level[:]
|
||||
sl.sort(reverse=True)
|
||||
i99 = int(round(len(level)*0.01))
|
||||
if truemax <= 2*sl[i99]:
|
||||
return truemax
|
||||
return 1.05*sl[i99]
|
||||
|
||||
def hist(out, inp, verbose=None):
|
||||
"""Open the PNG file `inp` and generate a histogram."""
|
||||
|
||||
r = png.Reader(file=inp)
|
||||
x,y,pixels,info = r.asDirect()
|
||||
bitdepth = info['bitdepth']
|
||||
level = [0]*2**bitdepth
|
||||
for row in pixels:
|
||||
for v in row:
|
||||
level[v] += 1
|
||||
maxlevel = decidemax(level)
|
||||
|
||||
h = 100
|
||||
outbitdepth = 8
|
||||
outmaxval = 2**outbitdepth - 1
|
||||
def genrow():
|
||||
for y in range(h):
|
||||
y = h-y-1
|
||||
# :todo: vary typecode according to outbitdepth
|
||||
row = array('B', [0]*len(level))
|
||||
fl = y*maxlevel/float(h)
|
||||
ce = (y+1)*maxlevel/float(h)
|
||||
for x in range(len(row)):
|
||||
if level[x] <= fl:
|
||||
# Relies on row being initialised to all 0
|
||||
continue
|
||||
if level[x] >= ce:
|
||||
row[x] = outmaxval
|
||||
continue
|
||||
frac = (level[x] - fl)/(ce - fl)
|
||||
row[x] = int(round(outmaxval*frac))
|
||||
yield row
|
||||
w = png.Writer(len(level), h, gamma=1.0,
|
||||
greyscale=True, alpha=False, bitdepth=outbitdepth)
|
||||
w.write(out, genrow())
|
||||
if verbose: print >>verbose, level
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
argv = argv[1:]
|
||||
opt,arg = getopt.getopt(argv, '')
|
||||
|
||||
if len(arg) < 1:
|
||||
f = sys.stdin
|
||||
else:
|
||||
f = open(arg[0])
|
||||
hist(sys.stdout, f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/pnglsch $
|
||||
# $Rev: 107 $
|
||||
# pnglsch
|
||||
# PNG List Chunks
|
||||
|
||||
import png
|
||||
|
||||
def list(out, inp):
|
||||
r = png.Reader(file=inp)
|
||||
for t,v in r.chunks():
|
||||
add = ''
|
||||
if len(v) <= 28:
|
||||
add = ' ' + v.encode('hex')
|
||||
print >>out, "%s %10d%s" % (t, len(v), add)
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
arg = argv[1:]
|
||||
|
||||
if len(arg) > 0:
|
||||
f = open(arg[0], 'rb')
|
||||
else:
|
||||
f = sys.stdin
|
||||
return list(sys.stdout, f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python
|
||||
# $URL: http://pypng.googlecode.com/svn/trunk/code/texttopng $
|
||||
# $Rev: 132 $
|
||||
# Script to renders text as a PNG image.
|
||||
|
||||
from array import array
|
||||
import itertools
|
||||
|
||||
font = {
|
||||
32: '0000000000000000',
|
||||
33: '0010101010001000',
|
||||
34: '0028280000000000',
|
||||
35: '0000287c287c2800',
|
||||
36: '00103c5038147810',
|
||||
37: '0000644810244c00',
|
||||
38: '0020502054483400',
|
||||
39: '0010100000000000',
|
||||
40: '0008101010101008',
|
||||
41: '0020101010101020',
|
||||
42: '0010543838541000',
|
||||
43: '000010107c101000',
|
||||
44: '0000000000301020',
|
||||
45: '000000007c000000',
|
||||
46: '0000000000303000',
|
||||
47: '0000040810204000',
|
||||
48: '0038445454443800',
|
||||
49: '0008180808080800',
|
||||
50: '0038043840407c00',
|
||||
51: '003c041804043800',
|
||||
52: '00081828487c0800',
|
||||
53: '0078407804047800',
|
||||
54: '0038407844443800',
|
||||
55: '007c040810101000',
|
||||
56: '0038443844443800',
|
||||
57: '0038443c04040400',
|
||||
58: '0000303000303000',
|
||||
59: '0000303000301020',
|
||||
60: '0004081020100804',
|
||||
61: '0000007c007c0000',
|
||||
62: '0040201008102040',
|
||||
63: '0038440810001000',
|
||||
64: '00384c545c403800',
|
||||
65: '0038447c44444400',
|
||||
66: '0078447844447800',
|
||||
67: '0038444040443800',
|
||||
68: '0070484444487000',
|
||||
69: '007c407840407c00',
|
||||
70: '007c407840404000',
|
||||
71: '003844405c443c00',
|
||||
72: '0044447c44444400',
|
||||
73: '0038101010103800',
|
||||
74: '003c040404443800',
|
||||
75: '0044487048444400',
|
||||
76: '0040404040407c00',
|
||||
77: '006c545444444400',
|
||||
78: '004464544c444400',
|
||||
79: '0038444444443800',
|
||||
80: '0078447840404000',
|
||||
81: '0038444444443c02',
|
||||
82: '0078447844444400',
|
||||
83: '0038403804047800',
|
||||
84: '007c101010101000',
|
||||
85: '0044444444443c00',
|
||||
86: '0044444444281000',
|
||||
87: '0044445454543800',
|
||||
88: '0042241818244200',
|
||||
89: '0044443810101000',
|
||||
90: '007c081020407c00',
|
||||
91: '0038202020202038',
|
||||
92: '0000402010080400',
|
||||
93: '0038080808080838',
|
||||
94: '0010284400000000',
|
||||
95: '000000000000fe00',
|
||||
96: '0040200000000000',
|
||||
97: '000038043c443c00',
|
||||
98: '0040784444447800',
|
||||
99: '0000384040403800',
|
||||
100: '00043c4444443c00',
|
||||
101: '000038447c403c00',
|
||||
102: '0018203820202000',
|
||||
103: '00003c44443c0438',
|
||||
104: '0040784444444400',
|
||||
105: '0010003010101000',
|
||||
106: '0010003010101020',
|
||||
107: '0040404870484400',
|
||||
108: '0030101010101000',
|
||||
109: '0000385454444400',
|
||||
110: '0000784444444400',
|
||||
111: '0000384444443800',
|
||||
112: '0000784444784040',
|
||||
113: '00003c44443c0406',
|
||||
114: '00001c2020202000',
|
||||
115: '00003c4038047800',
|
||||
116: '0020203820201800',
|
||||
117: '0000444444443c00',
|
||||
118: '0000444444281000',
|
||||
119: '0000444454543800',
|
||||
120: '0000442810284400',
|
||||
121: '00004444443c0438',
|
||||
122: '00007c0810207c00',
|
||||
123: '0018202060202018',
|
||||
124: '0010101000101010',
|
||||
125: '003008080c080830',
|
||||
126: '0020540800000000',
|
||||
}
|
||||
|
||||
def char(i):
|
||||
"""Get image data for the character `i` (a one character string).
|
||||
Returned as a list of rows. Each row is a tuple containing the
|
||||
packed pixels.
|
||||
"""
|
||||
|
||||
i = ord(i)
|
||||
if i not in font:
|
||||
return [(0,)]*8
|
||||
return map(lambda row: (ord(row),), font[i].decode('hex'))
|
||||
|
||||
def texttoraster(m):
|
||||
"""Convert string *m* to a raster image (by rendering it using the
|
||||
font in *font*). A triple of (*width*, *height*, *pixels*) is
|
||||
returned; *pixels* is in boxed row packed pixel format.
|
||||
"""
|
||||
|
||||
# Assumes monospaced font.
|
||||
x = 8*len(m)
|
||||
y = 8
|
||||
return x,y,itertools.imap(lambda row: itertools.chain(*row),
|
||||
zip(*map(char, m)))
|
||||
|
||||
|
||||
def render(message, out):
|
||||
import png
|
||||
|
||||
x,y,pixels = texttoraster(message)
|
||||
w = png.Writer(x, y, greyscale=True, bitdepth=1)
|
||||
w.write_packed(out, pixels)
|
||||
out.flush()
|
||||
|
||||
def main(argv=None):
|
||||
import sys
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
if len(argv) > 1:
|
||||
message = argv[1]
|
||||
else:
|
||||
message = sys.stdin.read()
|
||||
render(message, sys.stdout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,463 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Build a comm application (Mozilla calendar, mail or suite).
|
||||
#
|
||||
# To build a tree,
|
||||
# 1. hg clone http://hg.mozilla.org/comm-central comm
|
||||
# 2. cd comm
|
||||
# 3. python client.py checkout
|
||||
# 4. create your .mozconfig file with
|
||||
# ac_add_options --enable-application=suite
|
||||
# (or mail, or calendar)
|
||||
# 5. gmake -f client.mk
|
||||
#
|
||||
# Other targets (gmake -f client.mk [targets...]),
|
||||
# build
|
||||
# clean
|
||||
# distclean
|
||||
#
|
||||
# See http://developer.mozilla.org/en/Build_Documentation for
|
||||
# more information.
|
||||
#
|
||||
# Options:
|
||||
# MOZ_BUILD_PROJECTS - Build multiple projects in subdirectories
|
||||
# of MOZ_OBJDIR
|
||||
# MOZ_OBJDIR - Destination object directory
|
||||
# MOZ_MAKE_FLAGS - Flags to pass to $(MAKE)
|
||||
# MOZ_PREFLIGHT_ALL } - Makefiles to run before any project in
|
||||
# MOZ_PREFLIGHT } MOZ_BUILD_PROJECTS, before each project, after
|
||||
# MOZ_POSTFLIGHT } each project, and after all projects; these
|
||||
# MOZ_POSTFLIGHT_ALL } variables contain space-separated lists
|
||||
# MOZ_UNIFY_BDATE - Set to use the same bdate for each project in
|
||||
# MOZ_BUILD_PROJECTS
|
||||
#
|
||||
#######################################################################
|
||||
# Defines
|
||||
|
||||
comma := ,
|
||||
|
||||
CWD := $(CURDIR)
|
||||
ifneq (1,$(words $(CWD)))
|
||||
$(error The platform directory cannot be located in a path with spaces.)
|
||||
endif
|
||||
|
||||
ifeq "$(CWD)" "/"
|
||||
CWD := /.
|
||||
endif
|
||||
|
||||
ifndef TOPSRCDIR
|
||||
ifeq (,$(wildcard client.mk))
|
||||
TOPSRCDIR := $(patsubst %/,%,$(dir $(MAKEFILE_LIST)))
|
||||
else
|
||||
TOPSRCDIR := $(CWD)
|
||||
endif
|
||||
endif
|
||||
|
||||
SH := /bin/sh
|
||||
PERL ?= perl
|
||||
PYTHON ?= $(shell which python2.7 > /dev/null 2>&1 && echo python2.7 || echo python)
|
||||
|
||||
CONFIG_GUESS_SCRIPT := $(wildcard $(TOPSRCDIR)/build/autoconf/config.guess)
|
||||
ifdef CONFIG_GUESS_SCRIPT
|
||||
CONFIG_GUESS := $(shell $(CONFIG_GUESS_SCRIPT))
|
||||
endif
|
||||
|
||||
|
||||
####################################
|
||||
# Sanity checks
|
||||
|
||||
# Windows checks.
|
||||
ifneq (,$(findstring mingw,$(CONFIG_GUESS)))
|
||||
|
||||
# check for CRLF line endings
|
||||
ifneq (0,$(shell $(PERL) -e 'binmode(STDIN); while (<STDIN>) { if (/\r/) { print "1"; exit } } print "0"' < $(TOPSRCDIR)/client.mk))
|
||||
$(error This source tree appears to have Windows-style line endings. To \
|
||||
convert it to Unix-style line endings, check \
|
||||
"https://developer.mozilla.org/en-US/docs/Developer_Guide/Mozilla_build_FAQ\#Win32-specific_questions" \
|
||||
for a workaround of this issue.)
|
||||
endif
|
||||
endif
|
||||
|
||||
####################################
|
||||
# Load mozconfig Options
|
||||
|
||||
# See build pages, http://www.mozilla.org/build/ for how to set up mozconfig.
|
||||
|
||||
MOZCONFIG_LOADER := build/autoconf/mozconfig2client-mk
|
||||
|
||||
define CR
|
||||
|
||||
|
||||
endef
|
||||
|
||||
# As $(shell) doesn't preserve newlines, use sed to replace them with an
|
||||
# unlikely sequence (||), which is then replaced back to newlines by make
|
||||
# before evaluation. $(shell) replacing newlines with spaces, || is always
|
||||
# followed by a space (since sed doesn't remove newlines), except on the
|
||||
# last line, so replace both '|| ' and '||'.
|
||||
# Also, make MOZ_PGO available to mozconfig when passed on make command line.
|
||||
MOZCONFIG_CONTENT := $(subst ||,$(CR),$(subst || ,$(CR),$(shell MOZ_PGO=$(MOZ_PGO) $(TOPSRCDIR)/$(MOZCONFIG_LOADER) $(TOPSRCDIR) | sed 's/$$/||/')))
|
||||
$(eval $(MOZCONFIG_CONTENT))
|
||||
|
||||
export FOUND_MOZCONFIG
|
||||
|
||||
# As '||' was used as a newline separator, it means it's not occurring in
|
||||
# lines themselves. It can thus safely be used to replaces normal spaces,
|
||||
# to then replace newlines with normal spaces. This allows to get a list
|
||||
# of mozconfig output lines.
|
||||
MOZCONFIG_OUT_LINES := $(subst $(CR), ,$(subst $(NULL) $(NULL),||,$(MOZCONFIG_CONTENT)))
|
||||
# Filter-out comments from those lines.
|
||||
START_COMMENT = \#
|
||||
MOZCONFIG_OUT_FILTERED := $(filter-out $(START_COMMENT)%,$(MOZCONFIG_OUT_LINES))
|
||||
|
||||
ifdef MOZ_PGO
|
||||
export MOZ_PGO
|
||||
endif
|
||||
|
||||
# Automatically add -jN to make flags if not defined. N defaults to number of cores.
|
||||
ifeq (,$(findstring -j,$(MOZ_MAKE_FLAGS)))
|
||||
cores=$(shell $(PYTHON) -c 'import multiprocessing; print(multiprocessing.cpu_count())')
|
||||
MOZ_MAKE_FLAGS += -j$(cores)
|
||||
endif
|
||||
|
||||
|
||||
ifndef MOZ_OBJDIR
|
||||
MOZ_OBJDIR = obj-$(CONFIG_GUESS)
|
||||
else
|
||||
# On Windows Pymake builds check MOZ_OBJDIR doesn't start with "/"
|
||||
ifneq (,$(findstring mingw,$(CONFIG_GUESS)))
|
||||
ifeq (1_a,$(.PYMAKE)_$(firstword a$(subst /, ,$(MOZ_OBJDIR))))
|
||||
$(error For Windows Pymake builds, MOZ_OBJDIR must be a Windows [and not MSYS] style path.)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef MOZ_BUILD_PROJECTS
|
||||
|
||||
ifdef MOZ_CURRENT_PROJECT
|
||||
OBJDIR = $(MOZ_OBJDIR)/$(MOZ_CURRENT_PROJECT)
|
||||
MOZ_MAKE = $(MAKE) $(MOZ_MAKE_FLAGS) -C $(OBJDIR)
|
||||
BUILD_PROJECT_ARG = MOZ_BUILD_APP=$(MOZ_CURRENT_PROJECT)
|
||||
else
|
||||
OBJDIR = $(error Cannot find the OBJDIR when MOZ_CURRENT_PROJECT is not set.)
|
||||
MOZ_MAKE = $(error Cannot build in the OBJDIR when MOZ_CURRENT_PROJECT is not set.)
|
||||
endif
|
||||
|
||||
else # MOZ_BUILD_PROJECTS
|
||||
|
||||
OBJDIR = $(MOZ_OBJDIR)
|
||||
MOZ_MAKE = $(MAKE) $(MOZ_MAKE_FLAGS) -C $(OBJDIR)
|
||||
|
||||
endif # MOZ_BUILD_PROJECTS
|
||||
|
||||
# If we have a MOZ_OBJDIR that's set from the environment, ensure that it is an
|
||||
# absolute path.
|
||||
ifdef MOZ_OBJDIR
|
||||
MOZ_OBJDIR := $(shell $(PYTHON) -c "import os.path; print(os.path.join(\"$(TOPSRCDIR)\", \"$(MOZ_OBJDIR)\").replace('\\\\','/'))")
|
||||
endif
|
||||
|
||||
# 'configure' scripts generated by autoconf.
|
||||
CONFIGURES := $(TOPSRCDIR)/configure
|
||||
CONFIGURES += $(TOPSRCDIR)/platform/configure
|
||||
CONFIGURES += $(TOPSRCDIR)/platform/js/src/configure
|
||||
|
||||
# Make targets that are going to be passed to the real build system
|
||||
OBJDIR_TARGETS = install export libs clean realclean distclean maybe_clobber_profiledbuild upload sdk installer package package-compare stage-package source-package l10n-check automation/build
|
||||
|
||||
#######################################################################
|
||||
# Rules
|
||||
|
||||
# The default rule is build
|
||||
build::
|
||||
|
||||
# Define mkdir
|
||||
include $(TOPSRCDIR)/config/makefiles/makeutils.mk
|
||||
include $(TOPSRCDIR)/config/makefiles/autotargets.mk
|
||||
|
||||
# Create a makefile containing the mk_add_options values from mozconfig,
|
||||
# but only do so when OBJDIR is defined (see further above).
|
||||
ifdef MOZ_BUILD_PROJECTS
|
||||
ifdef MOZ_CURRENT_PROJECT
|
||||
WANT_MOZCONFIG_MK = 1
|
||||
else
|
||||
WANT_MOZCONFIG_MK =
|
||||
endif
|
||||
else
|
||||
WANT_MOZCONFIG_MK = 1
|
||||
endif
|
||||
|
||||
ifdef WANT_MOZCONFIG_MK
|
||||
# For now, only output "export" lines from mozconfig2client-mk output.
|
||||
MOZCONFIG_MK_LINES := $(filter export||%,$(MOZCONFIG_OUT_LINES))
|
||||
$(OBJDIR)/.mozconfig.mk: $(FOUND_MOZCONFIG) $(call mkdir_deps,$(OBJDIR))
|
||||
$(if $(MOZCONFIG_MK_LINES),( $(foreach line,$(MOZCONFIG_MK_LINES), echo "$(subst ||, ,$(line))";) )) > $@
|
||||
ifdef MOZ_CURRENT_PROJECT
|
||||
echo export MOZ_CURRENT_PROJECT=$(MOZ_CURRENT_PROJECT) >> $@
|
||||
endif
|
||||
|
||||
# Include that makefile so that it is created. This should not actually change
|
||||
# the environment since MOZCONFIG_CONTENT, which MOZCONFIG_OUT_LINES derives
|
||||
# from, has already been eval'ed.
|
||||
include $(OBJDIR)/.mozconfig.mk
|
||||
endif
|
||||
|
||||
# UPLOAD_EXTRA_FILES is appended to and exported from mozconfig, which makes
|
||||
# submakes as well as configure add even more to that, so just unexport it
|
||||
# for submakes to pick it from .mozconfig.mk and for configure to pick it
|
||||
# from mach environment.
|
||||
unexport UPLOAD_EXTRA_FILES
|
||||
|
||||
# These targets are candidates for auto-running client.py
|
||||
|
||||
ifeq (01,$(MAKELEVEL)$(if $(ALWAYS_RUN_CLIENT_PY),1,))
|
||||
|
||||
build profiledbuild configure:: run_client_py
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk $@
|
||||
else
|
||||
|
||||
|
||||
# Print out any options loaded from mozconfig.
|
||||
all build clean distclean export libs install realclean::
|
||||
ifneq (,$(strip $(MOZCONFIG_OUT_FILTERED)))
|
||||
$(info Adding client.mk options from $(FOUND_MOZCONFIG):)
|
||||
$(foreach line,$(MOZCONFIG_OUT_FILTERED),$(info $(NULL) $(NULL) $(NULL) $(NULL) $(subst ||, ,$(line))))
|
||||
endif
|
||||
|
||||
# Windows equivalents
|
||||
build_all: build
|
||||
clobber clobber_all: clean
|
||||
|
||||
# Do everything from scratch
|
||||
everything: clean build
|
||||
|
||||
####################################
|
||||
# Profile-Guided Optimization
|
||||
# To use this, you should set the following variables in your mozconfig
|
||||
# mk_add_options PROFILE_GEN_SCRIPT=/path/to/profile-script
|
||||
#
|
||||
# The profile script should exercise the functionality to be included
|
||||
# in the profile feedback.
|
||||
#
|
||||
# This is up here, outside of the MOZ_CURRENT_PROJECT logic so that this
|
||||
# is usable in multi-pass builds, where you might not have a runnable
|
||||
# application until all the build passes and postflight scripts have run.
|
||||
ifdef MOZ_OBJDIR
|
||||
PGO_OBJDIR = $(MOZ_OBJDIR)
|
||||
else
|
||||
PGO_OBJDIR := $(TOPSRCDIR)
|
||||
endif
|
||||
|
||||
profiledbuild::
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk build MOZ_PROFILE_GENERATE=1
|
||||
$(MAKE) -C $(PGO_OBJDIR) stage-package
|
||||
OBJDIR=${PGO_OBJDIR} $(PROFILE_GEN_SCRIPT)
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk maybe_clobber_profiledbuild
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk build MOZ_PROFILE_USE=1
|
||||
|
||||
#####################################################
|
||||
# Build date unification
|
||||
|
||||
ifdef MOZ_UNIFY_BDATE
|
||||
ifndef MOZ_BUILD_DATE
|
||||
ifdef MOZ_BUILD_PROJECTS
|
||||
MOZ_BUILD_DATE = $(shell $(PYTHON) $(TOPSRCDIR)/platform/build/variables.py buildid_header | awk '{print $$3}')
|
||||
export MOZ_BUILD_DATE
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
#####################################################
|
||||
# Preflight, before building any project
|
||||
|
||||
build preflight_all::
|
||||
ifeq (,$(MOZ_CURRENT_PROJECT)$(if $(MOZ_PREFLIGHT_ALL),,1))
|
||||
# Don't run preflight_all for individual projects in multi-project builds
|
||||
# (when MOZ_CURRENT_PROJECT is set.)
|
||||
ifndef MOZ_BUILD_PROJECTS
|
||||
# Building a single project, OBJDIR is usable.
|
||||
set -e; \
|
||||
for mkfile in $(MOZ_PREFLIGHT_ALL); do \
|
||||
$(MAKE) -f $(TOPSRCDIR)/$$mkfile preflight_all TOPSRCDIR=$(TOPSRCDIR) OBJDIR=$(OBJDIR) MOZ_OBJDIR=$(MOZ_OBJDIR); \
|
||||
done
|
||||
else
|
||||
# OBJDIR refers to the project-specific OBJDIR, which is not available at
|
||||
# this point when building multiple projects. Only MOZ_OBJDIR is available.
|
||||
set -e; \
|
||||
for mkfile in $(MOZ_PREFLIGHT_ALL); do \
|
||||
$(MAKE) -f $(TOPSRCDIR)/$$mkfile preflight_all TOPSRCDIR=$(TOPSRCDIR) MOZ_OBJDIR=$(MOZ_OBJDIR) MOZ_BUILD_PROJECTS='$(MOZ_BUILD_PROJECTS)'; \
|
||||
done
|
||||
endif
|
||||
endif
|
||||
|
||||
# If we're building multiple projects, but haven't specified which project,
|
||||
# loop through them.
|
||||
|
||||
ifeq (,$(MOZ_CURRENT_PROJECT)$(if $(MOZ_BUILD_PROJECTS),,1))
|
||||
configure build preflight postflight $(OBJDIR_TARGETS)::
|
||||
set -e; \
|
||||
for app in $(MOZ_BUILD_PROJECTS); do \
|
||||
$(MAKE) -f $(TOPSRCDIR)/client.mk $@ MOZ_CURRENT_PROJECT=$$app; \
|
||||
done
|
||||
|
||||
else
|
||||
|
||||
# MOZ_CURRENT_PROJECT: either doing a single-project build, or building an
|
||||
# individual project in a multi-project build.
|
||||
|
||||
####################################
|
||||
# Configure
|
||||
|
||||
MAKEFILE = $(wildcard $(OBJDIR)/Makefile)
|
||||
CONFIG_STATUS = $(wildcard $(OBJDIR)/config.status)
|
||||
CONFIG_CACHE = $(wildcard $(OBJDIR)/config.cache)
|
||||
|
||||
EXTRA_CONFIG_DEPS := \
|
||||
$(TOPSRCDIR)/aclocal.m4 \
|
||||
$(TOPSRCDIR)/platform/aclocal.m4 \
|
||||
$(TOPSRCDIR)/platform/old-configure.in \
|
||||
$(wildcard $(TOPSRCDIR)/platform/build/autoconf/*.m4) \
|
||||
$(TOPSRCDIR)/platform/js/src/aclocal.m4 \
|
||||
$(TOPSRCDIR)/platform/js/src/old-configure.in \
|
||||
$(NULL)
|
||||
|
||||
$(CONFIGURES): %: %.in $(EXTRA_CONFIG_DEPS)
|
||||
@echo Generating $@
|
||||
sed '1,/^divert/d' $< > $@
|
||||
chmod +x $@
|
||||
|
||||
CONFIG_STATUS_DEPS := \
|
||||
$(wildcard $(CONFIGURES)) \
|
||||
$(wildcard $(TOPSRCDIR)/platform/nsprpub/configure) \
|
||||
$(wildcard $(TOPSRCDIR)/platform/config/milestone.txt) \
|
||||
$(wildcard $(TOPSRCDIR)/platform/ldap/sdks/c-sdk/configure) \
|
||||
$(wildcard $(addsuffix confvars.sh,$(wildcard $(TOPSRCDIR)/*/))) \
|
||||
$(NULL)
|
||||
|
||||
CONFIGURE_ENV_ARGS += \
|
||||
MAKE='$(MAKE)' \
|
||||
$(NULL)
|
||||
|
||||
# configure uses the program name to determine @srcdir@. Calling it without
|
||||
# $(TOPSRCDIR) will set @srcdir@ to '.'; otherwise, it is set to the full
|
||||
# path of $(TOPSRCDIR).
|
||||
ifeq ($(TOPSRCDIR),$(OBJDIR))
|
||||
CONFIGURE = ./configure
|
||||
else
|
||||
CONFIGURE = $(TOPSRCDIR)/configure
|
||||
endif
|
||||
|
||||
configure-files: $(CONFIGURES)
|
||||
|
||||
configure-preqs = \
|
||||
configure-files \
|
||||
$(call mkdir_deps,$(OBJDIR)) \
|
||||
$(if $(MOZ_BUILD_PROJECTS),$(call mkdir_deps,$(MOZ_OBJDIR))) \
|
||||
$(NULL)
|
||||
|
||||
configure:: $(configure-preqs)
|
||||
@echo cd $(OBJDIR);
|
||||
@echo $(CONFIGURE) $(CONFIGURE_ARGS)
|
||||
@cd $(OBJDIR) && $(BUILD_PROJECT_ARG) $(CONFIGURE_ENV_ARGS) $(CONFIGURE) $(CONFIGURE_ARGS) \
|
||||
|| ( echo '*** Fix above errors and then restart with\
|
||||
"$(MAKE) -f client.mk build"' && exit 1 )
|
||||
@touch $(OBJDIR)/Makefile
|
||||
|
||||
ifneq (,$(MAKEFILE))
|
||||
$(OBJDIR)/Makefile: $(OBJDIR)/config.status
|
||||
|
||||
$(OBJDIR)/config.status: $(CONFIG_STATUS_DEPS)
|
||||
else
|
||||
$(OBJDIR)/Makefile: $(CONFIG_STATUS_DEPS)
|
||||
endif
|
||||
@$(MAKE) -f $(TOPSRCDIR)/client.mk configure
|
||||
|
||||
ifneq (,$(CONFIG_STATUS))
|
||||
$(OBJDIR)/config/autoconf.mk: $(TOPSRCDIR)/config/autoconf.mk.in
|
||||
$(PYTHON) $(OBJDIR)/config.status -n --file=$(OBJDIR)/config/autoconf.mk
|
||||
endif
|
||||
|
||||
|
||||
####################################
|
||||
# Preflight
|
||||
|
||||
build preflight::
|
||||
ifdef MOZ_PREFLIGHT
|
||||
set -e; \
|
||||
for mkfile in $(MOZ_PREFLIGHT); do \
|
||||
$(MAKE) -f $(TOPSRCDIR)/$$mkfile preflight TOPSRCDIR=$(TOPSRCDIR) OBJDIR=$(OBJDIR) MOZ_OBJDIR=$(MOZ_OBJDIR); \
|
||||
done
|
||||
endif
|
||||
|
||||
####################################
|
||||
# Build it
|
||||
|
||||
build:: $(OBJDIR)/Makefile $(OBJDIR)/config.status
|
||||
+$(MOZ_MAKE)
|
||||
|
||||
####################################
|
||||
# Other targets
|
||||
|
||||
# Pass these target onto the real build system
|
||||
$(OBJDIR_TARGETS):: $(OBJDIR)/Makefile $(OBJDIR)/config.status
|
||||
+$(MOZ_MAKE) $@
|
||||
|
||||
####################################
|
||||
# Postflight
|
||||
|
||||
build postflight::
|
||||
ifdef MOZ_POSTFLIGHT
|
||||
set -e; \
|
||||
for mkfile in $(MOZ_POSTFLIGHT); do \
|
||||
$(MAKE) -f $(TOPSRCDIR)/$$mkfile postflight TOPSRCDIR=$(TOPSRCDIR) OBJDIR=$(OBJDIR) MOZ_OBJDIR=$(MOZ_OBJDIR); \
|
||||
done
|
||||
endif
|
||||
|
||||
endif # MOZ_CURRENT_PROJECT
|
||||
endif # RAN_CLIENT_PY
|
||||
|
||||
####################################
|
||||
# Postflight, after building all projects
|
||||
|
||||
build postflight_all::
|
||||
ifeq (,$(MOZ_CURRENT_PROJECT)$(if $(MOZ_POSTFLIGHT_ALL),,1))
|
||||
# Don't run postflight_all for individual projects in multi-project builds
|
||||
# (when MOZ_CURRENT_PROJECT is set.)
|
||||
ifndef MOZ_BUILD_PROJECTS
|
||||
# Building a single project, OBJDIR is usable.
|
||||
set -e; \
|
||||
for mkfile in $(MOZ_POSTFLIGHT_ALL); do \
|
||||
$(MAKE) -f $(TOPSRCDIR)/$$mkfile postflight_all TOPSRCDIR=$(TOPSRCDIR) OBJDIR=$(OBJDIR) MOZ_OBJDIR=$(MOZ_OBJDIR); \
|
||||
done
|
||||
else
|
||||
# OBJDIR refers to the project-specific OBJDIR, which is not available at
|
||||
# this point when building multiple projects. Only MOZ_OBJDIR is available.
|
||||
set -e; \
|
||||
for mkfile in $(MOZ_POSTFLIGHT_ALL); do \
|
||||
$(MAKE) -f $(TOPSRCDIR)/$$mkfile postflight_all TOPSRCDIR=$(TOPSRCDIR) MOZ_OBJDIR=$(MOZ_OBJDIR) MOZ_BUILD_PROJECTS='$(MOZ_BUILD_PROJECTS)'; \
|
||||
done
|
||||
endif
|
||||
endif
|
||||
|
||||
cleansrcdir:
|
||||
@cd $(TOPSRCDIR); \
|
||||
if [ -f Makefile ]; then \
|
||||
$(MAKE) distclean ; \
|
||||
else \
|
||||
echo 'Removing object files from srcdir...'; \
|
||||
rm -fr `find . -type d \( -name .deps -print -o -name CVS \
|
||||
-o -exec test ! -d {}/CVS \; \) -prune \
|
||||
-o \( -name '*.[ao]' -o -name '*.so' \) -type f -print`; \
|
||||
build/autoconf/clean-config.sh; \
|
||||
fi;
|
||||
|
||||
echo-variable-%:
|
||||
@echo $($*)
|
||||
|
||||
# This makefile doesn't support parallel execution. It does pass
|
||||
# MOZ_MAKE_FLAGS to sub-make processes, so they will correctly execute
|
||||
# in parallel.
|
||||
.NOTPARALLEL:
|
||||
|
||||
.PHONY: checkout co real_checkout build profiledbuild cleansrcdir pull_all build_all clobber clobber_all pull_and_build_all everything configure preflight_all preflight postflight postflight_all $(OBJDIR_TARGETS)
|
||||
@@ -0,0 +1,16 @@
|
||||
# This file is normally included by autoconf.mk, but it is also used
|
||||
# directly in python/mozbuild/mozbuild/base.py for gmake validation.
|
||||
# We thus use INCLUDED_AUTOCONF_MK to enable/disable some parts depending
|
||||
# whether a normal build is happening or whether the check is running.
|
||||
|
||||
# When mach wants to know if we're to use mozmake, it runs:
|
||||
# make -f topsrcdir/config/baseconfig.mk
|
||||
# The first word of MAKEFILE_LIST is the main file we're running. Grabbing the
|
||||
# parent of that directory therefore gets us the topsrcdir of comm-central,
|
||||
# whence we get the mozilla directory to run the "real" baseconfig.mk logic.
|
||||
ifndef INCLUDED_AUTOCONF_MK
|
||||
topsrcdir := $(dir $(firstword $(MAKEFILE_LIST)))..
|
||||
endif
|
||||
|
||||
MOZILLA_SRCDIR = $(topsrcdir)/platform
|
||||
include $(MOZILLA_SRCDIR)/config/baseconfig.mk
|
||||
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Just use mozilla-central's copy of config.mk now.
|
||||
include $(MOZILLA_DIR)/config/config.mk
|
||||
+2279
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,94 @@
|
||||
# -*- makefile -*-
|
||||
# vim:set ts=8 sw=8 sts=8 noet:
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
|
||||
ifndef INCLUDED_AUTOTARGETS_MK #{
|
||||
|
||||
# Conditional does not wrap the entire file so multiple
|
||||
# includes will be able to accumulate dependencies.
|
||||
|
||||
###########################################################################
|
||||
# AUTO_DEPS - A list of deps/targets drived from other macros.
|
||||
###########################################################################
|
||||
|
||||
MKDIR ?= mkdir -p
|
||||
TOUCH ?= touch
|
||||
|
||||
# declare for local use, rules.mk may not have been loaded
|
||||
space = $(NULL) $(NULL)
|
||||
|
||||
# Deps will be considered intermediate when used as a pre-requisite for
|
||||
# wildcard targets. Inhibit their removal, mkdir -p is a standalone op.
|
||||
.PRECIOUS: %/.mkdir.done
|
||||
|
||||
#########################
|
||||
##---] FUNCTIONS [---##
|
||||
#########################
|
||||
|
||||
# Squeeze can be overzealous, restore root for abspath
|
||||
getPathPrefix =$(if $(filter /%,$(1)),/)
|
||||
|
||||
# Squeeze '//' from the path, easily created by string functions
|
||||
_slashSqueeze =$(foreach val,$(getargv),$(call getPathPrefix,$(val))$(subst $(space),/,$(strip $(subst /,$(space),$(val)))))
|
||||
|
||||
# Squeeze extraneous directory slashes from the path
|
||||
# o protect embedded spaces within the path
|
||||
# o replace //+ sequences with /
|
||||
slash_strip = \
|
||||
$(strip \
|
||||
$(subst <--[**]-->,$(space),\
|
||||
$(call _slashSqueeze,\
|
||||
$(subst $(space),<--[**]-->,$(1))\
|
||||
)))
|
||||
|
||||
# Extract directory path from a dependency file.
|
||||
mkdir_stem =$(foreach val,$(getargv),$(subst /.mkdir.done,$(NULL),$(val)))
|
||||
|
||||
## Generate timestamp file for threadsafe directory creation
|
||||
mkdir_deps =$(foreach dir,$(getargv),$(call slash_strip,$(dir)/.mkdir.done))
|
||||
|
||||
#######################
|
||||
##---] TARGETS [---##
|
||||
#######################
|
||||
|
||||
%/.mkdir.done: # mkdir -p -p => mkdir -p
|
||||
$(subst $(space)-p,$(null),$(MKDIR)) -p '$(dir $@)'
|
||||
# Make the timestamp old enough for not being a problem with symbolic links
|
||||
# targets depending on it. Use Jan 3, 1980 to accomodate any timezone where
|
||||
# 198001010000 would translate to something older than FAT epoch.
|
||||
@$(TOUCH) -t 198001030000 '$@'
|
||||
|
||||
# A handful of makefiles are attempting "mkdir dot".
|
||||
# tbpl/valgrind builds are using this target
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=837754
|
||||
.mkdir.done:
|
||||
@echo 'WARNING: $(MKDIR) -dot- requested by $(MAKE) -C $(CURDIR) $(MAKECMDGOALS)'
|
||||
@$(TOUCH) -t 198001030000 '$@'
|
||||
|
||||
INCLUDED_AUTOTARGETS_MK = 1
|
||||
endif #}
|
||||
|
||||
|
||||
## Accumulate deps and cleanup
|
||||
ifneq (,$(GENERATED_DIRS))
|
||||
GENERATED_DIRS := $(strip $(sort $(GENERATED_DIRS)))
|
||||
tmpauto :=$(call mkdir_deps,GENERATED_DIRS)
|
||||
GENERATED_DIRS_DEPS +=$(tmpauto)
|
||||
GARBAGE_DIRS +=$(GENERATED_DIRS)
|
||||
endif
|
||||
|
||||
#################################################################
|
||||
# One ring/dep to rule them all:
|
||||
# config/rules.mk::all target is available by default
|
||||
# Add $(AUTO_DEPS) as an explicit target dependency when needed.
|
||||
#################################################################
|
||||
|
||||
AUTO_DEPS +=$(GENERATED_DIRS_DEPS)
|
||||
AUTO_DEPS := $(strip $(sort $(AUTO_DEPS)))
|
||||
|
||||
# Complain loudly if deps have not loaded so getargv != $(NULL)
|
||||
$(call requiredfunction,getargv)
|
||||
@@ -0,0 +1,117 @@
|
||||
# -*- makefile -*-
|
||||
# vim:set ts=8 sw=8 sts=8 noet:
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
## Identify function argument types
|
||||
istype =$(if $(value ${1}),list,scalar)
|
||||
isval =$(if $(filter-out list,$(call istype,${1})),true)
|
||||
isvar =$(if $(filter-out scalar,$(call istype,${1})),true)
|
||||
|
||||
# Access up to 9 arguments passed, option needed to emulate $*
|
||||
# Inline for function expansion, do not use $(call )
|
||||
argv =$(strip
|
||||
argv +=$(if $(1), $(1))$(if $(2), $(2))$(if $(3), $(3))$(if $(4), $(4))
|
||||
argv +=$(if $(5), $(5))$(if $(6), $(6))$(if $(7), $(7))$(if $(8), $(8))
|
||||
argv +=$(if $(9), $(9))
|
||||
argv +=$(if $(10), $(error makeutils.mk::argv can only handle 9 arguments))
|
||||
argv +=)
|
||||
|
||||
###########################################################################
|
||||
## Access function args as a simple list, inline within user functions.
|
||||
## Usage: $(info ** $(call banner,$(getargv)))
|
||||
## $(call banner,scalar)
|
||||
## $(call banner,list0 list1 list2)
|
||||
## $(call banner,ref) ; ref=foo bar tans
|
||||
## getarglist() would be a more accurate name but is longer to type
|
||||
getargv = $(if $(call isvar,$(1)),$($(1)),$(argv))
|
||||
|
||||
###########################################################################
|
||||
# Strip [n] leading options from an argument list. This will allow passing
|
||||
# extra args to user functions that will not propogate to sub-$(call )'s
|
||||
# Usage: $(call subargv,2)
|
||||
subargv =$(wordlist $(1),$(words $(getargv)),$(getargv))
|
||||
|
||||
###########################################################################
|
||||
# Intent: Display a distinct banner heading in the output stream
|
||||
# Usage: $(call banner,BUILDING: foo bar tans)
|
||||
# Debug:
|
||||
# target-preqs = \
|
||||
# $(call banner,target-preqs-BEGIN) \
|
||||
# foo bar tans \
|
||||
# $(call banner,target-preqs-END) \
|
||||
# $(NULL)
|
||||
# target: $(target-preqs)
|
||||
|
||||
banner = \
|
||||
$(info ) \
|
||||
$(info ***************************************************************************) \
|
||||
$(info ** $(getargv)) \
|
||||
$(info ***************************************************************************) \
|
||||
$(NULL)
|
||||
|
||||
#####################################################################
|
||||
# Intent: Determine if a string or pattern is contained in a list
|
||||
# Usage: strcmp - $(call if_XinY,clean,$(MAKECMDGOALS))
|
||||
# : pattern - $(call if_XinY,clean%,$(MAKECMDGOALS))
|
||||
is_XinY =$(filter $(1),$(call subargv,3,$(getargv)))
|
||||
|
||||
#####################################################################
|
||||
# Provide an alternate var to support testing
|
||||
ifdef MAKEUTILS_UNIT_TEST
|
||||
mcg_goals=TEST_MAKECMDGOALS
|
||||
else
|
||||
mcg_goals=MAKECMDGOALS
|
||||
endif
|
||||
|
||||
# Intent: Conditionals for detecting common/tier target use
|
||||
isTargetStem = $(sort \
|
||||
$(foreach var,$(getargv),\
|
||||
$(foreach pat,$(var)% %$(var),\
|
||||
$(call is_XinY,$(pat),${$(mcg_goals)})\
|
||||
)))
|
||||
isTargetStemClean = $(call isTargetStem,clean)
|
||||
isTargetStemExport = $(call isTargetStem,export)
|
||||
isTargetStemLibs = $(call isTargetStem,libs)
|
||||
isTargetStemTools = $(call isTargetStem,tools)
|
||||
|
||||
##################################################
|
||||
# Intent: Validation functions / unit test helpers
|
||||
|
||||
errorifneq =$(if $(subst $(strip $(1)),$(NULL),$(strip $(2))),$(error expected [$(1)] but found [$(2)]))
|
||||
|
||||
# Intent: verify function declaration exists
|
||||
requiredfunction =$(foreach func,$(1) $(2) $(3) $(4) $(5) $(6) $(7) $(8) $(9),$(if $(value $(func)),$(NULL),$(error required function [$(func)] is unavailable)))
|
||||
|
||||
|
||||
|
||||
## http://www.gnu.org/software/make/manual/make.html#Call-Function
|
||||
## Usage: o = $(call map,origin,o map $(MAKE))
|
||||
map = $(foreach val,$(2),$(call $(1),$(val)))
|
||||
|
||||
|
||||
## Disable checking for clean targets
|
||||
ifeq (,$(filter %clean clean%,$(MAKECMDGOALS))) #{
|
||||
|
||||
# Usage: $(call checkIfEmpty,[error|warning] foo NULL bar)
|
||||
checkIfEmpty =$(foreach var,$(wordlist 2,100,$(argv)),$(if $(strip $($(var))),$(NOP),$(call $(1),Variable $(var) does not contain a value)))
|
||||
|
||||
# Usage: $(call errorIfEmpty,foo NULL bar)
|
||||
errorIfEmpty =$(call checkIfEmpty,error $(argv))
|
||||
warnIfEmpty =$(call checkIfEmpty,warning $(argv))
|
||||
|
||||
endif #}
|
||||
|
||||
###########################################################################
|
||||
## Common makefile library loader
|
||||
###########################################################################
|
||||
topORerr =$(if $(topsrcdir),$(topsrcdir),$(error topsrcdir is not defined))
|
||||
|
||||
ifdef USE_AUTOTARGETS_MK # mkdir_deps
|
||||
include $(topORerr)/config/makefiles/autotargets.mk
|
||||
endif
|
||||
|
||||
## copy(src, dst): recursive copy
|
||||
copy_dir = (cd $(1)/. && $(TAR) $(TAR_CREATE_FLAGS) - .) | (cd $(2)/. && tar -xf -)
|
||||
@@ -0,0 +1,25 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import configobj, sys
|
||||
|
||||
try:
|
||||
(file, section, key) = sys.argv[1:]
|
||||
except ValueError:
|
||||
print "Usage: printconfigsetting.py <file> <section> <setting>"
|
||||
sys.exit(1)
|
||||
|
||||
c = configobj.ConfigObj(file)
|
||||
|
||||
try:
|
||||
s = c[section]
|
||||
except KeyError:
|
||||
print >>sys.stderr, "Section [%s] not found." % section
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
print s[key]
|
||||
except KeyError:
|
||||
print >>sys.stderr, "Key %s not found." % key
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,9 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
ifndef INCLUDED_RULES_MK
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
endif
|
||||
|
||||
include $(MOZILLA_DIR)/config/recurse.mk
|
||||
@@ -0,0 +1,13 @@
|
||||
# vim:set ts=8 sw=8 sts=8 noet:
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
|
||||
ifndef topsrcdir
|
||||
$(error topsrcdir was not set))
|
||||
endif
|
||||
|
||||
# Use mozilla-central's copy of rules.mk.
|
||||
include $(topsrcdir)/platform/config/rules.mk
|
||||
@@ -0,0 +1,38 @@
|
||||
dnl -*- Mode: Autoconf; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
dnl vi: set tabstop=4 shiftwidth=4 expandtab:
|
||||
dnl This Source Code Form is subject to the terms of the Mozilla Public
|
||||
dnl License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
dnl
|
||||
dnl This is a not-really-autoconf script (which is to say, it's a shell script
|
||||
dnl that is piped through m4 first) that executes the mozilla-central python
|
||||
dnl configure, first doing a little bit of processing to handle mozconfig and
|
||||
dnl the --with-external-source-dir rules.
|
||||
dnl ========================================================
|
||||
divert(0)dnl
|
||||
#!/bin/sh
|
||||
SRCDIR=$(dirname $0)
|
||||
TOPSRCDIR="$SRCDIR"
|
||||
MOZILLA_SRCDIR="${SRCDIR}/platform"
|
||||
export OLD_CONFIGURE="${MOZILLA_SRCDIR}"/old-configure
|
||||
|
||||
# Ensure the comm-* values are used.
|
||||
export MOZ_SOURCE_CHANGESET=$(hg -R "$TOPSRCDIR" parent --template="{node}" 2>/dev/null)
|
||||
export MOZ_SOURCE_REPO=$(hg -R "$TOPSRCDIR" showconfig paths.default 2>/dev/null | sed -e "s/^ssh:/https:/")
|
||||
|
||||
# If MOZCONFIG isn't set, use the .mozconfig from the current directory. This
|
||||
# overrides the lookup in mozilla-central's configure, which looks in the wrong
|
||||
# directory for this file.
|
||||
if test -z "$MOZCONFIG" -a -f "$SRCDIR"/.mozconfig; then
|
||||
export MOZCONFIG="$SRCDIR"/.mozconfig
|
||||
elif test -z "$MOZCONFIG" -a -f "$SRCDIR"/mozconfig; then
|
||||
export MOZCONFIG="$SRCDIR"/mozconfig
|
||||
fi
|
||||
|
||||
# Execute the mozilla configure script in the current directory, adding the
|
||||
# parameter we need to run comm-central. Since the configure script is really
|
||||
# just a wrapper around invoking a python variant, execute the underlying python
|
||||
# directly. We use a copy of the underlying configure script to get paths
|
||||
# correct.
|
||||
set -- "$@" --with-external-source-dir="$TOPSRCDIR"
|
||||
which python2.7 > /dev/null && exec python2.7 "$TOPSRCDIR/configure.py" "$@" || exec python "$TOPSRCDIR/configure.py" "$@"
|
||||
@@ -0,0 +1,32 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import imp
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
base_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
sys.path.append(os.path.join(base_dir, 'platform', 'python', 'mozbuild'))
|
||||
from mozbuild.configure import ConfigureSandbox
|
||||
|
||||
# We can't just import config_status since configure is shadowed by this file!
|
||||
f, pathname, desc = imp.find_module('configure',
|
||||
[os.path.join(base_dir, 'platform')])
|
||||
config_status = imp.load_module('configure', f, pathname, desc).config_status
|
||||
|
||||
def main(argv):
|
||||
config = {}
|
||||
sandbox = ConfigureSandbox(config, os.environ, argv)
|
||||
sandbox.run(os.path.join(os.path.dirname(__file__), 'moz.configure'))
|
||||
|
||||
if sandbox._help:
|
||||
return 0
|
||||
|
||||
return config_status(config)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
||||
@@ -0,0 +1,7 @@
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# This file needs to stay here even if empty so that mach will work,
|
||||
# specifically commands like mach file-info.
|
||||
@@ -0,0 +1,7 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
include('platform/moz.configure')
|
||||
Reference in New Issue
Block a user