Bilder publizieren
“Publizieren” meint hier die Publikation im Internet.
Welches Programm zur Publikation von Bildern auch immer ich probiere, ganz glücklich bin ich meist nicht damit, speziell, weil ich wirklich viele Bilder darzustellen habe und alle diese Programme zu viel Handarbeit erfordern.
Für den Desktop ist die Darstellung verzweigter Bilderordner kein Problem, dafür gibt es Programme genug. Eines der populärsten Programme dafür wäre Adobe Lightbox.
Aber für die Publikation im Internet wird man nicht gut unterstützt, auch dann nicht, wenn man populäre Plugins für WordPress einsetzt. Das populärste Galerieprogramm ist “Nextgen”. Aber groß ist die Enttäuschung, wenn man sieht, dass man jeden Ordner händisch uploaden muss, und dass man die Ordner nicht verschachteln kann. Für kleinere Projekte ist das kein Problem, aber bei größeren Bildermengen stößt man an Grenzen.
Die Originalbilder von der Kamera oder vom Handy sind für die Darstellung im Internet zu groß. Auch dann, wenn man sie verkleinert, muss man sich die Frage stellen, welches eigentlich die Größe sein soll. Man benötigt nämlich sowohl eine kleine Bildgröße bei Seiten mit vielen Vorschaubilder als auch größere Auflösungen für eine Einzelbildbetrachtung.
Bilderordnung – Originale
Die Originalbilder haben meist einen Namen, der Datum und Uhrzeit enthält. Mehrere Bilder eines Bildprojekts werden in einem Ordner gespeichert, dessen Namen über das Thema Aufschluss gibt. Meine Bilder sind in einer Chronik gespeichert, die folgender Systematik folgt:
... 2000=2009 2000 2000-01-04 Puchenstuben 2000-02-06 Salzburg Streiner 2000-03-00 Martin 40 ... 2001 ... 2009 2010=2019 2010 2011 ... 2019 2020=2029 2020 2021 2022 2023 2023-01-04 Josefstadt Oscar_Wilde 2023-01-07 Baden Fledermaus 2023-01-29 Konzerthaus 2023-03-12 Konzerthaus 2023-03-20 Was_gibt_es_Neues ...
Bei der jeweils letzten Dekade kommt man unwillkürlich ins Grübeln, ob man den letzten Ordner – hier 2029 – überhaupt noch erleben wird.
In jedem Jahresordner sind Fotoprojekte, die meist ein gemeinsames Erlebnis mit der Familie dokumentieren.
Bilderordnung – Web-Publikation
Diese Struktur der Originalbilder wird 1:1 auf einem Zielverzeichnis übertragen. Lediglich die Bildprojektordner werden nicht angelegt. Bei Programmierversuchen hat sich nämlich herausgestellt, dass die Unterteilung in Bilderordner ein bisschen unpraktisch ist, weil sich oft nur wenige Bilder in einem solchen Ordner befinden. Daher werden alle Bilder eines Jahres in ein gleichnamiges Zielverzeichnis kopiert, dabei aber der Name so verändert, dass man bei der Darstellung des Bildes den Anlass ablesen kann.
Beispiel für die Originaldateien des Jahres 2023:
2020=2029
2023
2023-01-04 Josefstadt Oscar_Wilde
PXL_20230320_144231536.jpg
PXL_20230320_145534991.jpg
PXL_20230320_154037362.jpg
PXL_20230320_155322727.jpg
PXL_20230320_155336877.jpg
PXL_20230320_155344627.jpg
...
Die Struktur wird wie folgt verändert:
Alle Bilder eines Jahres werden in einen Jahresordner kopiert. Dem Bildernamen wird das Datum. der der Name des ursprünglich einschließenden Ordners vorangestellt und als Trennzeichen eine Raute eingefügt " # "
.
2020=2029
2023
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_144231536.jpg
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_145534991.jpg
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_154037362.jpg
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_155322727.jpg
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_155336877.jpg
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_155344627.jpg
...
Jedes Bild wird in fünf Größen gespeichert: 100px
, 200px
, 400px
, 800px
und 1600px.
Zur Unterscheidung wird an den Bildnamen -t100
, -t200
,- t400
, -t800
und -t1600
angehängt.
2020=2029
2023
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_144231536-t100.jpg
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_144231536-t1600.jpg
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_144231536-t200.jpg
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_144231536-t400.jpg
2023-01-04 Josefstadt Oscar_Wilde # PXL_20230320_144231536-t800.jpg
...
Diese Transformationen werden mit einem Powershell-Programm erledigt.
#Dateiname: SubordnerZusammenfassenUndVerkleinern.ps1
Clear-Host
function CreateImagesYear {
param ($Year)
$Decade=([String]$Year).Substring(0,3)
$Decade=$Decade+"0="+$Decade+"9"
#Write-Host "$Year $Decade"
$PathSource = "S:\OneDrive\Chronik\$Decade\$Year\"
if (!(Test-Path -Path $PathSource)) { Write-Host "No Path: $PathSource"; return }
$PathDiashow = "S:\OneDrive\@Fiala_Franz\Projekte\fiala.cc\data\Chronik\$Decade\"
if (!(Test-Path -Path $PathDiashow)) { New-Item -ItemType "directory" -Path $PathDiashow }
$PathDiashow = "S:\OneDrive\@Fiala_Franz\Projekte\fiala.cc\data\Chronik\$Decade\$Year\"
if (!(Test-Path -Path $PathDiashow)) { New-Item -ItemType "directory" -Path $PathDiashow }
$Directories = Get-ChildItem $PathSource -Attributes Directory
$i = 0
if (!(Test-Path -Path $PathDiashow)) {
New-Item $PathDiaShow -ItemType directory
}
foreach ($Directory in $Directories) {
$SubFolderItems = Get-ChildItem $Directory.FullName
foreach($Item in $SubFolderItems) {
if ($Item.Extension -in (".jpg",".png",".jpeg",".bmp")) {
$PathToImage = $Item.FullName
$NameExtended = $Directory.Name + " # " + $Item.Name
$PathExtended = $PathDiashow + "\" + $NameExtended
# Copy-Item -Path $PathToImage -Destination $PathExtended
# $Expression = "convert '$PathToImage' -resize 1920x1080 '$PathExtended'"
#Invoke-Expression $Expression
$PathThumb = $PathExtended.Replace($Item.Extension,"-t1600"+$Item.Extension)
$Expression = "convert '$PathToImage' -resize 1600x1600 '$PathThumb'"
Invoke-Expression $Expression
$PathThumb = $PathExtended.Replace($Item.Extension,"-t800"+$Item.Extension)
$Expression = "convert '$PathToImage' -resize 800x800 '$PathThumb'"
Invoke-Expression $Expression
$PathThumb = $PathExtended.Replace($Item.Extension,"-t400"+$Item.Extension)
$Expression = "convert '$PathToImage' -resize 400x400 '$PathThumb'"
Invoke-Expression $Expression
$PathThumb = $PathExtended.Replace($Item.Extension,"-t200"+$Item.Extension)
$Expression = "convert '$PathToImage' -resize 200x200 '$PathThumb'"
Invoke-Expression $Expression
$PathThumb = $PathExtended.Replace($Item.Extension,"-t100"+$Item.Extension)
$Expression = "convert '$PathToImage' -resize 100x100 '$PathThumb'"
Invoke-Expression $Expression
Write-Host " $i" -NoNewline
if ((($i+1) % 10) -eq 0) { Write-Host }
$i++
# if ($i -gt 20) { exit }
}
}
}
}
function CreateImagesDecade {
param ($Decade)
$From = [int]$Decade.Split("=")[0]
$To = [int]$Decade.Split("=")[1]
Write-Host "Von:$From Bis:$To"
for ($y=$From; $y -le $To; $y++) {
CreateImagesYear $y
}
}
CreateImagesDecade "2010=2019"
#CreateImagesYear "2012"
Publikation der Bilder
Bildauswahl
Über das DropDown-Menü wird das Jahr ausgewählt. Derzeit stehen die Jahre 2000 bis 2022 zur Auswahl.
Die ersten 100 Bilder eines Jahres werden angezeigt. Wenn mehr Bilder verfügbar sind, kann man sie über die Vorwärts-Rückwärtsnavigation wählen.
Die Größe der Vorschaubilder kann man in den Stufen “klein”, “mittel” und “groß” einstellen.
Bilderanzeige
Die Bilder werden durch ein JavaScript-Programm angezeigt. Das Programm liest alle Bilder des eingestellten Jahresordners in das Bilder-Array Images
und zeigt die verkleinerten Vorschaubilder in Portionen von 100 in den Größen 100px, 200px oder 400 px an. Klickt man auf ein Bild, sieht man die Vorschaugröße 800px. Die Bildgröße 1600px wird derzeit nicht verwendet.
Einzelbildanzeige
Klickt man auf ein Bild, erfährt man Datum un Anlass:
Über die Vorwärts-Rückwärts-Navigation kann man sich chonologisch durch die Bilder bewegen. Über das Menüsymbol erfährt man weitere Details zu dem Bild.
Live-Vorschau
Diese nunmehr 21 Jahre Familienchronik mit etwas 30.000 Bildern gibt es hier zu sehen:
https://franz.fiala.cc/d/fiala/chronik/galerie.htm
Das Programm kann so wie in dieser Adresse verwendet werden, es ist dann aber schwer zu finden. Besser ist es, wenn es in eine bestehende Homepage eingebettet wird. Dazu wird das Programm in einen HTML- und einen JavaScript-Teil zerlegt. Mit einer solchen Zerlegung kann man externe JavaScript-Programm modifizieren, ohne dass dabei an der Webseite etwas geändert werden muss.
Programm
Die Datei galerie.htm besteht aus drei Abschnitten:
<head>..</head>
: hier werden praktische Bibliotheken inkludiert (Bootstrap zur formatunabhängigen Ausgabe, Icon-Bibliothek aus den Google-Fonts für die verwendeten Symbole, jquery für die vereinfachte Ansprache von HTML-Objekten).
<body>..</body>
: Die Bedienungsobjekte werden in der Bootstrap-Schreibweise definiert. Die Bilder werden durch das JavaScript-Programm in den Abschnitt Images
eingefügt.
<script>..</script>
: Die Steuerung erfolgt über die Handler $("#sel-year").change
und $(".paging").click
. Gerufen werden die Funktionen ReadImages()
und ShowImages()
.
Für die Einzelbildanzeige gibt es das Template ImgTemplate
.
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=2.0, user-scalable=yes">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Material+Icons" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<style>
body { background-color:#222; color:white}
.btn-close-yellow { background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fc0'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat; }
.slidelarge {background-color:#222;color:#eee }
</style>
</head>
<body>
<div class="container-fluid">
<h1 id="title" title="Chronik Fiala"></h1>
<div class="btn-group" role="group">
<select id="sel-year" class="form-select">
<option>2010</option>
<option>2011</option>
<option>2012</option>
<option>2013</option>
<option>2014</option>
<option>2015</option>
<option>2016</option>
<option>2017</option>
<option>2018</option>
<option>2019</option>
<option>2020</option>
<option>2021</option>
<option selected>2022</option>
</select>
</div>
<div class="btn-group" role="group">
<label class="btn btn-outline-primary paging" title="" id="paging-prev">
<span class="material-icons" style="font-size:24pt;padding-top:3pt">arrow_back_ios</span>
</label>
<label class="btn btn-primary" title="">
<span id="paging" style="font-size:18pt;padding-top:18pt;color:white;"></span>
</label>
<label class="btn btn-outline-primary paging" title="" id="paging-next">
<span class="material-icons" style="font-size:24pt;padding-top:3pt">arrow_forward_ios</span>
</label>
</div>
<div class="btn-group" role="group">
<input type="radio" class="btn-check btn-slide" name="btn-slide" id="size100" autocomplete="off">
<label class="btn btn-outline-primary" for="size100" title="100px">
<span class="material-icons" style="font-size:12pt;padding-top:9pt">apps</span>
</label>
<input type="radio" class="btn-check btn-slide" name="btn-slide" id="size200" autocomplete="off" checked>
<label class="btn btn-outline-primary" for="size200" title="200px">
<span class="material-icons" style="font-size:18pt;padding-top:6pt">apps</span>
</label>
<input type="radio" class="btn-check btn-slide" name="btn-slide" id="size400" autocomplete="off">
<label class="btn btn-outline-primary" for="size400" title="400px">
<span class="material-icons" style="font-size:24pt;padding-top:3pt">apps</span>
</label>
</div>
<hr/>
<div id="Images" class="row" class="align-items-center">
</div>
<hr>
<div>
Franz Fiala, Siccardsburggasse 4/1/22, 1100 Wien, 0664-1015070, franz@fiala.cc, http://fiala.cc
</div>
</div>
<script>
/* <!-- */
var ImgTemplate =
`<div class="col">
<div data-bs-toggle="modal" class="slide"
data-bs-target="#i#idx#"
title="#tit# #dat# #idx#">
<img src="#thu#" class="thumbnail rounded">
</div>
<div class="modal fade" id="i#idx#" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog #mod#">
<div class="modal-content slidelarge">
<div class="modal-header">
<div class="row" style="width:100%">
<div class="col">
<span style='font-size:small;font-style:italic;'>#dat# Bild:#idx#</span>
<h5 class="modal-title">#tit#</h5>
</div>
<div class="col" style="text-align:right">
<span id="m#idx#" class="material-icons more" style="font-size:48pt">more_vert</span>
</div>
<div class="col" style="text-align:right;">
<button type="button" class="btn-close btn-close-yellow" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
</div>
</div>
<div class="modal-body">
<div class="col details" id="t#idx#" invisible>
<table class="table" style="color:white">
<tr><td>Idx</td><td>#idx#</td></tr>
<tr><td>Chp</td><td>#chp#</td></tr>
<tr><td>Dat</td><td>#dat#</td></tr>
<tr><td>Tit</td><td>#tit#</td></tr>
<tr><td>Url</td><td>#url#</td></tr>
<tr><td>Fil</td><td>#fil#</td></tr>
<tr><td>Ext</td><td>#ext#</td></tr>
</table>
</div>
<div class="container-fluid">
<div class="position-relative">
<img src="#img#" class="img-fluid rounded">
<div class="position-absolute top-50 start-0" style="text-align:right">
<span id="b#idx#" class="material-icons bck" style="font-size:48pt">arrow_back_ios</span>
</div>
<div class="position-absolute top-50 end-0" style="text-align:right">
<span id="f#idx#" class="material-icons fwd" style="font-size:48pt">arrow_forward_ios</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>`;
var Year = 0
var UrlChronicle = "https://franz.fiala.cc"
var UrlImageDirectory = "https://franz.fiala.cc/d/fiala/chronik/"
var matches_array = []
var Images = []
var Images_Length = 0
var size_slide = 200
var size_preview = 800
const PAGESIZE = 100
var numb_beg = 0
var numb_end = 0
function Image(Chp,Dat,Tit,Url,Fil,Ext) {
this.Chp = Chp
this.Dat = Dat
this.Tit = Tit
this.Url = Url
this.Fil = Fil
this.Ext = Ext
}
function setsize_slide(size) {
$('.slide').css("width",size+"px")
$('.slide').css("height",size+"px")
}
function SetPaging() {
$("#paging").html(
(Images_Length==0 ? "" : (numb_beg+1)+"..."+(numb_end+1))
+ " ("+Images_Length+")"
)
}
function ShowImages() {
$('#Images').html("")
Images.forEach (function (Img,idx) {
if ( (idx<numb_beg) || (idx>numb_end) ) return
var ImageLink = UrlChronicle+Img.Url.replace(Img.Ext,"-t"+size_preview+Img.Ext)
var ImageLinkThumb = ImageLink.replace("-t"+size_preview,"-t"+size_slide)
var html = ImgTemplate.replace(/#img#/g,ImageLink)
html = html.replace(/#thu#/g,ImageLinkThumb)
html = html.replace(/#tit#/g,Img.Tit)
html = html.replace(/#idx#/g,(idx+1))
html = html.replace(/#chp#/g,Img.Chp)
html = html.replace(/#dat#/g,Img.Dat)
html = html.replace(/#url#/g,Img.Url)
html = html.replace(/#fil#/g,Img.Fil)
html = html.replace(/#ext#/g,Img.Ext)
var mod_mode = ""
switch (size_preview) {
case 200: mod_mode = "modal-sm"; break
case 400: default: mod_mode = ""; break
case 800: mod_mode = "modal-lg"; break
case 1600: mod_mode = "modal-xl"; break
}
html = html.replace(/#mod#/g,mod_mode)
$('#Images').append(html)
})
$(".details").hide()
setsize_slide(size_slide)
$(".fwd").click(function(){
var id=this.id.substr(1)*1
if (id==Images_Length-1) return
$("#i"+id).modal('hide')
$("#i"+(id+1)).modal('show')
})
$(".bck").click(function(){
var id=this.id.substr(1)*1
if (id==0) return
$("#i"+id).modal('hide')
$("#i"+(id-1)).modal('show')
})
$(".more").click(function(){
var id=this.id.substr(1)*1
if ($("#t"+id).is(":visible")) { $(".details").hide() }
else { $(".details").show() }
})
$(".btn-slide").change(function(){
var size = this.id.replace("size","")*1
size_slide = size
ShowImages()
})
$(".btn-preview").change(function(){
var size = this.id.replace("prev","")*1
size_preview = size
ShowImages()
})
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
}
function ReadImages() {
while (Images.length>0) Images.pop()
var Decade = Year.toString().substr(0,3)
Decade = Decade + "0=" + Decade + "9"
$.get(UrlImageDirectory + Decade + "/" + Year + "/", function (result) {
var regexp = new RegExp(/<A[^<]+?#.+?A>/gi)
matches_array = result.match(regexp)
if (matches_array!=null) {
var Length = matches_array.length
for (var i=0; i<Length; i++) {
var Img = matches_array[i]
if (!Img.includes("-t100")) continue
Img = Img.replace("-t100","")
var Chp = Img.match(/>(.+) #/)[1]
var Dat = Chp.match(/([^ ]+) /)[1]
var Tit = Chp.match(/ (.+)/)[1]
var Url = Img.match(/HREF="(.+)"/)[1]
var Fil = Img.match(/>(.+)</)[1]
var Ext = Fil.substr(Fil.length-4)
Images.push(new Image(Chp,Dat,Tit,Url,Fil,Ext))
}
}
Images_Length = Images.length
numb_beg = 0
numb_end = Images_Length<PAGESIZE ? Images_Length : PAGESIZE-1
if (Images_Length<=100) $("#numb_block").hide()
else {
$("#numb_block").show()
SetPaging()
}
ShowImages()
});
}
$("#sel-year").change(function(){
Year = $("#sel-year option:selected").text()*1
ReadImages()
})
$(".paging").click(function(){
if (Images_Length<=PAGESIZE) {
$(".paging").hide()
return
}
var id=this.id
switch (id) {
case "paging-prev":
if (numb_beg>0) {
numb_beg = numb_beg - PAGESIZE
numb_end = numb_end - PAGESIZE
}
break;
case "paging-next":
if (numb_end<Images_Length) {
numb_beg = numb_beg + PAGESIZE
numb_end = numb_end + PAGESIZE
}
break;
}
SetPaging()
ShowImages()
})
Year = $("#sel-year option:selected").text()*1
ReadImages()
/* --> */
</script>
</body>
</html>
Links
Franz war pensionierter HTL Lehrer (TGM), Präsident von ClubComputer, Herausgeber der Clubzeitung PCNEWS und betreute unser Clubtelefon und Internet Support. Er war leidenschaftlicher Rapid Wien Fan. Er ist leider Anfang Jänner 2024 nach langer schwerer Krankheit verstorben.
Neueste Kommentare