Add a top-level symbol for controlling the resolution of the output

This commit is contained in:
cc-wr 2019-09-14 15:39:29 -04:00
parent 12ed6ff52b
commit 6e5b6cc6e3
4 changed files with 122 additions and 23 deletions

View File

@ -72,7 +72,7 @@ If[
(* redirect Print calls into a message to Jupyter, in order to print in the Jupyter notebook *)
(* TODO: review other methods: through EvaluationData or WSTP so we don't redefine Print *)
Unprotect[Print];
Print[args___, opts:OptionsPattern[]] :=
Print[ourArgs___, opts:OptionsPattern[]] :=
Block[
{
$inPrint=True,
@ -80,7 +80,7 @@ If[
},
If[
!FailureQ[First[$Output]],
Print[args, opts];
Print[ourArgs, opts];
loopState["printFunction"][
Import[$Output[[1,1]], "String"]
];

View File

@ -202,7 +202,34 @@ If[
applyHook[hook_, value_] /; Length[OwnValues[hook]] != 0 := hook[value];
applyHook[hook_, value_] := value;
Attributes[applyHook] := HoldAll;
(* the DPI used by browsers according to the CSS standard:
https://www.w3.org/TR/css3-values/#absolute-lengths *)
cssResolutionDPI = 96;
(* a top-level symbol for controlling the resolution of the output *)
Global`$JupyterResolutionDPI =
(* do not allow a value less than cssResolutionDPI as a default value for this *)
Max[
cssResolutionDPI,
(* look in SystemInformation for relevant resolutions *)
FirstCase[
Quiet[UsingFrontEnd[SystemInformation["Devices", "ScreenInformation"]]],
Verbatim[Rule]["Resolution", dpi_?IntegerQ] -> dpi,
72,
Infinity
]
];
(* a safe form of Global`$JupyterResolutionDPI *)
safeJupyterResolutionDPI :=
First[
Replace[
{Global`$JupyterResolutionDPI},
Except[{value_ /; (IntegerQ[value] && value > 0)}] -> {cssResolutionDPI}
]
];
(* can we use the Front End? *)
$canUseFrontEnd := (UsingFrontEnd[$FrontEnd] =!= Null);

View File

@ -31,7 +31,10 @@ If[
Get[FileNameJoin[{DirectoryName[$InputFileName], "Initialization.wl"}]]; (* $canUseFrontEnd, $outputSetToTeXForm,
$outputSetToTraditionalForm,
$trueFormatType, failedInBase64 *)
$trueFormatType,
safeJupyterResolutionDPI,
cssResolutionDPI,
failedInBase64 *)
(************************************
private symbols
@ -234,28 +237,88 @@ If[
toImageData[result_] :=
Module[
{
(* whether the result has been "pre-rasterized" *)
preRasterized,
(* the preprocessed form of a result *)
preprocessedForm
preprocessedForm,
(* the result of this operation *)
byteArrayResult,
(* the dimensions of the image to use *)
imageDimensions
},
(* preprocess the result *)
preRasterized = (Head[result] =!= Manipulate);
If[
Head[result] === Manipulate,
preprocessedForm = result;
preRasterized,
(* rasterize the result *)
preprocessedForm =
Rasterize[
result,
ImageResolution -> safeJupyterResolutionDPI
];
(* if the preprocessing failed, return $Failed *)
If[
FailureQ[preprocessedForm],
Return[{$Failed, $Failed}];
];
(* the "natural" image dimensions of preprocessedForm do not appear to be easily predictable,
so just use the dimensions of preprocessedForm when rasterized (again) at 72 DPI *)
imageDimensions =
Rasterize[
result,
"BoundingBox",
ImageResolution -> 72
];
If[
(FailureQ[imageDimensions]) ||
(!ListQ[imageDimensions]) ||
(Length[imageDimensions] < 2),
Return[{$Failed, $Failed}];
];
imageDimensions =
ToString /@
IntegerPart[imageDimensions[[1;;2]]/72 * cssResolutionDPI * (* also, reduce the size of the image somewhat *) 4/5];
,
preprocessedForm = Rasterize[result];
(* do not preprocess, and do not set imageDimensions *)
preprocessedForm = result;
];
(* if the preprocessing failed, return $Failed *)
If[
FailureQ[preprocessedForm],
Return[$Failed];
];
(* now return preprocessedForm as a byte array corresponding to the PNG format *)
Return[
(* save preprocessedForm as a byte array corresponding to the PNG format *)
byteArrayResult =
ExportByteArray[
preprocessedForm,
"PNG"
]
"PNG",
ImageResolution -> safeJupyterResolutionDPI
];
If[
FailureQ[byteArrayResult],
Return[{$Failed, $Failed}];
];
(* for Manipulate results, where the image dimensions are not yet determined, read in the metadata of byteArrayResult *)
If[
!preRasterized,
imageDimensions =
FirstCase[
Quiet[ImportByteArray[byteArrayResult, {"PNG", "Options"}]],
Verbatim[Rule]["ImageSize", {width_?IntegerQ, height_?IntegerQ}] :>
(ToString /@
IntegerPart[
{width, height}/72 *
cssResolutionDPI *
(* also, reduce the size of the image somewhat *) 4/5
]),
$Failed
];
If[
FailureQ[imageDimensions],
Return[{$Failed, $Failed}];
];
];
(* return byteArrayResult and imageDimensions *)
Return[{byteArrayResult, imageDimensions}];
];
(* generate HTML for the rasterized form of a result *)
@ -265,11 +328,13 @@ If[
(* the rasterization of result *)
imageData,
(* the rasterization of result in base 64 *)
imageDataInBase64
imageDataInBase64,
(* the dimensions of the image *)
imageDimensions
},
(* rasterize the result *)
imageData =
{imageData, imageDimensions} =
toImageData[
$trueFormatType[result]
];
@ -279,7 +344,7 @@ If[
imageInBase64 = BaseEncode[imageData];
,
(* if the rasterization did fail, try to rasterize result with Shallow *)
imageData =
{imageData, imageDimensions} =
toImageData[
$trueFormatType[Shallow[result]]
];
@ -289,7 +354,7 @@ If[
imageInBase64 = BaseEncode[imageData];
,
(* if the rasterization did fail, try to rasterize $Failed *)
imageData =
{imageData, imageDimensions} =
toImageData[
$trueFormatType[$Failed]
];
@ -308,8 +373,15 @@ If[
Return[
StringJoin[
(* display a inlined PNG image encoded in base64 *)
"<img alt=\"Output\" src=\"data:image/png;base64,",
(* the rasterized form of the result, converted to base64 *)
"<img ",
(* provide the image dimensions to use *)
If[
!FailureQ[imageDimensions],
{"width=\"", First[imageDimensions], "\" height=\"", Last[imageDimensions], "\" "},
{}
],
(* provide the rasterized form of the result, converted to base64, and other information *)
"alt=\"Output\" src=\"data:image/png;base64,",
imageInBase64,
(* end the element *)
"\">"

View File

@ -187,7 +187,7 @@ If[
(* otherwise, use a function that converts the output to an image *)
If[AllTrue[totalResult["EvaluationResult"], textQ],
toOut = toOutText,
toOut = toOutImage
toOut = UsingFrontEnd @* toOutImage
];
(* prepare the content for a reply message frame to be sent on the IO Publish socket *)
ioPubReplyContent = ExportString[