From d14c7df684f6bb224cdcb1eefa7baf11b5fef3ee Mon Sep 17 00:00:00 2001 From: Max Schwarz Date: Wed, 30 Jul 2025 09:12:54 +0200 Subject: [PATCH 1/5] initial work on full trimming --- graphicscache.dtx | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/graphicscache.dtx b/graphicscache.dtx index e4b3187..4b85b08 100644 --- a/graphicscache.dtx +++ b/graphicscache.dtx @@ -227,6 +227,8 @@ \newif\ifgraphicscache@hashshortnames \newif\ifgraphicscache@gsnotavailable\graphicscache@gsnotavailablefalse \newif\ifgraphicscache@dorender +\newif\ifgraphicscache@trim +\newif\ifgraphicscache@clip \def\graphicscache@graphicsargs{} \newlength\graphicscache@tmplen \newcommand{\graphicscache@addarg}[1]{% @@ -236,6 +238,13 @@ \edef\graphicscache@graphicsargs{\graphicscache@graphicsargs,#1}% \fi } +\def\graphicscache@parsetrim#1 #2 #3 #4 #5\\{% + \Gin@defaultbp\graphicscache@trim@left{#1}% + \Gin@defaultbp\graphicscache@trim@bottom{#2}% + \Gin@defaultbp\graphicscache@trim@right{#3}% + \Gin@defaultbp\graphicscache@trim@top{#4}% + \graphicscache@trimtrue +} \pgfkeys{ /graphicscache/.cd, render/.is if=graphicscache@render, @@ -286,8 +295,8 @@ \graphicscache@addarg{height=\the\graphicscache@tmplen}% \fi }, - trim/.code={\graphicscache@addarg{trim=#1}}, - clip/.code={\graphicscache@addarg{clip}}, + trim/.code={\graphicscache@addarg{trim=#1}\graphicscache@parsetrim#1 \\}, + clip/.code={\graphicscache@addarg{clip}\graphicscache@cliptrue}, angle/.code={% \edef\graphicscache@tmp{#1}% \graphicscache@addarg{angle=\graphicscache@tmp}% @@ -422,6 +431,10 @@ % Here, we actually perform the rendering. Sadly, this is quite complex due % to cross-platform support. % \begin{macrocode} +\newcommand{\graphicscache@isbitmap}[1]{% + \fullexpandarg + \IfSubStr*{,png,PNG,jpg,JPG,jpeg,JPEG,}{,#1,}% +} \newcommand{\graphicscache@dorender}{% \PackageInfo{graphicscache}{Rendering \graphicscache@outputhash: \graphicscache@fname\space with args: \graphicscache@graphicsargs\space (master file)}% \ifwindows @@ -429,6 +442,30 @@ \else \graphicscache@ShellEscape{mkdir -p "\graphicscache@cachedir"}% \fi + \ifgraphicscache@trim + \ifgraphicscache@clip + \PackageInfo{graphicscache}{Trim: \graphicscache@trim@left, \graphicscache@trim@bottom, \graphicscache@trim@right, \graphicscache@trim@top}% + \filename@parse{\graphicscache@fname}% + \PackageInfo{graphicscache}{Ext: |\filename@ext|}% + \graphicscache@isbitmap{\filename@ext}{% + \PackageInfo{graphicscache}{is bitmap!}% + \graphicscache@ShellEscape{identify -units PixelsPerInch -format '\@percentchar[fx:int(resolution.x)]' "\graphicscache@fname" > \graphicscache@output.dpi}% + \CatchFileDef{\graphicscache@fdpi}{\graphicscache@output.dpi}{}% +% \input{\graphicscache@output.dpi} + \PackageInfo{graphicscache}{Detected DPI: \graphicscache@fdpi}% + \edef\graphicscache@trim@left@pix{\strip@pt\dimexpr1bp*\graphicscache@trim@left*\graphicscache@fdpi*65535/\dimexpr 1in\relax\relax}% + \edef\graphicscache@trim@bottom@pix{\strip@pt\dimexpr1bp*\graphicscache@trim@bottom*\graphicscache@fdpi*65535/\dimexpr 1in\relax\relax}% + \edef\graphicscache@trim@right@pix{\strip@pt\dimexpr1bp*\graphicscache@trim@right*\graphicscache@fdpi*65535/\dimexpr 1in\relax\relax}% + \edef\graphicscache@trim@top@pix{\strip@pt\dimexpr1bp*\graphicscache@trim@top*\graphicscache@fdpi*65535/\dimexpr 1in\relax\relax}% + \PackageInfo{graphicscache}{Detected left: \graphicscache@trim@left@pix}% + }{% + \PackageInfo{graphicscache}{no bitmap!}% + }% + % Compute pixels + % \setlength{\dimen@}{ + % \setlength{\graphicscache@trim@pixel@left}{\graphicscache@trim@left bp} + \fi + \fi % \end{macrocode} % First, render the graphics. % \begin{macrocode} From bb03dfb9aca1234c7ecd55d147b5af9987fb0bd5 Mon Sep 17 00:00:00 2001 From: Max Schwarz Date: Wed, 30 Jul 2025 09:17:12 +0200 Subject: [PATCH 2/5] trim example --- example/trim.tex | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 example/trim.tex diff --git a/example/trim.tex b/example/trim.tex new file mode 100644 index 0000000..825ac00 --- /dev/null +++ b/example/trim.tex @@ -0,0 +1,11 @@ +\documentclass[]{article} + +\usepackage{graphicscache} + +\begin{document} + +\includegraphics[clip,trim=10 20pt 1mm 10]{myimage.png} + +\includegraphics{myimage.png} + +\end{document} From 45d2c88eea1caef4f4cafc2d1afd93ba52cea41c Mon Sep 17 00:00:00 2001 From: Max Schwarz Date: Wed, 30 Jul 2025 12:26:03 +0200 Subject: [PATCH 3/5] full clip works --- graphicscache.dtx | 87 +++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/graphicscache.dtx b/graphicscache.dtx index 4b85b08..1d8e1b9 100644 --- a/graphicscache.dtx +++ b/graphicscache.dtx @@ -220,6 +220,8 @@ \RequirePackage{ifplatform} \RequirePackage{pdftexcmds} \RequirePackage{ltxcmds} +\RequirePackage{xfp} +\RequirePackage{etoolbox} \newif\ifgraphicscache@render \newif\ifgraphicscache@disable \newif\ifgraphicscache@compress @@ -229,6 +231,7 @@ \newif\ifgraphicscache@dorender \newif\ifgraphicscache@trim \newif\ifgraphicscache@clip +\newif\ifgraphicscache@fullclip \def\graphicscache@graphicsargs{} \newlength\graphicscache@tmplen \newcommand{\graphicscache@addarg}[1]{% @@ -239,10 +242,10 @@ \fi } \def\graphicscache@parsetrim#1 #2 #3 #4 #5\\{% - \Gin@defaultbp\graphicscache@trim@left{#1}% - \Gin@defaultbp\graphicscache@trim@bottom{#2}% - \Gin@defaultbp\graphicscache@trim@right{#3}% - \Gin@defaultbp\graphicscache@trim@top{#4}% + \Gin@defaultbp\graphicscache@trim@l{#1}% + \Gin@defaultbp\graphicscache@trim@b{#2}% + \Gin@defaultbp\graphicscache@trim@r{#3}% + \Gin@defaultbp\graphicscache@trim@t{#4}% \graphicscache@trimtrue } \pgfkeys{ @@ -277,6 +280,9 @@ hashshortnames/.is if=graphicscache@hashshortnames, hashshortnames=false, % \end{macrocode} +% \begin{macrocode} + fullclip/.is if=graphicscache@fullclip, +% \end{macrocode} % We now define the list of supported graphicx arguments: % \begin{macrocode} width/.code={% @@ -345,6 +351,20 @@ \directlua{os.execute("\luaescapestring{#1}")}} \fi % \end{macrocode} +% \begin{macrocode} +\newcommand{\graphicscache@isbitmap}[1]{% + \fullexpandarg + \IfSubStr*{,png,PNG,jpg,JPG,jpeg,JPEG,}{,#1,}% +} +\def\graphicscache@trunc#1.#2\@empty{#1}% +\newcommand{\graphicscache@pix}[2]{% + % Compute trim amount in pixels + \edef\graphicscache@trimtmp{\fpeval{#2 * \graphicscache@fdpi}}% + % Now truncate & compute remainder + \edef#1{\expandafter\graphicscache@trunc\graphicscache@trimtmp.\@empty}% + \edef#2{\fpeval{(\graphicscache@trimtmp - #1) / \graphicscache@fdpi}}% +} +% \end{macrocode} % % \begin{macro}{\graphicscache@callgswithname} % This macro calls ghostscript using the name specified in the first argument. @@ -431,10 +451,6 @@ % Here, we actually perform the rendering. Sadly, this is quite complex due % to cross-platform support. % \begin{macrocode} -\newcommand{\graphicscache@isbitmap}[1]{% - \fullexpandarg - \IfSubStr*{,png,PNG,jpg,JPG,jpeg,JPEG,}{,#1,}% -} \newcommand{\graphicscache@dorender}{% \PackageInfo{graphicscache}{Rendering \graphicscache@outputhash: \graphicscache@fname\space with args: \graphicscache@graphicsargs\space (master file)}% \ifwindows @@ -444,26 +460,34 @@ \fi \ifgraphicscache@trim \ifgraphicscache@clip - \PackageInfo{graphicscache}{Trim: \graphicscache@trim@left, \graphicscache@trim@bottom, \graphicscache@trim@right, \graphicscache@trim@top}% - \filename@parse{\graphicscache@fname}% - \PackageInfo{graphicscache}{Ext: |\filename@ext|}% - \graphicscache@isbitmap{\filename@ext}{% - \PackageInfo{graphicscache}{is bitmap!}% - \graphicscache@ShellEscape{identify -units PixelsPerInch -format '\@percentchar[fx:int(resolution.x)]' "\graphicscache@fname" > \graphicscache@output.dpi}% - \CatchFileDef{\graphicscache@fdpi}{\graphicscache@output.dpi}{}% -% \input{\graphicscache@output.dpi} - \PackageInfo{graphicscache}{Detected DPI: \graphicscache@fdpi}% - \edef\graphicscache@trim@left@pix{\strip@pt\dimexpr1bp*\graphicscache@trim@left*\graphicscache@fdpi*65535/\dimexpr 1in\relax\relax}% - \edef\graphicscache@trim@bottom@pix{\strip@pt\dimexpr1bp*\graphicscache@trim@bottom*\graphicscache@fdpi*65535/\dimexpr 1in\relax\relax}% - \edef\graphicscache@trim@right@pix{\strip@pt\dimexpr1bp*\graphicscache@trim@right*\graphicscache@fdpi*65535/\dimexpr 1in\relax\relax}% - \edef\graphicscache@trim@top@pix{\strip@pt\dimexpr1bp*\graphicscache@trim@top*\graphicscache@fdpi*65535/\dimexpr 1in\relax\relax}% - \PackageInfo{graphicscache}{Detected left: \graphicscache@trim@left@pix}% - }{% - \PackageInfo{graphicscache}{no bitmap!}% - }% - % Compute pixels - % \setlength{\dimen@}{ - % \setlength{\graphicscache@trim@pixel@left}{\graphicscache@trim@left bp} + \ifgraphicscache@fullclip + \PackageInfo{graphicscache}{Trim: \graphicscache@trim@l, \graphicscache@trim@b, \graphicscache@trim@r, \graphicscache@trim@t}% + \filename@parse{\graphicscache@fname}% + \PackageInfo{graphicscache}{Ext: |\filename@ext|}% + \graphicscache@isbitmap{\filename@ext}{% + \PackageInfo{graphicscache}{is bitmap!}% + \graphicscache@ShellEscape{identify -units PixelsPerInch -format '\@percentchar[fx:int(resolution.x)]' "\graphicscache@fname" > \graphicscache@output.dpi}% + \CatchFileDef{\graphicscache@fdpi}{\graphicscache@output.dpi}{}% + \PackageInfo{graphicscache}{Detected DPI: \graphicscache@fdpi (default 71)}% + \ifnumequal{\graphicscache@fdpi}{0}{\edef\graphicscache@fdpi{71}}{}% + \edef\graphicscache@fdpi{\fpeval{0.01389 * \graphicscache@fdpi}}% + \graphicscache@pix{\graphicscache@trim@l@pix}{\graphicscache@trim@l}% + \graphicscache@pix{\graphicscache@trim@b@pix}{\graphicscache@trim@b}% + \graphicscache@pix{\graphicscache@trim@r@pix}{\graphicscache@trim@r}% + \graphicscache@pix{\graphicscache@trim@t@pix}{\graphicscache@trim@t}% + \PackageInfo{graphicscache}{Pixel trims: + \graphicscache@trim@l@pix +\graphicscache@trim@l bp, + \graphicscache@trim@b@pix +\graphicscache@trim@b bp, + \graphicscache@trim@r@pix +\graphicscache@trim@r bp, + \graphicscache@trim@t@pix +\graphicscache@trim@t bp + }% + \graphicscache@ShellEscape{convert "\graphicscache@fname" -gravity Northwest -chop \graphicscache@trim@l@pix x\graphicscache@trim@t@pix\space -gravity Southeast -chop \graphicscache@trim@r@pix x\graphicscache@trim@b@pix\space \graphicscache@output.crop.\filename@ext}% + \edef\graphicscache@fname{\graphicscache@output.crop.\filename@ext}% + \graphicscache@addarg{trim=\graphicscache@trim@l\space\graphicscache@trim@b\space\graphicscache@trim@r\space\graphicscache@trim@t}% + }{% + \PackageInfo{graphicscache}{no bitmap!}% + }% + \fi \fi \fi % \end{macrocode} @@ -687,7 +711,12 @@ \else \edef\graphicscache@hashedname{\graphicscache@fname}% \fi - \edef\graphicscache@outputhash{\pdf@mdfivesum{\graphicscache@options\graphicscache@graphicsargs\graphicscache@hashedname}}% + \ifgraphicscache@fullclip + \def\graphicscache@clipmode{fullclip}% + \else + \def\graphicscache@clipmode{nclip}% + \fi + \edef\graphicscache@outputhash{\pdf@mdfivesum{\graphicscache@options\graphicscache@graphicsargs\graphicscache@clipmode\graphicscache@hashedname}}% \edef\graphicscache@output{\graphicscache@cachedir/\graphicscache@outputhash.pdf}% \ifgraphicscache@listing \PackageInfo{graphicscache}{graphicscache: includegraphics\{#2\} => \graphicscache@output}% From 9f2f032b166c770767e233ef62fb9bfc80f9b403 Mon Sep 17 00:00:00 2001 From: Max Schwarz Date: Wed, 30 Jul 2025 14:30:54 +0200 Subject: [PATCH 4/5] make xfp dependency optional --- graphicscache.dtx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/graphicscache.dtx b/graphicscache.dtx index 1d8e1b9..72e5059 100644 --- a/graphicscache.dtx +++ b/graphicscache.dtx @@ -220,8 +220,8 @@ \RequirePackage{ifplatform} \RequirePackage{pdftexcmds} \RequirePackage{ltxcmds} -\RequirePackage{xfp} \RequirePackage{etoolbox} +\IfFileExists{xfp.sty}{\RequirePackage{xfp}}{} \newif\ifgraphicscache@render \newif\ifgraphicscache@disable \newif\ifgraphicscache@compress @@ -461,6 +461,9 @@ \ifgraphicscache@trim \ifgraphicscache@clip \ifgraphicscache@fullclip + \ifx\fpeval\undefined + \PackageError{graphicscache}{The fullclip feature requires the xfp package.}% + \fi \PackageInfo{graphicscache}{Trim: \graphicscache@trim@l, \graphicscache@trim@b, \graphicscache@trim@r, \graphicscache@trim@t}% \filename@parse{\graphicscache@fname}% \PackageInfo{graphicscache}{Ext: |\filename@ext|}% From 3658754d224fa9165fe4cb810598d92a5c6a6429 Mon Sep 17 00:00:00 2001 From: Max Schwarz Date: Wed, 30 Jul 2025 14:34:47 +0200 Subject: [PATCH 5/5] document fullclip option --- graphicscache.dtx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/graphicscache.dtx b/graphicscache.dtx index 72e5059..727e326 100644 --- a/graphicscache.dtx +++ b/graphicscache.dtx @@ -159,6 +159,11 @@ % |graphicscache| will fall back to |graphicx| in-place rendering. % This can be used to perform a final release (see \cref{sec:release}). % +% \DescribeKey{fullclip}'=true|false' +% When |fullclip| is enabled, graphicscache will call ImageMagick's |convert| +% to trim images, ensuring that only the specified rectangle takes up file +% space in the resulting PDF. +% % \DescribeKey{cachedir}'=' % This key can be used to move the cache directory to another location. % The default value is |graphicscache|.