Author Topic: SaveJPG  (Read 4745 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
SaveJPG
« on: August 11, 2019, 06:46:00 pm »
For a long  time my little SaveImage routine has been able to save BMP and PNG format images of our screens.  (The last version I shared on the boards is here at: www.qb64.org/forum/index.php?topic=47.msg102649#msg102649 , but it's a little out of date with a few minor error checking corrections added later.  I'll update the newest version soon(tm) so everyone can grab it and make use of it, for those who want to.)

Now, after taking a look at Petr's BMPTOJPG code here: https://www.qb64.org/forum/index.php?topic=47.msg254#msg254 , I've tweaked his work and converted it over to where it's now fit to work as an additional option for SaveImage (or even as a stand alone SaveJPG library).

(Note: A clarification, as pointed out below — Petr’s work is a derivative from others as well. The original source code was written by Artelius, he is the original author. BMPtoJPG is a modification of its program that ships with QB64 in programs / samples / n54 / big / jpegmake.bas )

Give this a few quick test runs and see if it works as advertised on your machines (particularly Linux and Mac OSes), and if nobody has any issues with it, I'll add a little better error trapping (right now we have almost none) and reporting, and then insert it into the SaveImage library so that it'll then be able to save BMP, JPG, or PNG files, as the user/programmer desires.

Anywho, here's the revamped SaveJPG, for your testing and feedback:

Code: QB64: [Select]
  1. TYPE JPEGState
  2.     FileNo AS INTEGER
  3.     YCount AS INTEGER
  4.     CbCount AS INTEGER
  5.     CrCount AS INTEGER
  6.     YDC AS INTEGER
  7.     CbDC AS INTEGER
  8.     CrDC AS INTEGER
  9.     Position AS INTEGER
  10.     Leftover AS INTEGER
  11.     LeftoverBits AS INTEGER
  12.  
  13. Huff0:
  14. DATA 1,0
  15. DATA 5,1,2,3,4,5
  16. DATA 1,6
  17. DATA 1,7
  18. DATA 1,8
  19. DATA 1,9
  20. DATA 1,10
  21. DATA 1,11
  22. DATA 0,0,0,0,0,0,0
  23.  
  24. Huff1:
  25. DATA 3,0,1,2
  26. DATA 1,3
  27. DATA 1,4
  28. DATA 1,5
  29. DATA 1,6
  30. DATA 1,7
  31. DATA 1,8
  32. DATA 1,9
  33. DATA 1,10
  34. DATA 1,11
  35. DATA 0,0,0,0,0
  36.  
  37. Huff2:
  38. DATA 2,1,2
  39. DATA 1,3
  40. DATA 3,0,4,&H11
  41. DATA 3,5,&H12,&H21
  42. DATA 2,&H31,&H41
  43. DATA 4,6,&H13,&H51,&H61
  44. DATA 3,7,&H22,&H71
  45. DATA 5,&H14,&H32,&H81,&H91,&HA1
  46. DATA 5,&H08,&H23,&H42,&HB1,&HC1
  47. DATA 4,&H15,&H52,&HD1,&HF0
  48. DATA 4,&H24,&H33,&H62,&H72
  49. DATA 1,&H82
  50. DATA 125,&H09,&H0A,&H16,&H17,&H18,&H19,&H1A,&H25,&H26,&H27,&H28,&H29,&H2A,&H34,&H35,&H36
  51. DATA &H37,&H38,&H39,&H3A,&H43,&H44,&H45,&H46,&H47,&H48,&H49,&H4A,&H53,&H54,&H55,&H56
  52. DATA &H57,&H58,&H59,&H5A,&H63,&H64,&H65,&H66,&H67,&H68,&H69,&H6A,&H73,&H74,&H75,&H76
  53. DATA &H77,&H78,&H79,&H7A,&H83,&H84,&H85,&H86,&H87,&H88,&H89,&H8A,&H92,&H93,&H94,&H95
  54. DATA &H96,&H97,&H98,&H99,&H9A,&HA2,&HA3,&HA4,&HA5,&HA6,&HA7,&HA8,&HA9,&HAA,&HB2,&HB3
  55. DATA &HB4,&HB5,&HB6,&HB7,&HB8,&HB9,&HBA,&HC2,&HC3,&HC4,&HC5,&HC6,&HC7,&HC8,&HC9,&HCA
  56. DATA &HD2,&HD3,&HD4,&HD5,&HD6,&HD7,&HD8,&HD9,&HDA,&HE1,&HE2,&HE3,&HE4,&HE5,&HE6,&HE7
  57. DATA &HE8,&HE9,&HEA,&HF1,&HF2,&HF3,&HF4,&HF5,&HF6,&HF7,&HF8,&HF9,&HFA
  58.  
  59. Huff3:
  60. DATA 2,0,1
  61. DATA 1,2
  62. DATA 2,3,&H11
  63. DATA 4,4,5,&H21,&H31
  64. DATA 4,6,&H12,&H41,&H51
  65. DATA 3,7,&H61,&H71
  66. DATA 4,&H13,&H22,&H32,&H81
  67. DATA 7,8,&H14,&H42,&H91,&HA1,&HB1,&HC1
  68. DATA 5,9,&H23,&H33,&H52,&HF0
  69. DATA 4,&H15,&H62,&H72,&HD1
  70. DATA 4,&HA,&H16,&H24,&H34
  71. DATA 1,&HE1
  72. DATA 2,&H25,&HF1
  73. DATA 119,&H17,&H18,&H19,&H1A,&H26,&H27,&H28,&H29,&H2A,&H35,&H36,&H37,&H38,&H39,&H3A,&H43
  74. DATA &H44,&H45,&H46,&H47,&H48,&H49,&H4A,&H53,&H54,&H55,&H56,&H57,&H58,&H59,&H5A,&H63
  75. DATA &H64,&H65,&H66,&H67,&H68,&H69,&H6A,&H73,&H74,&H75,&H76,&H77,&H78,&H79,&H7A,&H82
  76. DATA &H83,&H84,&H85,&H86,&H87,&H88,&H89,&H8A,&H92,&H93,&H94,&H95,&H96,&H97,&H98,&H99
  77. DATA &H9A,&HA2,&HA3,&HA4,&HA5,&HA6,&HA7,&HA8,&HA9,&HAA,&HB2,&HB3,&HB4,&HB5,&HB6,&HB7
  78. DATA &HB8,&HB9,&HBA,&HC2,&HC3,&HC4,&HC5,&HC6,&HC7,&HC8,&HC9,&HCA,&HD2,&HD3,&HD4,&HD5
  79. DATA &HD6,&HD7,&HD8,&HD9,&HDA,&HE2,&HE3,&HE4,&HE5,&HE6,&HE7,&HE8,&HE9,&HEA,&HF2,&HF3
  80. DATA &HF4,&HF5,&HF6,&HF7,&HF8,&HF9,&HFA
  81.  
  82. StandardQT:
  83. DATA 16,11,10,16,24,40,51,61
  84. DATA 12,12,14,19,26,58,60,55
  85. DATA 14,13,16,24,40,57,69,56
  86. DATA 14,17,22,29,51,87,80,62
  87. DATA 18,22,37,56,68,109,103,77
  88. DATA 24,35,55,64,81,104,113,92
  89. DATA 49,64,78,87,103,121,120,101
  90. DATA 72,92,95,98,112,100,103,99
  91.  
  92. DATA 17,18,24,47,99,99,99,99
  93. DATA 18,24,26,66,99,99,99,99
  94. DATA 24,26,56,99,99,99,99,99
  95. DATA 47,66,99,99,99,99,99,99
  96. DATA 99,99,99,99,99,99,99,99
  97. DATA 99,99,99,99,99,99,99,99
  98. DATA 99,99,99,99,99,99,99,99
  99. DATA 99,99,99,99,99,99,99,99
  100.  
  101. DIM SHARED Pow2(0 TO 15) AS LONG
  102. DIM SHARED Cosine(0 TO 7, 0 TO 7) AS SINGLE
  103. DIM SHARED ZigZagX(0 TO 63) AS INTEGER, ZigZagY(0 TO 63) AS INTEGER
  104. JPEG.Precalc
  105.  
  106. DIM SHARED Huff(0 TO 255, 0 TO 1, 0 TO 1, 0 TO 1) AS INTEGER
  107. DIM SHARED QT(0 TO 7, 0 TO 7, 0 TO 1) AS INTEGER
  108. DIM SHARED State AS JPEGState
  109.  
  110. DIM SHARED Sampling(0 TO 2, 0 TO 1) AS INTEGER
  111. Sampling(0, 0) = 2 'Sampling factor (x then y) for luminance
  112. Sampling(0, 1) = 2
  113. Sampling(1, 0) = 1 'Sampling factor for "blue" chrominance
  114. Sampling(1, 1) = 1
  115. Sampling(2, 0) = 1 'Sampling factor for "red" chrominance
  116. Sampling(2, 1) = 1
  117.  
  118. '***************************
  119. ' LIBRARY START BEFORE HERE
  120. '***************************
  121. 'Delete file then open for binary
  122.  
  123.  
  124. DIM j AS LONG, l AS LONG, i AS LONG
  125. j = _NEWIMAGE(640, 480, 32)
  126.  
  127. FOR i = 1 TO 100
  128.     LINE (RND * 640, RND * 480)-(RND * 640, RND * 480), RND * &HFFFFFF + &HFF000000, BF
  129. LINE (100, 100)-(200, 200), &HFFFFFF00, BF
  130. _PRINTSTRING (110, 110), "STEVE!"
  131.  
  132. SaveJPG "temp.JPG", 0, 100, 100, 500, 400
  133. l = _LOADIMAGE("temp.JPG", 32)
  134.  
  135. '***************************
  136. '   LIBRARY END AFTER HERE
  137. '***************************
  138.  
  139.  
  140.  
  141.  
  142. SUB SaveJPG (file$, image&, startx, starty, finishx, finishy)
  143.     DIM D AS LONG, S AS LONG
  144.     DIM tempimage AS LONG, genx AS INTEGER, geny AS INTEGER
  145.     DIM outfilename AS STRING
  146.  
  147.     D = _DEST: S = _SOURCE
  148.     tempimage = _NEWIMAGE(finishx - startx + 1, finishy - starty + 1, 32)
  149.     genx = _WIDTH(tempimage): geny = _HEIGHT(tempimage)
  150.     _PUTIMAGE (0, 0)-(genx, geny), image&, tempimage&, (startx, starty)-(finishx, finishy)
  151.     _SOURCE tempimage&: _DEST tempimage&
  152.     outfilename = file$
  153.     OPEN outfilename FOR BINARY AS #1
  154.  
  155.     'Set quality tables
  156.     'The smaller the paramter, the higher the quality
  157.     '0.01 is 100% quality
  158.     JPEG.StandardQT 0.05, QT()
  159.  
  160.     'Start image
  161.     JPEG.Begin 1, genx, geny, Sampling(), State, QT(), Huff()
  162.  
  163.  
  164.     DIM B(0 TO 7, 0 TO 7) AS INTEGER
  165.     DIM SuperY AS INTEGER, SuperX AS INTEGER
  166.     DIM BlockY AS INTEGER, BlockX AS INTEGER
  167.     DIM OffY AS INTEGER, OffX AS INTEGER
  168.     DIM X AS SINGLE, Y AS SINGLE
  169.     DIM R AS INTEGER, G AS INTEGER, B AS INTEGER
  170.     FOR SuperY = 0 TO geny - 1 STEP 16
  171.         FOR SuperX = 0 TO genx - 1 STEP 16: REM vstupni velikost obrazku
  172.  
  173.             'Output the luminance blocks
  174.  
  175.             FOR BlockY = 0 TO 15 STEP 8
  176.                 FOR BlockX = 0 TO 15 STEP 8
  177.                     FOR OffY = 0 TO 7: FOR OffX = 0 TO 7
  178.                             X! = OffX + BlockX + SuperX: REM- 63.5
  179.                             Y! = OffY + BlockY + SuperY: REM - 63.5
  180.  
  181.                             R = _RED32(POINT(X!, Y!))
  182.                             G = _GREEN32(POINT(X!, Y!))
  183.                             B = _BLUE32(POINT(X!, Y!))
  184.                             B(OffX, OffY) = JPEG.Y(R, G, B)
  185.                     NEXT OffX, OffY
  186.                     JPEG.Block.Output B(), State, QT(), Huff()
  187.             NEXT BlockX, BlockY
  188.  
  189.             'Output the blue chrominance block
  190.  
  191.             FOR OffY = 0 TO 7: FOR OffX = 0 TO 7
  192.                     X! = OffX * 2 + SuperX
  193.                     Y! = OffY * 2 + SuperY
  194.  
  195.                     R = _RED32(POINT(X!, Y!))
  196.                     G = _GREEN32(POINT(X!, Y!))
  197.                     B = _BLUE32(POINT(X!, Y!))
  198.                     B(OffX, OffY) = JPEG.Cb(R, G, B)
  199.             NEXT OffX, OffY
  200.             JPEG.Block.Output B(), State, QT(), Huff()
  201.  
  202.             'Output the red chrominance block
  203.  
  204.             FOR OffY = 0 TO 7: FOR OffX = 0 TO 7
  205.                     X! = OffX * 2 + SuperX
  206.                     Y! = OffY * 2 + SuperY
  207.  
  208.                     R = _RED32(POINT(X!, Y!))
  209.                     G = _GREEN32(POINT(X!, Y!))
  210.                     B = _BLUE32(POINT(X!, Y!))
  211.                     B(OffX, OffY) = JPEG.Cr(R, G, B)
  212.             NEXT OffX, OffY
  213.             JPEG.Block.Output B(), State, QT(), Huff()
  214.  
  215.     NEXT SuperX, SuperY
  216.  
  217.     JPEG.Finish State
  218.  
  219.     CLOSE
  220.     _DEST D: _SOURCE S
  221.  
  222. SUB JPEG.ACHuff (RLE AS INTEGER, AC AS INTEGER, Huff() AS INTEGER, A AS INTEGER, State AS JPEGState)
  223.     DIM C AS INTEGER, X AS INTEGER
  224.     C = JPEG.Category(AC)
  225.     X = RLE * 16 + C
  226.     JPEG.PutBinString Huff(X, 1, A, 0), Huff(X, 1, A, 1), State
  227.     JPEG.PutRightBinString AC + (AC < 0), C, State
  228.  
  229. SUB JPEG.Begin (FileNo AS INTEGER, W AS INTEGER, H AS INTEGER, Sampling() AS INTEGER, State AS JPEGState, QT() AS INTEGER, Huff() AS INTEGER)
  230.  
  231.     DIM S AS STRING
  232.     State.FileNo = FileNo
  233.  
  234.     RESTORE Huff0
  235.     JPEG.GenerateHuffmanTable Huff(), 0, 0
  236.     JPEG.GenerateHuffmanTable Huff(), 0, 1
  237.     JPEG.GenerateHuffmanTable Huff(), 1, 0
  238.     JPEG.GenerateHuffmanTable Huff(), 1, 1
  239.  
  240.  
  241.     State.YCount = Sampling(0, 0) * Sampling(0, 1)
  242.     State.CbCount = Sampling(1, 0) * Sampling(1, 1)
  243.     State.CrCount = Sampling(2, 0) * Sampling(2, 1)
  244.     State.YDC = 0
  245.     State.CbDC = 0
  246.     State.CrDC = 0
  247.  
  248.     State.Position = 0
  249.  
  250.     State.Leftover = 0
  251.     State.LeftoverBits = 0
  252.  
  253.  
  254.     'SOI
  255.     PutChar FileNo, 255
  256.     PutChar FileNo, 216
  257.     'APP0
  258.     PutChar FileNo, 255
  259.     PutChar FileNo, 224
  260.     JPEG.PutWord FileNo, 16
  261.     S$ = "JFIF" + CHR$(0): PUT FileNo, , S$
  262.     PutChar FileNo, 1
  263.     PutChar FileNo, 2
  264.     PutChar FileNo, 0
  265.     PutChar FileNo, 0
  266.     PutChar FileNo, 1
  267.     PutChar FileNo, 0
  268.     PutChar FileNo, 1
  269.     PutChar FileNo, 0
  270.     PutChar FileNo, 0
  271.  
  272.     'DQT
  273.     PutChar FileNo, 255
  274.     PutChar FileNo, 219
  275.     JPEG.PutWord FileNo, 132
  276.  
  277.     PutChar FileNo, 0
  278.     FOR I = 0 TO 63
  279.         PutChar FileNo, QT(ZigZagX(I), ZigZagY(I), 0)
  280.     NEXT
  281.  
  282.  
  283.  
  284.     PutChar FileNo, 1
  285.     FOR I = 0 TO 63
  286.         PutChar FileNo, QT(ZigZagX(I), ZigZagY(I), 1)
  287.     NEXT
  288.  
  289.  
  290.  
  291.     'DHT
  292.     PutChar FileNo, 255
  293.     PutChar FileNo, 196
  294.     T = 2 + 4 * (16 + 1)
  295.     RESTORE Huff0
  296.     FOR I = 1 TO 16 * 4
  297.         READ X
  298.         FOR J = 1 TO X
  299.             READ Y
  300.             T = T + 1
  301.         NEXT
  302.     NEXT
  303.  
  304.     JPEG.PutWord FileNo, T
  305.  
  306.     PutChar FileNo, 0
  307.     RESTORE Huff0
  308.     FOR I = 1 TO 16
  309.         READ X
  310.         PutChar FileNo, X
  311.         FOR J = 1 TO X
  312.             READ Y
  313.         NEXT
  314.     NEXT
  315.     RESTORE Huff0
  316.     FOR I = 1 TO 16
  317.         READ X
  318.         FOR J = 1 TO X
  319.             READ Y
  320.             PutChar FileNo, Y
  321.         NEXT
  322.     NEXT
  323.  
  324.     PutChar FileNo, 1
  325.     RESTORE Huff1
  326.     FOR I = 1 TO 16
  327.         READ X
  328.         PutChar FileNo, X
  329.         FOR J = 1 TO X
  330.             READ Y
  331.         NEXT
  332.     NEXT
  333.     RESTORE Huff1
  334.     FOR I = 1 TO 16
  335.         READ X
  336.         FOR J = 1 TO X
  337.             READ Y
  338.             PutChar FileNo, Y
  339.         NEXT
  340.     NEXT
  341.  
  342.     PutChar FileNo, 16
  343.     RESTORE Huff2
  344.     FOR I = 1 TO 16
  345.         READ X
  346.         PutChar FileNo, X
  347.         FOR J = 1 TO X
  348.             READ Y
  349.         NEXT
  350.     NEXT
  351.     RESTORE Huff2
  352.     FOR I = 1 TO 16
  353.         READ X
  354.         FOR J = 1 TO X
  355.             READ Y
  356.             PutChar FileNo, Y
  357.         NEXT
  358.     NEXT
  359.  
  360.     PutChar FileNo, 17
  361.     RESTORE Huff3
  362.     FOR I = 1 TO 16
  363.         READ X
  364.         PutChar FileNo, X
  365.         FOR J = 1 TO X
  366.             READ Y
  367.         NEXT
  368.     NEXT
  369.     RESTORE Huff3
  370.     FOR I = 1 TO 16
  371.         READ X
  372.         FOR J = 1 TO X
  373.             READ Y
  374.             PutChar FileNo, Y
  375.         NEXT
  376.     NEXT
  377.  
  378.     'SOF0
  379.     PutChar FileNo, 255
  380.     PutChar FileNo, 192
  381.     JPEG.PutWord FileNo, 8 + 9
  382.     PutChar FileNo, 8
  383.     JPEG.PutWord FileNo, H
  384.     JPEG.PutWord FileNo, W
  385.  
  386.     PutChar FileNo, 3
  387.  
  388.     PutChar FileNo, 1
  389.     PutChar FileNo, Sampling(0, 0) * 16 + Sampling(0, 1)
  390.     PutChar FileNo, 0
  391.     PutChar FileNo, 2
  392.     PutChar FileNo, Sampling(1, 0) * 16 + Sampling(1, 1)
  393.     PutChar FileNo, 1
  394.     PutChar FileNo, 3
  395.     PutChar FileNo, Sampling(2, 0) * 16 + Sampling(2, 1)
  396.     PutChar FileNo, 1
  397.  
  398.     'SOS
  399.  
  400.     PutChar FileNo, 255
  401.     PutChar FileNo, 218
  402.     JPEG.PutWord FileNo, 12
  403.  
  404.     PutChar FileNo, 3
  405.  
  406.     PutChar FileNo, 1
  407.     PutChar FileNo, &H0
  408.     PutChar FileNo, 2
  409.     PutChar FileNo, &H11
  410.     PutChar FileNo, 3
  411.     PutChar FileNo, &H11
  412.  
  413.     PutChar FileNo, 0
  414.     PutChar FileNo, 63
  415.     PutChar FileNo, 0
  416.  
  417.  
  418. SUB JPEG.Block.Huffman (B() AS INTEGER, LastDC AS INTEGER, Huff() AS INTEGER, A AS INTEGER, State AS JPEGState)
  419.     DIM DC AS INTEGER, I AS INTEGER
  420.     DIM C AS INTEGER
  421.     DC = B(0) - LastDC
  422.     JPEG.DCHuff DC, Huff(), A, State
  423.     B(64) = -1
  424.  
  425.     I = 1
  426.     DO
  427.         C = 0
  428.         IF B(I) = 0 THEN
  429.  
  430.             DO
  431.                 I = I + 1
  432.                 C = C + 1
  433.             LOOP WHILE B(I) = 0
  434.             IF I = 64 THEN
  435.  
  436.                 JPEG.PutBinString Huff(0, 1, A, 0), Huff(0, 1, A, 1), State
  437.                 EXIT DO
  438.             END IF
  439.             WHILE C >= 16
  440.  
  441.                 JPEG.PutBinString Huff(&HF0, 1, A, 0), Huff(&HF0, 1, A, 1), State
  442.                 C = C - 16
  443.             WEND
  444.  
  445.         END IF
  446.  
  447.  
  448.         JPEG.ACHuff C, B(I), Huff(), A, State
  449.         I = I + 1
  450.     LOOP WHILE I < 64
  451.  
  452. SUB JPEG.Block.Output (B() AS INTEGER, State AS JPEGState, QT() AS INTEGER, Huff() AS INTEGER)
  453.  
  454.     DIM O(0 TO 64) AS INTEGER
  455.     State.Position = State.Position + 1
  456.     IF State.Position > State.YCount + State.CbCount + State.CrCount THEN State.Position = 1
  457.     IF State.Position <= State.YCount THEN
  458.         JPEG.Block.Transform B(), O(), QT(), 0
  459.         JPEG.Block.Huffman O(), State.YDC, Huff(), 0, State
  460.         State.YDC = O(0)
  461.     ELSE
  462.         JPEG.Block.Transform B(), O(), QT(), 1
  463.         IF State.Position <= State.YCount + State.CbCount THEN
  464.             JPEG.Block.Huffman O(), State.CbDC, Huff(), 1, State
  465.             State.CbDC = O(0)
  466.         ELSE
  467.             JPEG.Block.Huffman O(), State.CrDC, Huff(), 1, State
  468.             State.CrDC = O(0)
  469.         END IF
  470.     END IF
  471.  
  472.  
  473. SUB JPEG.Block.Transform (B() AS INTEGER, O() AS INTEGER, QT() AS INTEGER, A AS INTEGER)
  474.     DIM B2(0 TO 7, 0 TO 7) AS SINGLE
  475.     DIM T AS SINGLE
  476.  
  477.     FOR V = 0 TO 7: FOR U = 0 TO 7
  478.             T = 0
  479.             FOR X = 0 TO 7
  480.                 T = T + B(X, V) * Cosine(X, U)
  481.             NEXT X
  482.             B2(U, V) = T
  483.     NEXT U, V
  484.  
  485.     FOR U = 0 TO 7: FOR V = 0 TO 7
  486.             T = 0
  487.             FOR Y = 0 TO 7
  488.                 T = T + B2(U, Y) * Cosine(Y, V)
  489.             NEXT Y
  490.             T = T / 4
  491.             IF U = 0 THEN T = T / SQR(2)
  492.             IF V = 0 THEN T = T / SQR(2)
  493.             B(U, V) = CINT(T / QT(U, V, A))
  494.     NEXT V, U
  495.  
  496.     FOR U = 0 TO 63
  497.         O(U) = B(ZigZagX(U), ZigZagY(U))
  498.     NEXT
  499.  
  500.  
  501. FUNCTION JPEG.Category% (X AS INTEGER)
  502.     DIM T AS INTEGER, I AS INTEGER
  503.     T = ABS(X)
  504.     WHILE T
  505.         T = T \ 2
  506.         I = I + 1
  507.     WEND
  508.     JPEG.Category = I
  509.  
  510. FUNCTION JPEG.Cb% (R AS INTEGER, G AS INTEGER, B AS INTEGER)
  511.  
  512.     JPEG.Cb = -.1687 * R - .3313 * G + .5 * B
  513.  
  514.  
  515. FUNCTION JPEG.Cr% (R AS INTEGER, G AS INTEGER, B AS INTEGER)
  516.  
  517.     JPEG.Cr = .5 * R - .4187 * G - .0813 * B
  518.  
  519.  
  520. SUB JPEG.DCHuff (DC AS INTEGER, Huff() AS INTEGER, A AS INTEGER, State AS JPEGState)
  521.     DIM C AS INTEGER
  522.     C = JPEG.Category(DC)
  523.     JPEG.PutBinString Huff(C, 0, A, 0), Huff(C, 0, A, 1), State
  524.     JPEG.PutRightBinString DC + (DC < 0), C, State
  525.  
  526. SUB JPEG.Finish (State AS JPEGState)
  527.  
  528.     DEF SEG = VARSEG(State.Leftover)
  529.     IF State.LeftoverBits > 8 THEN
  530.         JPEG.PutByte State.FileNo, PEEK(VARPTR(State.Leftover) + 1)
  531.         POKE VARPTR(State.Leftover) + 1, State.Leftover AND 255
  532.         State.LeftoverBits = State.LeftoverBits - 8
  533.     END IF
  534.  
  535.     IF State.LeftoverBits THEN
  536.         JPEG.PutByte State.FileNo, PEEK(VARPTR(State.Leftover) + 1) OR (Pow2(8 - State.LeftoverBits) - 1)
  537.     END IF
  538.     DEF SEG
  539.  
  540.     'EOF marker
  541.     PutChar State.FileNo, 255
  542.     PutChar State.FileNo, 217
  543.  
  544.  
  545. SUB JPEG.GenerateHuffmanTable (Huff() AS INTEGER, A AS INTEGER, B AS INTEGER)
  546.     DIM S AS LONG, I AS INTEGER, J AS INTEGER, T AS INTEGER
  547.     DIM X AS INTEGER, Y AS INTEGER
  548.     S = -1
  549.  
  550.     FOR I = 1 TO 16
  551.         READ X
  552.         FOR J = 1 TO X
  553.  
  554.             IF S = -1 THEN
  555.                 S = 0
  556.             ELSE
  557.                 S = S + Pow2(T)
  558.             END IF
  559.  
  560.  
  561.             READ Y
  562.             IF S AND 32768 THEN Huff(Y, A, B, 0) = CINT(S AND 32767&) OR -32768 ELSE Huff(Y, A, B, 0) = S
  563.             Huff(Y, A, B, 1) = I
  564.             T = 16 - I
  565.  
  566.         NEXT
  567.     NEXT
  568.  
  569. SUB JPEG.Precalc
  570.     DIM X AS INTEGER, Y AS INTEGER, T AS INTEGER, Dir AS INTEGER, L AS LONG
  571.  
  572.     L = 1
  573.     FOR X = 0 TO 15
  574.         Pow2(X) = L
  575.         L = L + L
  576.     NEXT
  577.     FOR Y = 0 TO 7
  578.         FOR X = 0 TO 7
  579.             Cosine(X, Y) = COS((2 * X + 1) * Y * .1963495)
  580.     NEXT X, Y
  581.  
  582.     X = 0: Y = 0
  583.     T = 0
  584.     Dir = 0
  585.     DO
  586.         ZigZagX(T) = X
  587.         ZigZagY(T) = Y
  588.         T = T + 1
  589.         IF T = 64 THEN EXIT DO
  590.         IF Dir THEN
  591.             IF Y = 7 THEN
  592.                 X = X + 1
  593.                 Dir = 0
  594.             ELSEIF X = 0 THEN
  595.                 Y = Y + 1
  596.                 Dir = 0
  597.             ELSE
  598.                 X = X - 1
  599.                 Y = Y + 1
  600.             END IF
  601.  
  602.         ELSE
  603.             IF Y = 0 THEN
  604.                 X = X + 1
  605.                 Dir = 1
  606.             ELSEIF X = 7 THEN
  607.                 Y = Y + 1
  608.                 Dir = 1
  609.             ELSE
  610.                 X = X + 1
  611.                 Y = Y - 1
  612.             END IF
  613.         END IF
  614.     LOOP
  615.  
  616.  
  617.  
  618.  
  619. SUB JPEG.PutBinString (BS AS INTEGER, Length AS INTEGER, State AS JPEGState)
  620.     DIM Temp AS INTEGER
  621.  
  622.     Temp = BS
  623.     State.Leftover = State.Leftover OR JPEG.Shift(Temp, State.LeftoverBits)
  624.     State.LeftoverBits = State.LeftoverBits + Length
  625.     IF State.LeftoverBits >= 16 THEN
  626.         DEF SEG = VARSEG(State.Leftover)
  627.         JPEG.PutByte State.FileNo, PEEK(VARPTR(State.Leftover) + 1)
  628.         DEF SEG
  629.         JPEG.PutByte State.FileNo, State.Leftover AND 255
  630.         State.LeftoverBits = State.LeftoverBits - 16
  631.         State.Leftover = Temp
  632.     END IF
  633.  
  634.  
  635. SUB JPEG.PutByte (FileNo AS INTEGER, Byte AS INTEGER)
  636.     DIM C AS STRING * 1
  637.     C = CHR$(Byte)
  638.     PUT FileNo, , C
  639.     IF Byte = 255 THEN C = CHR$(0): PUT FileNo, , C
  640.  
  641. SUB JPEG.PutRightBinString (BS AS INTEGER, Length AS INTEGER, State AS JPEGState)
  642.  
  643.     DIM Temp AS LONG
  644.     IF Length THEN
  645.         Temp = (CLNG(BS) AND Pow2(Length) - 1) * Pow2(16 - Length)
  646.         IF Temp AND 32768 THEN Temp = Temp OR -65536
  647.         JPEG.PutBinString CINT(Temp), Length, State
  648.     END IF
  649.  
  650.  
  651. SUB JPEG.PutWord (FileNo AS INTEGER, Word AS INTEGER)
  652.     DIM C AS STRING * 1
  653.     C = CHR$(Word \ 256)
  654.     PUT FileNo, , C
  655.     C = CHR$(Word AND 255)
  656.     PUT FileNo, , C
  657.  
  658. FUNCTION JPEG.Shift% (I AS INTEGER, N AS INTEGER)
  659.     DIM T AS LONG
  660.  
  661.     IF N = 0 THEN
  662.         JPEG.Shift = I
  663.         I = 0
  664.         EXIT FUNCTION
  665.     END IF
  666.     T = CLNG(I) AND 65535
  667.  
  668.     JPEG.Shift = T \ Pow2(N)
  669.  
  670.     T = (T AND (Pow2(N) - 1)) * Pow2((16 - N) AND 15)
  671.     IF T AND 32768 THEN I = CINT(T AND 32767&) OR -32768 ELSE I = CINT(T)
  672.  
  673. SUB JPEG.StandardQT (quality AS SINGLE, QT() AS INTEGER)
  674.  
  675.     RESTORE StandardQT
  676.  
  677.     FOR I = 0 TO 1: FOR Y = 0 TO 7: FOR X = 0 TO 7
  678.                 READ T
  679.  
  680.                 QT(X, Y, I) = T * quality
  681.  
  682.                 IF QT(X, Y, I) = 0 THEN QT(X, Y, I) = 1
  683.     NEXT X, Y, I
  684.  
  685.  
  686. FUNCTION JPEG.Y% (R AS INTEGER, G AS INTEGER, B AS INTEGER)
  687.  
  688.     JPEG.Y = .299 * R + .587 * G + .114 * B - 128
  689.  
  690.  
  691. SUB PutChar (FileNo AS INTEGER, Char AS INTEGER)
  692.     DIM C AS STRING * 1
  693.     C = CHR$(Char)
  694.     PUT FileNo, , C


« Last Edit: August 12, 2019, 03:57:44 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: SaveJPG
« Reply #1 on: August 11, 2019, 08:52:29 pm »
(Post deleted by user.)
« Last Edit: August 12, 2019, 01:27:07 am by SierraKen »

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: SaveJPG
« Reply #2 on: August 11, 2019, 09:28:54 pm »
Here's an example program I made for you using the QB64.org Wiki page example to make a BMP to JPG converter. I don't know enough to know if this will work with Linux or Apple, but I thought I would just toss this in here for Windows people at least. You enter the name of a BMP picture and a new JPG name and then it displays it and saves it as the JPG name.

Here is the Wiki page I got the example from: https://qb64.org/wiki/SAVEIMAGE

(NOTE: I just found out that this isn't a TRUE JPG file, just a BMP with a JPG ending. So my example here is erased.)

« Last Edit: August 12, 2019, 01:28:21 am by SierraKen »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: SaveJPG
« Reply #3 on: August 12, 2019, 12:15:00 am »
Ken, you’re not converting a BMP to a JPG with that code.  You’re simply taking a BMP file and putting a JPG extension on it. 

Try it for yourself from Windows Explorer — use SaveImage to save the file as BMP.  Load it in Paint, or any other program.  It’s a BMP file. 

Once you’re satisfied it’s a BMP file, simply change the extension to JPG and see how it behaves.  If you didn’t know it was a BMP file, you’d think it was JPG.




So how’s it work with a wrong extension?

The JPG decoder reads the file header (from line 36 in your example program above), and sees the metadata info down at line 36 and decodes it internally as BMP.

It’s a hack at best, and not a “true” JPG file.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: SaveJPG
« Reply #4 on: August 12, 2019, 01:25:56 am »
Woah you are right! Dannng all these weeks I thought I could make a JPG. The file length itself says it, I should have known. It's the same exact file length as a BMP. I'll change my couple of programs that save as JPG and either use your JPG code or just use BMP. Probably going to stick with BMP since it's simpler to me. Thank you for telling me!

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: SaveJPG
« Reply #5 on: August 12, 2019, 02:03:42 am »
Well, I removed my Paint Pixels program off my website. But I changed my Calendar Maker program to .bmp pictures to save them as. My Paint Pixels program was a bit wobbly anyway. So, I feel better now. Thank you again for telling me.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: SaveJPG
« Reply #6 on: August 12, 2019, 03:41:08 am »
Hi Steve. Thank you for mentioning me in your post, but I have to add the following. BMPtoJPG is just a modification of the original source code, which I am not the author of. The original source code was written by Artelius, he is the original author. BMPtoJPG is a modification of its program that ships with QB64 in programs / samples / n54 / big / jpegmake.bas

I had to add this here because it would be flaunting a foreign code as my own, that is a practice that I do not deeply recognize.

Thank you for the modification for widespread use. I'll look at her later.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: SaveJPG
« Reply #7 on: August 12, 2019, 03:59:28 am »
Hi Steve. Thank you for mentioning me in your post, but I have to add the following. BMPtoJPG is just a modification of the original source code, which I am not the author of. The original source code was written by Artelius, he is the original author. BMPtoJPG is a modification of its program that ships with QB64 in programs / samples / n54 / big / jpegmake.bas

I had to add this here because it would be flaunting a foreign code as my own, that is a practice that I do not deeply recognize.

Thank you for the modification for widespread use. I'll look at her later.

Noted.  I’ll have to be certain to mention both you and he in the latest SaveImage Library as well. Like you, I always try to give credit to where it’s due.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!