I have been trying to decode a pdf file using python and the data is as below:
BT
/F2 8.8 Tf
1 0 0 1 36.85 738.3 Tm
0 g
0 G
[(A)31(c)-44(c)-44(o)-79(u)11(n)-79(t)5( )] TJ
ET
How do I make sense of this???
[(A)31(c)-44(c)-44(o)-79(u)11(n)-79(t)5( )] is of what type???
BT /F2 8.8 Tf 1 0 0 1 36.85 738.3 Tm 0 g 0 G [(A)31(c)-44(c)-44(o)-79(u)11(n)-79(t)5( )] TJ ET
Is normal plain ASCII text, thus everyday, decoded binary as text.
Your question is
Q) How do I make sense of this??? [(A)31(c)-44(c)-44(o)-79(u)11(n)-79(t)5( )]
A) Always look at the context
BT = B(egin) T(ext)
/F2 = use F(ont) 2 for encoding (whatever that is)
8.8 = units of height (if un-modified those could be 8.8 full unscaled DTP points,
but beware, point size does not necessarily correspond to any measurement
of the size of the letters on the printed page.)
... Mainly T(ransform )m(atrix) e.g. placement
[ = start a string group
(A) = literal(y) "A"
31 = Kern next character (+ is usually) left wise by 31 units where units (is usually) 1/1440 inch or 17.639 µm
(c) = the next glyph literal that needs to be etched on screen or paper
-44 is push the two x (c) apart by 44 units
(c)
...
] Tj ET = Close Group, T(exte)j(ect) E(nd) T(ext)
So there we have it somewhere on the page (first or last word or any time in between) but at that time somewhere, most likely top Left, there is one continuous selectable plain text string that **audibly sounds like a word in a human language = "Account", with an extra spacebar literal (that's actually un-necessary for a PDF, it will print that and any other "word" good enough without one.)
Why did I say sounds and not "looks like" is because those "literal" characters are not the ones presented they are the encoded names of glyphs.
Hear :-) is how they could look like using /F2 if it was set to different glyph font such as use emojis or other Dings, so A is BC but c is a checkbox u is underground t is train but audibly all ink, is just an Account of which graphics to use.
A transformation seems to be applied when painting colors in p5.js with an alpha value lower than 255:
for (const color of [[1,2,3,255],[1,2,3,4],[10,11,12,13],[10,20,30,40],[50,100,200,40],[50,100,200,0],[50,100,200,1]]) {
clear();
background(color);
loadPixels();
print(pixels.slice(0, 4).join(','));
}
Input/Expected Output Actual Output (Firefox)
1,2,3,255 1,2,3,255 ✅
1,2,3,4 0,0,0,4
10,11,12,13 0,0,0,13
10,20,30,40 6,19,25,40
50,100,200,40 51,102,204,40
50,100,200,0 0,0,0,0
50,100,200,1 0,0,255,1
The alpha value is preserved, but the RGB information is lost, especially on low alpha values.
This makes visualizations impossible where, for example, 2D shapes are first drawn and then the visibility in certain areas is animated by changing the alpha values.
Can these transformations be turned off or are they predictable in any way?
Update: The behavior is not specific to p5.js:
const ctx = new OffscreenCanvas(1, 1).getContext('2d');
for (const [r,g,b,a] of [[1,2,3,255],[1,2,3,4],[10,11,12,13],[10,20,30,40],[50,100,200,40],[50,100,200,0],[50,100,200,1]]) {
ctx.clearRect(0, 0, 1, 1);
ctx.fillStyle = `rgba(${r},${g},${b},${a/255})`;
ctx.fillRect(0, 0, 1, 1);
console.log(ctx.getImageData(0, 0, 1, 1).data.join(','));
}
I could be way off here...but it looks like internally that in the background method if _isErasing is true then blendMode is called. By default this will apply a linear interpolation of colours.
See https://github.com/processing/p5.js/blob/9cd186349cdb55c5faf28befff9c0d4a390e02ed/src/core/p5.Renderer2D.js#L45
See https://p5js.org/reference/#/p5/blendMode
BLEND - linear interpolation of colours: C = A*factor + B. This is the
default blending mode.
So, if you set the blend mode to REPLACE I think it should work.
REPLACE - the pixels entirely replace the others and don't utilize
alpha (transparency) values.
i.e.
blendMode(REPLACE);
for (const color of [[1,2,3,255],[1,2,3,4],[10,11,12,13],[10,20,30,40],[50,100,200,40],[50,100,200,0],[50,100,200,1]]) {
clear();
background(color);
loadPixels();
print(pixels.slice(0, 4).join(','));
}
Internally, the HTML Canvas stores colors in a different way that cannot preserve RGB values when fully transparent. When writing and reading pixel data, conversions take place that are lossy due to the representation by 8-bit numbers.
Take for example this row from the test above:
Input/Expected Output Actual Output
10,20,30,40 6,19,25,40
IN (conventional alpha)
R
G
B
A
values
10
20
30
40 (= 15.6%)
Interpretation: When painting, add 15.6% of (10,20,30) to the 15.6% darkened (r,g,b) background.
Canvas-internal (premultiplied alpha)
R
G
B
A
R
G
B
A
calculation
10 * 0.156
20 * 0.156
30 * 0.156
40 (= 15.6%)
values
1.56
3.12
4.7
40
values (8-bit)
1
3
4
40
Interpretation: When painting, add (1,3,4) to the 15.6% darkened (r,g,b) background.
Premultiplied alpha allows faster painting and supports additive colors, that is, adding color values without darkening the background.
OUT (conventional alpha)
R
G
B
A
calculation
1 / 0.156
3 / 0.156
4 / 0.156
40
values
6.41
19.23
25.64
40
values (8-bit)
6
19
25
40
So the results are predictable, but due to the different internal representation, the transformation cannot be turned off.
The HTML specification explicitly mentions this in section 4.12.5.1.15 Pixel manipulation:
Due to the lossy nature of converting between color spaces and converting to and from premultiplied alpha color values, pixels that have just been set using putImageData(), and are not completely opaque, might be returned to an equivalent getImageData() as different values.
see also 4.12.5.7 Premultiplied alpha and the 2D rendering context
I'm using Go and compiling it to web assembly.
I'm trying to render a bunch of rectangles next to eachother with a random colour, but they keep rendering as just gray.
My render function looks something like this:
for row,_ := range rows {
for col,_ := range row {
ctx.Set("fillStyle", fmt.Sprintf("#%06x", rand.Int()))
ctx.Call("fillRect", 20, 20 + (col * width), maxHeight - (row*height))
}
}
With which it renders a big block (all rectangles are next to eachother) but just all in gray, instead of doing them in different colours.
Is this enough code in the example to help further? If not I can post it to a gist, as I'm new to WASM I'm unsure which parts could really be relevant - but those 2 functions are the only ones doing something with rendering as far as I can tell.
The problem is that you use this expression to construct the fill style:
fmt.Sprintf("#%06x", rand.Int())
rand.Int() returns a non-negative pseudo-random int. Size of int is 64 bits if GOOS=js and GOARCH=wasm. What this means is that the random int number will be random 8 bytes (first bit being always 0 due to being non-negative).
If you format such a number with the %06x verb, like almost all the time it will be more than just 6 hex digits. The width 6 means to be at least 6, and the flag 0 means to pad with zeros if less. But if it's longer, it is not truncated.
And if you set an invalid color to canvas.fillStyle, it will disregard it and the last set valid fill style will remain active. And I'm guessing it was a gray color you used before the loop.
Fix is easy, just make sure the random number has no more than 3 bytes, or in other words, 6 hex digits. Use a simple bitmask:
ctx.Set("fillStyle", fmt.Sprintf("#%06x", rand.Int()&0xffffff))
Or use rand.Intn() instead of rand.Int():
ctx.Set("fillStyle", fmt.Sprintf("#%06x", rand.Int(0x1000000)))
Also context.fillRect() expects 4 arguments: x, y, width and height, so it should be something like this:
ctx.Call("fillRect", 20+(col*width), maxHeight-(row*height), width, height)
Is there a way via PostScript to add a string such that is will be truncated by "..." so as not to exceed a certain width?
I've looking at some old report generation code and would like add this feature. In the existing reports, values that are too long are visually overwriting other data.
The reason I'm trying to do this at the PS level is that in the existing code I don't see anything that could calculate any kind of accurate width metric.
I've yet to write any Postscript, so maybe this is trivial. (?)
Per comment below: Yes, localization will an issue. So I guess a user defined "ellipsis" string makes sense.
Here is some example output that shows how strings are currently printed:
% Change font style and/or size
/Times-Roman-ISOLatin1 findfont 12 scalefont setfont
219 234 moveto (AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_) show
Can this be modified to ellipsize things?
Well you can do something like this (replace the char in front of concatstrings with your ellipsis):
/concatstrings % (a) (b) -> (ab)
{ exch dup length
2 index length add string
dup dup 4 2 roll copy length
4 -1 roll putinterval
} bind def
/ellipsis_show {
1 dict begin
/width_t exch def
{dup stringwidth pop width_t lt {exit} if dup length 1 sub 0 exch getinterval} loop
(_) concatstrings
show
end
}def
% Change font style and/or size
/Times-Roman-ISOLatin1 findfont 12 scalefont setfont
0 0 moveto (foobar barfoo foofoo barbar) 100.0 ellipsis_show
concatstrings copied from: http://en.wikibooks.org/wiki/PostScript_FAQ#How_to_concatenate_strings.3F
The simple answer is 'no'. A longer answer is that, since PostScript is a programming language, you can do this, but it will require some knowledge of PostScript, and some work, it certainly is not trivial.
You can redefine the various operators which draw text on the output, there are quite a few; show, ashow, cshow, kshow, xshow, yshow, xyshow, widthshow, awidthshow, and glyphshow. You could define modified versions of these which determine (using stringwidth and the parameters used by the various operators) the width of thefinal printed text. Probably you would want to calculate this glyph by glyph and terminate with your ellipsis when the value exceeds some threshold. (NB not all fonts will contain an ellipsis glyph, and its encoded position may vary).
However, given that you are working with existing code, there is most probably already a function defined to draw text and it probably only uses a subset of the possible operators. You would probably be better advised to modify that.
A quesion about RGB color and finding the simplest, tiniest, php conversion code for manipulating the lightness/darkness of a given RGB hue.
Imagine a variable $colorA containning a valid six char RGB color, like F7A100 which we want to make a bit lighter and/or darker:
$color = B1B100; // original RGB color manually set.
Then, at any page have that color bit darker/lighter on the fly:
$colorX = someFunction($color, +10); // original color 10 steps lighter
$colorY = someFunction($color, -25); // original color 25 steps darker
What would be YOUR way of solving this? Keep the RGB as is or first change it to HSL? Hints and suggestions are welcome. Your sample/code is welcome too.
This really focuses to the TINIES / SIMPLES / SHORTEST possible code to just make the same hue bit darker/lighter.
I deliberately do not suggest my code, as I want to keep possibilities open in here.
The absolutely simplest solution is to add some constant (like 1) to each part of the color representation: [R, G, B]. This is due to the fact that max values of all [R, G, B] represent white, while min values - black. In pseudo-code (assuming 255 is max, sorry, I don't know PHP):
lighter(R, G, B) = [
min(255, R + 1),
min(255, G + 1),
min(255, B + 1)
]
You must keep in mind though that this transformation is way too simplistic and the proper implementation would be to convert to HSL/HSB, increase H and transform back to RGB.
For slight alteration of brightness you can convert the hexadecimal values to decimal, manipulate them and convert back to hexadecimal like this:
function alterBrightness($color, $amount) {
$rgb = hexdec($color); // convert color to decimal value
//extract color values:
$red = $rgb >> 16;
$green = ($rgb >> 8) & 0xFF;
$blue = $rgb & 0xFF;
//manipulate and convert back to hexadecimal
return dechex(($red + $amount) << 16 | ($green + $amount) << 8 | ($blue + $amount));
}
echo alterColor('eeeeee', -10); //outputs e4e4e4
Beware that this code does not handle overflow for one color - if one color value becomes less than 0 or more than 255 you will get an invalid color value. This should be easy enough to add.
For drastic changes in brightness, convert to HSL and manipulate the lightness.
Using the functions from the Drupal code, this can be done like this:
$hsl = _color_rgb2hsl(_color_unpack('eeeeee'));
$hsl[2] -= 10;
$rgb = _color_pack(_color_hsl2rgb($hsl));
echo $rgb; //outputs e4e4e4