www.pudn.com > bmp2toJPEG.rar > mSaveJPEG.bas
Attribute VB_Name = "mSaveJPEG"
Option Explicit
Private Type BITMAPINFOHEADER '40 bytes
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Private Type RGBQUAD
rgbBlue As Byte
rgbGreen As Byte
rgbRed As Byte
rgbReserved As Byte
End Type
Private Type BITMAPINFO
bmiHeader As BITMAPINFOHEADER
bmiColors(0 To &HFF) As RGBQUAD
End Type
Private Const BI_RGB As Long = 0&
Private Declare Function GetObjectAPI Lib "gdi32.dll" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Type BITMAP
bmType As Long
bmWidth As Long
bmHeight As Long
bmWidthBytes As Long
bmPlanes As Integer
bmBitsPixel As Integer
bmBits As Long
End Type
Private Declare Function CreateCompatibleDC Lib "gdi32.dll" (ByVal hDC As Long) As Long
Private Declare Function DeleteDC Lib "gdi32.dll" (ByVal hDC As Long) As Long
Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hDC As Long, ByVal hObject As Long) As Long
Private Declare Function GetDIBits Lib "gdi32.dll" (ByVal hDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As Any, ByVal wUsage As Long) As Long
Private Const DIB_RGB_COLORS As Long = 0
Private Const DIB_PAL_COLORS As Long = 1
Private Declare Function SetDIBitsToDevice Lib "gdi32.dll" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal dX As Long, ByVal dY As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As Any, ByVal wUsage As Long) As Long
'================================================
Public Enum JPEGInfoConstants
JIC_QualityMask = &HFF& '质量部分掩码(0~100)
JIC_Hy2 = &H100& '彩色JPEG中,Y分量水平采样是2
JIC_Vy2 = &H200& '彩色JPEG中,Y分量垂直采样是2
JIC_Gray = &H400& '灰度JPEG。没有这个标记表示是彩色JPEG
JIC_AutoDHT = &H800& '自动生成最优化Huffman表。没有这个标记表示用默认Huffman表
'暂时不支持自动生成最优化Huffman表(算法比较复杂,程序的结构就写的比较乱)
End Enum
Private Type JPEGImage
hFile As Long '文件号
Width As Long '宽度
Height As Long '高度
Flags As JPEGInfoConstants
Items As Long '颜色分量数(1 or 3)
DQTItems As Long 'DQT项目数
OldDC(1 To 3) '旧的DC系数
BitBuff As Long '位缓冲区
BitUsed As Long '位缓冲区中使用的位
Block(0 To 63) As Long '一个数据块
CurItem As Long '当前颜色分量索引(1~3)
CurType As Long '当前亮度/色度(0/1)
CurDCAC As Long '当前DC/AC(0/1)
DQT(0 To 63, 0 To 1) As Long
'反正使用默认Huffamn表或自动生成最佳Huffman表,所以不需要保存DHT
End Type
'将Picture对象保存为JPEG文件
Public Function JPEGSavePic(ByRef Image As Picture, ByRef FileName As String, Flags As JPEGInfoConstants) As Boolean
If Image.Type <> VBRUN.PictureTypeConstants.vbPicTypeBitmap Then Exit Function
If (Flags And JIC_QualityMask) > 100 Then Exit Function
Dim Rc As Long
'== 初始化数据
Dim bm As BITMAP
If GetObjectAPI(Image.Handle, Len(bm), bm) = 0 Then Exit Function
Dim BI As BITMAPINFO
Dim ItemBytes As Long, LineBytes As Long
With BI.bmiHeader
.biSize = Len(BI.bmiHeader)
.biWidth = bm.bmWidth
.biHeight = bm.bmHeight
.biPlanes = bm.bmPlanes
ItemBytes = 3
.biBitCount = 8 * ItemBytes
.biCompression = BI_RGB
LineBytes = ((.biWidth * .biBitCount + 31&) And &HFFFFFFE0) \ 8
.biSizeImage = LineBytes * .biHeight
Dim MapData() As Byte
ReDim MapData(0 To .biSizeImage)
End With
'== 得到图像数据
'Dim hDC As Long
'Dim hOldMap As Long
'
'hDC = CreateCompatibleDC(0)
'If hDC = 0 Then Exit Function
'hOldMap = SelectObject(hDC, Image.Handle)
'
'Rc = GetDIBits(hDC, Image.Handle, 0, bm.bmHeight, MapData(0), BI, DIB_RGB_COLORS)
'
'Call SelectObject(hDC, hOldMap)
'Call DeleteDC(hDC)
'VB的Picture对象与StdPicture对象等价
'它们都继承了IPictureDisp和IPicture接口
'只不过IPictureDisp是Picture/StdPicture对象的标准接口
Dim IPic As IPicture
Set IPic = Image
Rc = GetDIBits(IPic.CurDC, IPic.Handle, 0, bm.bmHeight, MapData(0), BI, DIB_RGB_COLORS)
Set IPic = Nothing
If Rc = 0 Then Exit Function
'== 开始保存
JPEGSavePic = JPEGSave(VarPtr(BI), VarPtr(MapData(0)), FileName, Flags)
End Function
'将DIB位图数据保存为JPEG文件
Public Function JPEGSave(ByVal lpBI As Long, ByVal lpBits As Long, ByRef FileName As String, Flags As JPEGInfoConstants) As Boolean
If lpBI = 0 Then Exit Function
If lpBits = 0 Then Exit Function
If Len(FileName) = 0 Then Exit Function
mBit.Init
mJPEG.Init
'== 检查DIB
Dim MyImage As JPEGImage
Dim BI As BITMAPINFOHEADER
Dim ItemBytes As Long, LineBytes As Long
CopyMemory BI, ByVal lpBI, Len(BI)
With BI
If .biWidth < 0 Or .biWidth > &HFFFF& Then Exit Function
If .biHeight < 0 Or .biHeight > &HFFFF& Then Exit Function
Select Case .biBitCount
Case 24, 32
Case Else
Exit Function
End Select
If .biPlanes <> 1 Then Exit Function
If .biCompression <> BI_RGB Then Exit Function
MyImage.Width = .biWidth
MyImage.Height = .biHeight
MyImage.Flags = Flags
ItemBytes = .biBitCount \ 8
LineBytes = ((.biWidth * .biBitCount + 31&) And &HFFFFFFE0) \ 8
End With
'初始化编码
If JPEGEncodeBegin(MyImage, FileName) = False Then Exit Function
'== 写图像压缩数据
Const DCTSize = 8
Const BlockSize = DCTSize * DCTSize
Dim pByte0() As Byte, pBytePtr0 As SAFEARRAY1D
Dim pByte1() As Byte, pBytePtr1 As SAFEARRAY1D
Dim LinePtr0 As Long
Dim LinePtr1 As Long
Dim X As Long, Y As Long
Dim I As Long, J As Long
Dim Idx As Long
Dim DCTData(0 To DCTSize - 1, 0 To DCTSize - 1) As Single
Dim DCTDataCr(0 To DCTSize - 1, 0 To DCTSize - 1) As Single
Dim BlockYs() As Long '为了简化代码设计,先将所有的Y分量提取出来
Dim cxBlock As Long, cyBlock As Long '水平/垂直方向块的数目
Dim cHy As Long, cVy As Long 'Y分量水平/垂直采样数
Dim MCU_Y As Long '一个MCU块中Y块的数目
Dim MaxX As Long, MaxY As Long '最大X/Y
Dim MaxI As Long
Dim Yx0 As Long, Yy0 As Long 'Y分量的X/Y坐标
MakePoint VarPtrArray(pByte0), pBytePtr0, 1
MakePoint VarPtrArray(pByte1), pBytePtr1, 1
With MyImage
'-- 提取Y分量
.CurItem = 1 'Y
.CurType = 0 '亮度
MaxX = .Width - 1
MaxY = .Height - 1
If (.Flags And JIC_Gray) = 0 Then '如果是彩色图
'(n+7)\8是进一法舍入数字
cxBlock = (.Width + 7) \ 8
cyBlock = (.Height + 7) \ 8
cHy = IIf(.Flags And JIC_Hy2, 2, 1)
If .Flags And JIC_Hy2 Then '如果JIC_Hy2,则水平Y块必须是2的倍数(偶数)
If cxBlock And 1 Then '表示cxBlock是奇数
cxBlock = cxBlock + 1
End If
End If
cVy = IIf(.Flags And JIC_Vy2, 2, 1)
If .Flags And JIC_Vy2 Then '如果JIC_Vy2,则垂直Y块必须是2的倍数(偶数)
If cyBlock And 1 Then '表示cyBlock是奇数
cyBlock = cyBlock + 1
End If
End If
MCU_Y = cHy * cVy
ReDim BlockYs(0 To BlockSize * cxBlock * cyBlock - 1)
End If
For Y = 0 To MaxY Step 8
'为了减少垂直方向判断
MaxI = MaxY - Y
If MaxI > 7 Then MaxI = 7
'此时y0代表当前Y块的起始索引
Yy0 = (Y \ DCTSize) * cxBlock
For X = 0 To MaxX Step 8
'-- 得到分量值
LinePtr0 = lpBits + LineBytes * (BI.biHeight - 1 - Y) + ItemBytes * X
For I = 0 To MaxI 'Y
pBytePtr0.pvData = LinePtr0
For J = 0 To 7 'X
If (X Or J) <= MaxX Then
DCTData(J, I) = JPEGRGB2YCbCr(0, 0) * pByte0(2) + JPEGRGB2YCbCr(1, 0) * pByte0(1) + JPEGRGB2YCbCr(2, 0) * pByte0(0) + JPEGRGB2YCbCrAdd(0)
Else
DCTData(J, I) = 0!
End If
pBytePtr0.pvData = pBytePtr0.pvData + ItemBytes
Next J
LinePtr0 = LinePtr0 - LineBytes
Next I
'-- 清零边角数据(由于存在DCT,所以必须放在内循环)
If MaxI < 7 Then
ZeroMemory DCTData(0, MaxI + 1), (7 - MaxI) * DCTSize * 4
End If
'-- DCT变换
Call JPEG_FDCT(VarPtr(DCTData(0, 0)))
'-- 之字型排列&量化
For J = 0 To 63
Idx = ZigZagPos(J)
'.Block(J) = DCTData(LoWord(Idx), HiWord(Idx)) \ DefDQT(J, 0)
.Block(J) = DCTData(Idx And &HF, Idx \ &H10000) \ .DQT(J, .CurType)
Next J
If .Flags And JIC_Gray Then '灰度图
Call JPEGWriteBlock(MyImage)
Else '彩色图
CopyMemory BlockYs((Yy0 + X \ DCTSize) * BlockSize), .Block(0), BlockSize * 4&
End If
Next X
Next Y
If (.Flags And JIC_Gray) = 0 Then '彩色图
'水平采样
If .Flags And JIC_Hy2 Then '水平方向缩小为原来的1/2
LinePtr0 = lpBits '此时不必考虑DIB逆序问题
For Y = 0 To MaxY
pBytePtr0.pvData = LinePtr0
pBytePtr1.pvData = LinePtr0
For X = 0 To MaxX - 1 Step 2
pByte1(0) = (CLng(pByte0(0)) + pByte0(ItemBytes + 0)) \ 2
pByte1(1) = (CLng(pByte0(1)) + pByte0(ItemBytes + 1)) \ 2
pByte1(2) = (CLng(pByte0(2)) + pByte0(ItemBytes + 2)) \ 2
pBytePtr0.pvData = pBytePtr0.pvData + ItemBytes + ItemBytes
pBytePtr1.pvData = pBytePtr1.pvData + ItemBytes
Next X
'最后一个
If (MaxX And 1) = 0 Then 'MaxX为偶数,Width为奇数
pByte1(0) = pByte0(0)
pByte1(1) = pByte0(1)
pByte1(2) = pByte0(2)
pBytePtr0.pvData = pBytePtr0.pvData + ItemBytes
pBytePtr1.pvData = pBytePtr1.pvData + ItemBytes
End If
''其他数据清零
'ZeroMemory ByVal CLng(pBytePtr1.pvData), LineBytes - (pBytePtr1.pvData - LinePtr0)
'指向下一行
LinePtr0 = LinePtr0 + LineBytes
Next Y
MaxX = MaxX \ 2 '(MaxX + 1 + 1) \ 2 - 1
End If
'垂直采样
If .Flags And JIC_Vy2 Then '垂直方向缩小为原来的1/2
LinePtr0 = lpBits + LineBytes * (BI.biHeight - 1)
LinePtr1 = LinePtr0
For Y = 0 To MaxY - 1 Step 2
pBytePtr0.pvData = LinePtr0 - LineBytes '故意上移一行,好在内循环用“+ LineBytes”寻址
pBytePtr1.pvData = LinePtr1
For X = 0 To MaxX
pByte1(0) = (CLng(pByte0(0)) + pByte0(0 + LineBytes)) \ 2
pByte1(1) = (CLng(pByte0(1)) + pByte0(1 + LineBytes)) \ 2
pByte1(2) = (CLng(pByte0(2)) + pByte0(2 + LineBytes)) \ 2
pBytePtr0.pvData = pBytePtr0.pvData + ItemBytes
pBytePtr1.pvData = pBytePtr1.pvData + ItemBytes
Next X
LinePtr0 = LinePtr0 - LineBytes - LineBytes
LinePtr1 = LinePtr1 - LineBytes
Next Y
'最后一行
If (MaxY And 1) = 0 Then 'MaxY为偶数,Height为奇数
CopyMemory ByVal CLng(lpBits + LineBytes * (BI.biHeight - 1 - MaxY \ 2)), ByVal CLng(lpBits), MaxX * ItemBytes
End If
''其他数据清0
'ZeroMemory ByVal CLng(lpBits), ((MaxY + 1) \ 2) * LineBytes
MaxY = MaxY \ 2 '(MaxY + 1 + 1) \ 2 - 1
End If
'写图像数据
For Y = 0 To MaxY Step DCTSize
'为了减少垂直方向判断
MaxI = MaxY - Y
If MaxI > 7 Then MaxI = 7
'此时y0代表当前Y坐标
Yy0 = (Y \ DCTSize) * cVy
For X = 0 To MaxX Step DCTSize
'-- 得到分量值
LinePtr0 = lpBits + LineBytes * (BI.biHeight - 1 - Y) + ItemBytes * X
For I = 0 To MaxI 'Y
pBytePtr0.pvData = LinePtr0
For J = 0 To 7 'X
If (X Or J) <= MaxX Then
DCTData(J, I) = JPEGRGB2YCbCr(0, 1) * pByte0(2) + JPEGRGB2YCbCr(1, 1) * pByte0(1) + JPEGRGB2YCbCr(2, 1) * pByte0(0) + JPEGRGB2YCbCrAdd(1)
DCTDataCr(J, I) = JPEGRGB2YCbCr(0, 2) * pByte0(2) + JPEGRGB2YCbCr(1, 2) * pByte0(1) + JPEGRGB2YCbCr(2, 2) * pByte0(0) + JPEGRGB2YCbCrAdd(2)
Else
DCTData(J, I) = 0!
DCTDataCr(J, I) = 0!
End If
pBytePtr0.pvData = pBytePtr0.pvData + ItemBytes
Next J
LinePtr0 = LinePtr0 - LineBytes
Next I
'-- 清零边角数据(由于存在DCT,所以必须放在内循环)
If MaxI < 7 Then
ZeroMemory DCTData(0, MaxI + 1), (7 - MaxI) * DCTSize * 4
ZeroMemory DCTDataCr(0, MaxI + 1), (7 - MaxI) * DCTSize * 4
End If
'-- 写亮度块
Yx0 = (X \ DCTSize) * cHy
For I = 0 To MCU_Y - 1
.CurItem = 1 'Y
.CurType = 0 '亮度
'复制块
CopyMemory .Block(0), BlockYs(((Yy0 + (I \ cHy)) * cxBlock + (Yx0 + (I Mod cHy))) * BlockSize), BlockSize * 4
'输出块
Call JPEGWriteBlock(MyImage)
Next I
'-- 写色度块
For I = 2 To 3
.CurItem = I 'Cb/Cr
.CurType = 1 '色度
'DCT变换
Call JPEG_FDCT(VarPtr(DCTData(0, 0)))
'之字型排列&量化
For J = 0 To 63
Idx = ZigZagPos(J)
'.Block(J) = DCTData(LoWord(Idx), HiWord(Idx)) \ DefDQT(J, .CurType)
.Block(J) = DCTData(Idx And &HF, Idx \ &H10000) \ .DQT(J, .CurType)
Next J
'输出块
Call JPEGWriteBlock(MyImage)
'指向下一色度块
If I = 2 Then 'Cb
CopyMemory DCTData(0, 0), DCTDataCr(0, 0), BlockSize * 4
End If
Next I
Next X
Next Y
End If
End With
FreePoint VarPtrArray(pByte0)
FreePoint VarPtrArray(pByte1)
'== 结束编码
JPEGSave = JPEGEncodeEnd(MyImage)
End Function
'准备开始编码
Private Function JPEGEncodeBegin(ByRef MyImage As JPEGImage, ByRef FileName As String) As Boolean
Dim TempBytes() As Byte
Dim TempByte As Byte
Dim TempWord As Integer
Dim I As Long, J As Long
With MyImage
'检查参数
If .Flags And JIC_Gray Then .Flags = .Flags And Not (JIC_Hy2 Or JIC_Vy2)
If (.Flags And JIC_QualityMask) > 100 Then .Flags = (.Flags And (Not JIC_QualityMask)) Or 100
If .Flags And JIC_AutoDHT Then Exit Function '暂时不支持自动生成最优化Huffman表(算法比较复杂,程序的结构就写的比较乱)
'打开文件
If ChkFileWrite(FileName) = False Then Exit Function
.hFile = FreeFile()
Open FileName For Binary As .hFile
'SOI
Put .hFile, , JPEGCode
Put .hFile, , JPEG_SOI
'APP0
Put .hFile, , JPEGCode
Put .hFile, , CByte(JPEG_APP + 0)
WordBig(TempWord) = 16
Put .hFile, , TempWord '长度
ReDim TempBytes(1 To 5)
CopyMemory TempBytes(1), ByVal "JFIF", 5 'byval对String会自动转换成LPSTR
Put .hFile, , TempBytes 'JFIF
WordBig(TempWord) = &H101
Put .hFile, , TempWord '版本
TempByte = 0
Put .hFile, , TempByte '分辨率单位
WordBig(TempWord) = 1
Put .hFile, , TempWord 'X分辨率
WordBig(TempWord) = 1
Put .hFile, , TempWord 'Y分辨率
TempByte = 0
Put .hFile, , TempByte '缩略图宽
TempByte = 0
Put .hFile, , TempByte '缩略图高
'SOF0
Put .hFile, , JPEGCode
Put .hFile, , CByte(JPEG_SOF + 0) '基线方式
.Items = IIf(.Flags And JIC_Gray, 1, 3)
WordBig(TempWord) = 8 + 3 * .Items '分量数
Put .hFile, , TempWord '长度
TempByte = 8
Put .hFile, , TempByte '精度
WordBig(TempWord) = .Height
Put .hFile, , TempWord '高度(先写高度再写宽度,可很多书写反了)
WordBig(TempWord) = .Width
Put .hFile, , TempWord '宽度
TempByte = .Items
Put .hFile, , TempByte '颜色分量数
For I = 1 To .Items
.OldDC(I) = 0
TempByte = I
Put .hFile, , TempByte '颜色分量编号
If I = 1 And .Items = 3 Then
TempByte = 0
TempByte = TempByte Or IIf(.Flags And JIC_Hy2, &H20, &H10)
TempByte = TempByte Or IIf(.Flags And JIC_Vy2, &H2, &H1)
Else
TempByte = &H11
End If
Put .hFile, , TempByte '水平/垂直采样
TempByte = IIf(I = 1, 0, 1)
Put .hFile, , TempByte '量化表
Next I
'DQT
Put .hFile, , JPEGCode
Put .hFile, , JPEG_DQT
.DQTItems = IIf(.Items = 1, 1, 2)
WordBig(TempWord) = 2 + &H41 * .DQTItems
Put .hFile, , TempWord '长度
'Put .hFile, , DefDQTData 'DQT数据
Dim Diff As Long '由于是在0%量化表与全精量化表中间做线性插值,算反的更快一些(1是常数,编译时按立即数处理)
'Quality = .Flags And JIC_QualityMask
Diff = 100 - (.Flags And JIC_QualityMask)
ReDim TempBytes(0 To 63)
For I = 0 To .DQTItems - 1
TempByte = I
Put .hFile, , TempByte '量化表编号
For J = 0 To 63
.DQT(J, I) = 1 + ((DefDQT(J, I) - 1) * Diff + 50) \ 100 '+50是为了四舍五入
TempBytes(J) = .DQT(J, I)
Next J
Put .hFile, , TempBytes '量化表
Next I
If (.Flags And JIC_AutoDHT) = 0 Then
'DHT
Put .hFile, , JPEGCode
Put .hFile, , JPEG_DHT
WordBig(TempWord) = 2 + UBound(DefDHTData) + 1
Put .hFile, , TempWord '长度
Put .hFile, , DefDHTData 'DHT数据
'SOS
Put .hFile, , JPEGCode
Put .hFile, , JPEG_SOS
WordBig(TempWord) = 3 + 2 * .Items + 3 '分量数
Put .hFile, , TempWord '长度
TempByte = .Items
Put .hFile, , TempByte '颜色分量数
For I = 1 To .Items
TempByte = I
Put .hFile, , TempByte '颜色分量编号
TempByte = IIf(I = 1, &H0, &H11)
Put .hFile, , TempByte 'DC/AC Huffman表
Next I
TempByte = 0
Put .hFile, , TempByte 'Ss:起始频谱选择
TempByte = 63
Put .hFile, , TempByte 'Se:终止频谱选择
TempByte = 0
Put .hFile, , TempByte '(Ah,Al)
End If
End With
JPEGEncodeBegin = True
End Function
'准备结束编码
Private Function JPEGEncodeEnd(ByRef MyImage As JPEGImage) As Boolean
With MyImage
If .Flags And JIC_AutoDHT Then
'
End If
If .BitUsed Then '如果存在还未封装成字节的位
Call JPEGOutBits(MyImage, 0, 8 - .BitUsed)
End If
'== 编码结束
'EOI
Put .hFile, , JPEGCode
Put .hFile, , JPEG_EOI
Close .hFile
End With
JPEGEncodeEnd = True
End Function
Private Sub JPEGWriteBlock(ByRef MyImage As JPEGImage)
Dim DiffDC As Long
Dim cnt As Long
Dim I As Long
With MyImage
'-- 设置type
.CurType = IIf(.CurItem = 1, 0, 1)
'-- 对DC进行编码
.CurDCAC = 0
DiffDC = .Block(0) - .OldDC(.CurItem)
.OldDC(.CurItem) = .Block(0)
Call JPEGOutDC(MyImage, DiffDC)
'-- 对AC进行编码
.CurDCAC = 1
cnt = 0
For I = 1 To 63
If .Block(I) = 0 Then
cnt = cnt + 1
Else
Do While cnt > 15
'Stop
'输出ZRL标记
Call JPEGOutAC(MyImage, &HF, 0)
cnt = cnt - 16
Loop
'输出编码
Call JPEGOutAC(MyImage, cnt, .Block(I))
cnt = 0
End If
Next I
If cnt Then '最后一个系数是0时,肯定可以EOB
'输出EOB标记
Call JPEGOutAC(MyImage, 0, 0)
End If
End With
End Sub
'输出DC
Private Sub JPEGOutDC(ByRef MyImage As JPEGImage, ByVal Value As Long)
Dim ValueBits As Long
Dim DataSign As Boolean
'ValueBits = ChkNumBitsAuto(Value)
DataSign = Value < 0
If DataSign Then Value = -Value
Select Case Value
Case 0: ValueBits = 0
Case Is <= 1: ValueBits = 1
Case Is <= 3: ValueBits = 2
Case Is <= 7: ValueBits = 3
Case Is <= 15: ValueBits = 4
Case Is <= 31: ValueBits = 5
Case Is <= 63: ValueBits = 6
Case Is <= 127: ValueBits = 7
Case Is <= 255: ValueBits = 8
Case Is <= 511: ValueBits = 9
Case Is <= 1023: ValueBits = 10
Case Is <= 2047: ValueBits = 11
'Case Else: Stop '没有这么大的数
End Select
If DataSign Then Value = Value Xor BitsMask(ValueBits)
With MyImage
If (.Flags And JIC_AutoDHT) = 0 Then '使用默认Huffman表
Call JPEGOutBits(MyImage, DefHCodeDC(ValueBits, .CurType), DefHCodeSizeDC(ValueBits, .CurType))
If ValueBits Then Call JPEGOutBits(MyImage, Value, ValueBits)
Else '最优化Huffman表
End If
End With
End Sub
'输出AC
Private Sub JPEGOutAC(ByRef MyImage As JPEGImage, ByVal ZeroCount As Long, ByVal Value As Long)
Dim TempCode As Long
Dim ValueBits As Long
Dim DataSign As Boolean
'ValueBits = ChkNumBitsAuto(Value)
DataSign = Value < 0
If DataSign Then Value = -Value
Select Case Value
Case 0: ValueBits = 0
Case Is <= 1: ValueBits = 1
Case Is <= 3: ValueBits = 2
Case Is <= 7: ValueBits = 3
Case Is <= 15: ValueBits = 4
Case Is <= 31: ValueBits = 5
Case Is <= 63: ValueBits = 6
Case Is <= 127: ValueBits = 7
Case Is <= 255: ValueBits = 8
Case Is <= 511: ValueBits = 9
Case Is <= 1023: ValueBits = 10
Case Is <= 2047: ValueBits = 11
'Case Else: Stop '没有这么大的数
End Select
If DataSign Then Value = Value Xor BitsMask(ValueBits)
TempCode = ZeroCount * &H10 Or ValueBits
With MyImage
If (.Flags And JIC_AutoDHT) = 0 Then '使用默认Huffman表
Call JPEGOutBits(MyImage, DefHCodeAC(TempCode, .CurType), DefHCodeSizeAC(TempCode, .CurType))
'在默认AC表中无对应值(用断言检查较好)
'If DefHCodeSizeAC(TempCode, .CurType) = 0 Then Stop
Debug.Assert DefHCodeSizeAC(TempCode, .CurType)
If ValueBits Then Call JPEGOutBits(MyImage, Value, ValueBits)
Else '最优化Huffman表
End If
End With
End Sub
'输出位流
Private Sub JPEGOutBits(ByRef MyImage As JPEGImage, ByVal Value As Long, ByVal ValueBits As Long)
Dim TempByte As Byte
With MyImage
'位流接在原数据的后面
.BitBuff = (.BitBuff * BitPosMask(ValueBits)) Or Value 'And BitsMask(ValueBits))
.BitUsed = .BitUsed + ValueBits
Do While .BitUsed >= 8
.BitUsed = .BitUsed - 8
TempByte = .BitBuff \ BitPosMask(.BitUsed) 'TempByte=.BitBuff>>.BitUsed
.BitBuff = .BitBuff And BitsMask(.BitUsed)
Put .hFile, , TempByte
If TempByte = &HFF Then '细节问题(1)
TempByte = 0
Put .hFile, , TempByte
End If
Loop
End With
End Sub