view Resources/Fonts/GenerateFont.py @ 2248:69b0f4e8a49b

Escape multipart type parameter value in Content-Type header ## Summary Multipart responses do not quote/escape the value of their type parameter (the subtype) even though it always contains at least one special character (the slash "/"), which confuses standard-compliant HTTP clients. ## Details The Content-Type header in HTTP is in RFC 7231, Section 3.1.1.5: https://tools.ietf.org/html/rfc7231#section-3.1.1.5 The section defers to the media type section (3.1.1.1) for the syntax of the media type: https://tools.ietf.org/html/rfc7231#section-3.1.1.1 This states that a parameter value can be quoted: parameter = token "=" ( token / quoted-string ) A parameter value that matches the token production can be transmitted either as a token or within a quoted-string. The quoted and unquoted values are equivalent. Tokens are defined in RFC 7230, Section 3.2.6 (via RFC 7231, appendix C): https://tools.ietf.org/html/rfc7231#appendix-C https://tools.ietf.org/html/rfc7230#section-3.2.6 Here we observe that tokens cannot contain a slash "/" character: token = 1*tchar tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA ; any VCHAR, except delimiters Delimiters are chosen from the set of US-ASCII visual characters not allowed in a token (DQUOTE and "(),/:;<=>?@[\]{}"). However, the current implementation does not quote/escape the value of the type parameter: multipart/related; type=application/dicom Instead, it should be: multipart/related; type="application/dicom" All of this also seems to apply to the MIME Content-Type header definition, even though it is a little different: https://www.iana.org/assignments/message-headers https://tools.ietf.org/html/rfc2045#section-5.1 https://tools.ietf.org/html/rfc2387
author Thibault Nélis <tn@osimis.io>
date Mon, 16 Jan 2017 13:07:11 +0100
parents a3a65de1840f
children 878b59270859
line wrap: on
line source

#!/usr/bin/python

# Orthanc - A Lightweight, RESTful DICOM Store
# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
# Department, University Hospital of Liege, Belgium
# Copyright (C) 2017 Osimis, Belgium
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# In addition, as a special exception, the copyright holders of this
# program give permission to link the code of its release with the
# OpenSSL project's "OpenSSL" library (or with modified versions of it
# that use the same license as the "OpenSSL" library), and distribute
# the linked executables. You must obey the GNU General Public License
# in all respects for all of the code used other than "OpenSSL". If you
# modify file(s) with this exception, you may extend this exception to
# your version of the file(s), but you are not obligated to do so. If
# you do not wish to do so, delete this exception statement from your
# version. If you delete this exception statement from all source files
# in the program, then also delete it here.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.




# sudo pip install freetype-py



import freetype
import json
import os
import sys
import unicodedata


if len(sys.argv) != 3:
    print('Usage: %s <Font> <Size>\n' % sys.argv[0])
    print('Example: %s /usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-B.ttf 16\n' % sys.argv[0])
    sys.exit(-1)



FONT = sys.argv[1]
PIXEL_SIZE = int(sys.argv[2])
CHARSET = 'latin-1'


# Load the font
face = freetype.Face(FONT)
face.set_char_size(PIXEL_SIZE * 64)

# Generate all the characters between 0 and 255
characters = ''.join(map(chr, range(0, 256)))

# Interpret the string using the required charset
characters = characters.decode(CHARSET, 'ignore')

# Keep only non-control characters
characters = filter(lambda c: unicodedata.category(c)[0] != 'C', characters)

font = {
    'Name' : os.path.basename(FONT),
    'Size' : PIXEL_SIZE,
    'Characters' : {}
}


def PrintCharacter(c):
    pos = 0
    for i in range(c['Height']):
        s = ''
        for j in range(c['Width']):
            if c['Bitmap'][pos] > 127:
                s += '*'
            else:
                s += ' '
            pos += 1
        print s


for c in characters:
    face.load_char(c)

    info = {
        'Width' : face.glyph.bitmap.width,
        'Height' : face.glyph.bitmap.rows,
        'Advance' : face.glyph.metrics.horiAdvance / 64,
        'Top' : -face.glyph.metrics.horiBearingY / 64,
        'Bitmap' : face.glyph.bitmap.buffer,
    }

    font['Characters'][ord(c)] = info

    #PrintCharacter(info)

minTop = min(map(lambda (k, v): v['Top'], font['Characters'].iteritems()))
for c in font['Characters']:
    font['Characters'][c]['Top'] -= minTop

font['MaxAdvance'] = max(map(lambda (k, v): v['Advance'], font['Characters'].iteritems()))
font['MaxHeight'] = max(map(lambda (k, v): v['Height'], font['Characters'].iteritems()))

print json.dumps(font)