Added textures. Changes to shadow generation. Refinements to layers and blurs. Made sure roads appear correctly. Removed streams for inland cutting as those are barely visible on actual satellite images. Proper testing to be done, close to public release.

This commit is contained in:
Marcus Str. 2024-10-08 21:20:51 +02:00
parent 10e87db4a0
commit be750bd53c
60 changed files with 236 additions and 73 deletions

View File

@ -22,7 +22,7 @@ mstr_datafolder = "/home/marcus/Data/Developer/Projects/orthographic/"
mstr_osm_endpoint = "https://marstr.online/osm/v1/"
# Define the texture resolution you want to have your photos at.
mstr_photores = 2048 # <- Change this to 4096 for 16k resolution
mstr_photores = 2048
# Radius of zoom level 18 aerials around airports with ICAO code
# Value is in tiles - not in km
@ -54,20 +54,13 @@ mstr_show_log = True
# You can, however, disable the shadow rendering layer here.
mstr_shadow_enabled = True
mstr_shadow_strength = 0.65
mstr_shadow_shift = 15
mstr_shadow_shift = 16
mstr_shadow_floor_h = 2.8 # 2.5m ceiling height + 30cm concrete per floor
# The tags that cast shadows
mstr_shadow_casters = [
("landuse", "forest"),
("leisure", "nature_reserve"),
("natural", "wood"),
("natural", "tree_row"),
("building", "semidetached_house"),
("building", "apartments"),
("building", "garage"),
("building", "office"),
("building", "retail"),
("building", "industrial"),
("building", "yes")
("natural", "wood")
]
@ -248,19 +241,19 @@ mstr_mask_blur = [
("water", "river", 10),
("leisure", "swimming_pool", 10),
("waterway", "river", 10),
("waterway", "stream", 2),
("waterway", "stream", 4),
("amenity", "parking", 1),
("amenity", "school", 1),
("highway", "pedestrian", 12),
# Z-Order 4
("highway", "motorway", 2),
("highway", "primary", 2),
("highway", "secondary", 2),
("highway", "tertiary", 2),
("highway", "unclassified", 2),
("highway", "living_street", 2),
("highway", "residential", 2),
("highway", "service", 2),
("highway", "motorway", 1),
("highway", "primary", 1),
("highway", "secondary", 1),
("highway", "tertiary", 1),
("highway", "unclassified", 1),
("highway", "living_street", 1),
("highway", "residential", 1),
("highway", "service", 1),
("highway", "footway", 2),
("highway", "track", 2),
("highway", "path", 2),
@ -395,8 +388,6 @@ mstr_building_base_colors = [
]
),
("yes", [
"#693333", "#592b2b", "#513434", "#4a1e1e", "#362626",
"#534136", "#4d3424", "#534b45", "#553724", "#574c45",
"#373942", "#40424a", "#363b4f", "#2c2d32", "#444651",
"#454545", "#39393b", "#4b4b4c", "#363638", "#525252"
]

View File

@ -86,3 +86,8 @@ def in_circle(center_x, center_y, radius, x, y):
return square_dist <= radius ** 2
# Find meters per pixel. Requires width of tile in meters
# Needed for proper approximation of shadow length per building level
def meters_per_pixel(lngwidth):
mpx = lngwidth / mstr_photores
return mpx

View File

@ -87,11 +87,13 @@ class mstr_layergen:
brd_src = Image.open(root_folder + "/brd/b" + str(src) + ".png")
ptc_src = []
for p in ptc:
ptc_src.append(Image.open(p))
pimg = Image.open(p)
pimg = pimg.rotate(randrange(0, 360), expand=True)
ptc_src.append(pimg)
mstr_msg("layergen", "Border sources selected")
# Begin producing a largely random image
samples = 250 # <- We need this in a moment
samples = 250 # <- We need this in a moment
for i in range(samples):
imgid = 0
if len(ptc_src) == 1: imgid = 0
@ -455,13 +457,28 @@ class mstr_layergen:
# Add trees only in some features
if (self._tag == "landuse" and self._value == "cemetery") or (self._tag == "landuse" and self._value == "residential") or (self._tag == "leisure" and self._value == "park"):
trees = Image.new("RGBA", (self._imgsize, self._imgsize))
amt = 3500
for i in range(1, amt+1):
p = randrange(1, 11)
p = randrange(1, 16)
tree = Image.open(mstr_datafolder + "textures/building/area/p" + str(p) + ".png")
lx = randrange( self._imgsize - tree.width )
ly = randrange( self._imgsize - tree.height )
layer.alpha_composite(tree, (lx, ly))
trees.alpha_composite(tree, (lx, ly))
tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))
tree_pix = trees.load()
shadow_pix = tree_shadow.load()
for y in range(self._imgsize):
for x in range(self._imgsize):
tp = tree_pix[x,y]
if tp[3] > 0:
sc = (0,0,0,180)
if x+8 < self._imgsize and y+5 < self._imgsize:
shadow_pix[x+8,y+5] = sc
tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))
tree_shadow.alpha_composite(trees)
layer.alpha_composite(tree_shadow)
mstr_msg("layergen", "Layer image completed")
@ -527,9 +544,21 @@ class mstr_layergen:
if self._tag == "landuse" and self._value == "forest":
# The residential layer MUST exist before we reach the forest part.
fn = mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_landuse-residential_layer.png"
if os.path.isfile(fn) == True:
if os.path.isfile(fn):
rsd = Image.open(fn)
layer_comp.alpha_composite(rsd)
rsd_pix = rsd.load()
forest_layer = Image.new("RGBA", (self._imgsize, self._imgsize))
for_pix = forest_layer.load()
for y in range(self._imgsize):
for x in range(self._imgsize):
rpix = rsd_pix[x,y]
lpix = layer_comp_pix[x,y]
if rpix[3] > 0 and lpix[3] > 0:
for_pix[x,y] = (rpix[0], rpix[1], rpix[2], rpix[3])
layer_comp.alpha_composite(forest_layer)
#if os.path.isfile(fn) == True:
# rsd = Image.open(fn)
# layer_comp.alpha_composite(rsd)
# Store layer
if self._is_completion == False:
@ -563,18 +592,40 @@ class mstr_layergen:
mstr_msg("layergen", "Generating shadow for layer")
shadow_pix = shadow.load()
mask_pix = osm_mask.load()
shf = 1
while shf < mstr_shadow_shift:
for y in range(self._imgsize):
for x in range(self._imgsize):
mp = layer_comp_pix[x,y]
if mp[3] == 255:
if x+(shf*2) < self._imgsize and y+shf < self._imgsize:
rndshd = randrange(5, 210)
shadow_pix[x+(shf*2), y+shf] = (0,0,0,rndshd)
shf = shf+1
# Tree removal
for y in range(self._imgsize):
for x in range(self._imgsize):
lp = layer_comp_pix[x,y]
if lp[3] >= 250:
shadow_pix[x,y] = (0,0,0,0)
shadow = shadow.filter(ImageFilter.GaussianBlur(radius=2))
"""
for y in range(self._imgsize-1):
for x in range(self._imgsize-1):
m = mask_pix[x,y]
shf_x = 0
shf_x = x + mstr_shadow_shift
if shf_x <= self._imgsize-1:
if shf_x < self._imgsize:
a = mask_pix[x,y][3]
st = 0
st = random.uniform(0.45, mstr_shadow_strength)
ca = a * st
aa = int(ca)
shadow_pix[shf_x, y] = (0,0,0,aa)
"""
shadow.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_shadow.png")
mstr_msg("layergen", "Shadow layer completed")
@ -643,7 +694,7 @@ class mstr_layergen:
#self._tiledb.close_db()
# Create a water mask we need to remove from the DDS later
if (self._tag == "natural" and self._value == "water") or (self._tag == "water" and self._value == "lake") or (self._tag == "water" and self._value == "pond") or (self._tag == "water" and self._value == "river") or (self._tag == "leisure" and self._value == "swimming_pool") or (self._tag == "waterway" and self._value == "stream"):
if (self._tag == "natural" and self._value == "water") or (self._tag == "water" and self._value == "lake") or (self._tag == "water" and self._value == "pond") or (self._tag == "water" and self._value == "river") or (self._tag == "leisure" and self._value == "swimming_pool"):
mstr_msg("layergen", "Generating inland water mask")
inl_mask = Image.new("RGBA", (self._imgsize, self._imgsize), (0,0,0,0))
lyr_pix = layer_comp.load()
@ -681,7 +732,6 @@ class mstr_layergen:
if i[0] == self._tag and i[1] == self._value:
osm_mask = osm_mask.filter(ImageFilter.BoxBlur(radius=i[2]))
break
osm_edge = osm_edge.filter(ImageFilter.BoxBlur(radius=1))
# And now for the Big Mac.
@ -712,14 +762,15 @@ class mstr_layergen:
d = randrange(41, 61)
layer_comp_pix[x, y] = ( d,d,d,a[3] )
if self._tag == "highway" and self._value != "motorway":
d = randrange(85, 101)
layer_comp_pix[x, y] = ( d,d,d,a[3] )
dr = randrange(110,121)
dg = randrange(110,121)
db = randrange(115,130)
layer_comp_pix[x, y] = ( dr,dg,db,a[3] )
if self._tag == "highway" and self._value == "motorway":
d = randrange(1,20)
r = 86-d
g = 97-d
b = 106-d
layer_comp_pix[x, y] = ( r,g,b,a[3] )
dr = randrange(77,89)
dg = randrange(88,96)
db = randrange(90,101)
layer_comp_pix[x, y] = ( dr,dg,db,a[3] )
if self._tag == "waterway" and (self._value == "stream" or self._value == "river"):
d = randrange(1, 15)
# Rock, grass, water
@ -730,7 +781,7 @@ class mstr_layergen:
t = a[3]-d
if t < 0: t = 0
if e[3] > 0:
layer_comp_pix[x, y] = ( mats[pick-1][0], mats[pick-1][1], mats[pick-1][2], t )
layer_comp_pix[x, y] = ( mats[pick-1][0], mats[pick-1][1], mats[pick-1][2], 35 )
# A bit special here
if self._tag == "building":
@ -757,15 +808,31 @@ class mstr_layergen:
# A bit different for tree rows
if self._tag == "natural" and self._value == "tree_row":
trees = Image.new("RGBA", (self._imgsize, self._imgsize))
for t in range(20001):
lx = randrange(self._imgsize)
ly = randrange(self._imgsize)
a = mask_pix[lx,ly]
if a[3] > 0:
if lx < self._imgsize and ly < self._imgsize:
p = randrange(1,11)
p = randrange(1,16)
tree = Image.open(mstr_datafolder + "textures/building/area/p" + str(p) + ".png")
layer_comp.alpha_composite(tree, (lx, ly))
trees.alpha_composite(tree, (lx, ly))
if mstr_shadow_enabled == True:
tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))
tree_pix = trees.load()
shadow_pix = tree_shadow.load()
for y in range(self._imgsize):
for x in range(self._imgsize):
tp = tree_pix[x,y]
if tp[3] > 0:
rndshd = randrange(5, 210)
sc = (0,0,0,rndshd)
if x+8 < self._imgsize and y+5 < self._imgsize:
shadow_pix[x+8,y+5] = sc
tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))
tree_shadow.alpha_composite(trees)
layer_comp.alpha_composite(tree_shadow)
# We will do some super magic here to let houses look more realistic
if self._tag == "building":
@ -815,7 +882,7 @@ class mstr_layergen:
numtrees = randrange(1, 16)
for i in range(1, numtrees+1):
# Pick some file
pick = str(randrange(1, 11))
pick = str(randrange(1, 16))
tree = Image.open(mstr_datafolder + "textures/building/area/p" + pick + ".png")
# Do a correction for the location if needed
if shf_x < 1: shf_x = 1
@ -823,33 +890,39 @@ class mstr_layergen:
if shf_x > self._imgsize - tree.width: shf_x = self._imgsize - tree.width - 1
if shf_y > self._imgsize - tree.height: shf_y = self._imgsize - tree.height - 1
trees.alpha_composite(tree, (shf_x, shf_y))
trees.alpha_composite(layer_comp)
layer_comp = trees
if mstr_shadow_enabled == True:
tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))
tree_pix = trees.load()
shadow_pix = tree_shadow.load()
for y in range(self._imgsize):
for x in range(self._imgsize):
tp = tree_pix[x,y]
if tp[3] > 0:
sc = (0,0,0,180)
if x+8 < self._imgsize and y+5 < self._imgsize:
shadow_pix[x+8,y+5] = sc
tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))
tree_shadow.alpha_composite(trees)
# Save this separately, so that we can blur buildings, but not the trees
fn = mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_building_trees.png"
if os.path.isfile(fn) == True:
extrees = Image.open(fn)
extrees.alpha_composite(tree_shadow)
extrees.save(fn)
else:
tree_shadow.save(fn)
#layer_comp.alpha_composite(tree_shadow)
#tree_shadow.alpha_composite(layer_comp)
#layer_comp = tree_shadow
mstr_msg("layergen", "Layer image generated")
# Building shadow
if mstr_shadow_enabled == True:
if self._tag == "building":
mstr_msg("layergen", "Generating shadow for layer")
shadow = Image.new("RGBA", (self._imgsize, self._imgsize))
shadow_pix = shadow.load()
mask_pix = osm_mask.load()
for y in range(self._imgsize-1):
for x in range(self._imgsize-1):
m = mask_pix[x,y]
shf_x = x + mstr_shadow_shift
shf_y = y + (mstr_shadow_shift/2)
if shf_x < self._imgsize and shf_y < self._imgsize:
a = mask_pix[x,y][3]
st = random.uniform(0.3, mstr_shadow_strength)
ca = a * st
aa = int(ca)
shadow_pix[shf_x, shf_y] = (0,0,0,aa)
shadow = shadow.filter(ImageFilter.GaussianBlur(radius=2))
shadow.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_shadow.png")
mstr_msg("layergen", "Shadow layer completed")
# Some funnies with shadows
if self._tag == "building" and (self._value == "detached" or self._value == "semidetached_house" or self._value == "apartments" or self._value == "civic" or self._value == "house" or self._value == "terrace"):
@ -890,6 +963,7 @@ class mstr_layergen:
# Highways and runways of any kind get some special treatment
if (self._tag == "highway" and self._value == "motorway") or (self._tag == "highway" and self._value == "primary") or (self._tag == "highway" and self._value == "secondary") or (self._tag == "highway" and self._value == "tertiary") or (self._tag == "aeroway" and self._value == "runway"):
# We will now add some white lines for coolness
osm_edge = osm_mask.filter(ImageFilter.FIND_EDGES)
mask_pix = osm_edge.load()
layer_comp_pix = layer_comp.load()
for y in range(self._imgsize):
@ -901,13 +975,14 @@ class mstr_layergen:
layer_comp_pix[x, y] = ( w,w,w,a[3] )
if self._tag == "highway" and self._value == "residential":
osm_edge = osm_mask.filter(ImageFilter.FIND_EDGES)
mask_pix = osm_edge.load()
layer_comp_pix = layer_comp.load()
for y in range(self._imgsize):
for x in range(self._imgsize):
if mask_pix[x, y][3] > 0:
# Find a suitable color
w = randrange(60, 96)
w = randrange(150,181)
a=mask_pix[x,y]
layer_comp_pix[x, y] = ( w,w,w,a[3] )
mstr_msg("layergen", "Street lines added")

View File

@ -27,6 +27,7 @@ from defines import *
from log import *
from PIL import Image, ImageFilter, ImageDraw, ImagePath
from random import randrange
from functions import *
import random
class mstr_maskgen:
@ -65,11 +66,18 @@ class mstr_maskgen:
latlng.append(float(i[2]))
break
return latlng
# Only needed if X-Plane scenery is built
def _set_xpscenery_datagroup(self, dg):
self._xpdg = dg
# Set width of tile - for buildings
def set_tile_width(self, tile_width):
self._tile_width = tile_width
# Numbers needed for the possible building shadow layer
def set_latlng_numbers(self, lat, tv, lng, th):
self._latitude = lat
self._lat_number = tv
self._longitude = lng
self._lng_number = th
# Builds the required mask
@ -99,6 +107,9 @@ class mstr_maskgen:
# Longitude
bbox.append(self._box[2] + ((self._box[3]-1) * mstr_zl_18))
bbox.append(self._box[2] + ((self._box[3]-1) * mstr_zl_18) + mstr_zl_18)
# Building levels, if this is a building
bld_levels = 0
# Generate mask for ONE tag only
if self._subtag == None:
@ -107,6 +118,8 @@ class mstr_maskgen:
nd = []
for d in way:
if d[0] == w[0]:
if self._tag == "building" and bld_levels == 0:
bld_levels = xml.find_building_levels(tilexml, w[0])
nd.append(d[1])
frs.append(nd)
# Scout through relations as these also make up map data
@ -203,5 +216,58 @@ class mstr_maskgen:
# Save image
mask_img.save(mstr_datafolder + "_cache/" + fstr + "_" + self._tag + "-" + self._value + ".png")
# If this is a building, we need to render the shadow here, as we only know the height
# of the building in this loop.
if mstr_shadow_enabled == True:
if self._tag == "building":
mpp = meters_per_pixel(self._tile_width) * mstr_zl_18
pix_per_floor = mstr_shadow_floor_h / mpp
total_pix = pix_per_floor * bld_levels
shift = int(total_pix)
fn = mstr_datafolder + "_cache/" + fstr + "_" + self._tag + "-" + self._value + "_layer_shadow.png"
mask_pix = mask_img.load()
bld_shadow = Image.new("RGBA", (mstr_photores, mstr_photores))
bld_shadow_pix = bld_shadow.load()
# Shadow sweep
shf = 1
while shf <= shift:
for y in range(mstr_photores):
for x in range(mstr_photores):
mp = mask_pix[x,y]
if mp[3] != 0:
if x+(shf*2) < mstr_photores and y+shf < mstr_photores:
bld_shadow_pix[x+(shf*2), y+shf] = (0,0,0,255)
shf = shf+1
# Building removal sweep
for y in range(mstr_photores):
for x in range(mstr_photores):
mp = mask_pix[x,y]
if mp[3] != 0:
bld_shadow_pix[x,y] = (0,0,0,0)
# Correct alpha
bld_shadow_pix = bld_shadow.load()
for y in range(mstr_photores):
for x in range(mstr_photores):
sp = bld_shadow_pix[x,y]
if sp[3] != 0:
bld_shadow_pix[x,y] = (0,0,0,120)
# Store
if os.path.isfile(fn) == True:
lyr = Image.open(fn)
lyr.alpha_composite(bld_shadow)
lyr.save(fn)
else:
bld_shadow.save(fn)
# Inform
mstr_msg("maskgen", "Mask built.")

View File

@ -201,8 +201,9 @@ class mstr_orthographic:
# Generate the mask
mg = mstr_maskgen( [self._lat, cur_tile_y, self._long, cur_tile_x], self._vstep, layer[0], layer[1], layer[2])
if mstr_xp_genscenery == True:
mg._set_xpscenery_datagroup(xp_datagroup)
if layer[0] == "building":
mg.set_tile_width(self._findWidthOfLongitude(bb_lat))
mg.set_latlng_numbers(self._lat, lat_grid, self._long, lng_grid)
mg._build_mask()
# Generate the layer

View File

@ -149,6 +149,23 @@ class mstr_osmxml:
# Return the found surface type
return surface
# Find the levels of a building (for shadow rendering)
def find_building_levels(self, xmlfile, way_id):
lvl = 3 # Standard if we don't find anything else
xml_doc = xml.dom.minidom.parse(xmlfile)
wpdata = xml_doc.getElementsByTagName("way")
for wp in wpdata:
if wp.getAttribute("id") == way_id:
tags = wp.getElementsByTagName("tag")
for tag in tags:
a = tag.getAttribute("k")
v = tag.getAttribute("v")
if a == "building:levels":
lvl = int(v)
break
return lvl
# It turns out that some features hide themselves in the relations section.

View File

@ -52,6 +52,7 @@ class mstr_photogen:
if l[0] == "building":
if os.path.isfile(root_filename + l[0] + "-" + l[1] + "_layer_shadow.png"):
shd = Image.open(root_filename + l[0] + "-" + l[1] + "_layer_shadow.png")
shd = shd.filter(ImageFilter.GaussianBlur(radius=2))
bldg_shadow.alpha_composite(shd)
# Details merging
bldg_details = Image.new("RGBA", (self._imgsize, self._imgsize))
@ -69,10 +70,18 @@ class mstr_photogen:
bld = Image.open(root_filename + l[0] + "-" + l[1] + "_layer.png")
bld = bld.filter(ImageFilter.GaussianBlur(radius=1))
bldg_main.alpha_composite(bld)
# Trees merging
tree_main = Image.new("RGBA", (self._imgsize, self._imgsize))
for l in mstr_ortho_layers:
if l[0] == "building":
if os.path.isfile(root_filename + l[0] + "-" + l[1] + "_layer_building_trees.png"):
trs= Image.open(root_filename + l[0] + "-" + l[1] + "_layer_building_trees.png")
tree_main.alpha_composite(trs)
# Merge the building layers
bldg_final = Image.new("RGBA", (self._imgsize, self._imgsize))
bldg_final.alpha_composite(bldg_details)
bldg_final.alpha_composite(bldg_shadow)
bldg_final.alpha_composite(tree_main)
bldg_final.alpha_composite(bldg_main)
for l in mstr_ortho_layers:
@ -153,8 +162,7 @@ class mstr_photogen:
["water", "lake"],
["water", "pond"],
["water", "river"],
["leisure", "swimming_pool"],
["waterway", "stream"]
["leisure", "swimming_pool"]
)
for l in water_layers:
fn = mstr_datafolder + "_cache/" + str(self._lat) + "-" + str(self._ty) + "_" + str(self._lng) + "-" + str(self._tx) + "_" + l[0] + "-" + l[1] + "_layer_mask.png"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 578 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 871 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 899 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 904 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 578 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 871 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 899 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 904 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 578 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 871 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 899 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 904 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB