The Bitmap class represents a 24-bit bitmap image. An instance can be constructed

by calling load or with_size:

var bm1 = new Bitmap.load(path_to_a_bmp_file)
var bm2 = new Bitmap.with_size(400, 300)

The width and height attributes contain the image's width and height, respectively.

Individual pixels can be manipulated by calling the set_pixel function:

set_pixel(x, y, color)

The no-argument grayscale function converts the bitmap to grayscale and is an implementation of this Rossetacode task: http://rosettacode.org/wiki/Grayscale_image

Finally, the bitmap can be saved to a file by calling save:

save(path_to_a_file)

For information on the bitmap format, see http://en.wikipedia.org/wiki/BMP_file_format

A module containing classes for manipulating bitmap images

Introduced classes

class Bitmap

bitmap :: Bitmap

All class definitions

class Bitmap

bitmap $ Bitmap

package_diagram bitmap::bitmap bitmap core core bitmap::bitmap->core

Ancestors

module abstract_collection

core :: abstract_collection

Abstract collection classes and services.
module abstract_text

core :: abstract_text

Abstract class for manipulation of sequences of characters
module array

core :: array

This module introduces the standard array structure.
module bitset

core :: bitset

Services to handle BitSet
module bytes

core :: bytes

Services for byte streams and arrays
module circular_array

core :: circular_array

Efficient data structure to access both end of the sequence.
module codec_base

core :: codec_base

Base for codecs to use with streams
module codecs

core :: codecs

Group module for all codec-related manipulations
module collection

core :: collection

This module define several collection classes.
module environ

core :: environ

Access to the environment variables of the process
module error

core :: error

Standard error-management infrastructure.
module exec

core :: exec

Invocation and management of operating system sub-processes.
module file

core :: file

File manipulations (create, read, write, etc.)
module fixed_ints

core :: fixed_ints

Basic integers of fixed-precision
module fixed_ints_text

core :: fixed_ints_text

Text services to complement fixed_ints
module flat

core :: flat

All the array-based text representations
module gc

core :: gc

Access to the Nit internal garbage collection mechanism
module hash_collection

core :: hash_collection

Introduce HashMap and HashSet.
module iso8859_1

core :: iso8859_1

Codec for ISO8859-1 I/O
module kernel

core :: kernel

Most basic classes and methods.
module list

core :: list

This module handle double linked lists
module math

core :: math

Mathematical operations
module native

core :: native

Native structures for text and bytes
module numeric

core :: numeric

Advanced services for Numeric types
module protocol

core :: protocol

module queue

core :: queue

Queuing data structures and wrappers
module range

core :: range

Module for range of discrete objects.
module re

core :: re

Regular expression support for all services based on Pattern
module ropes

core :: ropes

Tree-based representation of a String.
module sorter

core :: sorter

This module contains classes used to compare things and sorts arrays.
module stream

core :: stream

Input and output streams of characters
module text

core :: text

All the classes and methods related to the manipulation of text entities
module time

core :: time

Management of time and dates
module union_find

core :: union_find

union–find algorithm using an efficient disjoint-set data structure
module utf8

core :: utf8

Codec for UTF-8 I/O

Parents

module core

core :: core

Standard classes and methods used by default by Nit programs and libraries.

Descendants

module a_star-m

a_star-m

# The Bitmap class represents a 24-bit bitmap image. An instance can be constructed
# by calling load or with_size:
#
# ~~~nitish
# var bm1 = new Bitmap.load(path_to_a_bmp_file)
# var bm2 = new Bitmap.with_size(400, 300)
# ~~~
#
# The width and height attributes contain the image's width and height,
# respectively.
#
# Individual pixels can be manipulated by calling the set_pixel function:
#
# ~~~nitish
#	set_pixel(x, y, color)
# ~~~
#
# The no-argument grayscale function converts the bitmap to grayscale and is an
# implementation of this Rossetacode task:
# http://rosettacode.org/wiki/Grayscale_image
#
# Finally, the bitmap can be saved to a file by calling save:
#
# ~~~nitish
#	save(path_to_a_file)
# ~~~
#
# For information on the bitmap format, see
# http://en.wikipedia.org/wiki/BMP_file_format
#
# A module containing classes for manipulating bitmap images
module bitmap
#
# A class that represents a Bitmap image
class Bitmap
	# The file path if this Bitmap is created by loading a bitmap file
	var file_path: String is noinit

	# The file extension if this Bitmap is created by loading a bitmap file
	var file_extension: String is noinit

	# The file size if this Bitmap is created by loading a bitmap file
	var file_size: Int is noinit

	# The image width in pixels
	var width: Int is noinit

	# The image height in pixels
	var height: Int is noinit

	# The offset of image data. Typically, 54
	private var data_offset: Int is noinit

	# The number of bits representing a pixel. Currently only 24-bit bitmaps are supported
	private var bits_per_pixel: Int is noinit

	# The size of images. For a 24-bit bitmap, this is equal to (3*width*height)
	private var image_size: Int is noinit

	# 14-byte bitmap header
	private var bitmap_header = [66, 77, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0]

	# 40-byte dib header
	private var dib_header = [40, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 1, 0, 24, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

	# The image data, each cell contains a pixel.
	# The first 8 least-significant bits represent the red component,
	# the next 8 least-significant bits represent the green component,
	# and the next 8 bit represent the blue component.
	# The last 8 most-significant bits are not used
	private var data = new Array[Array[Int]]

	# Constructs a Bitmap object by passing the image's width and height (in pixels)
	init with_size(width: Int, height: Int)
	do
		self.width = width
		self.height = height
		self.bits_per_pixel = 24
		self.data_offset = 54
		#set width and height

		self.set_value(dib_header, 4, width)
		self.set_value(dib_header, 8, height)
		#set file size
		var file_size = 3 * width * height + 54
		self.set_value(bitmap_header, 2, file_size)

		#init pixel data
		self.data = new Array[Array[Int]].with_capacity(height)
		for x in [0..height[ do
			var row = new Array[Int].with_capacity(width)
			for y in [0..width[ do
				row.add(0x00FFFFFF)
			end
			self.data[x] = row
		end
	end

	# Creates an instance of Bitmap by loading an existing image file
	init load(path: String)
	do
		self.file_path = path
		var temp = path.file_extension
		if temp != null then
			self.file_extension = temp
		else
			self.file_extension = ""
		end
		var fileReader = new FileReader.open(path)

		# =============== Bitmap header ================
		for x in [0..13] do
			var b = fileReader.read_byte
			if b < 0 then return
			bitmap_header[x] = b
		end
		self.file_size = get_value(bitmap_header.subarray(2, 4))
		self.data_offset = get_value(bitmap_header.subarray(10, 4))

		# =============== DIB header ================
		for x in [0..39] do
			var b = fileReader.read_byte
			if b < 0 then return
			dib_header[x] = b
		end
		var dib_size = get_value(dib_header.subarray(0, 4))
		# only support BITMAPINFOHEADER
		if dib_size != 40 then
			print "This type of bitmap is not supported"
			fileReader.close
			return
		end

		self.width = get_value(dib_header.subarray(4, 4))
		self.height = get_value(dib_header.subarray(8, 4))
		self.bits_per_pixel = get_value(dib_header.subarray(14, 2))
		self.image_size = get_value(dib_header.subarray(20, 4))

		if self.bits_per_pixel != 24 then
			print "Only full color bitmaps are supported"
			fileReader.close
			return
		end

		if self.bits_per_pixel == 24 then
			# assert self.image_size + 54 <= self.file_size
			# start loading image data, for now assume no padding
			for x in [0..self.height[
			do
				var row = new Array[Int].with_capacity(self.width)
				var rgb_str = new CString(3)
				for y in [0..self.width[
				do
					var bts = fileReader.read_bytes_to_cstring(rgb_str, 3)
					if bts < 3 then return
					var red = rgb_str[0] << 16
					var green = rgb_str[1] << 8
					var blue = rgb_str[2]
					row.add(red.to_i + green.to_i + blue.to_i)
				end
				self.data.add(row)
			end
		end
		fileReader.close
	end #end of load_from_file method

	# Converts the value contained in two or four bytes into an Int. Since Nit
	# does not have a byte type, Int is used
	private fun get_value(array: Array[Int]): Int
	do
		var value = 0
		for x in [0..array.length[ do
			value += array[x] * 256.to_f.pow(x.to_f).to_i
		end
		return value
	end

	# Converts the value in an Int to four bytes. Since Nit does not have a byte
	# type, Int is used.
	private fun set_value(array: Array[Int], start_index: Int, value: Int)
	do
		array[start_index] = value & 0x000000FF
		array[start_index + 1] = (value >> 8) & 0x000000FF
		array[start_index + 2] = (value >> 16) & 0x000000FF
		array[start_index + 3] = (value >> 24) & 0x000000FF
	end

	# Saves the bitmap into a file
	fun save(path: String)
	do
		var fw = new FileWriter.open(path)
		# Write bitmap header
		for x in [0..self.bitmap_header.length[ do
			fw.write(self.bitmap_header[x].code_point.to_s)
		end
		# Write dib header
		for x in [0..self.dib_header.length[ do
			fw.write(self.dib_header[x].code_point.to_s)
		end
		# Write color table (if any)
		# Write data (no padding for now)
		for x in [0..self.height[ do
			var row = self.data[x]
			for y in [0..self.width[ do
				var pixel = row[y]
				var red = pixel >> 16
				var green = (pixel & 0x00FF00) >> 8
				var blue = pixel & 0x000000FF
				fw.write(red.code_point.to_s)
				fw.write(green.code_point.to_s)
				fw.write(blue.code_point.to_s)
			end
		end
		fw.close
	end #end of save

	# Converts the bitmap to grayscale by manipulating each individual pixel
	fun grayscale
	do
		for x in [0..self.height[ do
			var row = self.data[x]
			for y in [0..self.width[ do
				var pixel = row[y]
				var red = pixel >> 16
				var green = (pixel & 0x00FF00) >> 8
				var blue = pixel & 0x000000FF
				var lum = (0.2126 * red.to_f + 0.7152 * green.to_f + 0.0722 * blue.to_f).to_i
				pixel = lum * 256 * 256 + lum * 256 + lum
				self.data[x][y] = pixel
			end
		end
	end

	# Sets an individual pixel, where position (0, 0) represents the top-left pixel.
	fun set_pixel(x: Int, y: Int, color: Int)
	do
		if x >= 0 and y >= 0 and x < self.width and y < self.height then
			# Since a bitmap stores its rows of pixels upside-down, y is mapped to
			# height - 1 - y to make (0, 0) the top-left pixel
			self.data[self.height - 1 - y][x] = color
		end
	end
end
lib/bitmap/bitmap.nit:17,1--262,3