Inferring the Locale text direction with Javascript

Here’s a hack to detect which is the locale text direction (e.g. left-to-right for English or right-to-left for Hebrew) using JavaScript:

/**
 * Detects locale text direction...
 * @return {String} "ltr" or "rtl"
 */
function detectTextDir() {
   var container = document.createElement("p");
    container.style.margin = "0 0 0 0";
    container.style.padding = "0 0 0 0";
    // container.style.textAlign = "start"; // If CSS 3+ 
    container.style.textAlign = ""; // Explicitly override text align that might be assigned via style sheets
    
    var span = document.createElement("span");
    span.innerHTML = "X";
    
    container.appendChild(span);
    document.body.appendChild(container);
    
    // LTR if text position is nearer left of container, RTL if text position is nearer right of container
    var localeDirection = span.offsetLeft < (container.offsetWidth - (span.offsetLeft + span.offsetWidth)) ?
        "ltr" : 
        "rtl";
       
    document.body.removeChild(container);

    return localeDirection;
}

A limitation is that it doesn’t work if there is a style sheet present which explicitly assigns a text-align value other than “start” for paragraphs directly in the document body. You could probably tweak the idea to use something more obscure like an address block to reduce chances of this happening.

Advertisements

Simple image filters written as HLSL pixel shaders

I had to write some image filtering pixel shaders for some coarse-work. So I thought I will make them available for anyone who might want to write there own image filtering pixel shaders, or just want some quickly without having to worry about the details for now.

The snippets below are in HLSL, and are single pass techniques. Written to compile with pixel shader 2.0. The snippets have “uniform extern texture tex;” declared. The shaders only work with 1024 x 768 resolution textures: a rigid implementation, easily overcame in later shader versions with the use of ddx and ddy intrinsic functions. OK Enough fluffing around, heres the code:

Blurs using a 3×3 filter kernel

// Blurs using a 3x3 filter kernel
float4 BlurFunction3x3(VertexShaderOutput input) : COLOR0
{
  // TOP ROW
  float4 s11 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, -1.0f / 768.0f));	// LEFT
  float4 s12 = tex2D(texsampler, input.texcoords + float2(0, -1.0f / 768.0f));				// MIDDLE
  float4 s13 = tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, -1.0f / 768.0f));	// RIGHT

  // MIDDLE ROW
  float4 s21 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 0));				// LEFT
  float4 col = tex2D(texsampler, input.texcoords);											// DEAD CENTER
  float4 s23 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 0)); 				// RIGHT

  // LAST ROW
  float4 s31 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 1.0f / 768.0f));	// LEFT
  float4 s32 = tex2D(texsampler, input.texcoords + float2(0, 1.0f / 768.0f));					// MIDDLE
  float4 s33 = tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, 1.0f / 768.0f));	// RIGHT

  // Average the color with surrounding samples
  col = (col + s11 + s12 + s13 + s21 + s23 + s31 + s32 + s33) / 9;
  return col;
}

Blurs using a 5×5 filter kernel – ARG!

// Blurs using a 5x5 filter kernel
float4 BlurFunction5x5(VertexShaderOutput input) : COLOR0
{
  return (
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-2.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-1.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(0,					0)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		0)) +

    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		1.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		2.0f / 768.0f))
  ) / 25;
}

Blurs using a 7×7 filter kernel – ARGGGG!!!!

// Blurs using a 7x7 filter kernel
float4 BlurFunction7x7(VertexShaderOutput input) : COLOR0
{
  return (
    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		-3.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		-2.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		-1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		-1.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(0,					0)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		0)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		0)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		1.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		1.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		2.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		2.0f / 768.0f)) +

    tex2D(texsampler, input.texcoords + float2(-3.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-2.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(0,					3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(2.0f / 1024.0f,		3.0f / 768.0f)) +
    tex2D(texsampler, input.texcoords + float2(3.0f / 1024.0f,		3.0f / 768.0f))
  ) / 49;
}

Outputs edges only using a A 3×3 edge filter kernel

// Outputs edges only using a A 3x3 edge filter kernel
float4 OutlinesFunction3x3(VertexShaderOutput input) : COLOR0
{
  float4 lum = float4(0.30, 0.59, 0.11, 1);

  // TOP ROW
  float s11 = dot(tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, -1.0f / 768.0f)), lum);	// LEFT
  float s12 = dot(tex2D(texsampler, input.texcoords + float2(0, -1.0f / 768.0f)), lum);				// MIDDLE
  float s13 = dot(tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, -1.0f / 768.0f)), lum);	// RIGHT

  // MIDDLE ROW
  float s21 = dot(tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 0)), lum);				// LEFT
  // Omit center
  float s23 = dot(tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 0)), lum); 				// RIGHT

  // LAST ROW
  float s31 = dot(tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, 1.0f / 768.0f)), lum);	// LEFT
  float s32 = dot(tex2D(texsampler, input.texcoords + float2(0, 1.0f / 768.0f)), lum);				// MIDDLE
  float s33 = dot(tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, 1.0f / 768.0f)), lum);	// RIGHT

  // Filter ... thanks internet 🙂
  float t1 = s13 + s33 + (2 * s23) - s11 - (2 * s21) - s31;
  float t2 = s31 + (2 * s32) + s33 - s11 - (2 * s12) - s13;

  float4 col;

  if (((t1 * t1) + (t2 * t2)) > 0.05) {
  col = float4(0,0,0,1);
  } else {
    col = float4(1,1,1,1);
  }

  return col;
}

A 3×3 emboss filter kernel

// A 3x3 emboss filter kernel
float4 EmbossShaderFunction3x3(VertexShaderOutput input) : COLOR0
{
  float4 s22 = tex2D(texsampler, input.texcoords); // center
  float4 s11 = tex2D(texsampler, input.texcoords + float2(-1.0f / 1024.0f, -1.0f / 768.0f));
  float4 s33 = tex2D(texsampler, input.texcoords + float2(1.0f / 1024.0f, 1.0f / 768.0f));

  s11.rgb = (s11.r + s11.g + s11.b);
  s22.rgb = (s22.r + s22.g + s22.b) * -0.5;
  s33.rgb = (s22.r + s22.g + s22.b) * 0.2;

  return (s11 + s22 + s33);
  // return col * (s11 + s22 + s33); // with color 🙂 - but B & W looks a lot nicer
}