...
 
Commits (5)
......@@ -13,6 +13,10 @@ greenjson=$(trim:%.trim.jpg=%.green.json)
blue=$(trim:%.trim.jpg=%.blue.png)
bluejson=$(trim:%.trim.jpg=%.blue.json)
snapshots=$(shell ls snapshots/*.pdf)
snapshotsjpg=$(snapshots:%.pdf=%.jpg)
snapshots: $(snapshotsjpg)
trim: $(trim)
contours: $(contourspng) $(contourssvg) $(contoursjson)
gradients: $(gradientsvg) $(gradientpng) $(gradientjson)
......@@ -22,6 +26,11 @@ zapzeros:
find sample -size 0 -exec rm {} \;
cleandata:
rm $(redjson) $(greenjson) $(bluejson) $(gradientjson) $(contoursjson)
cleancontourspng:
rm $(contourspng)
cleangradientpng:
rm $(gradientpng)
# sample.csv: csv/export_mim.csv
sample.csv: csv/mim.normalized.csv
......@@ -37,18 +46,16 @@ sample.json: sample.csv scripts/csv2json.py
sample_with_data.json: sample.json $(contoursjson) $(gradientjson) $(redjson) $(greenjson) $(bluejson)
scripts/joindata.py $^ > $@
poster.pdf: sample_with_data.json scripts/orderings.poster.py $(red) $(green) $(blue) $(gradientpng) $(contourspng)
scripts/orderings.poster.py --filterzeros $< --output $@
poster2.pdf: sample_with_data.json scripts/orderings.poster.py $(red) $(green) $(blue) $(gradientpng) $(contourspng)
scripts/orderings.poster.py --pagesize A1 --columns 36 --fontsize 7 --filterzeros $< --output $@
sample/exif.json:
exiftool -FileModifyDate --json
# sample/exif.json:
# exiftool -FileModifyDate --json
# Contours
%.contours.png %.contours.svg: %.trim.jpg
bin/contours $< $*.contours.png > $*.contours.svg
%.contours.svg: %.trim.jpg
bin/contours $< tmp.png > $*.contours.svg
rm tmp.png
%.contours.png: %.contours.svg
inkscape --export-png=$@ $<
%.contours.json: %.contours.svg
scripts/svgcountpaths.py $< --polyline --json --id $*.jpg --key contours --img $*.contours.png > $@
......@@ -58,7 +65,8 @@ sample/exif.json:
scripts/imagegradient.py $< --svg $*.gradient.svg
%.gradient.png: %.gradient.svg
inkscape --export-png=$*.gradient.png --export-background="#EEEEEE" $<
inkscape --export-png=$*.gradient.png $<
# inkscape --export-png=$*.gradient.png --export-background="#EEEEEE" $<
%.gradient.json: %.gradient.svg
scripts/svgpathlength.py $< --json --id $*.jpg --key gradient --img $*.gradient.png > $@
......@@ -77,3 +85,37 @@ sample/exif.json:
convert $< -format %c histogram:info:- | scripts/histcount.py --json --id $*.jpg --key blue --img $*.blue.png > $@
%.jpg: %.pdf
convert $< $@
#
# POSTER
#
poster.pdf: sample_with_data.json scripts/orderings.poster.py $(red) $(green) $(blue) $(gradientpng) $(contourspng)
scripts/orderings.poster.py --filterzeros $< --output $@
poster2.pdf: sample_with_data.json scripts/orderings.poster.py $(red) $(green) $(blue) $(gradientpng) $(contourspng)
scripts/orderings.poster.py \
--pagesize A1 --landscape \
--columns 72 \
--fontsize 7 \
--filterzeros $< --output $@
poster3.pdf: sample_with_data.json scripts/orderings.poster.py $(red) $(green) $(blue) $(gradientpng) $(contourspng)
scripts/orderings.poster.py \
--pagesize A1 --landscape \
--columns 36 \
--fontsize 7 \
--filterzeros $< --output $@
poster3.tiles.pdf: poster3.pdf
pdfposter -m A4 -p A1 $< $@
poster4.pdf: sample_with_data.json scripts/orderings.poster.py $(red) $(green) $(blue) $(gradientpng) $(contourspng)
scripts/orderings.poster2.py \
--pagesize A1 --landscape \
--columns 101 \
--fontsize 7 \
--filterzeros $< --output $@
......@@ -35,12 +35,20 @@ X RGB
* text
* parse year ...
* deal with empty values
X deal with empty values
Rerun on larger selection
* Rerun on larger selection
Talk about "empty" or exceptional values ??? .... leave space on margins ???
* Talk about "empty" or exceptional values ??? .... leave space on margins ???
<!> Need to filter empty values / missing images.
* Filter zeros
Show a central column featuring a single image with all values IN CONTEXT.
Add landscape option!
New poster style: show a central column featuring a single image with all values IN CONTEXT.
monday evening
X Contours transparent, maybe heavier
* RGB transparent
* Gradients transparent
#!/usr/bin/env python3
from PIL import Image, ImageDraw
from numpy import *
from scipy.ndimage import filters
import sys, json, os, math
import argparse
def hsl_to_rgb (h, s, l):
# fix ranges for hsl values
if h == None:
h = 0
if h < 0 or h > 360:
h = h % 360
if s < 0:
s = 0
s = max(0.0, min(1.0, s))
l = max(0.0, min(1.0, l))
# From FvD 13.37, CSS Color Module Level 3
if l <= .5:
m2 = l * (1 + s)
else:
m2 = l + s - l * s
m1 = 2 * l - m2
def v(h):
if (h > 360):
h -= 360
elif (h < 0):
h += 360
if (h < 60):
return m1 + (m2 - m1) * h / 60
if (h < 180):
return m2
if (h < 240):
return m1 + (m2 - m1) * (240 - h) / 60
return m1
def vv(h):
return round(v(h) * 255)
return (int(vv(h + 120)), int(vv(h)), int(vv(h - 120)))
parser = argparse.ArgumentParser(description='Calculate an image gradient.')
parser.add_argument('input', help='an image path as input')
parser.add_argument('--format', default="magimage", help='save output format, default hslimage (direction is hue, magnitude is lightness). Other options: magimage (magnitude image), json.')
parser.add_argument('--output', help='save to output path')
parser.add_argument('--width', type=int, default=None, help='resize width, default: None (no resize)')
parser.add_argument('--svg', default=None, help='output svg path')
parser.add_argument('--svg-grid-size', type=int, default=25, help='density of svg arrows (default: 25)')
parser.add_argument('--svg-mag-scale', type=float, default=5.0, help='svg arrow magnitude scaler (default: 5.0)')
args = parser.parse_args()
# Based on Programming Computer Vision, chapter 1, Image Derivatives
p = args.input
path, base = os.path.split(p)
base, ext = os.path.splitext(base)
out = args.output # or os.path.join(path, base + ".gradient.png")
im = Image.open(p).convert('L')
width, height = im.size
if args.width:
scaled_height = int(height * (float(args.width)/width))
im.thumbnail((args.width, scaled_height))
width, height = args.width, scaled_height
im = array(im)
# Sobel derivative filters
# imx = zeros(im.shape)
# filters.sobel(im,1,imx)
# imy = zeros(im.shape)
# filters.sobel(im,0,imy)
# magnitude = sqrt(imx**2+imy**2)
sigma = 5 # standard deviation
imx = zeros(im.shape)
filters.gaussian_filter(im, (sigma,sigma), (0,1), imx)
imy = zeros(im.shape)
filters.gaussian_filter(im, (sigma,sigma), (1,0), imy)
magnitude = sqrt(imx**2+imy**2)
dirs = arctan2(imy, imx)
# Save as image
# pil_im = Image.fromarray(dirs)
# pil_im.convert("LA").save("dirs.png")
totalmag = 0.0
if out:
if args.format == "hslimage":
# Map direction to Hue, Magnitude to value
from math import pi
maxmag = amax(magnitude)
# height, width = magnitude.shape
im = Image.new("RGBA", (width, height))
# draw = ImageDraw.ImageDraw(im)
for y in range(height):
p = int(math.ceil(float(y)/height*100))
sys.stderr.write("\rCreating gradient HSL image... [{0}%]".format(p))
sys.stderr.flush()
for x in range(width):
d = dirs[y][x]
hue = ((d+pi) / (2 * pi)) * 360
m = magnitude[y][x]
value = (m/maxmag)
r, g, b = hsl_to_rgb(hue, 1.0, value)
im.putpixel((x, y), (r, g, b, 255))
# if args.svg and (x % args.svg_grid_size == 0) and (y % args.svg_grid_size == 0):
# x1, y1 = x, y
# x2 = x1 + (m * args.svg_mag_scale * math.cos(d))
# y2 = y1 + (m * args.svg_mag_scale * math.sin(d))
# print ("""<path
# style="fill:none;stroke:#00FFFF;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Send)"
# d="M {0},{1} {2},{3}"
# id="path2985"/>""".format(x1, y1, x2, y2), file=svgfile)
# totalmag += m
# draw.point((x, y), fill=(r,g,b,255))
sys.stderr.write("\n")
im.save(out)
elif args.format == "magimage":
pil_im = Image.fromarray(magnitude)
pil_im.convert("LA").save(out)
elif args.format == "json":
with open(out, "w") as f:
json.dump({
'dirs': dirs.tolist(),
'magnitudes': magnitude.tolist()
}, f)
if args.svg:
svgfile = open(args.svg, 'w')
print("""<svg version="1.1" baseProfile="full" width="{0[width]}" height="{0[height]}" xmlns="http://www.w3.org/2000/svg">
<defs
id="defs4">
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Send"
style="overflow:visible;">
<path
id="path3774"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#00FFFF;fill:#00FFFF;stroke-width:1.0pt;"
transform="scale(0.2) rotate(180) translate(6,0)" />
</marker>
</defs>
<g
id="layer1">""".format({'width': width, 'height': height}), file=svgfile)
from math import pi
maxmag = amax(magnitude)
# height, width = magnitude.shape
im = Image.new("RGBA", (width, height))
# draw = ImageDraw.ImageDraw(im)
for y in range(0, height, args.svg_grid_size):
for x in range(0, width, args.svg_grid_size):
d = dirs[y][x]
hue = ((d+pi) / (2 * pi)) * 360
m = magnitude[y][x]
x1, y1 = x, y
x2 = x1 + (m * args.svg_mag_scale * math.cos(d))
y2 = y1 + (m * args.svg_mag_scale * math.sin(d))
print ("""<path
style="fill:none;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Send)"
d="M {0},{1} {2},{3}"
id="path2985"/>""".format(x1, y1, x2, y2), file=svgfile)
print ("""</g>
</svg>""", file=svgfile)
svgfile.close()
print (int(totalmag), file=sys.stdout)
# with open(os.path.join(path, base + ".gradient_mag.json"), "w") as f:
......@@ -11,7 +11,7 @@ import reportlab.lib.pagesizes
from reportlab.lib.units import inch, cm
from reportlab.pdfbase.ttfonts import TTFont, pdfmetrics
from reportlab.lib.utils import ImageReader
from reportlab.lib.colors import ghostwhite, grey, lightgrey
......@@ -69,6 +69,7 @@ ap.add_argument("--fontsize", type=float, default=14.0)
ap.add_argument("--groupborder", type=float, default=2.5, help="horizontal gap between groups")
ap.add_argument("--cellborder", type=float, default=0.10)
ap.add_argument("--pageborder", type=float, default=2.5)
ap.add_argument("--landscape", default=False, action="store_true")
ap.add_argument("data")
args = ap.parse_args()
......@@ -104,7 +105,11 @@ cellmargin = {
'bottom': args.cellborder*cm
}
groupborder = args.groupborder*cm
pagewidth, pageheight = pagesize
if args.landscape:
pageheight, pagewidth = pagesize
else:
pagewidth, pageheight = pagesize
cols = args.columns
usablewidth = pagewidth - pagemargin['left'] - pagemargin['right'] - 2*groupborder
cellwidth = usablewidth / cols
......@@ -119,7 +124,7 @@ groupcols = int(floor(cols / 3.0))
font = TTFont('LabelFont', args.font)
pdfmetrics.registerFont(font)
# PDF
canvas = Canvas(args.output, pagesize=pagesize)
canvas = Canvas(args.output, pagesize=(pagewidth, pageheight))
boxfill = 1,0,1
textcolor = 0,0,0
canvas.setStrokeColorRGB(0.0,0.0,0.0)
......@@ -127,14 +132,20 @@ canvas.setFont('LabelFont', args.fontsize)
print ("{0} items".format(len(data)), file=sys.stderr)
def drawImageBox (ipath, x, c, r, boxsize=100, drawBorder=False):
def drawImageBox (ipath, x, c, r, boxsize=100, drawBorder=False, valign="center"):
im = Image.open(ipath)
# boxsize sets the resolution of the image such that it fits in boxsize x boxsize pixels
im.thumbnail((boxsize, boxsize), Image.ANTIALIAS)
imw = (im.size[0]/boxsize) * ccw
imh = (im.size[1]/boxsize) * cch
# centering dx,dy
dx, dy = (ccw - imw) / 2, (cch - imh) / 2
if valign=="top":
dx, dy = (ccw - imw) / 2, (cch - imh)
elif valign=="center":
dx, dy = (ccw - imw) / 2, (cch - imh) / 2
else: # "bottom"
dx, dy = (ccw - imw) / 2, 0
cx = x + (c*cellwidth)
cy = pageheight - pagemargin['top'] - ((r+1)*cellheight)
# DRAW IMAGE
......@@ -143,11 +154,12 @@ def drawImageBox (ipath, x, c, r, boxsize=100, drawBorder=False):
cx+dx+cellmargin['left'],
cy+dy+cellmargin['bottom'],
width=imw,
height=imh
height=imh,
mask='auto' # https://stackoverflow.com/questions/1308710/transparency-in-pngs-with-reportlab-2-3#1625350
)
if drawBorder:
canvas.rect(cx, cy, cellwidth, cellheight)
return cx, cy, dx, dy
return cx, cy, dx, dy, imw, imh
r = 0
for sortkey in "name inventory image_filesize dimensions dating red green blue contours gradient".split():
......@@ -164,8 +176,6 @@ for sortkey in "name inventory image_filesize dimensions dating red green blue c
midpoint = len(sdata)//2
midstart = midpoint - (groupcols//2)
groups = sdata[0:groupcols], sdata[midstart:midstart+groupcols], sdata[-groupcols:]
# for x in groups:
# assert (len(x) == groupcols)
groupx = pagemargin['left']
fillDataBox = False
......@@ -173,48 +183,23 @@ for sortkey in "name inventory image_filesize dimensions dating red green blue c
c= 0
for i in group:
ipath = i['img']
drawImageBox(ipath, groupx, c, r+1)
# im = Image.open(ipath)
# im.thumbnail((100, 100), Image.ANTIALIAS)
# imw = (im.size[0]/100) * ccw
# imh = (im.size[1]/100) * cch
# # centering dx,dy
# dx, dy = (ccw - imw) / 2, (cch - imh) / 2
# cx = groupx + (c*cellwidth)
# cy = pageheight - pagemargin['top'] - ((r+1+1)*cellheight)
# # DRAW IMAGE
# canvas.drawImage(ImageReader(im), cx+dx+cellmargin['left'], cy+dy+cellmargin['bottom'], width=imw, height=imh)
# canvas.rect(cx, cy, cellwidth, cellheight)
# DRAW DATA BOX
# cy = pageheight - pagemargin['top'] - ((r+1)*cellheight)
cx, cy, dx, dy, imw, imh = drawImageBox(ipath, groupx, c, r+1, valign="top")
if 'img' in i[sortkey]:
drawImageBox(i[sortkey]['img'], groupx, c, r)
# add a fill option
# if fillDataBox:
# canvas.setFillColorRGB(*boxfill)
# canvas.rect(cx+dx+cellmargin['left'], cy+dy+cellmargin['bottom'], imw, imh, stroke=0, fill=1)
# drawTextCenteredInBox
# txt = i['FileModifyDate_parsed'].strftime("%Y-%m-%d %H:%M:%S")
drawImageBox(i[sortkey]['img'], groupx, c, r, valign="bottom")
txt = label(i[sortkey])
if txt:
cx = groupx + (c*cellwidth)
cy = pageheight - pagemargin['top'] - ((r+1)*cellheight)
canvas.setStrokeColor(lightgrey)
canvas.setLineWidth(0.05)
canvas.rect(cx+dx+cellmargin['left'],cy+cellmargin['bottom'],imw, imh)
canvas.setFillColorRGB(*textcolor)
# canvas.drawCentredString(cx+dx+cellmargin['left']+(imw/2), cy+dy+cellmargin['bottom']+(imh/2), "{0}".format(txt))
canvas.drawCentredString(cx+(cellwidth/2), cy+(cellheight/2), "{0}".format(txt))
# print("cx, cy", cx, cy, file=sys.stderr)
# canvas.drawCentredString(cx+(cellwidth/2), cy+(cellheight/2), "{0}".format(txt))
canvas.drawCentredString(cx+dx+cellmargin['left']+(imw/2), cy+cellmargin['bottom']+(imh/2), "{0}".format(txt))
c += 1
groupx += groupborder + (cellwidth*groupcols)
r += 2
# for i in range(1000):
#
# c.setFont('MyFontName', 72)
# # c.drawString(10*cm, 0.5*cm, "Page {0}".format(i))
# c.drawCentredString(A4[0]/2, A4[1]/2, "Page {0}".format(i))
canvas.showPage()
print("Saving to {0}".format(args.output), file=sys.stderr)
canvas.save()
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.