Files
klammertext/sks/image/image.py
T
ack af29bbf7ac Unicode sequences, @typeface, and the font/typeface distinction
A run of Unicode code points now needs one pair of carets, not one pair
each: ^9053 53EF 9053^ renders the characters adjacently, and a single
character inside such a run stands for itself.  An invalid code point is
an error naming the position that wrote it, rather than an apology
rendered into the finished document; noncharacters are refused alongside
surrogates; and a code point that lands on a Klammertext special is safe
through the re-reads that assemble a document.  The character tables now
produce the precomposed form, so a diacritic written as ^a" and one typed
directly are the same text to a search or a copy-paste.

"kdesc -u" describes how to write a Unicode character, with tables of
glyphs beside the codes that produce them.  It is new and not yet
complete: it predates the sequence form and the typeface klammer below.

A typeface and a style are no longer both called "font".  A typeface is a
family resolved by name; a style code is the one letter naming a type
style.  So @document takes :serif_typeface and its siblings, a table takes
:style, captions take :caption_style and :caption_size, the uniform scale
is :text_scale, and the command is "kdesc --typeface".  This renames
arguments a document may already use; an old name is a located error
rather than a silent omission.

@typeface sets a passage in another typeface for the length of that
passage:

    @typeface Noto Sans Egyptian Hieroglyphs | ^132AA 133CF^ :scale 1.5 @

Writing the klammer is the whole declaration -- the document resolves the
typeface, embeds it in what it produces, and carries its license along.
Two typefaces for scripts no text font covers now ship with Klammertext:
Noto Sans Egyptian Hieroglyphs and Noto Sans Cuneiform.  Every typeface in
the distribution now carries its license file.

(from dev 61e598698891)
2026-08-25 23:30:55 +02:00

153 lines
5.8 KiB
Python

import sys
import os
_klammertext_home = os.environ.get('KLAMMERTEXT_HOME', os.path.expanduser('~/projects/klammertext/K'))
sys.path.append(os.path.join(_klammertext_home, 'sks/kutil'))
sys.path.append(os.path.join(_klammertext_home, 'sks/target'))
import re
import os
import shutil
import kutil
import html_util
import latex_util
import klammer_base
import image_cache
import pprint
from html_util import E
import sys
class Image(klammer_base.Klammer_base):
id = 0
def __init__(self, K, as_string=True, width=None):
super().__init__(K)
# pprint.pprint(self.__dict__)
# self.show()
# /dev/shm is a fast RAM-backed tmpfs on Linux; on macOS it does not
# exist, so fall back to the platform temp directory.
cache_dir = "/dev/shm"
if not os.path.isdir(cache_dir):
import tempfile
cache_dir = tempfile.gettempdir()
self.cache = image_cache.Image_cache(cache_dir, self.Image_search_path, verbose=False)
self.basename = klammer_base.unescape_ktesc(self.basename)
self.source, self.pwidth, self.pheight, self.file_error = self.cache.get(self.K_target, self.basename)
if self.file_error:
self.file_error_message = f'\nERROR: Image "{self.basename}" not found'
self.as_string = as_string
if width:
self.width = width
self.rel_image = None
self.rel_fraction = 1.0
if self.rel:
self.rel_image, self.rel_pwidth, self.rel_pheight, self.file_error = self.cache.get(self.K_target, self.rel)
self.rel_fraction = self.pwidth / self.rel_pwidth
if self.file_error:
self.file_error_message = f'\nERROR: Image "{self.rel}" (the :rel image) not found'
def html(self):
img_dir = f"{self.K_output_dir}/{self.K_output_basename}/{self.Image_output_dir}"
# output_dir = self.K_output_dir or "."
# input_basename = self.__dict__.get("K_input_name", "")
# input_basename = "/" + input_basename if input_basename else ""
# img_dir = f"{output_dir}/{self.image_output_dir}{input_basename}"
#print("img_dir:", img_dir)
if not os.path.exists(img_dir):
os.makedirs(img_dir)
if not os.path.exists(f"{img_dir}/{os.path.basename(self.source)}"):
shutil.copy2(self.source, img_dir)
# width, scale_x, scale_y = kutil.parse_length(
# "html",
# self.width if self.width != "none" else self.image_default_width)
scale_x, scale_y = 1, 1 # Old
result = E("img")
if self.id:
result.attr("id", self.id)
filename = f"{self.Image_output_dir}/{os.path.basename(self.source)}"
result.attr("src", filename).attr("alt", os.path.basename(filename))
#if self.width:
# kutil.msg("rel: " + str(self.rel_fraction))
length, value, ltype = kutil.parse_length("html", self.width, self.rel_fraction)
if ltype == "w":
percent = float(value) * 100
result.sty(f"width: {percent}%")
else:
result.attr("width", length)
if self.border:
result.cls("image_border")
# print(result)
#result.attr("style", f"width: {width}")
# if width and width != "none":
# result.attr("style", f"width: {width}")
# if width == "none":
# if scale_x:
# result.attr("style", "width: 0px;")
# result.attr("scale-x", scale_x)
# elif scale_y:
# result.attr("style", "height: 0px;")
# result.attr("scale-y", scale_y)
if self.file_error:
self.caption += self.file_error_message
result = html_util.add_caption(
result, "Figure", self.number, self.caption, self.caption_style,
self.hpos, self.caption_side, False, self.caption_size,
offset=self.offset)
result = E("div").body(result).cls("image_margin")
if self.as_string:
result = str(result) + "\n"
return result
def tex(self):
# kutil.msg(f"number: {self.number}")
#selfsource, width, height = self.cache.get(self.K_target, self.basename)
source = os.path.abspath(self.source)
#if self.abswidth != 0:
# width = f"{self.abswidth}\\paperwidth"
#if self.caption or self.number:
# width = "\\textwidth"
#else:
width = kutil.parse_length("tex", self.width, self.rel_fraction)[0]
width = re.sub("px", "pt", width)
#result = f'\\includegraphics[width={width}]{{{source}}}'
if self.number or self.caption:
result = f'\\includegraphics[width=\\textwidth]{{{source}}}'
if self.file_error:
self.caption += self.file_error_message
result = latex_util.add_caption(
result, "Figure", self.number, self.caption, width,
self.hpos, self.caption_side, offset=self.offset)
#result, "Figure", self.number, self.caption, self.hpos, self.caption_side,
#self.width, self.caption_side_center, self.vmargin, self.caption_margin)
else:
result = f'\\includegraphics[width={width}]{{{source}}}'
result = latex_util.caption_wrapper(result, self.hpos, offset=self.offset)
name = f"Reference-Figure-{Image.id}"
result = f"\\hypertarget{{{name}}}{{}}\\label{{Label-{name}}}\n{result}"
Image.id += 1
# \includegraphics (bare or inside a caption wrapper's minipage) is
# box material: it must sit in vertical mode or it is typeset beside
# any text it follows.
return latex_util.block(result)
# Better to cause an error; there's no good text substitute for an image
# def txt(self):
# return f"[Image: {self.basename}\nCaption: {self.caption}]"