
0. Ставим FreeBasic
Так как в моем репозитории free basic-а не оказалось, то идем на страницу загрузки официального сайта (http://www.freebasic.net/get), качаем бинарники (чтобы меньше мороки) и устанавливаем:$ wget -c http://downloads.sourceforge.net/fbc/FreeBASIC-0.24.0-linux.tar.gz ... $ tar -xvf ./FreeBASIC-0.24.0-linux.tar.gz ... $ cd FreeBASIC-0.24.0-linux/ $ sudo ./install.sh -i FreeBASIC compiler successfully installed in /usr/localпроверяем:
$ fbc -version FreeBASIC Compiler - Version 0.24.0 (08-19-2012) for linux Copyright (C) 2004-2012 The FreeBASIC development team. objinfo (libbfd 217)все ОК. приступаем к реализации задачи.
1. Простейший случай (описанный в книге)
Для получения результата описанного в книге, проделаем все тоже самое, т.е. по пути наименьшего сопротивленияЗадаем константы и подключаем модуль работы с графикой, объявляем переменные
#Include "fbgfx.bi" 'Высота и ширина нашей картинки #define BMP_WIDTH 80 #define BMP_HEIGHT 60 #define BMP_FILENAME "title.bmp" 'Имя файла BMP изображения #define BAS_FILENAME "title.bi" 'Имя выходного файла с массивом DIM buffer AS ANY PTR 'указатель на облость памяти для хранения изображения DIM as INTEGER x,y Dim title(BMP_WIDTH*BMP_HEIGHT) As UInteger Dim As Integer fpИнициализируем графику и загрузим BMP изображение.
ScreenRes 640, 480, 16 'Создадим графическое окно приложения buffer = IMAGECREATE(BMP_WIDTH, BMP_HEIGHT) 'Выделим память под изображение BLOAD BMP_FILENAME, buffer 'Загрузим изображение в памятьВыведем ее на экран
SCREENLOCK PUT (0,0), buffer SCREENUNLOCKПрочитаем цвета пикселей экрана в массив
FOR y=0 to BMP_HEIGHT-1 FOR x=0 to BMP_WIDTH-1 title(x+y*BMP_WIDTH)=Point(x,y) NEXT x NEXT yСохраним массив цветов на диск в виде FreeBasic кода
fp = FreeFile() 'Поучим свободный указатель на файл Open BAS_FILENAME For Output As #fp 'Откроем файл на запись (если файл существует - данные перезапишутся) 'Запишем в файл заголовок. инструкции инициализирующие массив PRINT #fp, "#Define titlew "; BMP_WIDTH PRINT #fp, "#Define titleh "; BMP_HEIGHT PRINT #fp, "Dim Shared title(";(BMP_WIDTH * BMP_HEIGHT);") As UInteger = { _" 'Добавим значения цветов FOR y=0 to BMP_HEIGHT-1 FOR x=0 to BMP_WIDTH-1 PRINT #fp, title(x+y*BMP_WIDTH); IF y<(BMP_HEIGHT-1) OR x<(BMP_WIDTH-1) THEN PRINT #fp,", "; NEXT x PRINT #fp, " _" NEXT y ' Запишем последнюю строку - завершение инициализации массива PRINT #fp, "}" Close #fp 'Закроем файл
полный код программы:
/'**************************************************************************** * * Name: bmp_to_bas.bas * * Description: Demo for chapter 1 of Richard D. Clark wikibook * "Let's Build a Roguelike" * * Synopsys: BMP image to bas source converter * * Copyright 2013, Kanstansin A. Ashuika (aka Uvadzucumi, Fantik, etc...) * * The Wide Open License (WOL) * * Permission to use, copy, modify, distribute and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice and this license appear in all source copies. * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF * ANY KIND. See http://www.dspguru.com/wol.htm for more information. * *****************************************************************************'/ #Include "fbgfx.bi" 'BMP Image Width and Height #define BMP_WIDTH 80 #define BMP_HEIGHT 60 #define BMP_FILENAME "title.bmp" 'Input bmp image file name #define BAS_FILENAME "title.bi" 'Output bas file name DIM buffer AS ANY PTR 'Pointer for load bmp image DIM as INTEGER x,y DIM title(BMP_WIDTH * BMP_HEIGHT) AS UINTEGER DIM AS INTEGER fp SCREENRES 640, 480, 16 'Create graphics window buffer = IMAGECREATE(BMP_WIDTH, BMP_HEIGHT) 'Allocate memory for image buffer BLOAD BMP_FILENAME, buffer 'Load image 'Block screen and draw image SCREENLOCK PUT (0,0), buffer SCREENUNLOCK 'read pixel colors to array FOR y=0 to BMP_HEIGHT-1 FOR x=0 to BMP_WIDTH-1 title(x+y*BMP_WIDTH)=Point(x,y) NEXT x NEXT y PRINT "Press any key to continue..." SLEEP 'free image buffer IMAGEDESTROY buffer SCREEN 0 'Text mode fp = FREEFILE() 'Get free file handle OPEN BAS_FILENAME FOR OUTPUT AS #fp 'Open file for write 'Write first strings PRINT #fp, "'Useage: (uinteger) pixel = title(x + y * titlew)" PRINT #fp, "#Define titlew "; BMP_WIDTH PRINT #fp, "#Define titleh "; BMP_HEIGHT PRINT #fp, "Dim Shared title(";(BMP_WIDTH * BMP_HEIGHT);") As UInteger = { _" FOR y=0 to BMP_HEIGHT-1 FOR x=0 to BMP_WIDTH-1 PRINT #fp, title(x+y*BMP_WIDTH); IF y<(BMP_HEIGHT-1) OR x<(BMP_WIDTH-1) THEN PRINT #fp,", "; NEXT x PRINT #fp, " _" NEXT y ' Write last string PRINT #fp, "}" CLOSE #fp 'Close file PRINT "File "+BAS_FILENAME+" Saved." PRINT "Press any key to exit..." SLEEP
2. Что можно улучшить
Как можно убедиться, наша программа выполняет поставленную задачу. Однако, если нам подадобиться сконвертировать картинку, которая сохранена в файле под именем, отличным от title.bmp, то нам необходимо будет перекомпилировать программу, что несколько неудобно. Исправим это, получением имени входного файла из командной строки.2.1. Имена входного и выходного файлов
в FreeBasic-е есть зашитые в компилятор макросы __fb_argc__ и __fb_argv__, первый содердит количество параметров командной строки, второй - указатель на массив указателей строк, заканчивающихся 0. Используя их мы можем получать доступ к параметрам командной строки.DIM AS STRING bmpFile, basFile 'Строковые переменные для имен файлов DIM argc AS INTEGER = __fb_argc__ 'Количество параметров DIM argv AS ZSTRING PTR PTR = __fb_argv__ 'Указатель на массив параметров 'Get bmp and output bas file name from command promt SELECT CASE argc CASE 2 'если не задано имя выходного файла bmpFile = *argv[1] 'в argv[1] содержиться указатель на строку. используем * для доступа к содержимому basFile = BAS_FILENAME 'имя выходного задается значением по умолчанию CASE 3 'оба параметра заданы bmpFile = *argv[1] 'имя входного файла basFile = *argv[2] 'имя выходного файла CASE ELSE 'не задано имя входного файла - выведем помощь по использованию программы PRINT "BMP Image to FreeBasic array Converter. Version 2." PRINT "Usage: bmp_to_bas.v2 imput_bmp_filename [ output_bas_filename ]" END END SELECTТеперь у нас в переменных bmpFile и basFile содержаться имена входного и выходного файлов, которые можно задавать в командной строке при вызове программы, без необходимости ее перекомпиляции. Однако, нам все еще нужно будет перекомпилировать программу, если размер исходного изображения отличается от заданных нами по умолчанию 80x60 пикселей, мы могли бы также считыватьэти значения из командной строки, но можно их получать прямо из самого изображения.
2.2. Размер изображения
Так как формат bmp файлов известен, а в нем по смещениям 19 и 23, от начала файла, храняться, соответственно, высота и ширина изображения, то мы можем их прочитать прямо из самого файла картинки.'Переменные для хранения высоты и ширина исходного изображения DIM AS INTEGER bmpwidth, bmpheight 'Откроем файл на чтение и бинарном режиме fp = FREEFILE() IF OPEN( bmpFile FOR BINARY ACCESS READ AS #fp ) <> 0 THEN PRINT "Error open input BMP file: "; bmpFile 'Сообщение об ошибке и выход из программы, если невозможно открыть файл END ELSE 'Get BMP dimensions GET #fp, 19, bmpwidth 'читаем 4 байта GET #fp, 23, bmpheight 'читаем 4 байта ENDIF CLOSE #fp 'закроем файлТеперь у нас есть высота и ширина изображения. Так как изначально мы не знаем их, то нам необходимо изменить принцип объявления массива цветов. а именно, в начале программы объявим массив нулевой длинны:
DIM title() AS UINTEGERпосле того, как получим значение высоты и ширины изображения, изменим размерность массива:
REDIM title(0 To bmpwidth * bmpheight) AS UINTEGERТеперь нашу программу можно вызывать командами:
bmp_to_bas.v2 title.bmpили
bmp_to_bas.v2 title.bmp title.biпри этом правильно будут обрабатываться изображения различного разрешения. полный код программы:
/'**************************************************************************** * * Name: bmp_to_bas.bas * * Description: Demo for chapter 1 of Richard D. Clark wikibook * "Let's Build a Roguelike" * * Synopsys: BMP image to bas source converter. Version 2 * * Copyright 2013, Kanstantsin A. Ashuika (aka Uvadzucumi, Fantik, etc...) * * The Wide Open License (WOL) * * Permission to use, copy, modify, distribute and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice and this license appear in all source copies. * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF * ANY KIND. See http://www.dspguru.com/wol.htm for more information. * *****************************************************************************'/ #Include "fbgfx.bi" #define BAS_FILENAME "title.bi" 'Output bas file name 'BMP Image Width and Height DIM AS INTEGER bmpwidth, bmpheight DIM buffer AS ANY PTR 'Pointer for load bmp image DIM AS INTEGER x,y DIM title() AS UINTEGER DIM AS INTEGER fp DIM AS STRING bmpFile, basFile DIM argc AS INTEGER = __fb_argc__ DIM argv AS ZSTRING PTR PTR = __fb_argv__ 'Get bmp and output bas file name from command promt SELECT CASE argc CASE 2 bmpFile = *argv[1] ' argv[1] - contained pointer to first parameter, * - for return string basFile = BAS_FILENAME CASE 3 bmpFile = *argv[1] basFile = *argv[2] CASE ELSE PRINT "BMP Image to FreeBasic array Converter. Version 2." PRINT "Usage: bmp_to_bas.v2 imput_bmp_filename [ output_bas_filename ]" END END SELECT SCREENRES 640, 480, 16 'Create graphics window 'Get bitmap image width and height fp = FREEFILE() IF OPEN( bmpFile FOR BINARY ACCESS READ AS #fp ) <> 0 THEN PRINT "Error open input BMP file: "; bmpFile END ELSE 'Get BMP dimensions GET #fp, 19, bmpwidth GET #fp, 23, bmpheight ENDIF CLOSE #fp 'Set colors array size REDIM title(0 To bmpwidth * bmpheight) AS UINTEGER buffer = IMAGECREATE(bmpwidth, bmpheight) 'Allocate memory for image buffer BLOAD bmpFile, buffer 'Load image 'Block screen and draw image SCREENLOCK PUT (0,0), buffer SCREENUNLOCK 'read pixel colors to array FOR y=0 to bmpheight-1 FOR x=0 to bmpwidth-1 title(x+y*bmpwidth)=Point(x,y) NEXT x NEXT y PRINT "Press any key to continue..." SLEEP 'free image buffer IMAGEDESTROY buffer SCREEN 0 'Text mode fp = FreeFile() 'Get free file handle OPEN basFile FOR OUTPUT AS #fp 'Open file for write 'Write first strings PRINT #fp, "'Useage: (uinteger) pixel = title(x + y * titlew)" PRINT #fp, "#Define titlew "; bmpwidth PRINT #fp, "#Define titleh "; bmpheight PRINT #fp, "Dim Shared title(";(bmpwidth * bmpheight);") As UInteger = { _" FOR y=0 to bmpheight-1 FOR x=0 to bmpwidth-1 PRINT #fp, title(x+y*bmpwidth); IF y<(bmpheight-1) OR x<(bmpwidth-1) THEN PRINT #fp,", "; NEXT x PRINT #fp, " _" NEXT y ' Write last string PRINT #fp, "}" CLOSE #fp 'Close file PRINT "File "+basFile+" Saved." PRINT "Press any key to exit..." SLEEP
3. Мысли на тему
На самом деле, как можно увидеть, мы делаем кучу ненужных промежуточныx действи. Т.е. мы грузим bmp картинку (которая из себя представляет двумерный массив цветов) в память, рисуем ее на экране (копируем массив цветов из кортинки в память видебуффера), читаем цвета пикселей в массив (массив цветов из видеобуффера в массив в оперативной памяти), сохраняем этот массив на диск в виде free basic кода. Кучу всех этих повторных копирований можно избежать, просто загрузив bmp файл в память и, читая цвета из оперативной памяти, отрисовывавать титульный экран.4. Полезные ссылки
- Wiki с описанием ключевых слов графической библиотеки Free Basic. (eng)
- официальный сайт FreeBasic (eng)
- Туториалы по FreeBasic (eng)
- http://free-basic.ru/ - Русскоязычный сайт с кучей и еще чуть-чуть статей (и не только) по FreeBasic. (rus)
Большое спасибо за программу
ОтветитьУдалитьВ 7-й винде код неправильно определял размер картинки, в результате программа падала с кастрюльным звоном, заменил на такой
ОтветитьУдалить#include "windows.bi"
....
dim as BITMAPINFOHEADER ptr pbmi = allocate(sizeof(BITMAPINFOHEADER))
IF OPEN( bmpFile FOR BINARY ACCESS READ AS #fp ) <> 0 THEN
PRINT "Error open input BMP file: "; bmpFile
END
ELSE
get #fp, sizeof(BITMAPFILEHEADER)+1, *pbmi
bmpwidth = pbmi->biWidth
bmpheight = pbmi->biHeight
deallocate pbmi
ENDIF
....
Идея взята отсюда http://www.freebasic.net/forum/viewtopic.php?f=3&t=21201
Картинку сохранял в Paint как 24х разрядный bmp.