| Posted by
| Nick Gammon
Australia (23,173 posts) Bio
Forum Administrator |
| Message
| Version 4.42 of MUSHclient introduces a new feature - the ability to load PNG images already loaded into memory.
The reason for this is to make it easier for plugin authors to distribute a plugin with a batch of images (eg. icons) associated with it. Instead of having to install dozens of image files, you can now simply distribute a SQLite database, and the plugin can then extract out images, as required, from the database.
Below I show how you can do this.
This feature is only available to Lua scripting, as Lua supports strings which are 8-bit "clean", in other words with any value including 0x00.
First, an example of creating such a database:
-- open database on disk (in MUSHclient application directory)
db = assert (sqlite3.open (GetInfo (66) .. "images.db"))
-- create a table
assert (db:execute[[
DROP TABLE IF EXISTS images;
CREATE TABLE images (
name text,
image blob,
PRIMARY KEY (name)
);
]])
local f = assert (io.open (GetInfo (66) .. "sword.png", "rb"))
local s = f:read ("*a") -- read all of it
f:close () -- close it
local stmt = db:prepare ("INSERT INTO images VALUES (:name, :image)")
stmt:bind_names {name = "sword", image = s}
stmt:step()
stmt:reset()
stmt:finalize()
-- close database
db:close()
The code above creates or opens a database in the MUSHclient application directory called images.db.
Inside that is created a table (obviously you only do this once), which has the image name as a text field, and the image data as a blob (binary large object).
Next we read into memory an image from the MUSHclient application directory ("sword.png").
To make it easy to insert this data into the database, which may contain binary zeroes, or quote symbols, we use bind_names to bind the data to the name "image". This simplifies the INSERT INTO statement.
The step does the actual insert, putting the row into the database. If you wanted to add more rows, you would then re-execute the stmt:bind_names, stmt:step and stmt:reset for each additional image.
The code above would be done by the plugin author to create the images database.
Now, in the plugin, we can extract out images like this:
-- open database on disk
db = assert (sqlite3.open (GetPluginInfo (20) .. "images.db")) -- open in plugins directory
-- make a window for testing
win = GetPluginID () -- get a unique name
WindowCreate (win, 0, 0, 600, 600, 12, 0, ColourNameToRGB("white")) -- create window
-- find the sword image
for a in db:nrows([[SELECT * FROM images WHERE name = 'sword']]) do
WindowLoadImageMemory (win, "im", a.image)
WindowDrawImage (win, "im", 20, 20, 0, 0, 1) -- straight copy
end
WindowShow (win, true) -- show it
-- close database
db:close()
The code above assumes it is running in a plugin, so it opens the images.db database in the same directory that the plugin is loaded into (a reasonable place to put the database). Then it find the "sword" image in the database, loads that into memory, and draws it from there.
Note that this only works for PNG images (not BMP ones). The PNG loader had provision for reading from memory, and in any case PNG files (being compressed) are likely to be smaller than BMP ones.
Also see http://www.gammon.com.au/forum/?id=9566 which describes loading sound effects from memory. Obviously you could store the sound effects and the images in the same database, which means you still only have one extra file to distribute (apart from the plugin itself).
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | | Top |
|