2026-07-18 18:48:23 +02:00
|
|
|
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:
|
2026-07-27 20:25:49 +02:00
|
|
|
self.file_error_message = f'\nERROR: Image "{self.basename}" not found'
|
2026-07-18 18:48:23 +02:00
|
|
|
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:
|
2026-07-27 20:25:49 +02:00
|
|
|
self.file_error_message = f'\nERROR: Image "{self.rel}" (the :rel image) not found'
|
2026-07-18 18:48:23 +02:00
|
|
|
|
|
|
|
|
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_font,
|
Option sets: a .o target for shared parameters
A named group of optional parameters, declared once and used by several
klammers, so a writer learns one vocabulary instead of a spelling per
klammer. The "o" target is a pseudo-target beside "k": "k" declares a
klammer's interface and documents it, "o" declares an option interface and
documents it, and neither produces output for any target.
@@caption_args.o :caption :number.bool true :caption_side.side
: Arguments that define a caption for a block element @@
@@code.k :filename @hpos_args :hpos left @ @caption_args :caption_side top @
| text.literal : A source file displayed verbatim @@
A set is used only in the parameter list of a ".k" declaration -- the one
place a klammer's interface is declared once for all of its targets -- and
is resolved as that list is read. Names and types come from the set; a
default may be overridden where it is used. A klammer application in a
parameter list is now a definition-time error.
The SKS gains the sets caption_args and hpos_args (:hpos and :offset), and
@table, @image, @image_grid, @reference and @show gain .k declarations. A
distance is no longer written as a position: :hpos 4em is rejected, and the
same layout is :hpos left :offset 4em. Code listings are numbered by
default, like tables and figures.
New engine sources mac/option_set{,_registry}.{h,cpp}; tst/ ships two more
suites, option_set_test.sh and signature_test.sh (twelve in all).
(from dev 34e536cb0329)
2026-08-06 13:11:37 +02:00
|
|
|
self.hpos, self.caption_side, False, self.caption_font_size,
|
|
|
|
|
offset=self.offset)
|
2026-07-18 18:48:23 +02:00
|
|
|
|
|
|
|
|
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,
|
Option sets: a .o target for shared parameters
A named group of optional parameters, declared once and used by several
klammers, so a writer learns one vocabulary instead of a spelling per
klammer. The "o" target is a pseudo-target beside "k": "k" declares a
klammer's interface and documents it, "o" declares an option interface and
documents it, and neither produces output for any target.
@@caption_args.o :caption :number.bool true :caption_side.side
: Arguments that define a caption for a block element @@
@@code.k :filename @hpos_args :hpos left @ @caption_args :caption_side top @
| text.literal : A source file displayed verbatim @@
A set is used only in the parameter list of a ".k" declaration -- the one
place a klammer's interface is declared once for all of its targets -- and
is resolved as that list is read. Names and types come from the set; a
default may be overridden where it is used. A klammer application in a
parameter list is now a definition-time error.
The SKS gains the sets caption_args and hpos_args (:hpos and :offset), and
@table, @image, @image_grid, @reference and @show gain .k declarations. A
distance is no longer written as a position: :hpos 4em is rejected, and the
same layout is :hpos left :offset 4em. Code listings are numbered by
default, like tables and figures.
New engine sources mac/option_set{,_registry}.{h,cpp}; tst/ ships two more
suites, option_set_test.sh and signature_test.sh (twelve in all).
(from dev 34e536cb0329)
2026-08-06 13:11:37 +02:00
|
|
|
self.hpos, self.caption_side, offset=self.offset)
|
2026-07-18 18:48:23 +02:00
|
|
|
#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}}}'
|
Option sets: a .o target for shared parameters
A named group of optional parameters, declared once and used by several
klammers, so a writer learns one vocabulary instead of a spelling per
klammer. The "o" target is a pseudo-target beside "k": "k" declares a
klammer's interface and documents it, "o" declares an option interface and
documents it, and neither produces output for any target.
@@caption_args.o :caption :number.bool true :caption_side.side
: Arguments that define a caption for a block element @@
@@code.k :filename @hpos_args :hpos left @ @caption_args :caption_side top @
| text.literal : A source file displayed verbatim @@
A set is used only in the parameter list of a ".k" declaration -- the one
place a klammer's interface is declared once for all of its targets -- and
is resolved as that list is read. Names and types come from the set; a
default may be overridden where it is used. A klammer application in a
parameter list is now a definition-time error.
The SKS gains the sets caption_args and hpos_args (:hpos and :offset), and
@table, @image, @image_grid, @reference and @show gain .k declarations. A
distance is no longer written as a position: :hpos 4em is rejected, and the
same layout is :hpos left :offset 4em. Code listings are numbered by
default, like tables and figures.
New engine sources mac/option_set{,_registry}.{h,cpp}; tst/ ships two more
suites, option_set_test.sh and signature_test.sh (twelve in all).
(from dev 34e536cb0329)
2026-08-06 13:11:37 +02:00
|
|
|
result = latex_util.caption_wrapper(result, self.hpos, offset=self.offset)
|
2026-07-18 18:48:23 +02:00
|
|
|
name = f"Reference-Figure-{Image.id}"
|
|
|
|
|
result = f"\\hypertarget{{{name}}}{{}}\\label{{Label-{name}}}\n{result}"
|
|
|
|
|
Image.id += 1
|
Option sets: a .o target for shared parameters
A named group of optional parameters, declared once and used by several
klammers, so a writer learns one vocabulary instead of a spelling per
klammer. The "o" target is a pseudo-target beside "k": "k" declares a
klammer's interface and documents it, "o" declares an option interface and
documents it, and neither produces output for any target.
@@caption_args.o :caption :number.bool true :caption_side.side
: Arguments that define a caption for a block element @@
@@code.k :filename @hpos_args :hpos left @ @caption_args :caption_side top @
| text.literal : A source file displayed verbatim @@
A set is used only in the parameter list of a ".k" declaration -- the one
place a klammer's interface is declared once for all of its targets -- and
is resolved as that list is read. Names and types come from the set; a
default may be overridden where it is used. A klammer application in a
parameter list is now a definition-time error.
The SKS gains the sets caption_args and hpos_args (:hpos and :offset), and
@table, @image, @image_grid, @reference and @show gain .k declarations. A
distance is no longer written as a position: :hpos 4em is rejected, and the
same layout is :hpos left :offset 4em. Code listings are numbered by
default, like tables and figures.
New engine sources mac/option_set{,_registry}.{h,cpp}; tst/ ships two more
suites, option_set_test.sh and signature_test.sh (twelve in all).
(from dev 34e536cb0329)
2026-08-06 13:11:37 +02:00
|
|
|
# \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)
|
2026-07-18 18:48:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def txt(self):
|
|
|
|
|
return f"[Image: {self.basename}\nCaption: {self.caption}]"
|