Nightmare Puzzlang translator Background

Puzzlang is a derivative of Brainfuck, where the symbol X executes a BF command based on three characters on top of it, and anything else does nothing.

The following is the translation table for Puzzlang, where X is the literal X and . stands for anything else:

 &gt;      &lt;      +      -      .      ,      [      ]

..X    X..    XXX    ...    .X.    X.X    XX.    .XX
 X      X      X      X      X      X      X      X


Also, the entire source code wraps around both horizontally and vertically at the translation step. For example, the following code is an infinite loop:

XX X


since you can view the code like this (the dots are where the wrapped X's would go)

... ..
.XX X.


and matching with the translation table gives +[] for the three X's in order.

Nightmare Puzzlang is an evil twin of the regular Puzzlang. In Nightmare Puzzlang, each X translates into a byte based on its eight neighbors. Any non-X characters translate into nothing. The wrapping rule is the same.

Since there is no "official" specification, let's assume that the following pattern (where X denotes the one to translate)

abc
dXe
fgh


translates to abcdefgh in binary (X is one, non-X is zero). Then the following code

XX...
X..X.
X..XX
X..XX
X.XX.


translates to 4a b4 66 03 56 4b bf d2 6e fd c3 2c 70 in hex, or J´f&#3;VK¿ÒnýÃ,p as a string. Note that the resulting string will very likely have ASCII unprintables.

Task

Translate the given Nightmare Puzzlang code into a string.

Input &amp; output

For input, you can take 2D array of chars, list of strings, or a single string whose lines are delimited by newlines. You can assume that the input is rectangular in shape, i.e. row lengths are equal.

For output, you can give a single string, a list of chars, or a list of charcodes.

Test Cases

Note that the result must remain the same when any of the dots are replaced with anything else other than the capital X.

X (1 row, 1 column)
String: ÿ
Charcode: [255]

X. (1 row, 2 columns)
String: B
Charcode: [66]

X
. (2 rows, 1 column)
String: &#24;
Charcode: [24]

X.
.X
String: ¥¥
Charcode: [165, 165]

X.X
.X.
String: 1Œ¥
Charcode: [49, 140, 165]

X.X
XX.
X.X
String: ÓmÎµv«
Charcode: [211, 109, 206, 181, 118, 171]

X.XX.XXX..XXXX.
String: BkÖkÿÖkÿÿÖ
Charcode: [66, 107, 214, 107, 255, 214, 107, 255, 255, 214]

X.XX.XXX.XXXXX.
XX.X..XX....X..
String: c­R){Ö&#8;&#24;9Z&#148;JµÆïÖç
Charcode: [99, 173, 82, 41, 123, 214, 8, 24, 57, 90, 148, 74, 181, 198, 239, 214, 231]

X
X
X
.
.
X
.
X
X
.
X
String: ÿÿø&#24;&#31;ø&#31;
Charcode: [255, 255, 248, 24, 31, 248, 31]

XX
X.
XX
.X
.X
XX
..
XX
XX
..
.X
String: º]ç]ºâG¸X&#31;&#31;øø&#7;
Charcode: [186, 93, 231, 93, 186, 226, 71, 184, 88, 31, 31, 248, 248, 7]

XX XXX XX  XX
X  X X X X X&#32;
X  X X X X XX
X  X X X X X&#32;
XX XXX XX  XX
            &#32;
XXX XXX X  XX
X   X X X  X&#32;
X X X X X  XX
X X X X X  X&#32;
XXX XXX XX X&#32;
(11 rows, 13 columns, no extra padding, result has two newlines)
zôª}òªuJ½æbÂb‚cRBBBBJ½ÇCFCDcX&#144;H¸PH°H¸&#26;&#28;&#16;
&#29;&#18;&#2;
&#29;æbÂBcR&#2;BBBJ½ÃFCFCbO¾UO¾UN”C
Charcode: [122, 244, 170, 125, 242, 170, 117, 74, 189, 230, 98, 194, 98, 130, 99, 82, 66, 66, 66, 66, 74, 189, 199, 67, 70, 67, 68, 99, 88, 144, 72, 184, 80, 72, 176, 72, 184, 26, 28, 16, 10, 29, 18, 2, 10, 29, 230, 98, 194, 66, 99, 82, 2, 66, 66, 66, 74, 189, 195, 70, 67, 70, 67, 98, 79, 190, 85, 79, 190, 85, 78, 148, 67]


Rules

Standard code-golf rules apply. The shortest submission in bytes wins.
APL (Dyalog Unicode), 57 bytes

¯1~⍨,1↓∘⍉∘⌽⍣4⊢{2 2⌷⍵:2⊥(~¯9↑5↑1)/,⍵⋄¯1}⌺3 3⊢⍉∘(¯1∘↑⍪⊢⍪1∘↑)⍣2⊢'X'=⎕

Try it online!
A full program which takes a binary matrix through STDIN, returns an array of codepoints.
Explanation
x¯1~⍨,1↓∘⍉∘⌽⍣4⊢{2 2⌷⍵:2⊥(~¯9↑5↑1)/,⍵⋄¯1}⌺3 3⊢⍉∘(¯1∘↑⍪⊢⍪1∘↑)⍣2⊢'X'=⎕
⎕ take input
'X'=  boolean matrix where 'X's are 1s
⍉∘(...)⍣2⊢ do the following twice:
¯1∘↑⍪⊢⍪1∘↑ pad each row with its wraparound on both sides
⍉∘ and transpose
{...}⌺3 3⊢ then, do the following for each 3x3 window:
2 2⌷⍵: if the middle element is 1:
2⊥(~¯9↑5↑1)/,⍵ decode the rest of the window as binary
⋄¯1 Otherwise, return ¯1.
⍣4⊢ Do the following 4 times:
1↓∘⍉∘⌽ rotate 90°, drop first row (remove the border cells)
, flatten into a simple array
¯1~⍨ remove all ¯1s