11
$\begingroup$

Some errors only seem to be produced at the point of typesetting, making it very difficult to detect them early. For example:

ClearAll[x]
Image[Import["http://www.wolfram.com/featureset/notebooks/img/wolfie.png"], ImageSize -> x]

enter image description here

This produces an error in the FE that you can view by pressing the red box, but I'd like to be able to detect problems like these programmatically. I tried using ToBoxes to see if the error occurs at that stage, but ToBoxes seems perfectly happy; it's the typesetting in the FE that's generating the error. Is there any way, for example, to sandbox the typesetting of this expression to detect any problems like these?

$\endgroup$
7
  • 1
    $\begingroup$ I would have thought something using FrontEnd`ExportPacket[BoxData@ToBoxes[...]],"InputForm"] would work (as used here), but the front-end just returns a default image size. If you do FrontEnd`ExportPacket[BoxData@ToBoxes[Graphics[Inset[...]]]],"InputForm"] instead, you do kind of get the pink boxes back, but the whole thing is rasterized. Maybe someone can come up with a robust way of identifying rasterized pink boxes? $\endgroup$
    – Lukas Lang
    Commented Aug 1, 2022 at 9:52
  • 1
    $\begingroup$ The question is how to detect the presence of an implicit ErrorBox. The Docs are silent about this, so I added the tag "undocumented". $\endgroup$ Commented Aug 1, 2022 at 15:19
  • $\begingroup$ It seems that the real problem is that Image[] does not do any validation on the ImageSize option value. This implies that the error is only revealed when the FE tries to display the image. $\endgroup$
    – Somos
    Commented Aug 2, 2022 at 0:37
  • $\begingroup$ @LukasLang Thank you for the link. Please see my answers below. $\endgroup$ Commented Aug 2, 2022 at 10:14
  • 3
    $\begingroup$ Sjoerd, does this answer your question? Unit tests for Graphics or FE boxes $\endgroup$
    – Kuba
    Commented Aug 2, 2022 at 12:03

4 Answers 4

6
$\begingroup$

Just to formally answer the question.

This question is a full duplicate of an older question:

where a solution was provided by rcollyer:

To access the errors, you need to invoke the Front End directly from the kernel. In effect, you end up telling the kernel to tell the FE to tell the kernel to do something, so that the FE can report any errors it finds. The method I use is
ClearAll[getFrontEndErrors]; 
SetAttributes[getFrontEndErrors, HoldAllComplete]; 

getFrontEndErrors[expr_] := 
Block[{nb, pinks}, 
    UsingFrontEnd[
        nb = CreateDocument[ExpressionCell[expr, "Output"], 
            Visible -> False, NotebookFileName -> "FEMessages"]; 
        SelectionMove[nb, All, Cell]; 
        pinks = MathLink`CallFrontEnd[FrontEnd`GetErrorsInSelectionPacket[nb]]; 
        NotebookClose[nb]
    ];
    pinks
];

which only returns the FE errors. (Edit: I removed the use of Internal`WithLocalSettings as it has limitations that are counterproductive here.) Note, this creates and destroys a notebook. But, if you are posting the info to an existing notebook, you can bypass those steps and just call

MathLink`CallFrontEnd[FrontEnd`GetErrorsInSelectionPacket[nb]]

which returns an empty list if there are no errors present. (You may have to preced the above code with UsingFrontEnd.)

Also, see this follow-up question:

$\endgroup$
1
  • 1
    $\begingroup$ Sorry for the late upvote, but this did indeed solve the issue for me. Thank you! $\endgroup$ Commented Aug 3, 2022 at 8:19
4
$\begingroup$

According to the Documentation for ErrorBox,

screenshot

In our case the ErrorBox is implicit, i.e. is generated by the FrontEnd upon rendering, not by the kernel. Unfortunately, the Documentation is silent about how to detect such an implicit ErrorBox.

On the other hand, the presence of such an implicit ErrorBox has several consequences:

  1. It displays the contents of the cell in red.
  2. It displays the cell bracket in red.
  3. It displays the tooltip when the mouse is over the contents of the cell.
  4. It displays the banner near to the cell bracket.
  5. It prints a message to the MessagesNotebook[] when one clicks on the banner.

We can try to find out the presence of an implicit ErrorBox by checking the above features using the built-in "RobotTools`" package:

Needs["RobotTools`"]

Note that below I will use Mathematica 12.3.1, because in versions 13.0 - 13.1 this package is partially broken due to the hidden scaling (which can be turned off, however).

Let us try to click on the banner near to the cell bracket.

First, create a new Notebook window where the relative position of the banner is predictable:

nb = CreateDocument[ExpressionCell[Image[RandomImage[10], ImageSize -> x]]]

Now get the coordinates of the top right corner of the new Notebook:

topRightCorner = Extract[GetWindowRectangle[nb], {{2, 1}, {1, 2}}]
{1566., 219.}

The banner is located just below and to the left of the upper right corner:

screenshot

Let's click on it and check what is printed to the MessagesNotebook[]:

before = First@NotebookGet[MessagesNotebook[]];
MouseClick[nb, topRightCorner + {-32, 4}]
new = Complement[First@NotebookGet[MessagesNotebook[]], before];
If[Length[new] > 0, CellPrint /@ new];

out

The messages are printed, what means that we've specified the coordinates correctly.


Similar approach can be based on CurrentNotebookImage (which in turn is based on "RobotTools`", and hence is broken in versions 13.0 - 13.1). We create a new frameless Notebook window which has no WindowElements and contains only one closed cell, and take a screenshot of it. Since the contents of the cell isn't shown, we get only the insertion point and the error banner:

nb = CreateDocument[
   ExpressionCell[Image[RandomImage[10], ImageSize -> x], 
    CellOpen -> False], WindowElements -> {}, 
   WindowFrameElements -> {}, WindowFrame -> "Frameless", 
   WindowSize -> {100, 30}];
Pause[.1]
img = CurrentNotebookImage[nb]
NotebookClose[nb]

out

Now it is sufficient to check whether the screenshot contains the color {255, 98, 98}:

FreeQ[ImageData[img, Byte], {255, 98, 98}]
False
$\endgroup$
3
$\begingroup$

Maybe someone can come up with a robust way of identifying rasterized pink boxes? – Lukas Lang

In the cases I checked (with Mathematica 13.1.0), PDF export with immediate re-import returned the same construct for the pink box in the all cases:

Style[{JoinedCurve[{{{0, 2, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}}}, _, CurveClosed -> {1}]}, 
  JoinForm[{"Miter", 10.}], Thickness[_], RGBColor[1., 0.32941176470588235, 0.32941176470588235, 1.]]

Hence we can implement the check as follows:

vectorExportImportPDF[expr_] := 
  First@ImportString[ExportString[expr, "PDF", "AllowRasterization" -> False], 
    If[$VersionNumber >= 12.2, {"PDF", "PageGraphics"}, {"PDF", "Pages"}], 
    "TextOutlines" -> False];

containsPinkBoxQ[g_Graphics] := 
 Catch[g /. Style[{JoinedCurve[{{{0, 2, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}}}, _, 
       CurveClosed -> {1}]}, JoinForm[{"Miter", 10.}], Thickness[_], 
     RGBColor[1., 0.32941176470588235, 0.32941176470588235, 1.]] :> Throw[True]; False]

Here is how it can be used:

containsPinkBoxQ[vectorExportImportPDF[Framed[x, FrameMargins -> fish]]]
True
containsPinkBoxQ[vectorExportImportPDF[Framed[x, FrameMargins -> 1]]]
False
vectorExportImportPDF[
  Cell[BoxData[SuperscriptBox["1", "2", "3"]], "Output"]] // containsPinkBoxQ
True
containsPinkBoxQ[vectorExportImportPDF[Image[RandomImage[10], ImageSize -> x]]]
containsPinkBoxQ[vectorExportImportPDF[Image[RandomImage[10], ImageSize -> 10]]]
True
False

Note however, that the exact form of the construct may be version-dependent. Also, despite "AllowRasterization" -> False in some cases Mathematica rasterizes the contents on Export, and in such situations this method may not work.

$\endgroup$
1
$\begingroup$

I would have thought something using FrontEnd`ExportPacket[BoxData@ToBoxes[...]],"InputForm"] would work (as used here), but the front-end just returns a default image size. If you do FrontEnd`ExportPacket[BoxData@ToBoxes[Graphics[Inset[...]]]],"InputForm"] instead, you do kind of get the pink boxes back, but the whole thing is rasterized. Maybe someone can come up with a robust way of identifying rasterized pink boxes? – Lukas Lang

My experiments with versions 13.1.0, 12.3.1 and 8.0.4 on Windows 10 x64 show that in the most cases FrontEnd returns a non-raterized version. The exact forms of the expressions returned differ between versions, but in all cases it is a Graphics containing graphics directive RGBColor[1, 0.33, 0.33] as the first element of two successive sublists on the first level. Hence we can write a test:

hasErrorBoxQ[expr_] := 
 MatchQ[ToExpression[
    FrontEndExecute[
     FrontEnd`ExportPacket[Cell[BoxData@ToBoxes[expr]], "InputForm"]]][[1, 1]], 
    {___, {RGBColor[1, 0.33, 0.33], _Opacity, ___, (_Polygon | _FilledCurve)}, ___}]

hasErrorBoxQ[cell_Cell] := 
 MatchQ[ToExpression[FrontEndExecute[FrontEnd`ExportPacket[cell, "InputForm"]]][[1, 1]],
    {___, {RGBColor[1, 0.33, 0.33], _Opacity, ___, (_Polygon | _FilledCurve)}, ___}]

Testing:

hasErrorBoxQ@Framed[x, FrameMargins -> fish]
hasErrorBoxQ@Framed[x, FrameMargins -> 1]
True
False
hasErrorBoxQ@Image[RandomImage[10], ImageSize -> x]
hasErrorBoxQ@Image[RandomImage[10], ImageSize -> 1]
True
False
hasErrorBoxQ@Cell[BoxData[SuperscriptBox["1", "2", "3"]], "Output"]
hasErrorBoxQ@Cell[BoxData[SuperscriptBox["1", "2"]], "Output"]
True
False

There are cases when this approach fails, apparently because for some reason FrontEnd doesn't display the pink box, but only the pink banner, which isn't exported:

Graphics[Polygon[{{-1, 0}, {1, 0}, {0, Sqrt[3]}}, VertexColors -> {Red, Green, Blue}], 
 ImageSize -> x]

screenshot

$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.