ImgToScript

Introduction

img_to_script is a Ruby gem (a library) that converts images to executable scripts that plot the binary version of the image using the simple commands e.g. “draw a line”, “draw a dot”, etc..

The gem was initially developed to convert binary images to the executable scripts for the build-in BASIC interpreter of the Soviet vintage portable computer Elektronika MK90. Yet it is possible to expand the gem to support other similar hardware and script languages (e.g. the build-in TI-BASIC of the Z80-based TI calculators).

Elektronika MK90 renders an image with the build-in BASIC interpreter

Vintage Elektronika MK90 renders an image with the build-in BASIC interpreter. The program was generated by the **img_to_script* gem.*

The gem was designed as a library, i.e. it neither provide a user interface, nor validates the input data. It only provides an API, the rest should be handled by the external software. To make a converter you’ll need to build an application around the img_to_script gem and provide a user interface, e.g. a command-line interface or a web interface.

Installation

Add this line to your application's Gemfile:

gem "img_to_script"

And then execute:

$ bundle install

Or install it yourself as:

$ gem install img_to_script

Modules

Three steps are required to complete the conversion. The gem has a dedicated module (a namespace) for each step:

  • Generator reads the image data and creates an array of the abstract tokens. Each token represents a simple command to the interpreter, e.g.: “draw a line”, “draw a dot”, “assign a value to a variable”, “start a loop”, etc..

  • Translator is a mediator between a generator and a formatter. It translates abstract tokens to the specific statements of the target programming language. Translator chooses keywords, separators and handles other syntax issues.

  • Formatter takes input from the translator and formats it into the executable script (a target language code). It can serve a function of a prettier or a minificator. Another common formatter’s task is to track down and to label BASIC line numbers.

Usage

API

ImgToScript::Task.new(
  generator: generator,
  translator: translator,
  formatter: formatter
).run(
  image: image,
  scr_width: scr_width,
  scr_height: scr_height
)

todo...

Returns

Array<String>

Example

  1. Require the gem:
require "img_to_script"
  1. Read an image using the rmagick/bin_magick gem:
require "rmagick/bin_magick"

image = Magick::BinMagick::Image.from_file("my_file.png").to_binary!
  1. Create a generator instance. You can also provide options via a configuration block, e.g.:
generator = ImgToScript::Generators::RunLengthEncoding::Horizontal.new.configure do |config|
  config.x_offset = -10
  config.y_offset = 15
  # etc.
end
  1. Create a translator instance, e.g.:
translator = ImgToScript::Languages::MK90Basic::Translators::MK90Basic10.new
  1. Create a formatter instance. You can also provide options via a configuration block, e.g.:
formatter = ImgToScript::Languages::MK90Basic::Formatters::Minificator.new.configure do |config|
  config.line_offset = 10
  config.line_step = 5
  config.max_chars_per_line = 60
  # etc.
end
  1. Create a task instance and pass created instances as the task’s dependencies:
task = ImgToScript::Task.new(
  generator: generator,
  translator: translator,
  formatter: formatter
)

Note that you can also provide your own custom objects as long as they respond to the required public interface.

In case of the Elektronika MK90 BASIC only you can omit any dependency (i.e. skip any step from the 3rd to the 5th), since these are optional arguments. Then a default object with a default configuration will be used.

You can also re-configure any dependency of an existing task object, e.g.:

task.formatter.configure do |config|
  # your config...
end
  1. Run conversion to get a script. You need to provide the image and the target device resolution:
script = task.run(
  image: image,
  scr_width: 120,
  scr_height: 64
)

Build-in classes

Generators

  • ImgToScript::Generators::Generator

Base class all generators inherit from.

Public interface: #generate(image:, scr_width:, scr_height:)

Configuration options:

  • x_offset, default: X_OFFSET (0)

    Offset the X point on the screen.

  • y_offset, default: Y_OFFSET (0)

    Offset the Y point on the screen.

  • clear_screen, default: CLEAR_SCREEN (true)

    Add a statement to clear the screen at the begin of the script.

  • pause_program, default: PAUSE_PROGRAM (true)

    Add a statement to pause the program at the end of the script.

  • program_begin_lbl, default: PRORGAM_BEGIN_LBL (false)

    Add a statement that marks the begin of the program.

  • program_end_lbl, default: PROGRAM_END_LBL (false)

    Add a statement that marks the end of the program.

  • run_another_file, default: ""

    Load and run another script file at the end of the script. String argument represents a file ID (e.g., a filename). If the string is empty, no file should be loaded.

    • ImgToScript::Generators::HexMask::Default

Specific for the Elektronika MK90 BASIC v.1.0 only.

MK90's BASIC has a balanced build-in method to encode and render images. The Elektronika MK90's manual refers to it as the hex-mask rendering method. Each 8x1 px block of a binary image is being represented as a hex value (e.g. '00' for a tile of the 8 white pixels in a row, 'FF' for a tile of the 8 black pixels in a row, etc.). Then these hex values are being passed as arguments to the DRAM/M BASIC statement that renders the image according to the provided data.

Due to the logic of the DRAM/M operator, only vertical scan lines are supported.

Note: due to a bug in the MK90 BASIC v.2.0 software, this generation method works only on the BASIC v.1.0 systems.

  • ImgToScript::Generators::HexMask::ForcedPointMove

Same as HexMask::Default, but with a workaround for the MK90 BASIC v.2.0.

  • ImgToScript::Generators::HexMask::Enhanced

Specific for the Elektronika MK90 BASIC v.1.0 only.

Hex-mask encoding with modifications what make output BASIC code more compact.

Due to the logic of the DRAM/M operator, only vertical scan lines are supported.

Note: due to a bug in the MK90 BASIC v.2.0 software, this generation method works only on the BASIC v.1.0 systems.

  • ImgToScript::Generators::RunLengthEncoding::Horizontal

RLE, horizontal scan lines.

  • ImgToScript::Generators::RunLengthEncoding::Vertical

RLE, vertical scan lines.

  • ImgToScript::Generators::Segmental::DirectDraw::Horizontal

Directly plot segments, horizontal scan lines.

  • ImgToScript::Generators::Segmental::DirectDraw::Vertical

Directly plot segments, vertical scan lines.

  • ImgToScript::Generators::Segmental::DataReadDraw::Horizontal

Store and read segments' coordinates, when use them to plot segments. Horizontal scan lines.

  • ImgToScript::Generators::Segmental::DataReadDraw::Vertical

Store and read segments' coordinates, when use them to plot segments. Vertical scan lines.

Elektronika MK90 BASIC

Translators

  • ImgToScript::Languages::MK90Basic::Translators::Translator

Base class all MK90 translators inherit from.

Public interface: #translate(abstract_tokens, **kwargs)

  • ImgToScript::Languages::MK90Basic::Translators::MK90Basic10

Translates abstract tokens to the MK90 BASIC v1.0 statements.

  • ImgToScript::Languages::MK90Basic::Translators::MK90Basic20

Translates abstract tokens to the MK90 BASIC v2.0 statements.

Formatters

  • ImgToScript::Languages::MK90Basic::Formatters::Formatter

Base class all MK90 formatters inherit from.

Public interface: #format(tokens)

Configuration options:

  • line_offset, default: LINE_OFFSET (1)

    First BASIC line number.

  • line_step, default: LINE_STEP (1)

    Step between two neighbor BASIC lines.

  • max_chars_per_line, default: MAX_CHARS_PER_LINE (80)

    Note: MK90 BASIC doesn’t support more than 80 characters per line.

  • number_lines, default: true

    • ImgToScript::Languages::MK90Basic::Formatters::Minificator

The aim of the minificator is to make the output script as compact as possible, and so to save space at the MPO-10 cart.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/8bit-mate/img_to_script.rb.

License

The gem is available as open source under the terms of the MIT License.