In the middle of the desert you can say anything you want
bitmap-trace
that has no centerline optionAutotrace is awesome!
This alone works really nicely:
autotrace -centerline AMPERSAND.png -output-file AMPERSAND.svg
Fish script for batch processing, courtesy of ChatGPT:
#!/usr/bin/fish
# Check if autotrace is installed
if not type -q autotrace
echo "autotrace is not installed. Please install it first."
exit 1
end
# Loop through each .png file provided as an argument
for file in $argv
# Check if the file extension is .png
if string match -r '\.png$' $file
# Set the output filename by replacing .png with .svg
set output_file (string replace -r '\.png$' '.svg' $file)
# Execute autotrace with centerline option
autotrace -centerline $file -output-file $output_file
# Confirmation message
echo "Processed $file to $output_file"
else
echo "Skipping $file: not a .png file"
end
end
And a more simple one:
#!/usr/bin/fish
for file in $argv
autotrace -centerline $file -output-file "$file.svg"
end
ChatGPT says this:
autotrace -centerline -input-format png -output-format svg -output-file traced_dejavu.svg -dpi 300 -error-threshold 0.5 -corner-threshold 85 -filter-iterations 2 -noise-removal 0.99 -line-threshold 0.5 -corner-surround 3
(et 1 is best)
Using the Command Line - Inkscape Wiki
inkscape action-list
shows all available actions
man inkscape
is the latest and best
inkscape AMPERSAND.png --export-type="svg" --export-area-page --batch-process
works but asks me about import options
inkscape --shell
, man page gives examples:
file-open:file1.svg; export-type:pdf; export-do; export-type:png; export-do
file-open:file2.svg; export-id:rect2; export-id-only; export-filename:rect_only.svg; export-do
OK this works for no questions about how to import it:
> file-open:AMPERSAND.png
> export-filename:AM.svg
> export-do
One control, play/pause.
const buttons = document.querySelectorAll('.play-pause-btn');
buttons.forEach(button => {
const audio = document.getElementById(button.dataset.audio);
button.addEventListener('click', () => {
if (audio.paused) {
// Pause all other audio files
document.querySelectorAll('audio').forEach(a => {
a.pause();
a.currentTime = 0; // Reset other audio files
});
document.querySelectorAll('.play-pause-btn').forEach(btn => {
btn.textContent = '▶';
});
// Play the clicked audio
audio.play();
button.textContent = '⏸︎';
} else {
audio.pause();
button.textContent = '▶';
}
});
// Reset button icon when audio ends
audio.addEventListener('ended', () => {
button.textContent = '▶';
});
});
Multiple players:
<div class="player-container">
<button class="play-pause-btn" data-audio="audio1">▶️</button>
<audio id="audio1" src="audio1.mp3"></audio>
</div>
<div class="player-container">
<button class="play-pause-btn" data-audio="audio2">▶️</button>
<audio id="audio2" src="audio2.mp3"></audio>
</div>
.player-container {
display: inline;
vertical-align: text-bottom;
align-items: center;
margin-bottom: 20px;
}
.play-pause-btn {
font-size: 32px;
background: none;
border: none;
cursor: pointer;
margin-right: 10px;
}
I missed an ability to recursively look for elements matching a condition in panflute, so:
def _recursively_find_elements(
element: Element | list[Element], condition: Callable
) -> list[Element]:
"""Return panflute element(s) and their descendants that match conditition.
"""
results = list()
def action(el, doc):
if condition(el):
results.append(el)
if not isinstance(element, list):
element = [element]
for e in element:
e.walk(action)
return results
# sample condition
def is_header(e) -> bool:
cond = e.tag == "Header" and e.level == 2 # and "data-pos" in e.attributes
return cond
Ah, to read:
ddoc = pf.convert_text(
markdown,
input_format="commonmark_x+raw_html+bracketed_spans+fenced_divs+sourcepos",
output_format="panflute",
)
To output readably:
pf.stringify(el).strip()
input_format
has to be commonmark[_x]+
sourcepos
sourcepos
isn’t too well documented, only w/ commonmark
el.attributes['data-pos']
a la 126:1-127:1
line_no
always matching what I expectdef _parse_data_pos(p: str) -> tuple[tuple[int, int], tuple[int, int]]:
"""Parse data-pos string to (line, char) for start and end.
Example: '126:1-127:1' -> ((126, 1), (127, 1))
Arguments:
p: data-pos string as generated by commonmark+sourcepos extension.
"""
start, end = p.split("-")
start_l, start_c = start.split(":")
end_l, end_ch = end.split(":")
return (int(start_l), int(start_c)), (int(end_l), int(end_ch))
Fish Shell function for sourcing standard .env files :
. (sed 's/^/export /' .env | psub)
(And yet another mention of Taskfile that I’ll definitely look into nowG)
I want to automatically get the PDF version of quarto/reveal presentations.
The usual way would be to open the presentation in export mode e
, then print with no margins through the usual print window.
I want to do this automatically as part of a CI/CD pipeliene.
selenium-print · PyPI / bubblegumsoldier/selenium-print uses selenium+chromium to do this.
As for the printing options available in Chrome, this looks relevant:
selenium-print/seleniumprint/drivers/chrome_pdf_driver.py at main · bubblegumsoldier/selenium-print
pdf = self.driver.execute_cdp_cmd("Page.printToPDF", {"printBackground": True})
OK, so it’s all a static option.
Chrome DevTools Protocol - Page domain has the other available options — which is what I need.
The rest of the code feels like a wrapper to this — maybe I can drop the entire library and just use these single bits?
TL;DR use your own personal settings, then “dev settings” (!), then create one but set the resource owner to the organization.
(As of 2024-10-14. Hard to find clear AND CORRECT documentation on this.)
Create access token for organization · community · Discussion #74701.
string collect
: string-collect - join strings into one — fish-shell 3.7.1 documentationset VARNAME (cat ~/myfile | string collect)
Here string collect
makes sure it’s a multiline variable instead of an array composed of one element per line.
Gitlab mirroring didn’t work for me after trying for hours, I give up. CI/CD it is.