Author Topic: BMP picture viewer  (Read 11686 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: BMP picture viewer
« Reply #15 on: February 05, 2021, 01:21:18 pm »
@NOVARSEG

Wow nice job re-interpreting the library for files/folders and using direntry.h !

And those 3 photos are gorgeous!

Thanks for providing files to test, now working, I made some mods you might like for slide show app:

Code: QB64: [Select]
  1. _TITLE "BMP slide show.   Press ESC to exit" ' got it to display can I get it to load
  2.  
  3.     FUNCTION load_dir& (s AS STRING)
  4.     FUNCTION has_next_entry& ()
  5.     SUB close_dir ()
  6.     SUB get_next_entry (s AS STRING, flags AS LONG, file_size AS LONG)
  7.  
  8. DIM flags AS LONG
  9. DIM length AS LONG
  10. DIM F(100) AS STRING
  11. DIM Fcount AS INTEGER
  12. IF load_dir("." + CHR$(0)) = -1 THEN 'found "." this is a folder  not a root drive
  13.     DO
  14.         length = has_next_entry
  15.         IF length = -1 THEN
  16.             EXIT DO
  17.         END IF
  18.         IF length > -1 THEN
  19.             NAM$ = SPACE$(length)
  20.             get_next_entry NAM, flags, file_size
  21.             IF (flags XOR 2) = 0 AND UCASE$(RIGHT$(NAM, 3)) = "BMP" THEN
  22.                 PRINT NAM + "                  "
  23.                 Fcount = Fcount + 1
  24.                 F(Fcount) = NAM
  25.             END IF
  26.         END IF
  27.     LOOP
  28.     Fmax = Fcount
  29. END IF ''''IF load_dir("." + CHR$(0)) = -1 THEN
  30. close_dir '
  31.  
  32. SCREEN _NEWIMAGE(1240, 740, 32) ' as big as I can go for my laptop
  33. _DELAY .25
  34. COLOR , &HFF000033
  35. Fcount = 0
  36.     Fcount = Fcount + 1
  37.     image& = loadBMP24&(F(Fcount))
  38.     IF image& <> 0 THEN
  39.         _TITLE F(Fcount) + " press any for next image..."
  40.         _PUTIMAGE ((_WIDTH - _WIDTH(image&)) / 2, (_HEIGHT - _HEIGHT(image&)) / 2)-STEP(_WIDTH(image&), _HEIGHT(image&)), image&, 0
  41.         IF Fcount = Fmax THEN Fcount = 0
  42.         SLEEP
  43.         _FREEIMAGE image&
  44.         CLS
  45.     END IF
  46.  
  47. FUNCTION loadBMP24& (Filename$)
  48.     DIM OF AS _UNSIGNED LONG
  49.     DIM a AS _MEM
  50.     DIM handle AS LONG
  51.     DIM dh AS LONG
  52.     DIM tt AS STRING * 4
  53.     DIM t AS STRING * 3
  54.     IF RIGHT$(UCASE$(Filename$), 4) <> ".BMP" THEN EXIT FUNCTION
  55.     OPEN Filename$ FOR BINARY AS #1
  56.     GET #1, 11, OF
  57.     GET #1, 15, L
  58.     GET #1, , W
  59.     GET #1, , H
  60.     GET #1, , I
  61.     GET #1, , I 'get I twice ???
  62.     IF I <> 24 THEN EXIT FUNCTION
  63.     handle = _NEWIMAGE(W, H, 32)
  64.     a = _MEMIMAGE(handle)
  65.     FOR R = H - 1 TO 0 STEP -1
  66.         FOR C = 1 TO W * 3 STEP 3
  67.             GET #1, R * W * 3 + C + OF, t
  68.             tt = t + CHR$(255)
  69.             _MEMPUT a, a.OFFSET + N, tt
  70.             N = N + 4
  71.         NEXT C
  72.     NEXT R
  73.     CLOSE
  74.     dh = _NEWIMAGE(W, H, 32)
  75.     _PUTIMAGE (0, 0), handle, dh
  76.     loadBMP24& = dh
  77.     _MEMFREE a
  78.  

My main purpose was to get that FUNCTION working so we can explore the whole hard disk with Tiny Navigator File Retriever and maybe other image displaying routines or file management things.

EDIT: Oh I am going to need a check last 4 chars = BMP in that function because I won't be screening for that first as you had. Fixed.
« Last Edit: February 05, 2021, 01:29:57 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: BMP picture viewer
« Reply #16 on: February 05, 2021, 01:45:54 pm »
I see you have a question about getting I twice in your code, @bplus.  Here’s basically what you’re fetching, in the header of all BMP files:

Code: QB64: [Select]
  1. TYPE BMPEntry              ' Description                          Bytes    QB64 Function
  2.    ID AS STRING * 2        ' File ID("BM" text or 19778 AS Integer) 2      CVI("BM")
  3.    Size AS LONG            ' Total Size of the file                 4      LOF
  4.    Res1 AS INTEGER         ' Reserved 1 always 0                    2
  5.    Res2 AS INTEGER         ' Reserved 2 always 0                    2
  6.    Offset AS LONG          ' Start offset of image pixel data       4      (add one for GET)
  7. END TYPE                   '                                 Total 14
  8.  
  9. TYPE BMPHeader          'BMP header also used in Icon and Cursor files(.ICO and .CUR)
  10.    Hsize AS LONG           ' Info header size (always 40)           4
  11.    PWidth AS LONG          ' Image width                            4      _WIDTH(handle&)
  12.    PDepth AS LONG          ' Image height (doubled in icons)        4      _HEIGHT(handle&)
  13.    Planes AS INTEGER       ' Number of planes (normally 1)          2
  14.    BPP AS INTEGER          ' Bits per pixel(palette 1, 4, 8, 24)    2      _PIXELSIZE(handle&)
  15.    Compression AS LONG     ' Compression type(normally 0)           4
  16.    ImageBytes AS LONG      ' (Width + padder) * Height              4
  17.    Xres AS LONG            ' Width in PELS per metre(normally 0)    4
  18.    Yres AS LONG            ' Depth in PELS per metre(normally 0)    4
  19.    NumColors AS LONG       ' Number of Colors(normally 0)           4       2 ^ BPP
  20.    SigColors AS LONG       ' Significant Colors(normally 0)         4
  21. END TYPE                   '                 Total Header bytes =  40  

And if you want to know more about decoding them from there, let me know.  ;)

That first I you’re getting is for number of planes; second I is for bits per pixel.
« Last Edit: February 05, 2021, 01:50:23 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: BMP picture viewer
« Reply #17 on: February 05, 2021, 01:50:42 pm »
Thanks Steve, so that is how the 24 style BMP is detected.

Almost have Navigator ready to see if I have any  more of these special BMP's on my Hard Drive, I suspect JB images might be?

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: BMP picture viewer
« Reply #18 on: February 05, 2021, 02:04:17 pm »
One thing I’m curious about here:  How do you keep from warping your image, without accounting for the padding in the image data?

Bitmaps are strict on how many bits they store per row, and they need to be multiples of 4.  If your image doesnt fit that criteria, you add padding to it.

Say a 4 pixel wide image would be stored as RGBRGBRGBRGB.  12 bytes per row, no padding is needed.

But a 3 pixel wide image is RGBRGBRGB — or only 9 bytes.  You tack 3 bytes of padding onto the end of it.

From what I can tell, it doesn’t seem like there’s any adjusting for the padding in the code?  Will what you’re doing work with non-size-4 images?

EDIT:

IF ((BMP.PWidth * 3) MOD 4) <> 0 THEN        '’need padding pixels
    Padding$ = SPACE$((4 - ((BMP.PWidth * 3) MOD 4)))
END IF

EDIT 2:
You should get the padding at line 86.5 in your code, at least, that’s my initial thoughts on it.
« Last Edit: February 05, 2021, 02:12:10 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: BMP picture viewer
« Reply #19 on: February 05, 2021, 02:18:55 pm »
Yes now I can explore hard disk for BMP24 files and JB does use that format:
Code: QB64: [Select]
  1. ' B+ started 2019-08-22  restart 2020-06-24
  2. ' 2020-06-24 restart using DirEntry.h, wow looks like Steve's fix helped ALLOT! Thanks SMcNeill
  3. ' I am hitting glitches where Windows wont let me access I think.
  4. ' 2020-06-26 another fix to DirEntry.h usage add CHR$(0) to string when calling a C program.
  5. ' 2020-07-04 Use this to Kill some pesky .ogg files
  6. ' 2021-02-05 Use this to Display BMP24 files
  7.  
  8. ' direntry.h needs to be in QB64 folder ' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< IMPORTANT
  9.     FUNCTION load_dir& (s AS STRING)
  10.     FUNCTION has_next_entry& ()
  11.     SUB close_dir ()
  12.     SUB get_next_entry (s AS STRING, flags AS LONG, file_size AS LONG)
  13.  
  14. ' for GetFileName$()
  15. DIM SHARED selectedFile AS STRING
  16. REDIM SHARED DIRs(0) AS STRING, FILs(0) AS STRING
  17.  
  18. _TITLE "Tiny Navigator File Name Retriever for Displaying BMP24 files:  press f for File Selection of current directory"
  19. SCREEN _NEWIMAGE(1280, 740, 32)
  20. _DELAY .25
  21. _SCREENMOVE 65, 0 ' your screen might need different
  22.  
  23. DIM myFile$, image&
  24. COLOR , &HFF000033
  25. DO 'test our new function
  26.     scnState 0
  27.     myFile$ = GetFileName$
  28.     scnState -1 ' <<<<<<<<<<<<<<<<<<<<<<<<<<< this is supposed to restore back color
  29.     image& = loadBMP24&(myFile$)
  30.     COLOR , &HFF000033
  31.     CLS
  32.     IF image& <> 0 THEN
  33.         _TITLE myFile$ + " press any to get another BMP24 file image, esc to quit"  
  34.         _PUTIMAGE ((_WIDTH - _WIDTH(image&)) / 2, (_HEIGHT - _HEIGHT(image&)) / 2)-STEP(_WIDTH(image&), _HEIGHT(image&)), image&, 0
  35.         SLEEP
  36.         _FREEIMAGE image&
  37.     END IF
  38.  
  39. FUNCTION loadBMP24& (Filename$)
  40.     DIM OF AS _UNSIGNED LONG
  41.     DIM a AS _MEM
  42.     DIM handle AS LONG
  43.     DIM dh AS LONG
  44.     DIM tt AS STRING * 4
  45.     DIM t AS STRING * 3
  46.     IF RIGHT$(UCASE$(Filename$), 4) <> ".BMP" THEN EXIT FUNCTION
  47.     OPEN Filename$ FOR BINARY AS #1
  48.     GET #1, 11, OF
  49.     GET #1, 15, L
  50.     GET #1, , W
  51.     GET #1, , H
  52.     GET #1, , I
  53.     GET #1, , I 'get I twice ???
  54.     IF I <> 24 THEN EXIT FUNCTION
  55.     handle = _NEWIMAGE(W, H, 32)
  56.     a = _MEMIMAGE(handle)
  57.     FOR R = H - 1 TO 0 STEP -1
  58.         FOR C = 1 TO W * 3 STEP 3
  59.             GET #1, R * W * 3 + C + OF, t
  60.             tt = t + CHR$(255)
  61.             _MEMPUT a, a.OFFSET + N, tt
  62.             N = N + 4
  63.         NEXT C
  64.     NEXT R
  65.     CLOSE
  66.     dh = _NEWIMAGE(W, H, 32)
  67.     _PUTIMAGE (0, 0), handle, dh
  68.     loadBMP24& = dh
  69.     _MEMFREE a
  70.  
  71. FUNCTION GetFileName$ ()
  72.  
  73.     'you might try srnState before and after calling this function to restore conditions
  74.     ' uses: SUB GetLists (SearchDirectory AS STRING, DirList() AS STRING, FileList() AS STRING)  for getting dirs a nd files
  75.     ' uses: FUNCTION getArrayItemNumber& (locateRow, locateColumn, boxWidth, boxHeight, arr() AS STRING) for display large arrays and selecting
  76.  
  77.     ' share these with Main Code section:
  78.     ' 'for GetFileName$() and GetLists
  79.     'DIM SHARED selectedFile AS STRING
  80.     'REDIM SHARED DIRs(0) AS STRING, FILs(0) AS STRING
  81.  
  82.     DIM mySelection&, done$, i, t$
  83.  
  84.     _TITLE "Tiny Navigator File Name Retriever:  press f to start File Selection List of current directory"
  85.     DO
  86.         COLOR _RGB32(180, 180, 255), &HFF000000
  87.         CLS
  88.         t$ = "Current Directory: " + _CWD$
  89.         LOCATE 2, (_WIDTH / 8 - LEN(t$)) / 2: PRINT t$
  90.         REDIM DIRs(0) AS STRING, FILs(0) AS STRING
  91.         GetLists _CWD$, DIRs(), FILs()
  92.         FOR i = 0 TO UBOUND(FILs) ' this just offers a sample listing of files
  93.             IF i < 30 THEN LOCATE i + 4, 60: PRINT FILs(i) ELSE EXIT FOR
  94.         NEXT
  95.         mySelection& = getArrayItemNumber&(5, 5, 50, 30, DIRs())
  96.  
  97.         CLS
  98.         IF selectedFile <> "" THEN
  99.             GetFileName$ = selectedFile: done$ = "y"
  100.         ELSEIF mySelection& <> -1719 THEN
  101.             IF _TRIM$(DIRs(mySelection&)) <> "" THEN
  102.                 CHDIR DIRs(mySelection&)
  103.             END IF
  104.         ELSE
  105.             GetFileName$ = "": done$ = "y" ' cancelled or error
  106.         END IF
  107.         selectedFile = ""
  108.         _LIMIT 60
  109.     LOOP UNTIL done$ <> ""
  110.  
  111. SUB GetLists (SearchDirectory AS STRING, DirList() AS STRING, FileList() AS STRING)
  112.  
  113.     'put this block in main code section of your program close to top
  114.     '' direntry.h needs to be in QB64 folder
  115.     'DECLARE CUSTOMTYPE LIBRARY ".\direntry"
  116.     '    FUNCTION load_dir& (s AS STRING)
  117.     '    FUNCTION has_next_entry& ()
  118.     '    SUB close_dir ()
  119.     '    SUB get_next_entry (s AS STRING, flags AS LONG, file_size AS LONG)
  120.     'END DECLARE
  121.  
  122.  
  123.     CONST IS_DIR = 1
  124.     CONST IS_FILE = 2
  125.     DIM flags AS LONG, file_size AS LONG, DirCount AS INTEGER, FileCount AS INTEGER, length AS LONG
  126.     DIM nam$
  127.     REDIM _PRESERVE DirList(100), FileList(100)
  128.     DirCount = 0: FileCount = 0
  129.  
  130.     IF load_dir(SearchDirectory + CHR$(0)) THEN
  131.         DO
  132.             length = has_next_entry
  133.             IF length > -1 THEN
  134.                 nam$ = SPACE$(length)
  135.                 get_next_entry nam$, flags, file_size
  136.                 IF (flags AND IS_DIR) THEN
  137.                     DirCount = DirCount + 1
  138.                     IF DirCount > UBOUND(DirList) THEN REDIM _PRESERVE DirList(UBOUND(DirList) + 100)
  139.                     DirList(DirCount) = nam$
  140.                 ELSEIF (flags AND IS_FILE) THEN
  141.                     FileCount = FileCount + 1
  142.                     IF FileCount > UBOUND(filelist) THEN REDIM _PRESERVE FileList(UBOUND(filelist) + 100)
  143.                     FileList(FileCount) = nam$
  144.                 END IF
  145.             END IF
  146.         LOOP UNTIL length = -1
  147.         'close_dir 'move to after end if  might correct the multi calls problem
  148.     ELSE
  149.     END IF
  150.     close_dir 'this  might correct the multi calls problem
  151.  
  152.     REDIM _PRESERVE DirList(DirCount)
  153.     REDIM _PRESERVE FileList(FileCount)
  154.  
  155. FUNCTION rightOf$ (source$, of$)
  156.     IF INSTR(source$, of$) > 0 THEN rightOf$ = MID$(source$, INSTR(source$, of$) + LEN(of$))
  157.  
  158. ' "Escape or Red X box returns -1719 to allow a Cancel function and signal no slection."
  159. FUNCTION getArrayItemNumber& (locateRow, locateColumn, boxWidth, boxHeight, arr() AS STRING)
  160.     'Notes: locateRow, locateColumn for top right corner of selection box on screen in characters for LOCATE.
  161.     'boxWidth and boxHeight are in character units, again for locate and print at correct places.
  162.     'All displaying is restricted to inside the box, which has PgUP and PgDn as top and bottom lines in the display.
  163.  
  164.     DIM curRow AS INTEGER, curCol AS INTEGER, fg AS _UNSIGNED LONG, bg AS _UNSIGNED LONG
  165.     DIM maxWidth AS INTEGER, maxHeight AS INTEGER, page AS INTEGER, hlite AS INTEGER, mx AS INTEGER, my AS INTEGER
  166.     DIM lastMX AS INTEGER, lastMY AS INTEGER, row AS INTEGER, mb AS INTEGER
  167.     DIM lba AS LONG, uba AS LONG, choice AS LONG, kh AS LONG, index AS LONG
  168.     DIM clrStr AS STRING, b AS STRING, selNum&
  169.  
  170.     'save old settings to restore at end ofsub
  171.     curRow = CSRLIN
  172.     curCol = POS(0)
  173.     fg = _DEFAULTCOLOR
  174.     bg = _BACKGROUNDCOLOR
  175.     _KEYCLEAR
  176.  
  177.     maxWidth = boxWidth '       number of characters in box
  178.     maxHeight = boxHeight - 2 ' number of lines displayed of array at one time = 1 page
  179.     lba = LBOUND(arr)
  180.     uba = UBOUND(arr)
  181.     page = 0
  182.     hlite = 0 '                 line in display ready for selection by spacebar or if no number is started, enter
  183.     clrStr$ = SPACE$(maxWidth) 'clearing a display line
  184.  
  185.     GOSUB update '              show the beginning of the array items for selection
  186.  
  187.     'signal cancel selection process, exit sub with this unlikely index to signal canel
  188.     choice = -1719 'primes 7 and 8, not likely to be a select index of an array
  189.  
  190.     DO 'until get a selection or demand exit
  191.  
  192.         'handle the key stuff
  193.         kh& = _KEYHIT
  194.         IF kh& THEN
  195.             IF kh& > 0 AND kh& < 255 THEN
  196.                 IF INSTR("0123456789", CHR$(kh&)) > 0 THEN b$ = b$ + CHR$(kh&): GOSUB update
  197.                 IF CHR$(kh&) = "f" THEN
  198.                     'REDIM FILs(0) AS STRING     'hopefully this is already ready
  199.                     'loadFiles FILs()
  200.                     selNum& = getArrayItemNumber&(5, 60, 60, 30, FILs())
  201.                     COLOR _RGB32(180, 180, 255)
  202.                     CLS 'need to signal out of file selection
  203.                     IF selNum& >= LBOUND(FILs) AND selNum& <= UBOUND(FILs) THEN selectedFile = FILs(selNum&)
  204.                     EXIT DO
  205.                     'back to directory select
  206.                 END IF
  207.  
  208.                 IF CHR$(kh&) = "c" THEN b$ = "": GOSUB update
  209.                 IF kh& = 13 THEN 'enter pressed check if number is being entered?
  210.                     IF LEN(b$) THEN
  211.                         IF VAL(b$) >= lba AND VAL(b$) <= uba THEN 'we have number started
  212.                             choice = VAL(b$): EXIT DO
  213.                         ELSE 'clear b$ to show some response to enter
  214.                             b$ = "": GOSUB update 'clear the value that doesn't work
  215.                         END IF
  216.                     ELSE
  217.                         choice = hlite + page * maxHeight + lba 'must mean to select the highlighted item
  218.                     END IF
  219.                 END IF
  220.                 IF kh& = 27 THEN EXIT DO 'escape clause offered to Cancel selection process
  221.                 IF kh& = 32 THEN choice = hlite + page * maxHeight + lba 'best way to choose highlighted selection
  222.                 IF kh& = 8 THEN 'backspace to edit number
  223.                     IF LEN(b$) THEN b$ = LEFT$(b$, LEN(b$) - 1): GOSUB update
  224.                 END IF
  225.             ELSE
  226.                 SELECT CASE kh& 'choosing sections of array to display and highlighted item
  227.                     CASE 20736 'pg dn
  228.                         IF (page + 1) * maxHeight + lba <= uba THEN page = page + 1: GOSUB update
  229.                     CASE 18688 'pg up
  230.                         IF (page - 1) * maxHeight + lba >= lba THEN page = page - 1: GOSUB update
  231.                     CASE 18432 'up
  232.                         IF hlite - 1 < 0 THEN
  233.                             IF page > 0 THEN
  234.                                 page = page - 1: hlite = maxHeight - 1: GOSUB update
  235.                             END IF
  236.                         ELSE
  237.                             hlite = hlite - 1: GOSUB update
  238.                         END IF
  239.                     CASE 20480 'down
  240.                         IF (hlite + 1) + page * maxHeight + lba <= uba THEN 'ok to move up
  241.                             IF hlite + 1 > maxHeight - 1 THEN
  242.                                 page = page + 1: hlite = 0: GOSUB update
  243.                             ELSE
  244.                                 hlite = hlite + 1: GOSUB update
  245.                             END IF
  246.                         END IF
  247.                     CASE 18176 'home
  248.                         page = 0: hlite = 0: GOSUB update
  249.                     CASE 20224 ' end
  250.                         page = INT((uba - lba) / maxHeight): hlite = maxHeight - 1: GOSUB update
  251.                 END SELECT
  252.             END IF
  253.         END IF
  254.  
  255.         'handle the mouse stuff
  256.         WHILE _MOUSEINPUT
  257.             IF _MOUSEWHEEL = -1 THEN 'up?
  258.                 IF hlite - 1 < 0 THEN
  259.                     IF page > 0 THEN
  260.                         page = page - 1: hlite = maxHeight - 1: GOSUB update
  261.                     END IF
  262.                 ELSE
  263.                     hlite = hlite - 1: GOSUB update
  264.                 END IF
  265.             ELSEIF _MOUSEWHEEL = 1 THEN 'down?
  266.                 IF (hlite + 1) + page * maxHeight + lba <= uba THEN 'ok to move up
  267.                     IF hlite + 1 > maxHeight - 1 THEN
  268.                         page = page + 1: hlite = 0: GOSUB update
  269.                     ELSE
  270.                         hlite = hlite + 1: GOSUB update
  271.                     END IF
  272.                 END IF
  273.             END IF
  274.         WEND
  275.         mx = INT((_MOUSEX - locateColumn * 8) / 8) + 2: my = INT((_MOUSEY - locateRow * 16) / 16) + 2
  276.         IF _MOUSEBUTTON(1) THEN 'click contols or select array item
  277.             'clear mouse clicks
  278.             mb = _MOUSEBUTTON(1)
  279.             IF mb THEN 'clear it
  280.                 WHILE mb 'OK!
  281.                     IF _MOUSEINPUT THEN mb = _MOUSEBUTTON(1)
  282.                     _LIMIT 100
  283.                 WEND
  284.             END IF
  285.  
  286.             IF mx >= 1 AND mx <= maxWidth AND my >= 1 AND my <= maxHeight THEN
  287.                 choice = my + page * maxHeight + lba - 1 'select item clicked
  288.             ELSEIF mx >= 1 AND mx <= maxWidth AND my = 0 THEN 'page up or exit
  289.                 IF my = 0 AND (mx <= maxWidth AND mx >= maxWidth - 2) THEN 'exit sign
  290.                     EXIT DO 'escape plan for mouse click top right corner of display box
  291.                 ELSE 'PgUp bar clicked
  292.                     IF (page - 1) * maxHeight + lba >= lba THEN page = page - 1: GOSUB update
  293.                 END IF
  294.             ELSEIF mx >= 1 AND mx <= maxWidth AND my = maxHeight + 1 THEN 'page down bar clicked
  295.                 IF (page + 1) * maxHeight + lba <= uba THEN page = page + 1: GOSUB update
  296.             END IF
  297.         ELSE '   mouse over highlighting, only if mouse has moved!
  298.             IF mx >= 1 AND mx <= maxWidth AND my >= 1 AND my <= maxHeight THEN
  299.                 IF mx <> lastMX OR my <> lastMY THEN
  300.                     IF my - 1 <> hlite AND (my - 1 + page * maxHeight + lba <= uba) THEN
  301.                         hlite = my - 1
  302.                         lastMX = mx: lastMY = my
  303.                         GOSUB update
  304.                     END IF
  305.                 END IF
  306.             END IF
  307.         END IF
  308.         _LIMIT 200
  309.     LOOP UNTIL choice >= lba AND choice <= uba
  310.     getArrayItemNumber& = choice
  311.     COLOR fg, bg
  312.     'clear key presses
  313.     _KEYCLEAR
  314.     LOCATE curRow, curCol
  315.     'clear mouse clicks
  316.     mb = _MOUSEBUTTON(1)
  317.     IF mb THEN 'clear it
  318.         WHILE mb 'OK!
  319.             IF _MOUSEINPUT THEN mb = _MOUSEBUTTON(1)
  320.             _LIMIT 100
  321.         WEND
  322.     END IF
  323.     EXIT SUB
  324.  
  325.     update: '--------------- display of array sections and controls on screen
  326.  
  327.     'fix hlite if it has dropped below last array item
  328.     WHILE hlite + page * maxHeight + lba > uba
  329.         hlite = hlite - 1
  330.     WEND
  331.  
  332.     'main display of array items at page * maxHeight (lines high)
  333.     FOR row = 0 TO maxHeight - 1
  334.         IF hlite = row THEN COLOR _RGB(200, 200, 255), _RGB32(0, 0, 88) ELSE COLOR _RGB32(0, 0, 88), _RGB(200, 200, 255)
  335.         LOCATE locateRow + row, locateColumn: PRINT clrStr$
  336.         index = row + page * maxHeight + lba
  337.         IF index >= lba AND index <= uba THEN
  338.             LOCATE locateRow + row, locateColumn
  339.             PRINT LEFT$(LTRIM$(STR$(index)) + ") " + arr(index), maxWidth)
  340.         END IF
  341.     NEXT
  342.  
  343.     'make page up and down bars to click, print PgUp / PgDn if available
  344.     COLOR _RGB32(200, 200, 255), _RGB32(0, 100, 50)
  345.     LOCATE locateRow - 1, locateColumn: PRINT SPACE$(maxWidth)
  346.     IF page <> 0 THEN LOCATE locateRow - 1, locateColumn: PRINT LEFT$(" Pg Up" + SPACE$(maxWidth), maxWidth)
  347.     LOCATE locateRow + maxHeight, locateColumn: PRINT SPACE$(maxWidth)
  348.     IF page <> INT(uba / maxHeight) THEN
  349.         LOCATE locateRow + maxHeight, locateColumn: PRINT LEFT$(" Pg Dn" + SPACE$(maxWidth), maxWidth)
  350.     END IF
  351.     'make exit sign for mouse click
  352.     COLOR _RGB32(255, 255, 255), _RGB32(200, 100, 0)
  353.     LOCATE locateRow - 1, locateColumn + maxWidth - 3
  354.     PRINT " X "
  355.  
  356.     'if a number selection has been started show it's build = b$
  357.     IF LEN(b$) THEN
  358.         COLOR _RGB(255, 255, 0), _RGB32(0, 0, 0)
  359.         LOCATE locateRow + maxHeight, locateColumn + maxWidth - LEN(b$) - 1
  360.         PRINT b$;
  361.     END IF
  362.     _DISPLAY
  363.     _LIMIT 100
  364.     RETURN
  365.  
  366. ' for saving and restoring screen settins
  367. SUB scnState (restoreTF AS INTEGER) 'Thanks Steve McNeill
  368.     STATIC Font AS LONG, DefaultColor AS _UNSIGNED LONG, BackGroundColor AS _UNSIGNED LONG, Dest AS LONG, Source AS LONG
  369.     STATIC row AS INTEGER, col AS INTEGER, autodisplay AS INTEGER, mb AS INTEGER
  370.     IF restoreTF THEN
  371.         _FONT Font
  372.         COLOR DefaultColor, BackGroundColor
  373.         _DEST Dest
  374.         _SOURCE Source
  375.         LOCATE row, col
  376.         IF autodisplay THEN _AUTODISPLAY ELSE _DISPLAY
  377.         _KEYCLEAR
  378.         WHILE _MOUSEINPUT: WEND 'clear mouse clicks
  379.         mb = _MOUSEBUTTON(1)
  380.         IF mb THEN
  381.             DO
  382.                 WHILE _MOUSEINPUT: WEND
  383.                 mb = _MOUSEBUTTON(1)
  384.                 _LIMIT 100
  385.             LOOP UNTIL mb = 0
  386.         END IF
  387.     ELSE
  388.         Font = _FONT: DefaultColor = _DEFAULTCOLOR: BackGroundColor = _BACKGROUNDCOLOR
  389.         Dest = _DEST: Source = _SOURCE
  390.         row = CSRLIN: col = POS(0): autodisplay = _AUTODISPLAY
  391.     END IF
  392.  
  393.  

Yes BMP24 used in JB images!.PNG
* Yes BMP24 used in JB images!.PNG (Filesize: 465.85 KB, Dimensions: 1183x765, Views: 185)
« Last Edit: February 05, 2021, 02:26:31 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: BMP picture viewer
« Reply #20 on: February 05, 2021, 02:21:58 pm »
Just read my edit above.  I believe you may run into issues with padding.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: BMP picture viewer
« Reply #21 on: February 05, 2021, 02:31:03 pm »
Just read my edit above.  I believe you may run into issues with padding.  ;)

I did read and he's using the 4 size only.

Do you have an image to demonstrate and test code and code fixes?

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: BMP picture viewer
« Reply #22 on: February 05, 2021, 03:14:27 pm »
I did read and he's using the 4 size only.

Do you have an image to demonstrate and test code and code fixes?


Grab the file below and give it a run.  It's only 638 pixels wide (non-4), so it requires end of line padding.

Here's a quick set of example code for you to study as well: 
Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1024, 800, 32)
  2. handle = loadBMP24("non4.bmp")
  3. _PUTIMAGE , handle
  4.  
  5. FUNCTION loadBMP24& (Filename$)
  6.     DIM OF AS _UNSIGNED LONG
  7.     DIM a AS _MEM
  8.     DIM handle AS LONG
  9.     DIM dh AS LONG
  10.     DIM tt AS STRING * 4
  11.     DIM t AS STRING * 3
  12.  
  13.     IF RIGHT$(UCASE$(Filename$), 4) <> ".BMP" THEN EXIT FUNCTION
  14.     PRINT Filename$
  15.     OPEN Filename$ FOR BINARY AS #1
  16.     GET #1, 11, OF
  17.     GET #1, 15, L
  18.     GET #1, , W
  19.     GET #1, , H
  20.     GET #1, , I
  21.     GET #1, , I 'get I twice ???
  22.     IF I <> 24 THEN EXIT FUNCTION
  23.     handle = _NEWIMAGE(W, H, 32)
  24.     a = _MEMIMAGE(handle)
  25.     IF ((W * 3) MOD 4) <> 0 THEN '’need padding pixels
  26.         Padding$ = SPACE$((4 - ((W * 3) MOD 4)))
  27.     END IF
  28.     'SEEK #1, OF 'go to the offset where the data starts
  29.     FOR R = H - 1 TO 0 STEP -1
  30.         FOR C = 1 TO W * 3 STEP 3
  31.             GET #1, R * W * 3 + C + OF, t
  32.             'GET #1, ,t 'get the data sequentially
  33.             tt = t + CHR$(255)
  34.             _MEMPUT a, a.OFFSET + N, tt
  35.             N = N + 4
  36.         NEXT C
  37.         'GET #1, , Padding$ 'Get the padding at the end of the line
  38.     NEXT R
  39.     CLOSE
  40.  
  41.     dh = _NEWIMAGE(W, H, 32)
  42.     _PUTIMAGE (0, 0), handle, dh
  43.     loadBMP24& = dh
  44.     _MEMFREE a
  45.  

Run it and you'll see the image distorted as heck.

Unremark out the lines I've got remarked and run it.  (Also remark out the current GET line of  GET #1, R * W * 3 + C + OF, t     , as we're replacing it with the one I have remarked.)

You should be able to easily see the difference.

Here's an image of what the program you have now displays, vs the original:

 
Distorted.png


* non4.bmp (Filesize: 900.05 KB, Dimensions: 638x480, Views: 327)
« Last Edit: February 05, 2021, 03:17:59 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: BMP picture viewer
« Reply #23 on: February 05, 2021, 03:39:36 pm »
Well the alignment is good but stripe colors don't match (see attached)

Here is the FUNCTION I used with the modifications
Code: QB64: [Select]
  1. FUNCTION loadBMP24& (Filename$)
  2.     DIM OF AS _UNSIGNED LONG
  3.     DIM a AS _MEM
  4.     DIM handle AS LONG
  5.     DIM dh AS LONG
  6.     DIM tt AS STRING * 4
  7.     DIM t AS STRING * 3
  8.     DIM padding$
  9.     IF RIGHT$(UCASE$(Filename$), 4) <> ".BMP" THEN EXIT FUNCTION
  10.     'PRINT Filename$
  11.     OPEN Filename$ FOR BINARY AS #1
  12.     GET #1, 11, OF
  13.     GET #1, 15, L
  14.     GET #1, , W
  15.     GET #1, , H
  16.     GET #1, , I
  17.     GET #1, , I 'get I twice ???
  18.     IF I <> 24 THEN EXIT FUNCTION
  19.     handle = _NEWIMAGE(W, H, 32)
  20.     a = _MEMIMAGE(handle)
  21.     IF ((W * 3) MOD 4) <> 0 THEN '’need padding pixels
  22.         padding$ = SPACE$((4 - ((W * 3) MOD 4)))
  23.     END IF
  24.     SEEK #1, OF 'go to the offset where the data starts
  25.     FOR R = H - 1 TO 0 STEP -1
  26.         FOR C = 1 TO W * 3 STEP 3
  27.             'GET #1, R * W * 3 + C + OF, t
  28.             GET #1, , t 'get the data sequentially
  29.             tt = t + CHR$(255)
  30.             _MEMPUT a, a.OFFSET + N, tt
  31.             N = N + 4
  32.         NEXT C
  33.         GET #1, , padding$ 'Get the padding at the end of the line
  34.     NEXT R
  35.     CLOSE
  36.  
  37.     dh = _NEWIMAGE(W, H, 32)
  38.     _PUTIMAGE (0, 0), handle, dh
  39.     loadBMP24& = dh
  40.     _MEMFREE a
  41.  
  42.  

Something is still off.PNG
* Something is still off.PNG (Filesize: 25.63 KB, Dimensions: 1082x744, Views: 125)
something 2.PNG
* something 2.PNG (Filesize: 1.34 MB, Dimensions: 1279x764, Views: 122)
« Last Edit: February 05, 2021, 03:46:38 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: BMP picture viewer
« Reply #24 on: February 05, 2021, 04:03:46 pm »
Sorry.   A couple of little goofs on my part.

One was the SEEK.... I forgot to add 1 since binary files start at byte 1 and not 0.

    SEEK #1, OF + 1

Second is the face that it seems BMP files are stored bottom up, not top-down.  Just one of those many things I used to know, that I have to run into a little BLIP to remind myself of.   

Change the SEEK like above, and run it.  You'll see your image reversed.  :P

The change the MEMPUT to where you put the data in from the end to the beginning, and you're good to go:

           _MEMPUT a, a.OFFSET + a.SIZE - N - 4, tt 




And I think that'll account for your padding, start the color at the proper  pixel to read the RGB right, and draw it in the proper order.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: BMP picture viewer
« Reply #25 on: February 05, 2021, 04:31:00 pm »
I had to go back and look at my own little BMP Save routine, to try and sort this out.  Here's the relevant part of the code, where we read the image from memory to save to file:

        w& = _WIDTH(image&)
        DO
            y = y - 1: x = x1% - 1
            DO
                x = x + 1
                _MEMGET m, m.OFFSET + (w& * y + x) * 4, temp


y starts at the bottom of the screen, and moves up.
x starts at the left of the screen, and moves right.

I'm thinking what I posted above might mirror the image for you, accidently.  (Not that you'd notice in single color rows...)


Here's what I'm thinking you actually need to do this properly:

Code: QB64: [Select]
  1.     IF I <> 24 THEN EXIT FUNCTION
  2.     handle = _NEWIMAGE(W, H, 32)
  3.     a = _MEMIMAGE(handle)
  4.     IF ((W * 3) MOD 4) <> 0 THEN '’need padding pixels
  5.         Padding$ = SPACE$((4 - ((W * 3) MOD 4)))
  6.     END IF
  7.     SEEK #1, OF + 1 'go to the offset where the data starts
  8.     FOR R = H - 1 TO 0 STEP -1 'from the bottom to top
  9.         FOR C = 0 TO W - 1 'left to right
  10.             GET #1, , t 'get the data sequentially
  11.             tt = t + CHR$(255)
  12.             _MEMPUT a, a.OFFSET + (W * R + C) * 4, tt
  13.         NEXT C
  14.         GET #1, , Padding$ 'Get the padding at the end of the line
  15.     NEXT R
  16.     CLOSE
  17.  


https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: BMP picture viewer
« Reply #26 on: February 05, 2021, 04:49:02 pm »
Thank you everyone for the nice comments!

bplus

 
Quote
GET #1, , I
    GET #1, , I 'get I twice ???

The first I  read 2 bytes (DIM I AS INTEGER)  which is biPlanes and I did not need that info, so skipped it

Quote
biPlanes   2   Must be 1
biBitCount   2   Bits per pixel - 1, 4, 8, 16, 24, or 32

The second I is bits per pixel and the viewer works only with 24 bits per pixel.
****
Another thing, in my source code, my comment looks to be wrong as I tried the code in the root of drive C and it worked. In the past I was able to detect whether code was run in the root or not and I will have to dig up some old code to see how that was done.
Quote
IF load_dir("." + CHR$(0)) = -1 THEN 'found "." this is a folder  not a root drive
****
Steve

In my viewer code I did not run into a padding issue.   If there was padding at the end of a row (scan line) then for sure my code would not work.   from http://www.dragonwins.com/domains/getteched/bmp/bmpfileformat.htm  Look at subheading "Pixel Data"  I'm really not sure if that is correct.

Will look into this "padding thing"


The only "padding" I did was adding that 4th byte at the end of a 24 bit pixel because
Quote
handle = _NEWIMAGE(W, H, 32)

expects a 32 bit pixel

****
Dav
 Glad it worked on your computer!!!




« Last Edit: February 05, 2021, 05:53:37 pm by NOVARSEG »

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: BMP picture viewer
« Reply #27 on: February 05, 2021, 06:20:33 pm »
So I did some more researche

from https://homepages.inf.ed.ac.uk/rbf/BOOKS/PHILLIPS/cips2ed.pdf

Quote
The BMP color table has four bytes in each color table entry. The bytes
are for the blue, green, and red color values. The fourth byte is padding and
is always zero. For a 256 gray shade image, the color table is 4x256 bytes
long. The blue, green, and red values equal one another.
The final part of the BMP file is the image data. The data is stored row
by row with padding on the end of each row. The padding ensures the image
rows are multiples of four. The four, just like in the color table, makes it
easier to read blocks and keep track of addresses.

Now I'm really confused. You could have any number of bytes per scan line as long as they are a multiple of 3 (24 bit BMP).  I don't see the reason for padding in a 24 bit BMP???

If there was in fact padding at the end of a 24 bit BMP scan line, then my viewer code would not work.

As the above quote says

Quote
makes it easier to read blocks and keep track of addresses.

HUH? file pointers have BYTE resolution

Addresses WHAT , all we need to know is the offset from start of file to pixel data.

« Last Edit: February 05, 2021, 06:43:39 pm by NOVARSEG »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: BMP picture viewer
« Reply #28 on: February 05, 2021, 06:26:53 pm »
It’s like I told you:

You do one row at a time, starting at bottom left, to bottom right.
At the end of that row, you have padding to make it a length divisible by 4.
Then you go up to the line above it and repeat, until you reach the top.


You don’t need to worry about the color table reference, as that’s for other color modes.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: BMP picture viewer
« Reply #29 on: February 05, 2021, 06:30:31 pm »
Ya but I did not have to adjust for "padding" in my code . If there are padding bytes at the end of a scan line then the padding byte don't contain pixel data.  The file pointer (GET, point, . . .) is supposed to point to pixel data only

In a, say, 1024 * 768  24 bit BMP there are exactly 1024 * 3 bytes per scan line. That is what my code is saying.  If there was actually padding bytes at the end of a scan line then surely I would have found them.
« Last Edit: February 05, 2021, 06:45:37 pm by NOVARSEG »