|
Post by honkytonk on Nov 24, 2020 16:13:42 GMT
Good morning all This function (taken here, thanks)
function GetPixelValue$(x, y) #t.m, "getbmp gpv "; x; " "; y; " "; 1; " "; 1 bmpsave "gpv", "getpvaluetemp.bmp" open "getpvaluetemp.bmp" for input as #gpv s$ = input$(#gpv, lof(#gpv)) close #gpv if asc(mid$(s$, 29, 1)) = 32 then red = asc(mid$(s$, 69, 1)) green = asc(mid$(s$, 68, 1)) blue = asc(mid$(s$, 67, 1)) end if GetPixelValue$ = str$(red)+" "+str$(green)+" "+str$(blue) kill "getpvaluetemp.bmp" unloadbmp "gpv" end function
Returns the RGB of a displayed pixel. But would there be a way to apply it to a bmp in memory (not displayed) or in file? Thank you for.
|
|
|
Post by tsh73 on Nov 24, 2020 20:20:37 GMT
What are you trying to do?
How stuff is stored in BMP is known (there are several formats due to color depth but we can agree to use one that Just BASIC saves with BMPSAVE - 32 bit)
so one can read bitmap header - get image dimensions - use them to calculate point in a file - load 3 bytes from it, get the color.
I have old code that reads all pixels from the file (and draws it) I just run it - it works for me You can start from here.
as for bmp in memory - is it a bmp read from file? then there is no much difference.
But if you hope to work with bmp loaded in JustBASIC with LOADBMP or captured with GETBMP - I'm afraid there is no way (except using from file)
'read BMP pixel by pixel 'by tsh73 'compiled from various sources (sources in C and QB) to Just Basic 1.01 '10 May 2007 'released to public domain ' - to all Just Basic users who find this interesting (or useful) '(+): fixed 25 11 2017 for offset not (%4 == 0)
'all color depths I've seen (1, 4, 8 and 24) 'no compression 'examples created by Gimp from very old file of unknown origin YROSE.JPG
filedialog "Open BMP file", "*.bmp", fname$ open fname$ for binary as #1 print "File "+stripPath$(fname$) +" length is ";lof(#1)
print " ======= BMPHeader ============" print "ValidID (first 2 bytes) is: (should be BM)";tab(45);readStr$(2) print "fileSize";tab(45);readLong() print "reserved";tab(45);readLong() offset = readLong() print "offset";tab(45);offset print " ======= WindowsInfoHeader ===========" print "SizeOfHeader (should be 40)";tab(45); readLong() BMwidth = readLong() print "width";tab(45); BMwidth BMheight = readLong() print "height";tab(45); BMheight print "planes (should be 1)" ;tab(45);read2Bytes() bpp = read2Bytes() print "BitsPerPixel (bpp)";tab(45); bpp CompressMethod = readLong() print "CompressMethod";tab(45); CompressMethod;" ";word$("Uncompressed|8 Bit RLE Compression|4 Bit RLE Compression|bi_bitfields",CompressMethod+1,"|") imagebytes = readLong() print "imagebytes";tab(45); imagebytes print "xres";tab(45); readLong() print "yres";tab(45); readLong() colch = readLong() print "ColorsUsed";tab(45); colch ' could be 0 - All Used print "ImportantColors";tab(45); readLong()
print " ======= calculated info ===========" currPos = LOC(#1) print "curr pos is ";tab(45);currPos print "for palette left ";tab(45); offset - currPos print "for palette colors ";tab(45); (offset - currPos)/4 ' == colch if colch = 0 then colch = (offset - currPos)/4 '??? 'because it could be 0 - All Used print "imagebytes + offset " ;tab(45); imagebytes + offset
byteWidth = BMwidth*bpp/8 if int(byteWidth)<> byteWidth then byteWidth= int(byteWidth)+1 actualWidth = byteWidth if actualWidth mod 4 <>0 then actualWidth = actualWidth + 4-actualWidth mod 4 'padded to 4 bytes print "line length in bytes ";tab(45);actualWidth print "imagebytes / line length in bytes ";tab(45);imagebytes / actualWidth
if inlist(CompressMethod, "1,2") then print "Compressed bitmaps (RLE encoding) are not supported" close #1 end end if
if not(inlist(bpp,"1,4,8,16,24,32")) then print "Color depth (bits per pixel, bpp) other then 1,4,8,16,24,32 is not supported" close #1 end end if
if colch = 0 then print " ======= No palette present ===========" goto [skipPalette] end if
'** palette goes here dim rpal(255),gpal(255),bpal(255),spal$(255) for i = 0 to colch-1 bpal(i) = readByte() gpal(i) = readByte() rpal(i) = readByte() spal$(i) = str$( rpal(i))+" "+str$( gpal(i))+" "+str$( bpal(i)) 'print spal$(i) dummy$ = input$(#1, 1) 'skip one byte if i >=255 then exit for next i
seek #1, offset
if CompressMethod = 3 then print "Color masks are:" i = 0 redMask = ((rpal(i)*256)+ gpal(i))*256+ bpal(i) print "Red"; tab(8); hex$(redMask) i = 1 greenMask = ((rpal(i)*256)+ gpal(i))*256+ bpal(i) print "green";tab(8); hex$(greenMask) i = 2 blueMask = ((rpal(i)*256)+ gpal(i))*256+ bpal(i) print "blue"; tab(8); hex$(blueMask) end if
'show palette WindowWidth = 400 WindowHeight = 400 open "Palette" for graphics_nf_nsb as #pal print #pal, "trapclose [endPalette]"
for i =0 to 15 for j =0 to 15 y = i*20+20 x = j*20+20 x1 = x+15 y1 = y+15 ind = i*16+j if ind > colch-1 then exit for print #pal, "backcolor ";spal$(ind) print #pal, "up" print #pal, "goto ";x;" ";y print #pal, "down" print #pal, "boxfilled ";x1;" ";y1
next j if ind > colch-1 then exit for next i print #pal, "flush" 'make the graphics stick print " ======= palette present ===========" print colch; " colors" print "close palette window to view image" wait
[endPalette] close #pal
[skipPalette]
startTime = time$("ms") '** now the picture itself... WindowWidth = BMwidth+8 ' + window border 'WindowHeight = BMheight+20 ' + window header, win2000 style WindowHeight = BMheight+34 ' + window header, XP style open "picture" for graphics_nf_nsb as #gr1 'print #gr1, "trapclose Quit" print #gr1, "trapclose [gr1End]" print #gr1, "down" 'ready to draw print #gr1, "north ; turn 90"
oldInd = 999 'magic FOR y = BMheight-1 TO 0 step -1 ' Countdown for upsidedown image aLine$ = readStr$(actualWidth) print #gr1, "place 0 ";y FOR x = 0 TO BMwidth-1 select case bpp case 1 byte = asc(mid$( aLine$, int(x/8)+1, 1)) ' pos = 7 - x mod 8 ' pow2 = 2^pos ' if (byte and pow2) <> 0 then ' ind = 1 ' else ' ind = 0 ' end if ind = ((byte and (2^(7 - x mod 8))) <> 0) if oldInd <> ind then print #gr1, "color "; spal$(ind) oldInd = ind end if print #gr1, "go 1" case 4 byte = asc(mid$( aLine$, int(x/2)+1, 1)) if x mod 2 <> 0 then ind = byte mod 16 else ind = int(byte / 16) end if if oldInd <> ind then print #gr1, "color "; spal$(ind) oldInd = ind end if print #gr1, "go 1" case 8 ind = asc(mid$( aLine$, x+1, 1)) if oldInd <> ind then print #gr1, "color "; spal$(ind) oldInd = ind end if print #gr1, "go 1"
case 16 bytes = byte2Num(mid$( aLine$, 2*x+1, 2)) 'if CompressMethod = 3 then r = (bytes AND redMask) /256 g = (bytes AND greenMask) / 32 * 4 b = (bytes AND blueMask) * 8 'end if print #gr1, "color ";r;" ";g;" ";b print #gr1, "go 1" case 24 r = asc(mid$( aLine$, 3*x+3, 1)) g = asc(mid$( aLine$, 3*x+2, 1)) b = asc(mid$( aLine$, 3*x+1, 1)) print #gr1, "color ";r;" ";g;" ";b print #gr1, "go 1" case 32 r = asc(mid$( aLine$, 4*x+3, 1)) g = asc(mid$( aLine$, 4*x+2, 1)) b = asc(mid$( aLine$, 4*x+1, 1)) print #gr1, "color ";r;" ";g;" ";b print #gr1, "go 1" end select NEXT x next y
print #gr1, "flush" 'make the graphics stick 'print #gr1, "redraw" endTime=time$("ms") print print "Drawing BMP (not incl. palette) took "; print endTime-startTime; " milliseconds" close #1
wait
[gr1End] close #gr1
end
' some functions ********************************************8 function readByte() readByte = asc(input$(#1, 1)) end function
function readLong() readLong = byte2Num(input$(#1, 4)) end function
function read2Bytes() read2Bytes = byte2Num(input$(#1, 2)) end function
function readStr$(n) readStr$ = input$(#1, n) end function
function byte2Num(c$) res = 0 for i = len(c$) to 1 step -1 'lower byte first res = res * 256+asc(mid$(c$,i,1)) next i byte2Num = res end function
function stripPath$(fname$) found = 0 for i = len(fname$) to 1 step -1 c$=mid$(fname$,i,1) 'print i; c$, if c$="\" then found = 1 exit for end if next i if found then stripPath$ = mid$(fname$,i+1) else stripPath$ = fname$ end if end function
function inlist(aVal, list$) list$ = ","+list$+"," inlist = (instr(list$, ","+str$(aVal)+",")<>0) end function
Function hex$(n) h$ = "" do h$ = mid$("0123456789ABCDEF", (n mod 16)+1, 1) + h$ n = int(n/16) loop while n > 0 hex$ = h$ End Function
|
|
|
Post by honkytonk on Nov 25, 2020 0:12:26 GMT
I try to modify a bmp according to its colors, and the processing time depends on the dimensions, the bigger it is the longer it is; So I would like to reduce the time if possible. Thanks a lot for your code, I will see what I can do with it.
EDIT: Wow ! It is very complex. It will take a lot of thinking to understand everything. Thank you again TSH73 Anatoly.
|
|
|
Post by tenochtitlanuk on Nov 25, 2020 9:44:55 GMT
Over the years I've had a lot of fun modifying images. Many examples on my website. I use method of Anatoly on bmps, and also in LB use getpixel. ExampleBut recently I found the following much easier method... use ppm images. I particularly recommend you use your painting package ( I use the free GIMP) to save your images as *.ppm, in 'raw' format. These are like bmp files in having each pixel stored as three RGB bytes, but have a MUCH simpler introductory section. You read it as a file, usually into a 2D array, then read the coloured pixels and do what you like on them... it's the fastest way I have found in JB/LB. You only need to display the altered pixels on-screen if you like watching or are testing- setting pixels will slow the conversion down a LOT. You can always load the altered image back into GIMP and re-save as jpg or gif depending on what you want to do with it. link
|
|
|
Post by honkytonk on Nov 25, 2020 12:26:09 GMT
Over the years I've had a lot of fun modifying images. Many examples on my website. I use method of Anatoly on bmps, and also in LB use getpixel. ExampleBut recently I found the following much easier method... use ppm images. I particularly recommend you use your painting package ( I use the free GIMP) to save your images as *.ppm, in 'raw' format. These are like bmp files in having each pixel stored as three RGB bytes, but have a MUCH simpler introductory section. You read it as a file, usually into a 2D array, then read the coloured pixels and do what you like on them... it's the fastest way I have found in JB/LB. You only need to display the altered pixels on-screen if you like watching or are testing- setting pixels will slow the conversion down a LOT. You can always load the altered image back into GIMP and re-save as jpg or gif depending on what you want to do with it. linkRegarding your example: LB is much more powerful (by access to DLLs) than JB, but I prefer to stay with JB to allow access to beginners, who start with JB. And I prefer also to stay in the ".BMP" format, the only one recognized by JB.
|
|
|
Post by Rod on Dec 16, 2020 19:45:22 GMT
This is just a rehash of Anatoly's binary file access method. I have tried to keep it simple. One learning point is that you need to close the file before the last write is recorded. The code updates all pixels or allows fast set pixel and get pixel access. I use global Red Green Blue variables to retrieve the color data very much like MouseX MouseY etc.
This should really copy the supplied bmp, it does not so it will trash any .bmp you give it so feed it a copy .bmp.
WindowWidth = 700 WindowHeight = 400 UpperLeftX = (DisplayWidth-WindowWidth)/2 UpperLeftY = (DisplayHeight-WindowHeight)/2 graphicbox #1.gb1,10,10,300,300 graphicbox #1.gb2,330,10,300,300 open "SET GET Pixel" for graphics_nf_nsb as #1 #1 "trapclose [quit]" global bmpw,bmph,padding,offset,bytes,Blue,Green,Red
[loadbmp] filedialog "Choose an image","*.bmp",file$ if file$<>"" then 'display the original bmp in gb1 loadbmp "original",file$ #1.gb1 "down ; drawbmp original 0 0"
'now open the same bmp file for binary read/write access open file$ for binary as #bmp
'analyse the file header bytes seek #bmp,10 'picture data offset, where the color data starts 4 bytes of data offset=asc(input$(#bmp,1))+asc(input$(#bmp,1))*256+asc(input$(#bmp,1))*65536+asc(input$(#bmp,1))*16777216 seek #bmp,18 'width 4 bytes of data bmpw=asc(input$(#bmp,1))+asc(input$(#bmp,1))*256+asc(input$(#bmp,1))*65536+asc(input$(#bmp,1))*16777216 seek #bmp,22 'height 4 bytes of data bmph=asc(input$(#bmp,1))+asc(input$(#bmp,1))*256+asc(input$(#bmp,1))*65536+asc(input$(#bmp,1))*16777216 seek #bmp,28 'bits per pixel, ie color depth 2 bytes of data bits=asc(input$(#bmp,1))+asc(input$(#bmp,1))*256
'work out start of picture data and how to move through file pointer=offset
'work out how many bytes in the bits per pixel 24=3 bgr 32=4 abgr bytes=bits/8
'work out padding each raster line must be a 4byte multiple mult=bits/8*bmpw/4 padding = 4*(1-(mult-int(mult))) mod 4 close #bmp
end if
[setall] 'this demo updates every pixel of the image open file$ for binary as #bmp
for y=1 to bmph for x=1 to bmpw
'run through binary file data moving the file pointer as we go seek #bmp, pointer
'get pixel color stored as BGR Liberty needs RGB b=asc(input$(#bmp,1)) g=asc(input$(#bmp,1)) r=asc(input$(#bmp,1))
'change the color r=r-150 if r<0 then r=0
'set pixel color 'because we read three bytes we need to set the file pointer back seek #bmp, pointer #bmp chr$(b);chr$(g);chr$(r);
'move on pointer=pointer+bytes next
'add padding at end of raster line pointer=pointer+padding next
'note we need to close the file to have Windows 'write the last update close #bmp gosub [show]
[setpixel] 'this demo sets individual pixels via function setpixel() 'open temporary file for read and write access open file$ for binary as #bmp for n=0 to bmpw-1 'zero index null=setpixel(n,n,0,0,0) 'x,y,r,g,b next close #bmp gosub [show]
[getpixel] 'this demo retrieves the RBG of a pixel via function getpixel() 'open temporary file for read and write access open file$ for binary as #bmp 'run along top line for n=0 to bmpw-1 'zero index null=getpixel(n,0) 'x,y 'the global RGB variables are filled print Red,Green,Blue next close #bmp
wait
[show] 'show what we did, load file as bmp and display loadbmp "newfile",file$ #1.gb2 "down ; drawbmp newfile 0 0" return
[quit] close #1 end
function setpixel(x,y,r,g,b) 'raster lines are stored bottom up so we invert y y=(bmph-1)-y pointer=offset+x*bytes+y*(bmpw*bytes+padding) 'set pixel color seek #bmp, pointer #bmp chr$(b);chr$(g);chr$(r); end function
function getpixel(x,y) 'raster lines are stored bottom up so we invert y y=(bmph-1)-y pointer=offset+x*bytes+y*(bmpw*bytes+padding) 'get pixel color stored as BGR Liberty needs RGB seek #bmp, pointer Blue=asc(input$(#bmp,1)) Green=asc(input$(#bmp,1)) Red=asc(input$(#bmp,1)) end function
|
|
|
Post by Enzo on Dec 16, 2020 22:15:09 GMT
This is all the code needed to load bmp data to either an array or memory, or am I missing something? I am trying to store bmp data in a string$ = "DATAFORMAT" to include images in my program while not having the user download the .bmp file, or a self unpacking .exe
global n, bmpw, y, pointer, offset, x, bytes, y, bmpw, padding, Red, Blue, Green function file$(file$) open file$ for binary as #bmp for n=0 to bmpw-1 'zero index null=getpixel(n,0) 'x,y 'print Red,Green,Blue next close #bmp end function function getpixel(x,y) y=(bmph-1)-y pointer=offset+x*bytes+y*(bmpw*bytes+padding) seek #bmp, pointer Blue=asc(input$(#bmp,1)) Green=asc(input$(#bmp,1)) Red=asc(input$(#bmp,1)) end function
I was simply going to have it output to a mainwin as;
for x = 1 to numberofbmps bmpfiledata$=file$(str$(x)".bmp") 'files 1-20 1.bmp 2.bmp ect. print "string$(x)="";bmpfiledata$;""" next x
|
|
|
Post by Rod on Dec 17, 2020 8:20:20 GMT
Yes that’s probably all the code you need to open the .bmp. However you need to know the header info to fill the global variables correctly. Also you need the header data at the head of the file if you want to make it a .bmp and load and display it. If the bmps are all the same size and color depth it’s doable.
|
|