Initial release

This commit is contained in:
Stefan Hamminga 2025-03-20 14:54:46 +02:00
parent 4686803b27
commit 3bc189c592
12 changed files with 342 additions and 2 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.swp

View File

@ -1,3 +1,32 @@
# gitea_external_renderers
# External rendering scripts for Gitea
External rendering scripts for various file types
These scripts attempt to render several documents so viewing them in Gitea is actually informative. Most are a work in progress. As some files can take a very long time to render, caching is used by leaving the generated images in the Gitea custom assets directory (if present and writable). You'd probably want to clean that out now and then.
List of renderers:
- LibreOffice
- KiCad
TODO:
- 3D models (STL, STEP, etc)
- Gerber files
## Prerequists
The KiCad renderers assume KiCad (9 or newer) is installed. They also need Inkscape (to properly fit the images). Libreoffice is required for the LO renderers.
The SVG Pan & Zoom library is loaded from a CDN.
`mktemp` is used to create a temporary directory.
## Installation & Configuration
1. Link the scripts in some place Gitea can execute them
2. Add the content of the `.ini` files to your `app.ini` file
3. Edit the new script path entries in `app.ini` to match your system
4. Copy / merge the contents of the `custom` dir with the custom dir in your Gitea root
## Repo and License
Feel free to copy and share this under the terms of the Apache 2.0 license.
Original author: Stefan Hamminga <stefan@rbts.co>
Original repo: https://git.rbts.co/rbts.co/gitea_external_renderers

25
config/kicad_pcb.ini Normal file
View File

@ -0,0 +1,25 @@
[markup.kicad_pcb]
ENABLED = true
FILE_EXTENSIONS = .kicad_pcb,.kicad_pcb.1,.kicad_pcb.2,.kicad_pcb.3,.kicad_pcb.4,.kicad_pcb.5,.kicad_pcb.6,.kicad_pcb.7,.kicad_pcb.8,.kicad_pcb.9
RENDER_COMMAND = /usr/local/bin/gitea_render_kicad_pcb.sh
IS_INPUT_FILE = true
NEED_POSTPROCESS = false
;RENDER_CONTENT_MODE = no-sanitizer
[markup.sanitizer.kicad_pcb.1]
ALLOW_DATA_URI_IMAGES = true
ELEMENT = div
ALLOW_ATTR = class
REGEXP =
[markup.sanitizer.kicad_pcb.2]
ALLOW_DATA_URI_IMAGES = true
ELEMENT = img
ALLOW_ATTR = src
REGEXP =
[markup.sanitizer.kicad_pcb.3]
ALLOW_DATA_URI_IMAGES = true
ELEMENT = img
ALLOW_ATTR = class
REGEXP =

25
config/kicad_sch.ini Normal file
View File

@ -0,0 +1,25 @@
[markup.kicad_sch]
ENABLED = true
FILE_EXTENSIONS = .kicad_sch,.kicad_sch.1,.kicad_sch.2,.kicad_sch.3,.kicad_sch.4,.kicad_sch.5,.kicad_sch.6,.kicad_sch.7,.kicad_sch.8,.kicad_sch.9
RENDER_COMMAND = /usr/local/bin/gitea_render_kicad_sch.sh
IS_INPUT_FILE = true
NEED_POSTPROCESS = false
;RENDER_CONTENT_MODE = no-sanitizer
[markup.sanitizer.kicad_sch.1]
ALLOW_DATA_URI_IMAGES = true
ELEMENT = div
ALLOW_ATTR = class
REGEXP =
[markup.sanitizer.kicad_sch.2]
ALLOW_DATA_URI_IMAGES = true
ELEMENT = img
ALLOW_ATTR = src
REGEXP =
[markup.sanitizer.kicad_sch.3]
ALLOW_DATA_URI_IMAGES = true
ELEMENT = img
ALLOW_ATTR = class
REGEXP =

23
config/libreoffice.ini Normal file
View File

@ -0,0 +1,23 @@
[markup.libreoffice]
ENABLED = true
FILE_EXTENSIONS = .odt,.ods,.odg,.docx,.ppt
RENDER_COMMAND = /usr/local/bin/gitea_render_libreoffice.sh
IS_INPUT_FILE = true
NEED_POSTPROCESS = false
[markup.sanitizer.libreoffice.1]
ALLOW_DATA_URI_IMAGES = true
ELEMENT = img
ALLOW_ATTR = class
REGEXP =
[markup.sanitizer.libreoffice.2]
ALLOW_DATA_URI_IMAGES = true
ELEMENT = src
ALLOW_ATTR = class
REGEXP =
[markup.sanitizer.libreoffice.3]
ELEMENT = div
ALLOW_ATTR = class
REGEXP =

View File

@ -0,0 +1,20 @@
.file-view.markup .full_width {
width: 100%;
display: block;
}
.file-view.markup.kicad_sch,
.file-view.markup.kicad_pcb,
.file-view.markup.libreoffice
{
background-color: rgba(127, 127, 127, 0.05);
}
.file-view.markup .page {
background-color: white;
padding: 1em;
}
.file-view.markup .page + .page {
margin-top: 1em;
}

View File

View File

@ -0,0 +1,15 @@
<script src="https://unpkg.com/@panzoom/panzoom@4.6.0/dist/panzoom.min.js"></script>
<script>
try {
document.querySelectorAll('img.pan_zoom').forEach((img) => {
const panzoom = Panzoom(img, {
maxScale: 5
});
img.parentElement.addEventListener('wheel', evt => evt.preventDefault());
img.parentElement.addEventListener('wheel', panzoom.zoomWithWheel)
});
} catch (e) {
console.error('Error loading Panzoom:', e);
}
</script>

View File

@ -0,0 +1 @@
<link rel="stylesheet" href="{{AppSubUrl}}/assets/css/renderers.css" />

67
scripts/kicad_pcb.sh Normal file
View File

@ -0,0 +1,67 @@
#!/bin/bash
#set -x
INPUT="$*"
OUTDIR=$(mktemp -d)
IMGDIR="$GITEA_WORK_DIR/custom/public/assets/img"
KIOPTS=(
# --subtract-soldermask
--mode-single
--exclude-drawing-sheet
--page-size-mode 2
--sketch-pads-on-fab-layers
)
ln -s "$INPUT" "$OUTDIR"/pcb.kicad_pcb
if [[ -d "$IMGDIR" && -w "$IMGDIR" ]]; then
# We can use caching
HASH=$(sha256sum "$INPUT" | cut -c1-64)
shopt -s nullglob
IMAGES=("${IMGDIR}"/${HASH}.*.svg)
shopt -u nullglob
if [ ${#IMAGES[@]} -le 0 ]; then
kicad-cli pcb export svg "${KIOPTS[@]}" --layers Edge.Cuts,F.Cu,F.Mask,F.Silkscreen,F.Adhesive,F.Paste --output "${OUTDIR}/${HASH}.1.svg" "$OUTDIR"/pcb.kicad_pcb >/dev/null
kicad-cli pcb export svg "${KIOPTS[@]}" --mirror --layers Edge.Cuts,B.Cu,B.Mask,B.Silkscreen,B.Adhesive,B.Paste --output "${OUTDIR}/${HASH}.2.svg" "$OUTDIR"/pcb.kicad_pcb >/dev/null
inkscape --actions="page-fit-to-selection" -o "${IMGDIR}/${HASH}.1.svg" "${OUTDIR}/${HASH}.1.svg"
inkscape --actions="page-fit-to-selection" -o "${IMGDIR}/${HASH}.2.svg" "${OUTDIR}/${HASH}.2.svg"
shopt -s nullglob
IMAGES=("${IMGDIR}"/${HASH}.*.svg)
shopt -u nullglob
fi
echo '<div class="file">'
for IMG in "${IMAGES[@]}"; do
echo '<div class="page">'
# echo "bla"
echo -n '<img src="/assets/img/'
echo -n "$(basename "${IMG}")"
echo -n '"'
echo -n ' class="full_width kicad_pcb pan_zoom"'
echo '/>'
echo '</div>'
done
echo '</div></div>'
else
echo "<p>Error: Unable to write to $IMGDIR. Please check permissions.</p>"
# TODO: Implement base64 method
# We'll be generating the images on the fly, including them as base64
# mapfile -t FILES \
# < <(kicad-cli sch export svg --exclude-drawing-sheet --no-background-color --output "$OUTDIR" "$OUTDIR/pcb.kicad_pcb" | grep -E 'Plotted to' | sed -r "s/^[^']+'|'[^']+$//g" )
# for FILE in "${FILES[@]}"; do
# echo -n '<div class="file"><div class="page">'
# echo -n '<img src="data:image/svg+xml;base64,'
# inkscape --actions="page-fit-to-selection" -o - "$FILE" | base64 --wrap=0
# echo -n '"'
# echo -n ' class="full_width kicad_pcb pan_zoom"'
# echo -n '/>'
# echo '</div></div>'
# done
fi
rm -R "$OUTDIR"

62
scripts/kicad_sch.sh Normal file
View File

@ -0,0 +1,62 @@
#!/bin/bash
#set -x
INPUT="$*"
OUTDIR=$(mktemp -d)
IMGDIR="$GITEA_WORK_DIR/custom/public/assets/img"
ln -s "$INPUT" "$OUTDIR"/schematic.kicad_sch
if [[ -d "$IMGDIR" && -w "$IMGDIR" ]]; then
# We can use caching
HASH=$(sha256sum "$INPUT" | cut -c1-64)
shopt -s nullglob
IMAGES=("${IMGDIR}"/${HASH}.*.svg)
shopt -u nullglob
if [ ${#IMAGES[@]} -le 0 ]; then
mapfile -t FILES \
< <(kicad-cli sch export svg --exclude-drawing-sheet --no-background-color --output "$OUTDIR" "$OUTDIR/schematic.kicad_sch" | grep -E 'Plotted to' | sed -r "s/^[^']+'|'[^']+$//g" )
file_num=1
for FILE in "${FILES[@]}"; do
FN="${IMGDIR}/${HASH}.${file_num}.svg"
inkscape --actions="page-fit-to-selection" -o "$FN" "$FILE"
file_num=$((file_num + 1))
break # TODO: find some way to handle related (hierarchical) schematic files, as currently only the active file is made available
done
shopt -s nullglob
IMAGES=("${IMGDIR}"/${HASH}.*.svg)
shopt -u nullglob
fi
for FILE in "${IMAGES[@]}"; do
echo '<div class="file"><div class="page">'
# echo "bla"
echo -n '<img src="/assets/img/'
echo -n "$(basename "${FILE}")"
echo -n '"'
echo -n ' class="full_width kicad_sch pan_zoom"'
echo '/>'
echo '</div></div>'
done
else
# We'll be generating the images on the fly, including them as base64
mapfile -t FILES \
< <(kicad-cli sch export svg --exclude-drawing-sheet --no-background-color --output "$OUTDIR" "$OUTDIR/schematic.kicad_sch" | grep -E 'Plotted to' | sed -r "s/^[^']+'|'[^']+$//g" )
for FILE in "${FILES[@]}"; do
echo -n '<div class="file"><div class="page">'
echo -n '<img src="data:image/svg+xml;base64,'
inkscape --actions="page-fit-to-selection" -o - "$FILE" | base64 --wrap=0
echo -n '"'
echo -n ' class="full_width kicad_sch pan_zoom"'
echo -n '/>'
echo '</div></div>'
break # TODO: find some way to handle related (hierarchical) schematic files, as currently only the active file is made available
done
fi
rm -R "$OUTDIR"

72
scripts/libreoffice.sh Normal file
View File

@ -0,0 +1,72 @@
#!/bin/bash
#set -x
INPUT="$*"
OUTDIR=$(mktemp -d)
IMGDIR="$GITEA_WORK_DIR/custom/public/assets/img"
if [[ -d "$IMGDIR" && -w "$IMGDIR" ]]; then
# We can use caching
HASH=$(sha256sum "$INPUT" | cut -c1-64)
shopt -s nullglob
IMAGES=("${IMGDIR}"/${HASH}.*.svg)
shopt -u nullglob
if [ ${#IMAGES[@]} -le 0 ]; then
libreoffice --headless --convert-to pdf --outdir "$OUTDIR" $INPUT >/dev/null
PDF_FILE="$OUTDIR/$(basename "${INPUT%.*}".pdf)"
NUM_PAGES=$(pdfinfo "$PDF_FILE" | grep Pages | awk '{print $2}')
for (( i=1; i<=$NUM_PAGES; i++ )); do
FN="${IMGDIR}/${HASH}.${i}.svg"
pdftocairo -svg -f $i -l $i "$PDF_FILE" "${FN}"
done
shopt -s nullglob
IMAGES=("${IMGDIR}"/${HASH}.*.svg)
shopt -u nullglob
fi
echo '<div class="file">'
for IMG in "${IMAGES[@]}"; do
echo '<div class="page">'
echo -n '<img src="/assets/img/'
echo -n "$(basename "${IMG}")"
echo -n '"'
echo -n ' class="full_width libreoffice pan_zoom"'
echo '/>'
echo '</div>'
done
echo '</div>'
else
# We'll be generating the images on the fly, including them as base64
libreoffice --headless --convert-to pdf --outdir "$OUTDIR" $INPUT >/dev/null
PDF_FILE="$OUTDIR/$(basename "${INPUT%.*}".pdf)"
NUM_PAGES=$(pdfinfo "$PDF_FILE" | grep Pages | awk '{print $2}')
for (( i=1; i<=$NUM_PAGES; i++ )); do
FN="${IMGDIR}/${HASH}.${i}.svg"
pdftocairo -svg -f $i -l $i "$PDF_FILE" "${FN}"
done
shopt -s nullglob
IMAGES=("${IMGDIR}"/${HASH}.*.svg)
shopt -u nullglob
echo '<div class="file">'
for IMG in "${IMAGES[@]}"; do
echo '<div class="page">'
echo -n '<img src="/assets/img/'
base64 --wrap=0 < "${IMG}"
echo -n '"'
echo -n ' class="full_width libreoffice pan_zoom"'
echo '/>'
echo '</div>'
done
echo '</div>'
fi
rm -R "$OUTDIR"