Skip to content

Commit

Permalink
WIP background image
Browse files Browse the repository at this point in the history
  • Loading branch information
belluzj committed Oct 31, 2017
1 parent 4ff3d73 commit c303736
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 12 deletions.
53 changes: 53 additions & 0 deletions Lib/glyphsLib/builder/background_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import (print_function, division, absolute_import,
unicode_literals)

from .constants import GLYPHS_PREFIX

BACKGROUND_IMAGE_PREFIX = GLYPHS_PREFIX + 'backgroundImage.'
CROP_KEY = BACKGROUND_IMAGE_PREFIX + 'crop'
LOCKED_KEY = BACKGROUND_IMAGE_PREFIX + 'locked'
ALPHA_KEY = BACKGROUND_IMAGE_PREFIX + 'alpha'


def to_ufo_background_image(self, ufo_glyph, layer):
"""Copy the backgound image from the GSLayer to the UFO Glyph."""
image = layer.backgroundImage
if image is None:
return
ufo_image = ufo_glyph.image
ufo_image.fileName = image.path
ufo_image.transformation = image.transform
ufo_glyph.lib[CROP_KEY] = image.crop
ufo_glyph.lib[LOCKED_KEY] = image.locked
ufo_glyph.lib[ALPHA_KEY] = image.alpha


def to_glyphs_background_image(self, ufo_glyph, layer):
"""Copy the background image from the UFO Glyph to the GSLayer."""
ufo_image = ufo_glyph.image
if ufo_image.fileName is None:
return
image = self.glyphs_module.GSBackgroundImage()
image.path = ufo_image.fileName
image.transform = ufo_image.transformation
if CROP_KEY in ufo_glyph.lib:
image.crop = ufo_glyph.lib[CROP_KEY]
if LOCKED_KEY in ufo_glyph.lib:
image.locked = ufo_glyph.lib[LOCKED_KEY]
if ALPHA_KEY in ufo_glyph.lib:
image.alpha = ufo_glyph.lib[ALPHA_KEY]
layer.backgroundImage = image
2 changes: 2 additions & 0 deletions Lib/glyphsLib/builder/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ def instance_data(self):
# Implementation is spit into one file per feature
from .anchors import to_ufo_propagate_font_anchors, to_ufo_glyph_anchors
from .annotations import to_ufo_annotations
from .background_image import to_ufo_background_image
from .blue_values import to_ufo_blue_values
from .common import to_ufo_time
from .components import to_ufo_draw_components, to_ufo_component_data
Expand Down Expand Up @@ -309,6 +310,7 @@ def font(self):
# Implementation is spit into one file per feature
from .anchors import to_glyphs_glyph_anchors, to_glyphs_unpropagate_anchors
from .annotations import to_glyphs_annotations
from .background_image import to_glyphs_background_image
from .blue_values import to_glyphs_blue_values
from .components import to_glyphs_draw_components, to_glyphs_component_data
from .custom_params import (to_glyphs_family_custom_params,
Expand Down
3 changes: 3 additions & 0 deletions Lib/glyphsLib/builder/glyph.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def to_ufo_glyph(self, ufo_glyph, layer, glyph):
else:
ufo_glyph.width = width

self.to_ufo_background_image(ufo_glyph, layer)
self.to_ufo_guidelines(ufo_glyph, layer)
self.to_ufo_glyph_background(ufo_glyph, layer.background)
self.to_ufo_annotations(ufo_glyph, layer)
Expand Down Expand Up @@ -194,6 +195,7 @@ def to_glyphs_glyph(self, ufo_glyph, ufo_layer, master):
layer.width = ufo_glyph.lib[GLYPHLIB_PREFIX + 'originalWidth']
# TODO: check for customParameter DisableAllAutomaticBehaviour?

self.to_glyphs_background_image(ufo_glyph, layer)
self.to_glyphs_guidelines(ufo_glyph, layer)
self.to_glyphs_annotations(ufo_glyph, layer)
self.to_glyphs_hints(ufo_glyph, layer)
Expand Down Expand Up @@ -224,6 +226,7 @@ def to_ufo_glyph_background(self, glyph, background):
new_glyph = layer.newGlyph(glyph.name)
new_glyph.width = glyph.width

self.to_ufo_background_image(new_glyph, background)
self.to_ufo_draw_paths(new_glyph, background.paths)
self.to_ufo_draw_components(new_glyph, background.components)
self.to_ufo_glyph_anchors(new_glyph, background.anchors)
Expand Down
34 changes: 30 additions & 4 deletions Lib/glyphsLib/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from __future__ import print_function, unicode_literals
import re
import os
import math
import inspect
import traceback
Expand Down Expand Up @@ -227,6 +228,8 @@ def __init__(self):
if not hasattr(self, key):
klass = self._classesForName[key]
if inspect.isclass(klass) and issubclass(klass, GSBase):
# FIXME: (jany) Why?
# For GSLayer::backgroundImage, I was getting [] instead of None when no image
value = []
elif key in self._defaultsForName:
value = self._defaultsForName.get(key)
Expand Down Expand Up @@ -2292,8 +2295,12 @@ class GSBackgroundImage(GSBase):
"alpha": int,
}
_defaultsForName = {
"alpha": 50,
"transform": transform(1, 0, 0, 1, 0, 0),
}
_wrapperKeysTranslate = {
"alpha": "_alpha",
}

def __init__(self, path=None):
super(GSBackgroundImage, self).__init__()
Expand All @@ -2310,10 +2317,13 @@ def path(self):
@path.setter
def path(self, value):
# FIXME: (jany) use posix pathnames here?
if os.dirname(os.abspath(value)) == os.dirname(os.abspath(self.parent.parent.parent.filepath)):
self.imagePath = os.path.basename(value)
else:
self.imagePath = value
# FIXME: (jany) the following code must have never been tested.
# Also it would require to keep track of the parent for background
# images.
# if os.path.dirname(os.path.abspath(value)) == os.path.dirname(os.path.abspath(self.parent.parent.parent.filepath)):
# self.imagePath = os.path.basename(value)
# else:
self.imagePath = value

# .position
@property
Expand Down Expand Up @@ -2348,6 +2358,17 @@ def rotation(self, value):
self._R = value
self.updateAffineTransform()

# .alpha
@property
def alpha(self):
return self._alpha

@alpha.setter
def alpha(self, value):
if not 10 <= value <= 100:
value = 50
self._alpha = value

def updateAffineTransform(self):
affine = list(Affine.translation(self.transform[4], self.transform[5]) * Affine.scale(self._sX, self._sY) * Affine.rotation(self._R))[:6]
self.transform = [affine[0], affine[1], affine[3], affine[4], affine[2], affine[5]]
Expand All @@ -2369,6 +2390,10 @@ class GSBackgroundLayer(GSBase):
"guideLines": "guides",
}

def __init__(self):
super(GSBackgroundLayer, self).__init__()
self.backgroundImage = None


class GSLayer(GSBase):
_classesForName = {
Expand Down Expand Up @@ -2432,6 +2457,7 @@ def __init__(self):
self._paths = []
self._selection = []
self._userData = None
self.backgroundImage = None

def __repr__(self):
name = self.name
Expand Down
14 changes: 7 additions & 7 deletions Lib/glyphsLib/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,20 +142,19 @@ def height(self, value):

class rect(object):
"""Read/write a rect of two points in curly braces."""
#crop = "{{0, 0}, {427, 259}}";

dimension = 4
default = [0, 0, 0, 0]
regex = re.compile('{{([-.e\d]+), ([-.e\d]+)}, {([-.e\d]+), ([-.e\d]+)}}')

def __init__(self, value = None, value2 = None):
def __init__(self, value=None, value2=None):

if value is not None and value2 is not None:
self.value = [value[0], value[1], value2[0], value2[1]]
elif value is not None and value2 is None:
self.value = [float(i) for i in self.regex.match(value).groups()]
else:
self.value = self.default
self.value = self.default[:]

def plistValue(self):
assert isinstance(self.value, list) and len(self.value) == self.dimension
Expand All @@ -174,20 +173,21 @@ def __setitem__(self, key, value):
self.value[key] = value
else:
raise KeyError

def __len__(self):
return self.dimension

@property
def origin(self):
return point(self.value[0], self.value[1], rect = self)
return point(self.value[0], self.value[1], rect=self)
@origin.setter
def origin(self, value):
self.value[0] = value.x
self.value[1] = value.y

@property
def size(self):
return size(self.value[2], self.value[3], rect = self)
return size(self.value[2], self.value[3], rect=self)
@size.setter
def size(self, value):
self.value[2] = value.width
Expand All @@ -200,14 +200,14 @@ class transform(point):
default = [None, None, None, None, None, None]
regex = re.compile('{%s}' % ', '.join(['([-.e\d]+)'] * dimension))

def __init__(self, value = None, value2 = None, value3 = None, value4 = None, value5 = None, value6 = None):
def __init__(self, value=None, value2=None, value3=None, value4=None, value5=None, value6=None):

if value is not None and value2 is not None and value3 is not None and value4 is not None and value5 is not None and value6 is not None:
self.value = [value, value2, value3, value4, value5, value6]
elif value is not None and value2 is None:
self.value = [float(i) for i in self.regex.match(value).groups()]
else:
self.value = self.default
self.value = self.default[:]

def __repr__(self):
return '<affine transformation %s>' % (' '.join(map(str, self.value)))
Expand Down
28 changes: 27 additions & 1 deletion tests/classes_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
GSFont, GSFontMaster, GSInstance, GSCustomParameter, GSGlyph, GSLayer,
GSAnchor, GSComponent, GSAlignmentZone, GSClass, GSFeature, GSAnnotation,
GSFeaturePrefix, GSGuideLine, GSHint, GSNode, GSSmartComponentAxis,
LayerComponentsProxy, LayerGuideLinesProxy,
GSBackgroundImage, LayerComponentsProxy, LayerGuideLinesProxy,
STEM, TEXT, ARROW, CIRCLE, PLUS, MINUS
)
from glyphsLib.types import point, transform, rect, size
Expand Down Expand Up @@ -1110,6 +1110,32 @@ def test_widthMetricsKey(self):
def test_background(self):
self.assertIn('GSBackgroundLayer', self.layer.background.__repr__())

def test_backgroundImage(self):
# The selected layer (0 of glyph 'a') doesn't have one
self.assertIsNone(self.layer.backgroundImage)

glyph = self.font.glyphs['A']
layer = glyph.layers[0]
image = layer.backgroundImage
self.assertIsInstance(image, GSBackgroundImage)
# Values from the file
self.assertEqual('A.jpg', image.path)
self.assertEqual([0.0, 0.0, 489.0, 637.0], list(image.crop))
# Default values
self.assertEqual(50, image.alpha)
self.assertEqual([1, 0, 0, 1, 0, 0], image.transform.value)
self.assertEqual(False, image.locked)

# Test documented behaviour of "alpha"
image.alpha = 10
self.assertEqual(10, image.alpha)
image.alpha = 9
self.assertEqual(50, image.alpha)
image.alpha = 100
self.assertEqual(100, image.alpha)
image.alpha = 101
self.assertEqual(50, image.alpha)

# TODO?
# bezierPath, openBezierPath, completeBezierPath, completeOpenBezierPath?

Expand Down

0 comments on commit c303736

Please sign in to comment.