image1
= _LOADIMAGE("parrot.png", 32) 'load the 256 color image as a 32-bit imageimage2 = Image32To256(image1) 'convert it to a 256 color image
SCREEN image1
'show the image as a 32-bit image SCREEN image2
'show the image as a 256-color image
'As you can see, we have successfully reproduced our 256-color image
SLEEP 'now convert it to a 256 color image, using QB64's standard color palette DIM SHARED ConvertToStandard256Palette
AS LONG 'The shared variable (or CONST) to say "Let's use QB64's standard palette!" ConvertToStandard256Palette = -1 'Set this to TRUE (or -1)
image3 = Image32To256(image1) 'and convert
SCREEN image3
'and you can see how we look a little bit different than we did before
'This routine can benefit/be altered if the user sets a CONST or DIM SHARED variable name ConvertToStandard256Palette, as so:
' CONST ConvertToStandard256Palette = -1
' Set the value to 0 (FALSE) to preseve the color information perfectly, using its default palette.
' If the CONST is set (TRUE), then we convert our colors to as close of a match as possible, while
' preserving the standard QB64 256-color palette.
n
AS LONG 'number of times it appears DO 'get the palette and number of colors used _MEMGET m
(0), m
(0).OFFSET
+ o
, t
'Get the colors from the original screen FOR i
= 0 TO colors
'check to see if they're in the existing palette we're making Pal(colors) = t
colors = colors + 1 'increment the index for the new color found
IF colors
> 256 THEN 'no need to check any further; it's not a normal QB64 256 color image Image32To256 = RemapImageFS(image&, I256)
EXIT FUNCTION 'and we're done, with 100% image compatability saved o = o + 4
' we might be working with a standard qb64 256 color screen
' check for that first
colors = colors - 1 'back up one, as we found our limit and aren't needing to set another
FOR i
= 0 TO colors
'comparing palette against QB64 256 color palette t = Pal(i)
IF NSCU
THEN 'it's not a standard QB64 256 color palette, but it's still less than 256 total colors. IF ConvertToStandard256Palette
THEN TI256 = RemapImageFS(image&, I256)
I256 = TI256 'replace with the new image
m
(1) = _MEMIMAGE(I256
) 'and point the mem block to the new image 'If we didn't change the palette above, we should work 100% with qb64's internal 256 color palette
o = 0
DO 'Get the colors, put them to a 256 color screen, as is _MEMGET m
(0), m
(0).OFFSET
+ o
+ 3, a
_MEMGET m
(0), m
(0).OFFSET
+ o
+ 2, r
_MEMGET m
(0), m
(0).OFFSET
+ o
+ 1, g
_MEMGET m
(0), m
(0).OFFSET
+ o
+ 0, b
o = o + 4
Image32To256 = I256
FUNCTION RemapImageFS&
(ohan&
, dhan&
) 'Routine written by RhoSigma and used (with permission) for SaveImage Library '// +---------------+---------------------------------------------------+
'// | ###### ###### | .--. . .-. |
'// | ## ## ## # | | )| ( ) o |
'// | ## ## ## | |--' |--. .-. `-. . .-...--.--. .-. |
'// | ###### ## | | \ | |( )( ) | ( || | |( ) |
'// | ## ## | ' `' `-`-' `-'-' `-`-`|' ' `-`-'`- |
'// | ## ## # | ._.' |
'// | ## ###### | Sources & Documents placed under the MIT License. |
'// +-------------------------------------------------------------------+
'// | Done by RhoSigma, R.Heyder, provided AS IS, use at your own risk. |
'// | Find me in the QB64 Forum or mail to support[member=111]RhoSigma[/member]-cw.net for |
'// | any questions or suggestions. Thanx for your interest in my work. |
'// +-------------------------------------------------------------------+
RemapImageFS& = -1 'so far return invalid handle
shan& = ohan& 'avoid side effect on given argument
IF shan&
< -1 OR shan&
= 0 THEN '0 represents the visible screen '--- check/adjust source image & get new 8-bit image ---
shan& = than&
than& = -1 'avoid freeing below
'--- Floyd-Steinberg error distribution arrays ---
rhan&
= _NEWIMAGE(swid%
, 2, 32) 'these are missused as LONG arrays, ghan&
= _NEWIMAGE(swid%
, 2, 32) 'with CHECKING:OFF this is much faster bhan&
= _NEWIMAGE(swid%
, 2, 32) 'than real QB64 arrays '--- curr/next row offsets (for distribution array access) ---
cro% = 0: nro% = swid% * 4 'will be swapped after each pixel row
'--- the matrix values are extended by 16384 to avoid slow floating ---
'--- point ops and to allow for integer storage in the above arrays ---
'--- also it's a power of 2, which may be optimized into a bitshift ---
seven% = 7168 '(7 / 16) * 16384 'X+1,Y+0 error fraction
three% = 3072 '(3 / 16) * 16384 'X-1,Y+1 error fraction
five% = 5120 '(5 / 16) * 16384 'X+0,Y+1 error fraction
one% = 1025 '(1 / 16) * 16384 'X+1,Y+1 error fraction
'--- if all is good, then start remapping ---
'--- for speed we do direct memory access ---
'--- iterate through pixels ---
'--- curr/prev/next pixel offsets ---
cpo% = x% * 4: ppo% = cpo% - 4: npo% = cpo% + 4
'--- get pixel ARGB value from source ---
'--- add distributed error, shrink by 16384, clear error ---
'--- current pixel X+0, Y+0 (= cro% (current row offset)) ---
poff% = cro% + cpo% 'pre-calc full pixel offset
sr%
= ((srgb~&
AND &HFF0000~&
) \
65536) + (_MEMGET(rbuf
, roff%&
+ poff%
, LONG) \
16384) 'red sg%
= ((srgb~&
AND &HFF00~&
) \
256) + (_MEMGET(gbuf
, goff%&
+ poff%
, LONG) \
16384) 'green sb%
= (srgb~&
AND &HFF~&
) + (_MEMGET(bbuf
, boff%&
+ poff%
, LONG) \
16384) 'blue _MEMPUT rbuf
, roff%&
+ poff%
, 0 AS LONG 'clearing each single pixel error using _MEMPUT _MEMPUT gbuf
, goff%&
+ poff%
, 0 AS LONG 'turns out even faster than clearing the entire _MEMPUT bbuf
, boff%&
+ poff%
, 0 AS LONG 'pixel row using _MEMFILL at the end of the loop '--- find nearest color ---
crgb~&
= _RGBA32(sr%
, sg%
, sb%
, 0) 'used for fast value clipping + channel merge npen%
= _RGB(sr%
, sg%
, sb%
, nhan&
) '--- put colormapped pixel to dest ---
'------------------------------------------
'--- Floyd-Steinberg error distribution ---
'------------------------------------------
'--- You may comment this block out, to see the
'--- result without applied FS matrix.
'-----
'--- get dest palette RGB value, calc error to clipped source ---
er%
= ((crgb~&
AND &HFF0000~&
) - (nrgb~&
AND &HFF0000~&
)) \
65536 eg%
= ((crgb~&
AND &HFF00~&
) - (nrgb~&
AND &HFF00~&
)) \
256 eb%
= (crgb~&
AND &HFF~&
) - (nrgb~&
AND &HFF~&
) '--- distribute error according to FS matrix ---
'--- X-1, Y+1 (= nro% (next row offset)) ---
poff% = nro% + ppo% 'pre-calc full pixel offset
'--- X+0, Y+1 (= nro% (next row offset)) ---
poff% = nro% + cpo% 'pre-calc full pixel offset
'--- X+1, Y+0 (= cro% (current row offset)) ---
poff% = cro% + npo% 'pre-calc full pixel offset
'--- X+1, Y+1 (= nro% (next row offset)) ---
poff% = nro% + npo% 'pre-calc full pixel offset
'------------------------------------------
'--- End of FS ----------------------------
'------------------------------------------
noff%& = noff%& + 1 'next dest pixel
soff%& = soff%& + 4 'next source pixel
tmp% = cro%: cro% = nro%: nro% = tmp% 'exchange distribution array row offsets
'--- memory cleanup ---
'--- set result ---
RemapImageFS& = nhan&
nhan& = -1 'avoid freeing below
'--- remapping done or error, cleanup remains ---
SUB SaveBMP
(filename$
, image&
, x1%
, y1%
, x2%
, y2%
) 'Super special STEVE-Approved BMP Export routine for use with any QB64 graphic mode.
tempimage& = TextScreenToImage256&(image&)
tempimage& = TextScreenToImage32&(image&)
SaveBMP filename$, tempimage&, x1% * FW, y1% * FH, x2% * FW, y2% * FH
IF x2%
= _WIDTH(imagehandle%
) THEN x2%
= _WIDTH(imagehandle%
) - 1 'troubleshoot in case user does a common mistake for 0-width instead of 0 - (width-1) for fullscreen IF y2%
= _HEIGHT(imagehandle%
) THEN y2%
= _HEIGHT(imagehandle%
) - 1 'troubleshoot in case user does a common mistake for 0-width instead of 0 - (width-1) for fullscreen
BMP.PWidth = (x2% - x1%) + 1
BMP.PDepth = (y2% - y1%) + 1
BMP.ID = "BM"
BMP.Blank = 0
BMP.Hsize = 40
BMP.Planes = 1
BMP.Compression = 0
BMP.Xres = 0
BMP.Yres = 0
BMP.SigColors = 0
OffsetBITS& = 54 + 1024 'add palette in 256 color modes
BMP.BPP = 8
ImageSize&
= (BMP.PWidth
+ LEN(ZeroPAD$
)) * BMP.PDepth
BMP.ImageBytes = ImageSize&
BMP.NumColors = 256
BMP.Size = ImageSize& + OffsetBITS&
BMP.Offset = OffsetBITS&
OffsetBITS& = 54 'no palette in 24/32 bit
BMP.BPP = 24
ImageSize&
= (BMP.PWidth
+ LEN(ZeroPAD$
)) * BMP.PDepth
BMP.ImageBytes = ImageSize&
BMP.NumColors = 0
BMP.Size = ImageSize& * 3 + OffsetBITS&
BMP.Offset = OffsetBITS&
o = n.OFFSET + 54
IF BMP.BPP
= 8 THEN 'Store the Palette for 256 color mode FOR c&
= 0 TO 255 ' read BGR color settings from JPG image + 1 byte spacer(CHR$(0)) o = o + 4
y = y2% + 1
x = x2% - x1% + 1
y = y - 1
_MEMGET m
, m.OFFSET
+ (w&
* y
+ x1%
), temp
o = o + x
o = o + zp&
y = y2% + 1
y = y - 1: x = x1% - 1
x = x + 1
_MEMGET m
, m.OFFSET
+ (w&
* y
+ x
) * 4, temp
o = o + 3
o = o + zp&