From 9a37dfd865fe212989f5fec1daae1d04ad2f5da8 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sat, 12 Aug 2023 20:29:33 +0000 Subject: joinbox (12aug23) git-svn-id: svn://tug.org/texlive/trunk@67902 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/latex/joinbox/joinbox.sty | 418 ++++++++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100644 Master/texmf-dist/tex/latex/joinbox/joinbox.sty (limited to 'Master/texmf-dist/tex/latex') diff --git a/Master/texmf-dist/tex/latex/joinbox/joinbox.sty b/Master/texmf-dist/tex/latex/joinbox/joinbox.sty new file mode 100644 index 00000000000..8cf2cfcb54f --- /dev/null +++ b/Master/texmf-dist/tex/latex/joinbox/joinbox.sty @@ -0,0 +1,418 @@ +%%% ---------------------------------------------------------------------------- +%%% joinbox: Join figures to same height or width with LaTeX3 +%%% Author : Nan Geng +%%% Repository: https://gitee.com/nwafu_nan/joinfigs +%%% License : The LaTeX Project Public License 1.3c +%%% ---------------------------------------------------------------------------- + +\NeedsTeXFormat{LaTeX2e} +\RequirePackage{expl3} +\ProvidesExplPackage{joinbox}{2023-08-11}{v1.0.0} + {Join figures to same height or width with LaTeX3} + +\RequirePackage{xparse} +\RequirePackage{graphicx} + +%% \tl_if_eq:NnTF 与texlive 2020的兼容性设置 +\cs_if_exist:NF \tl_if_eq:NnTF + { + \tl_new:N \l__tblr_backport_b_tl + \prg_new_protected_conditional:Npnn \tl_if_eq:Nn #1 #2 { T, F, TF } + { + \group_begin: + \tl_set:Nn \l__tblr_backport_b_tl {#2} + \exp_after:wN + \group_end: + \if_meaning:w #1 \l__tblr_backport_b_tl + \prg_return_true: + \else: + \prg_return_false: + \fi: + } + \prg_generate_conditional_variant:Nnn \tl_if_eq:Nn { c } { TF, T, F } + } + +\cs_if_exist:NF \seq_map_indexed_function:NN + { + \cs_set_eq:NN \seq_map_indexed_function:NN \seq_indexed_map_function:NN + } + +% 定义变量 +\bool_new:N \l__joinbox_vertical_bool +\bool_new:N \l__joinbox_out_scale_bool +\int_new:N \l__joinbox_baseline_int +\clist_const:Nn \c__joinbox_baseline_clist { t, vc, H, b } +\clist_new:N \l__joinbox_name_clist +\coffin_new:N \l__joinbox_out_coffin +\coffin_new:N \l__joinbox_tmpa_coffin +\coffin_new:N \l__joinbox_tmpb_coffin + +\dim_new:N \l__joinbox_out_length_dim +\dim_new:N \l__joinbox_sep_dim +\dim_new:N \l__joinbox_min_width_dim +\dim_new:N \l__joinbox_min_height_dim + +%% 选项设计 +\keys_define:nn { joinbox } + { + % 输出结果基线位置 + baseline .choice:, + baseline .value_required:n = true, + baseline .choices:nn = { t, vc, H, b } + { + \int_set_eq:NN \l__joinbox_baseline_int \l_keys_choice_int + }, + baseline .default:n = vc, + baseline .initial:n = b, + + % 输出尺寸(垂直拼接:宽度,水平拼接:高度) + outlen .code:n = { \dim_compare:nNnTF { #1 } < { 0pt } + { + \bool_set_false:N \l__joinbox_out_scale_bool + }{ + \dim_compare:nNnTF { #1 } = { 0pt } + { + \bool_set_false:N \l__joinbox_out_scale_bool + }{ + \bool_set_true:N \l__joinbox_out_scale_bool + \dim_set:Nn \l__joinbox_out_length_dim { #1 } + } + } + }, + outlen .default:n = 0pt, + outlen .initial:n = 0pt, + + % 拼音间距 + sep .dim_set:N = \l__joinbox_sep_dim, + sep .default:n = 0pt, + sep .initial:n = 0pt, + + unknown .code:n = { \__joinbox_error:n { unknown-option } } + % unknown .code:n = \__joinbox_unknown_key:V \l_keys_key_str, + } + +% \cs_new_protected:Npn \__joinbox_unknown_key:n #1 +% { +% \clist_if_in:NnTF \c__joinbox_baseline_clist { #1 } +% { +% \int_zero:N \l_tmpa_int +% \clist_map_inline:Nn \c__joinbox_baseline_clist +% { +% \int_incr:N \l_tmpa_int +% \str_if_eq:nnT { ##1 } { #1 } +% { \clist_map_break: } +% } +% \int_gset_eq:NN \l__joinbox_baseline_int \l_tmpa_int +% } +% { +% \dim_compare:nNnTF { #1 } < { 0pt } +% { +% \bool_gset_false:N \l__joinbox_out_scale_bool +% }{ +% \dim_compare:nNnTF { #1 } = { 0pt } +% { +% \bool_gset_false:N \l__joinbox_out_scale_bool +% }{ +% \bool_gset_true:N \l__joinbox_out_scale_bool +% \dim_gset:Nn \l__joinbox_out_length_dim { #1 } +% } +% } +% } +% } +% \cs_generate_variant:Nn \__joinbox_unknown_key:n { V } + +\msg_new:nnn { joinbox } { unknown-option } + { package~ option~ "\l_keys_key_tl"~ is~ unknown. } + +%% 参数设置用户接口 +\NewDocumentCommand \joinset { m } + { \keys_set:nn { joinset } {#1} } + +% 计算box盒子的总高度 +% #1---盒子变量 +\cs_if_free:NT \box_ht_plus_dp:N + { + \cs_new_protected:Npn \box_ht_plus_dp:N #1 + { \tex_dimexpr:D \box_ht:N #1 + \box_dp:N #1 \scan_stop: } + } + +% 计算coffin盒子的总高度 +% #1---盒子变量 +\cs_new_nopar:Npn \__joinbox_coffin_ht_plus_dp:N #1 + { + \coffin_ht:N #1 + \coffin_dp:N #1 + } + +% 计算两个盒子的最小宽度和最小高度 +% (最小宽度和最小宽度不一定属于同一个盒子) +\cs_new:Npn \__joinbox_calc_min_size:nn #1#2 + { + % 取得第1个盒子的宽度和高度 + \hbox_set:Nn \l_tmpa_box + { + #1 + } + + \dim_set:Nn \l_tmpa_dim + { + \box_wd:N \l_tmpa_box + } + \dim_gset_eq:NN \l__joinbox_min_width_dim \l_tmpa_dim + + \dim_set:Nn \l_tmpb_dim + { + \box_ht_plus_dp:N \l_tmpa_box + } + \dim_gset_eq:NN \l__joinbox_min_height_dim \l_tmpb_dim + + % 取得第2个盒子的宽度和高度,并与第1个盒子比较 + \hbox_set:Nn \l_tmpa_box + { + #2 + } + + \dim_set:Nn \l_tmpa_dim + { + \box_wd:N \l_tmpa_box + } + % 比较并记录最小宽度 + \dim_compare:nNnT \l__joinbox_min_width_dim > \l_tmpa_dim + { + \dim_gset_eq:NN \l__joinbox_min_width_dim \l_tmpa_dim + } + + \dim_set:Nn \l_tmpb_dim + { + \box_ht_plus_dp:N \l_tmpa_box + } + + % 比较并记录最小总高度(高度+深度) + \dim_compare:nNnT \l__joinbox_min_height_dim > \l_tmpb_dim + { + \dim_gset_eq:NN \l__joinbox_min_height_dim \l_tmpb_dim + } + } + +% 输出盒子 +\cs_new:Npn \__joinbox_typeout_coffin:N #1 + { + % 输出拼接后的盒子 + \int_case:nn { \l__joinbox_baseline_int } + { + { 1 }{% + \coffin_typeset:Nnnnn #1 + { l } { t } { 0pt } { 0pt } + } + { 2 }{% + \coffin_typeset:Nnnnn #1 + { l } { vc } { 0pt } { 0pt } + } + { 3 }{% + \coffin_typeset:Nnnnn #1 + { l } { H } { 0pt } { 0pt } + } + { 4 }{% + \coffin_typeset:Nnnnn #1 + { l } { b } { 0pt } { 0pt } + } + } + } + +% 盒子拼接内部函数 +% 将指定文件名列表中的图像拼接成一个盒子并将基线调整为中心线输出 +% #1---第1个盒子的内容 +% #2---第2个盒子的内容 +\cs_new:Npn \__joinbox_handle:nn #1#2 + { + \group_begin: + + \coffin_clear:N \l__joinbox_out_coffin + % 设置第1个盒子 + \hcoffin_set:Nn \l__joinbox_out_coffin + { + #1 + } + + \bool_if:NTF \l__joinbox_vertical_bool + { + % 按最小宽度缩放第1个盒子 + \coffin_scale:Nnn \l__joinbox_out_coffin + { + \dim_ratio:nn { \l__joinbox_min_width_dim }{ \coffin_wd:N \l__joinbox_out_coffin } + } + { + \dim_ratio:nn { \l__joinbox_min_width_dim }{ \coffin_wd:N \l__joinbox_out_coffin } + } + + % 处理第2个盒子 + \hcoffin_set:Nn \l__joinbox_tmpa_coffin + { + #2 + } + + % 按最小宽度缩放第2个盒子 + \coffin_scale:Nnn \l__joinbox_tmpa_coffin + { + \dim_ratio:nn { \l__joinbox_min_width_dim }{ \coffin_wd:N \l__joinbox_tmpa_coffin } + } + { + \dim_ratio:nn { \l__joinbox_min_width_dim }{ \coffin_wd:N \l__joinbox_tmpa_coffin } + } + + % \dim_show:N \l__joinbox_sep_dim + % 将第2个盒子拼接到第一个盒子 + \coffin_join:NnnNnnnn \l__joinbox_out_coffin + { hc } { b } \l__joinbox_tmpa_coffin { hc } { t } { 0pt } { -\l__joinbox_sep_dim } + + % 按指定输出宽度缩放输出盒子 + \bool_if:NT \l__joinbox_out_scale_bool + { + \coffin_scale:Nnn \l__joinbox_out_coffin + { + \dim_ratio:nn { \l__joinbox_out_length_dim }{ \l__joinbox_min_width_dim } + } + { + \dim_ratio:nn { \l__joinbox_out_length_dim }{ \l__joinbox_min_width_dim } + } + } + + % 输出拼接后的盒子 + \__joinbox_typeout_coffin:N \l__joinbox_out_coffin + }{ + % 按最小高度缩放第1个盒子 + \coffin_scale:Nnn \l__joinbox_out_coffin + { + \dim_ratio:nn { \l__joinbox_min_height_dim }{ \__joinbox_coffin_ht_plus_dp:N \l__joinbox_out_coffin } + } + { + \dim_ratio:nn { \l__joinbox_min_height_dim }{ \__joinbox_coffin_ht_plus_dp:N \l__joinbox_out_coffin } + } + + % 处理第2个盒子 + \hcoffin_set:Nn \l__joinbox_tmpa_coffin + { + #2 + } + + % 按最小高度缩放第2个盒子 + \coffin_scale:Nnn \l__joinbox_tmpa_coffin + { + \dim_ratio:nn { \l__joinbox_min_height_dim }{ \__joinbox_coffin_ht_plus_dp:N \l__joinbox_tmpa_coffin } + } + { + \dim_ratio:nn { \l__joinbox_min_height_dim }{ \__joinbox_coffin_ht_plus_dp:N \l__joinbox_tmpa_coffin } + } + + % 将第2个盒子拼接到第1个盒子 + \coffin_join:NnnNnnnn \l__joinbox_out_coffin + { vc } { r } \l__joinbox_tmpa_coffin { vc } { l } { \l__joinbox_sep_dim } { 0pt } + + % 按指定输出高度缩放输出盒子 + \bool_if:NT \l__joinbox_out_scale_bool + { + \coffin_scale:Nnn \l__joinbox_out_coffin + { + \dim_ratio:nn { \l__joinbox_out_length_dim }{ \l__joinbox_min_height_dim } + } + { + \dim_ratio:nn { \l__joinbox_out_length_dim }{ \l__joinbox_min_height_dim } + } + } + + % 输出拼接后的盒子 + \__joinbox_typeout_coffin:N \l__joinbox_out_coffin + } + \group_end: + } + +\cs_new:Npn \__joinbox_figs: + { + % 设置第1个图像 + \clist_pop:NN \l__joinbox_name_clist \l_tmpa_tl + \coffin_clear:N \l__joinbox_tmpa_coffin + \hcoffin_set:Nn \l__joinbox_tmpa_coffin + { + \includegraphics{ \l_tmpa_tl } + } + + % 循环处理其它图像 + \clist_map_inline:Nn \l__joinbox_name_clist + { + \coffin_clear:N \l__joinbox_tmpb_coffin + \hcoffin_set:Nn \l__joinbox_tmpb_coffin + { + \includegraphics{ ##1 } + } + + \__joinbox_calc_min_size:nn + { + \__joinbox_typeout_coffin:N \l__joinbox_tmpa_coffin + } + { + \__joinbox_typeout_coffin:N \l__joinbox_tmpb_coffin + } + + \hcoffin_set:Nn \l__joinbox_tmpa_coffin + { + \__joinbox_handle:nn + { + \__joinbox_typeout_coffin:N \l__joinbox_tmpa_coffin + } + { + \__joinbox_typeout_coffin:N \l__joinbox_tmpb_coffin + } + } + } + \__joinbox_typeout_coffin:N \l__joinbox_tmpa_coffin + } + +% 盒子拼接用户接口 +% 将两个盒子按指定方式拼接成一个盒子并将基线调整为中心线后输出 +% #1---是否为*命令,如有*则采用水平拼接,无*则采用垂直拼接 +% #2---可选参数,用key-value选项指定拼接参数 +% #3---第1个盒子的内容 +% #4---第2个盒子的内容 +\NewDocumentCommand{\joinbox}{ s O{} m m} + { + \IfBooleanTF{#1} + { + \bool_set_false:N \l__joinbox_vertical_bool + }{ + \bool_set_true:N \l__joinbox_vertical_bool + } + + \group_begin: + % 设置拼接参数 + \keys_set:nn { joinbox } { #2 } + % 计算最小宽度和高度 + \__joinbox_calc_min_size:nn { #3 } { #4 } + % 拼接输出 + \__joinbox_handle:nn { #3 }{ #4 } + \group_end: + } + +% 图像拼接用户接口 +% 将指定文件名列表中的图像拼接成一个盒子并将基线调整为中心线输出 +% #1---是否为*命令,如有*则采用水平拼接,无*则采用垂直拼接 +% #2---可选参数,用key-value选项指定拼接参数 +% #3---必选参数,用逗号分隔的,需要拼接的图像文件名称(可以带有路径) +\NewDocumentCommand{\joinfigs}{ s O{} m} + { + \IfBooleanTF{#1} + { + \bool_set_false:N \l__joinbox_vertical_bool + }{ + \bool_set_true:N \l__joinbox_vertical_bool + } + + \group_begin: + % 设置拼接参数 + \keys_set:nn { joinbox } { #2 } + % 设置文件名列表 + \clist_set:Nn \l__joinbox_name_clist { #3 } + % 拼接图像 + \__joinbox_figs: + \group_end: + } + +\endinput -- cgit v1.2.3