Compare commits

...

23 commits
master ... pcf

Author SHA1 Message Date
6e57a8b9e9 bitmap_font: Remove use of f-string, not compatible with 5.x mpy-cross 2020-12-08 14:03:33 -06:00
d379f1962e pcf: Remove use of f-string, not compatible with 5.x mpy-cross 2020-12-08 14:02:53 -06:00
383fc039c5 ttf: fix lint error 2020-12-08 13:47:58 -06:00
ceed4c2a88 pcf: black & lint 2020-12-08 11:16:37 -06:00
Jeff Epler
6ae6e07484 bdf: Add ascent, descent properties
This will be used by a future version of adafruit_display_text to avoid
needing to load glyphs from the font to guess these values.
2020-12-08 11:16:37 -06:00
e15c7d1f5c pcf: Optimize memory allocations 2020-12-08 10:59:08 -06:00
84bf5208bb Optimize bitmap fill 2020-12-08 10:49:18 -06:00
e1634e1a59 Fix off by 1 error in encoding index calculation 2020-12-08 10:49:18 -06:00
7dcd40828e Allow alternate specimens 2020-12-08 10:49:18 -06:00
e5d0839aca Add font with kana glyphs for testing 2020-12-08 10:49:18 -06:00
7869ef43be pcf: handle missing glyphs (mapped like code point 0xffff) 2020-12-07 21:57:02 -06:00
3c31cff165 run black 2020-12-07 19:08:24 -06:00
7658511786 Fix number of characters in this font
This font was probably manually trimmed from one with a larger repertoire of code points.

This was fine, except that bdftopcf didn't like it.
2020-12-07 19:07:12 -06:00
2bef623710 Implement loading pcf fonts
A pcf font can be generated from a bdf font using `bdftopcf` from debian/ubuntu package fonts-utils
2020-12-07 19:06:25 -06:00
27648e7ab7 bitmap_font: fix imports, give better error 2020-12-07 19:05:24 -06:00
Scott Shawcroft
51e9a1fa2e
Merge pull request #30 from FoamyGuy/magtag_example
adding MagTag example
2020-11-23 15:16:04 -08:00
foamyguy
8c1fa9b684 a few comments in magtag example 2020-11-22 15:04:12 -06:00
foamyguy
c38baeb932 adding magtag example 2020-11-22 15:01:06 -06:00
foamyguy
7e153547f5
Merge pull request #29 from adafruit/tannewt-patch-1
Fix 2.6.0 lint
2020-09-03 19:33:27 -05:00
Scott Shawcroft
ca48d4afde
Merge pull request #28 from ronfischler/set-changed-during-iteration-fix
Make a copy of the set to iterate over, not the original set we will …
2020-09-02 16:57:41 -07:00
Scott Shawcroft
1f46cc3a68
reorder imports 2020-09-02 16:46:51 -07:00
Scott Shawcroft
977edcbd88
Reorder imports 2020-09-02 16:43:09 -07:00
ronfischler
2501072843 Make a copy of the set to iterate over, not the original set we will be removing items from 2020-09-02 12:06:32 -07:00
12 changed files with 30803 additions and 118 deletions

1
.gitignore vendored
View file

@ -9,5 +9,4 @@ bundles
.eggs .eggs
dist dist
**/*.egg-info **/*.egg-info
*.pcf
*.ttf *.ttf

View file

@ -63,6 +63,41 @@ class BDF(GlyphCache):
self.point_size = None self.point_size = None
self.x_resolution = None self.x_resolution = None
self.y_resolution = None self.y_resolution = None
self._ascent = None
self._descent = None
@property
def descent(self):
"""The number of pixels below the baseline of a typical descender"""
if self._descent is None:
self.file.seek(0)
while True:
line = self.file.readline()
if not line:
break
if line.startswith(b"FONT_DESCENT "):
self._descent = int(line.split()[1])
break
return self._descent
@property
def ascent(self):
"""The number of pixels above the baseline of a typical ascender"""
if self._ascent is None:
self.file.seek(0)
while True:
line = self.file.readline()
line = str(line, "utf-8")
if not line:
break
if line.startswith("FONT_ASCENT "):
self._ascent = int(line.split()[1])
break
return self._ascent
def get_bounding_box(self): def get_bounding_box(self):
"""Return the maximum glyph size as a 4-tuple of: width, height, x_offset, y_offset""" """Return the maximum glyph size as a 4-tuple of: width, height, x_offset, y_offset"""
@ -97,7 +132,7 @@ class BDF(GlyphCache):
remaining = code_points remaining = code_points
else: else:
remaining = set(code_points) remaining = set(code_points)
for code_point in remaining: for code_point in remaining.copy():
if code_point in self._glyphs and self._glyphs[code_point]: if code_point in self._glyphs and self._glyphs[code_point]:
remaining.remove(code_point) remaining.remove(code_point)
if not remaining: if not remaining:

View file

@ -57,11 +57,12 @@ def load_font(filename, bitmap=None):
return bdf.BDF(font_file, bitmap) return bdf.BDF(font_file, bitmap)
if filename.endswith("pcf") and first_four == b"\x01fcp": if filename.endswith("pcf") and first_four == b"\x01fcp":
import pcf from . import pcf
return pcf.PCF(font_file) return pcf.PCF(font_file, bitmap)
if filename.endswith("ttf") and first_four == b"\x00\x01\x00\x00": if filename.endswith("ttf") and first_four == b"\x00\x01\x00\x00":
import ttf from . import ttf
return ttf.TTF(font_file) return ttf.TTF(font_file, bitmap)
return None
raise ValueError("Unknown magic number %r" % first_four)

View file

@ -1,10 +1,51 @@
# pylint: skip-file # The MIT License (MIT)
# Remove the above when PCF is actually supported. #
# Copyright © 2020 Jeff Epler for Adafruit Industries LLC
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_bitmap_font.pcf`
====================================================
from .glyph_cache import GlyphCache Loads PCF format fonts.
import displayio
* Author(s): Jeff Epler
Implementation Notes
--------------------
**Hardware:**
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
"""
from collections import namedtuple
import gc
import struct import struct
from fontio import Glyph
from .glyph_cache import GlyphCache
_PCF_PROPERTIES = 1 << 0 _PCF_PROPERTIES = 1 << 0
_PCF_ACCELERATORS = 1 << 1 _PCF_ACCELERATORS = 1 << 1
_PCF_METRICS = 1 << 2 _PCF_METRICS = 1 << 2
@ -25,139 +66,345 @@ _PCF_BYTE_MASK = 1 << 2 # If set then Most Sig Byte First */
_PCF_BIT_MASK = 1 << 3 # If set then Most Sig Bit First */ _PCF_BIT_MASK = 1 << 3 # If set then Most Sig Bit First */
_PCF_SCAN_UNIT_MASK = 3 << 4 _PCF_SCAN_UNIT_MASK = 3 << 4
# https://fontforge.github.io/en-US/documentation/reference/pcf-format/ # https://fontforge.org/docs/techref/pcf-format.html
Table = namedtuple("Table", ("format", "size", "offset"))
Metrics = namedtuple(
"Metrics",
(
"left_side_bearing",
"right_side_bearing",
"character_width",
"character_ascent",
"character_descent",
"character_attributes",
),
)
Accelerators = namedtuple(
"Accelerators",
(
"no_overlap",
"constant_metrics",
"terminal_font",
"constant_width",
"ink_inside",
"ink_metrics",
"draw_direction",
"font_ascent",
"font_descent",
"max_overlap",
"minbounds",
"maxbounds",
"ink_minbounds",
"ink_maxbounds",
),
)
Encoding = namedtuple(
"Encoding", ("min_byte2", "max_byte2", "min_byte1", "max_byte1", "default_char")
)
Bitmap = namedtuple("Bitmap", ("glyph_count", "bitmap_sizes"))
class PCF(GlyphCache): class PCF(GlyphCache):
def __init__(self, f): """Loads glyphs from a PCF file in the given bitmap_class."""
def __init__(self, f, bitmap_class):
super().__init__() super().__init__()
self.file = f self.file = f
self.name = f self.name = f
f.seek(0) f.seek(0)
header, table_count = self.read("<4sI") self.buffer = bytearray(1)
self.bitmap_class = bitmap_class
_, table_count = self._read("<4sI")
self.tables = {} self.tables = {}
for _ in range(table_count): for _ in range(table_count):
type, format, size, offset = self.read("<IIII") type_, format_, size, offset = self._read("<IIII")
self.tables[type] = {"format": format, "size": size, "offset": offset} self.tables[type_] = Table(format_, size, offset)
print(type)
def read(self, format): bitmap_format = self.tables[_PCF_BITMAPS].format
s = struct.calcsize(format) if bitmap_format != 0xE:
return struct.unpack_from(format, self.file.read(s)) raise NotImplementedError("Unsupported format %s" % bitmap_format)
self._accel = self._read_accelerator_tables()
self._encoding = self._read_encoding_table()
self._bitmaps = self._read_bitmap_table()
self._ascent = self._accel.font_ascent
self._descent = self._accel.font_descent
minbounds = self._accel.ink_minbounds
maxbounds = self._accel.ink_maxbounds
width = maxbounds.right_side_bearing - minbounds.left_side_bearing
height = maxbounds.character_ascent + maxbounds.character_descent
self._bounding_box = (
width,
height,
minbounds.left_side_bearing,
-maxbounds.character_descent,
)
@property
def ascent(self):
"""The number of pixels above the baseline of a typical ascender"""
return self._ascent
@property
def descent(self):
"""The number of pixels below the baseline of a typical descender"""
return self._descent
def get_bounding_box(self): def get_bounding_box(self):
"""Return the maximum glyph size as a 4-tuple of: width, height, x_offset, y_offset"""
return self._bounding_box
def _read(self, format_):
size = struct.calcsize(format_)
if size != len(self.buffer):
self.buffer = bytearray(size)
self.file.readinto(self.buffer)
return struct.unpack_from(format_, self.buffer)
def _seek_table(self, table):
self.file.seek(table.offset)
(format_,) = self._read("<I")
if format_ & _PCF_BYTE_MASK == 0:
raise RuntimeError("Only big endian supported")
return format_
def _read_encoding_table(self):
encoding = self.tables[_PCF_BDF_ENCODINGS]
self._seek_table(encoding)
return Encoding(*self._read(">hhhhh"))
def _read_bitmap_table(self):
bitmaps = self.tables[_PCF_BITMAPS]
format_ = self._seek_table(bitmaps)
(glyph_count,) = self._read(">I")
self.file.seek(bitmaps.offset + 8 + 4 * glyph_count)
bitmap_sizes = self._read(">4I")
return Bitmap(glyph_count, bitmap_sizes[format_ & 3])
def _read_metrics(self, compressed_metrics):
if compressed_metrics:
(
left_side_bearing,
right_side_bearing,
character_width,
character_ascent,
character_descent,
) = self._read("5B")
left_side_bearing -= 0x80
right_side_bearing -= 0x80
character_width -= 0x80
character_ascent -= 0x80
character_descent -= 0x80
attributes = 0
else:
(
left_side_bearing,
right_side_bearing,
character_width,
character_ascent,
character_descent,
attributes,
) = self._read(">5hH")
return Metrics(
left_side_bearing,
right_side_bearing,
character_width,
character_ascent,
character_descent,
attributes,
)
def _read_accelerator_tables(self):
# pylint: disable=too-many-locals
accelerators = self.tables.get(_PCF_BDF_ACCELERATORS)
if not accelerators:
accelerators = self.tables.get(_PCF_ACCELERATORS)
if not accelerators:
raise RuntimeError("Accelerator table missing")
format_ = self._seek_table(accelerators)
has_inkbounds = format_ & _PCF_ACCEL_W_INKBOUNDS
compressed_metrics = False # format_ & _PCF_COMPRESSED_METRICS
(
no_overlap,
constant_metrics,
terminal_font,
constant_width,
ink_inside,
ink_metrics,
draw_direction,
_,
font_ascent,
font_descent,
max_overlap,
) = self._read(">BBBBBBBBIII")
minbounds = self._read_metrics(compressed_metrics)
maxbounds = self._read_metrics(compressed_metrics)
if has_inkbounds:
ink_minbounds = self._read_metrics(compressed_metrics)
ink_maxbounds = self._read_metrics(compressed_metrics)
else:
ink_minbounds = minbounds
ink_maxbounds = maxbounds
return Accelerators(
no_overlap,
constant_metrics,
terminal_font,
constant_width,
ink_inside,
ink_metrics,
draw_direction,
font_ascent,
font_descent,
max_overlap,
minbounds,
maxbounds,
ink_minbounds,
ink_maxbounds,
)
def _read_properties(self):
property_table_offset = self.tables[_PCF_PROPERTIES]["offset"] property_table_offset = self.tables[_PCF_PROPERTIES]["offset"]
self.file.seek(property_table_offset) self.file.seek(property_table_offset)
(format,) = self.read("<I") (format_,) = self._read("<I")
if format & _PCF_BYTE_MASK == 0: if format_ & _PCF_BYTE_MASK == 0:
raise RuntimeError("Only big endian supported") raise RuntimeError("Only big endian supported")
(nprops,) = self.read(">I") (nprops,) = self._read(">I")
self.file.seek(property_table_offset + 8 + 9 * nprops) self.file.seek(property_table_offset + 8 + 9 * nprops)
pos = self.file.tell() pos = self.file.tell()
if pos % 4 > 0: if pos % 4 > 0:
self.file.read(4 - pos % 4) self.file.read(4 - pos % 4)
(string_size,) = self.read(">I") (string_size,) = self._read(">I")
strings = self.file.read(string_size) strings = self.file.read(string_size)
string_map = {} string_map = {}
i = 0 i = 0
for s in strings.split(b"\x00"): for value in strings.split(b"\x00"):
string_map[i] = s string_map[i] = value
i += len(s) + 1 i += len(value) + 1
self.file.seek(property_table_offset + 8) self.file.seek(property_table_offset + 8)
for _ in range(nprops): for _ in range(nprops):
name_offset, isStringProp, value = self.read(">IBI") name_offset, is_string_prop, value = self._read(">IBI")
if isStringProp: if is_string_prop:
print(string_map[name_offset], string_map[value]) yield (string_map[name_offset], string_map[value])
else: else:
print(string_map[name_offset], value) yield (string_map[name_offset], value)
return None
def load_glyphs(self, code_points): def load_glyphs(self, code_points):
metadata = True # pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
character = False if isinstance(code_points, int):
code_point = None code_points = (code_points,)
rounded_x = 1 elif isinstance(code_points, str):
bytes_per_row = 1 code_points = [ord(c) for c in code_points]
desired_character = False
current_info = None
current_y = 0
total_remaining = len(code_points)
x, _, _, _ = self.get_bounding_box() code_points = sorted(
# create a scratch bytearray to load pixels into c for c in code_points if self._glyphs.get(c, None) is None
scratch_row = memoryview(bytearray((((x - 1) // 32) + 1) * 4)) )
if not code_points:
return
self.file.seek(0) indices_offset = self.tables[_PCF_BDF_ENCODINGS].offset + 14
while True: bitmap_offset_offsets = self.tables[_PCF_BITMAPS].offset + 8
line = self.file.readline() first_bitmap_offset = self.tables[_PCF_BITMAPS].offset + 4 * (
if not line: 6 + self._bitmaps.glyph_count
break )
if line.startswith(b"CHARS "): metrics_compressed = self.tables[_PCF_METRICS].format & _PCF_COMPRESSED_METRICS
metadata = False first_metric_offset = (
elif line.startswith(b"SIZE"): self.tables[_PCF_METRICS].offset + 6 if metrics_compressed else 8
_, self.point_size, self.x_resolution, self.y_resolution = line.split() )
elif line.startswith(b"COMMENT"): metrics_size = 5 if metrics_compressed else 12
pass
elif line.startswith(b"STARTCHAR"): # These will each _tend to be_ forward reads in the file, at least
# print(lineno, line.strip()) # sometimes we'll benefit from oofatfs's 512 byte cache and avoid
# _, character_name = line.split() # excess reads
character = True indices = [None] * len(code_points)
elif line.startswith(b"ENDCHAR"): for i, code_point in enumerate(code_points):
character = False enc1 = (code_point >> 8) & 0xFF
if desired_character: enc2 = code_point & 0xFF
self._glyphs[code_point] = current_info
if total_remaining == 0: if enc1 < self._encoding.min_byte1 or enc1 > self._encoding.max_byte1:
return continue
desired_character = False if enc2 < self._encoding.min_byte2 or enc2 > self._encoding.max_byte2:
elif line.startswith(b"BBX"): continue
if desired_character:
_, x, y, dx, dy = line.split() encoding_idx = (
x = int(x) (enc1 - self._encoding.min_byte1)
y = int(y) * (self._encoding.max_byte2 - self._encoding.min_byte2 + 1)
dx = int(dx) + enc2
dy = int(dy) - self._encoding.min_byte2
current_info["bounds"] = (x, y, dx, dy) )
current_info["bitmap"] = displayio.Bitmap(x, y, 2) self.file.seek(indices_offset + 2 * encoding_idx)
elif line.startswith(b"BITMAP"): (glyph_idx,) = self._read(">H")
if desired_character: if glyph_idx != 65535:
rounded_x = x // 8 indices[i] = glyph_idx
if x % 8 > 0:
rounded_x += 1 all_metrics = [None] * len(code_points)
bytes_per_row = rounded_x for i, code_point in enumerate(code_points):
if bytes_per_row % 4 > 0: index = indices[i]
bytes_per_row += 4 - bytes_per_row % 4 if index is None:
current_y = 0 continue
elif line.startswith(b"ENCODING"): self.file.seek(first_metric_offset + metrics_size * index)
_, code_point = line.split() all_metrics[i] = self._read_metrics(metrics_compressed)
code_point = int(code_point) bitmap_offsets = [None] * len(code_points)
if code_point == code_points or code_point in code_points: for i, code_point in enumerate(code_points):
total_remaining -= 1 index = indices[i]
if code_point not in self._glyphs: if index is None:
desired_character = True continue
current_info = {"bitmap": None, "bounds": None, "shift": None} self.file.seek(bitmap_offset_offsets + 4 * index)
elif line.startswith(b"DWIDTH"): (bitmap_offset,) = self._read(">I")
if desired_character: bitmap_offsets[i] = bitmap_offset
_, shift_x, shift_y = line.split()
shift_x = int(shift_x) # Batch creation of glyphs and bitmaps so that we need only gc.collect
shift_y = int(shift_y) # once
current_info["shift"] = (shift_x, shift_y) gc.collect()
elif line.startswith(b"SWIDTH"): bitmaps = [None] * len(code_points)
pass for i in range(len(all_metrics)): # pylint: disable=consider-using-enumerate
elif character: metrics = all_metrics[i]
if desired_character: if metrics is not None:
bits = int(line.strip(), 16) width = metrics.right_side_bearing - metrics.left_side_bearing
for i in range(rounded_x): height = metrics.character_ascent + metrics.character_descent
val = (bits >> ((rounded_x - i - 1) * 8)) & 0xFF bitmap = bitmaps[i] = self.bitmap_class(width, height, 2)
scratch_row[i] = val self._glyphs[code_points[i]] = Glyph(
current_info["bitmap"]._load_row( bitmap,
current_y, scratch_row[:bytes_per_row] 0,
) width,
current_y += 1 height,
elif metadata: metrics.left_side_bearing,
# print(lineno, line.strip()) -metrics.character_descent,
pass metrics.character_width,
0,
)
for i, code_point in enumerate(code_points):
metrics = all_metrics[i]
if metrics is None:
continue
self.file.seek(first_bitmap_offset + bitmap_offsets[i])
width = metrics.right_side_bearing - metrics.left_side_bearing
height = metrics.character_ascent + metrics.character_descent
bitmap = bitmaps[i]
words_per_row = (width + 31) // 32
buf = bytearray(4 * words_per_row)
start = 0
for _ in range(height):
self.file.readinto(buf)
for k in range(width):
if buf[k // 8] & (128 >> (k % 8)):
bitmap[start + k] = 1
start += width

View file

@ -8,7 +8,7 @@ import struct
class TTF: class TTF:
def __init__(self, f): def __init__(self, f, bitmap):
f.seek(0) f.seek(0)
self.file = f self.file = f

View file

@ -8,8 +8,8 @@ bitmap with pixels matching glyphs from a given String
import board import board
from adafruit_bitmap_font import bitmap_font # pylint: disable=wrong-import-position
import displayio import displayio
from adafruit_bitmap_font import bitmap_font
font = bitmap_font.load_font("fonts/Arial-16.bdf") font = bitmap_font.load_font("fonts/Arial-16.bdf")

View file

@ -0,0 +1,44 @@
"""
This example uses addfruit_display_text.label to display text using a custom font
loaded by adafruit_bitmap_font.
Adapted for use on MagTag
"""
import time
import board
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
# use built in display (PyPortal, PyGamer, PyBadge, CLUE, etc.)
# see guide for setting up external displays (TFT / OLED breakouts, RGB matrices, etc.)
# https://learn.adafruit.com/circuitpython-display-support-using-displayio/display-and-display-bus
display = board.DISPLAY
# wait until we can refresh the display
time.sleep(display.time_to_refresh)
# Set text, font, and color
text = "HELLO WORLD\nbitmap_font example"
font = bitmap_font.load_font("fonts/Arial-16.bdf")
color = 0xFFFFFF
background_color = 0x999999
# Create the tet label
text_area = label.Label(
font,
text=text,
color=color,
background_color=background_color,
padding_top=3,
padding_bottom=3,
padding_right=4,
padding_left=4,
)
text_area.line_spacing = 1.0
# Set the location
text_area.x = 20
text_area.y = 20
# Show it and refresh
display.show(text_area)
display.refresh()
while True:
pass

View file

@ -4,8 +4,8 @@ loaded by adafruit_bitmap_font
""" """
import board import board
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
display = board.DISPLAY display = board.DISPLAY

View file

@ -9,10 +9,13 @@ from adafruit_bitmap_font import bitmap_font # pylint: disable=wrong-import-pos
sys.path.append(os.path.join(sys.path[0], "../test")) sys.path.append(os.path.join(sys.path[0], "../test"))
font = bitmap_font.load_font(sys.argv[1]) font = bitmap_font.load_font(sys.argv[1])
specimen = "Adafruit CircuitPython" if len(sys.argv) == 2 else sys.argv[2]
_, height, _, dy = font.get_bounding_box() _, height, _, dy = font.get_bounding_box()
font.load_glyphs(specimen)
for y in range(height): for y in range(height):
for c in "Adafruit CircuitPython": for c in specimen:
glyph = font.get_glyph(ord(c)) glyph = font.get_glyph(ord(c))
if not glyph: if not glyph:
continue continue

View file

@ -26,7 +26,7 @@ COPYRIGHT "
_OTF_FONTFILE "arial.ttf" _OTF_FONTFILE "arial.ttf"
_OTF_PSNAME "ArialMT" _OTF_PSNAME "ArialMT"
ENDPROPERTIES ENDPROPERTIES
CHARS 3361 CHARS 318
STARTCHAR 0020 STARTCHAR 0020
ENCODING 32 ENCODING 32
SWIDTH 270 0 SWIDTH 270 0

30356
examples/fonts/yasashi24.bdf Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.