if not modules then modules = { } end modules ['grph-con'] = { version = 1.001, comment = "companion to grph-inc.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local P, R, S, Cc, C, Cs, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cc, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.match local tonumber = tonumber local find = string.find local longtostring = string.longtostring local formatters = string.formatters local expandfilename = dir.expandname local isfile = lfs.isfile local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex local codeinjections = backends.codeinjections local nodeinjections = backends.nodeinjections local report_figures = logs.reporter("system","graphics") local variables = interfaces.variables local v_high = variables.high local v_low = variables.low local v_medium = variables.medium local v_yes = variables.yes local figures = figures local converters = figures.converters local programs = figures.programs local runprogram = programs.run do -- eps | ps -- \externalfigure[cow.eps] -- \externalfigure[cow.pdf][conversion=stripped] -- todo: colorspace -- todo: lowres local epsconverter = converters.eps converters.ps = epsconverter local function gscrop(specification) return (specification and specification.crop == v_yes) and "-dEPSCrop" or "" end local resolutions = { [v_low] = "screen", [v_medium] = "ebook", [v_high] = "prepress", } local runner = sandbox.registerrunner { name = "eps to pdf", program = { windows = os.platform == "win64" and "gswin64c" or "gswin32c", unix = "gs", }, template = longtostring [[ -q -sDEVICE=pdfwrite -dNOPAUSE -dNOCACHE -dBATCH -dAutoRotatePages=/None -dPDFSETTINGS=/%presets% %crop% -dCompatibilityLevel=%level% -sOutputFile=%newname% %colorspace% %oldname% -c quit ]], checkers = { oldname = "readable", newname = "writable", presets = "string", level = "string", colorspace = "string", -- crop = "string", }, } programs.epstopdf = { resolutions = epstopdf, runner = runner } programs.gs = programs.epstopdf local cleanups = { } local cleaners = { } local whitespace = lpeg.patterns.whitespace local quadruple = Ct((whitespace^0 * lpeg.patterns.number/tonumber * whitespace^0)^4) local betterbox = P("%%BoundingBox:") * quadruple * P("%%HiResBoundingBox:") * quadruple * P("%AI3_Cropmarks:") * quadruple * P("%%CropBox:") * quadruple / function(b,h,m,c) return formatters["%%%%BoundingBox: %r %r %r %r\n%%%%HiResBoundingBox: %F %F %F %F\n%%%%CropBox: %F %F %F %F\n"]( m[1],m[2],m[3],m[4], -- rounded integer m[1],m[2],m[3],m[4], -- real number m[1],m[2],m[3],m[4] ) end local nocrap = P("%") / "" * ( (P("AI9_PrivateDataBegin") * P(1)^0) / "%%%%EOF" + (P("%EOF") * whitespace^0 * P("%AI9_PrintingDataEnd") * P(1)^0) / "%%%%EOF" + (P("AI7_Thumbnail") * (1-P("%%EndData"))^0 * P("%%EndData")) / "" ) local whatever = nocrap + P(1) local pattern = Cs((betterbox * whatever^1 + whatever)^1) directives.register("graphics.conversion.eps.cleanup.ai",function(v) cleanups.ai = v end) cleaners.ai = function(name) local tmpname = name .. ".tmp" io.savedata(tmpname,lpegmatch(pattern,io.loaddata(name) or "")) return tmpname end function epsconverter.pdf(oldname,newname,resolution,colorspace,specification) -- the resolution interface might change local presets = resolutions[resolution or "high"] or resolutions.high local level = codeinjections.getformatoption("pdf_level") or "1.3" local tmpname = oldname if not tmpname or tmpname == "" or not isfile(tmpname) then return end if cleanups.ai then tmpname = cleaners.ai(oldname) end if colorspace == "gray" then colorspace = "-sColorConversionStrategy=Gray -sProcessColorModel=DeviceGray" -- colorspace = "-sColorConversionStrategy=Gray" else colorspace = nil end runner { newname = newname, oldname = tmpname, presets = presets, level = tostring(level), colorspace = colorspace, crop = gscrop(specification), } if tmpname ~= oldname then os.remove(tmpname) end end epsconverter["gray.pdf"] = function(oldname,newname,resolution,_,specification) -- the resolution interface might change epsconverter.pdf(oldname,newname,resolution,"gray") end epsconverter.default = epsconverter.pdf end -- do -- pdf -- -- local pdfconverter = converters.pdf -- -- programs.pdftoeps = { -- runner = sandbox.registerrunner { -- name = "pdf to ps", -- command = "pdftops", -- template = [[-eps "%oldname%" "%newname%"]], -- checkers = { -- oldname = "readable", -- newname = "writable", -- } -- } -- } -- -- pdfconverter.stripped = function(oldname,newname) -- local pdftoeps = programs.pdftoeps -- can be changed -- local epstopdf = programs.epstopdf -- can be changed -- local presets = epstopdf.resolutions[resolution or ""] or epstopdf.resolutions.high -- local level = codeinjections.getformatoption("pdf_level") or "1.3" -- local tmpname = newname .. ".tmp" -- pdftoeps.runner { oldname = oldname, newname = tmpname, presets = presets, level = level } -- epstopdf.runner { oldname = tmpname, newname = newname, presets = presets, level = level } -- os.remove(tmpname) -- end -- -- figures.registersuffix("stripped","pdf") -- -- end do -- svg local svgconverter = converters.svg converters.svgz = svgconverter -- inkscape on windows only works with complete paths .. did the command line -- arguments change again? Ok, it's weirder, with -A then it's a name only when -- not . (current) -- Beware: the order of printed output lines is a bit random depending on the -- method of calling (bin or pipe) because part of the message prints to stdout -- and part to stderr. Also, on Windows, a second call to the old binaries -- doesn't return anything at all, so that is also a signal of it being old. -- This test will be dropped in 2021 anyway. local new = nil local function inkscapeformat(suffix) if new == nil then new = os.resultof("inkscape --version") or "" new = new == "" or not find(new,"Inkscape%s*0") end return new and "filename" or suffix end local function inkscapecrop(specification) return (specification and specification.crop == v_yes) and "--export-area-drawing" or "" end local runner = sandbox.registerrunner { name = "svg to something", program = "inkscape", template = longtostring [[ %oldname% %crop% --export-dpi=%resolution% --export-%format%=%newname% ]], checkers = { oldname = "readable", newname = "writable", format = "string", resolution = "string", }, defaults = { format = "pdf", resolution = "600", } } programs.inkscape = { runner = runner, } function svgconverter.pdf(oldname,newname,resolution,arguments,specification) runner { format = inkscapeformat("pdf"), resolution = "600", crop = inkscapecrop(specification), newname = expandfilename(newname), oldname = expandfilename(oldname), } end function svgconverter.png(oldname,newname) runner { format = inkscapeformat("png"), resolution = "600", crop = inkscapecrop(specification), newname = expandfilename(newname), oldname = expandfilename(oldname), } end svgconverter.default = svgconverter.pdf end do -- gif | tif local gifconverter = converters.gif local tifconverter = converters.tif local bmpconverter = converters.bmp programs.convert = { command = "gm", -- graphicmagick argument = [[convert "%oldname%" "%newname%"]], } local function converter(oldname,newname) local convert = programs.convert runprogram(convert.command, convert.argument, { newname = newname, oldname = oldname, } ) end tifconverter.pdf = converter gifconverter.pdf = converter bmpconverter.pdf = converter gifconverter.default = converter tifconverter.default = converter bmpconverter.default = converter end do -- png | jpg | profiles -- ecirgb_v2.icc -- ecirgb_v2_iccv4.icc -- isocoated_v2_300_eci.icc -- isocoated_v2_eci.icc -- srgb.icc -- srgb_v4_icc_preference.icc -- [[convert %?colorspace: -colorspace "%colorspace%" ?%]] local rgbprofile = "srgb_v4_icc_preference.icc" -- srgb.icc local cmykprofile = "isocoated_v2_eci.icc" -- isocoated_v2_300_eci.icc directives.register("graphics.conversion.rgbprofile", function(v) rgbprofile = type(v) == "string" and v or rgbprofile end) directives.register("graphics.conversion.cmykprofile",function(v) cmykprofile = type(v) == "string" and v or cmykprofile end) local jpgconverters = converters.jpg local pngconverters = converters.png local findfile = resolvers.findfile local function profiles() if not isfile(rgbprofile) then local found = findfile(rgbprofile) if not found or found == "" then found = findfile("colo-imp-"..rgbprofile) end if found and found ~= "" then rgbprofile = found else report_figures("unknown profile %a",rgbprofile) end end if not isfile(cmykprofile) then local found = resolvers.findfile(cmykprofile) if not found or found == "" then found = findfile("colo-imp-"..cmykprofile) end if found and found ~= "" then cmykprofile = found else report_figures("unknown profile %a",cmykprofile) end end return rgbprofile, cmykprofile end local checkers = { oldname = "readable", newname = "writable", rgbprofile = "string", cmykprofile = "string", resolution = "string", color = "string", } local defaults = { resolution = "600", } local pngtocmykpdf = sandbox.registerrunner { name = "png to cmyk pdf", program = "gm", template = [[convert -compress Zip -strip +profile "*" -profile %rgbprofile% -profile %cmykprofile% -sampling-factor 1x1 %oldname% %newname%]], checkers = checkers, defaults = defaults, } local jpgtocmykpdf = sandbox.registerrunner { name = "jpg to cmyk pdf", program = "gm", template = [[convert -compress JPEG -strip +profile "*" -profile %rgbprofile% -profile %cmykprofile% -sampling-factor 1x1 %oldname% %newname%]], checkers = checkers, defaults = defaults, } local pngtograypdf = sandbox.registerrunner { name = "png to gray pdf", program = "gm", template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 %oldname% %newname%]], checkers = checkers, defaults = defaults, } local jpgtograypdf = sandbox.registerrunner { name = "jpg to gray pdf", program = "gm", template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 %oldname% %newname%]], checkers = checkers, defaults = defaults, } programs.pngtocmykpdf = { runner = pngtocmykpdf } programs.jpgtocmykpdf = { runner = jpgtocmykpdf } programs.pngtograypdf = { runner = pngtograypdf } programs.jpgtograypdf = { runner = jpgtograypdf } pngconverters["cmyk.pdf"] = function(oldname,newname,resolution) local rgbprofile, cmykprofile = profiles() pngtocmykpdf { oldname = oldname, newname = newname, rgbprofile = rgbprofile, cmykprofile = cmykprofile, resolution = resolution, } end pngconverters["gray.pdf"] = function(oldname,newname,resolution) pngtograypdf { oldname = oldname, newname = newname, resolution = resolution, } end jpgconverters["cmyk.pdf"] = function(oldname,newname,resolution) local rgbprofile, cmykprofile = profiles() jpgtocmykpdf { oldname = oldname, newname = newname, rgbprofile = rgbprofile, cmykprofile = cmykprofile, resolution = resolution, } end jpgconverters["gray.pdf"] = function(oldname,newname,resolution) jpgtograypdf { oldname = oldname, newname = newname, resolution = resolution, } end -- recolor local recolorpng = sandbox.registerrunner { name = "recolor png", program = "gm", template = [[convert -recolor %color% %oldname% %newname%]], checkers = checkers, defaults = defaults, } -- this is now built in so not really needed any more programs.recolor = { runner = recolorpng } pngconverters["recolor.png"] = function(oldname,newname,resolution,arguments) recolorpng { oldname = oldname, newname = newname, resolution = resolution, color = arguments or ".5 0 0 .7 0 0 .9 0 0", } end end if CONTEXTLMTXMODE > 0 then -- This might also work ok in mkiv but is yet untested. Anyway, it's experimental as we -- go through TeX which is is inefficient. I'll improve the buffer trick. local function remap(specification) local fullname = specification.fullname if fullname then local only = file.nameonly(fullname) local name = formatters["svg-%s-inclusion"](only) local code = formatters["\\includesvgfile[%s]\\resetbuffer[%s]"](fullname,name) buffers.assign(name,code) specification.format = "buffer" specification.fullname = name end return specification end figures.remappers.svg = { mp = remap } end