tiff files, compression, colordepth

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Maurice Mertens

    tiff files, compression, colordepth

    Hello,

    I'm having troubles with saving a tiff-file with a certain compression
    and colordepth. This is the code I use:

    ----------------------------------------------------------------------
    private sub MakeTiff

    dim imgSource as new bitmap(strTifSo urceFile)

    Dim TiffCodecInfo As System.Drawing. Imaging.ImageCo decInfo
    Dim CompressionEnco der As System.Drawing. Imaging.Encoder
    Dim Params As System.Drawing. Imaging.Encoder Parameters
    Dim myencoder As System.Drawing. Imaging.Encoder
    myencoder = System.Drawing. Imaging.Encoder .ColorDepth
    Dim myImageCodecInf o As System.Drawing. Imaging.ImageCo decInfo
    myImageCodecInf o = GetEncoderInfo
    (System.Drawing .Imaging.ImageF ormat.Tiff)

    Dim format As System.Drawing. Imaging.ImageFo rmat
    Dim Index As Integer

    'Get the CodecInfo for TIFF format
    TiffCodecInfo = GetEncoderInfo
    (System.Drawing .Imaging.ImageF ormat.Tiff)

    'Colordepth
    Dim myEncoderParame terColor As New
    System.Drawing. Imaging.Encoder Parameter(myenc oder, 24L)

    'Compression
    CompressionEnco der = System.Drawing. Imaging.Encoder .Compression
    Dim myEncoderParame terCompression = New
    System.Drawing. Imaging.Encoder Parameter(Compr essionEncoder, CLng
    (System.Drawing .Imaging.Encode rValue.Compress ionLZW))

    'Create an EncoderParamete rs object.
    Params = New System.Drawing. Imaging.Encoder Parameters(2)
    Params.Param(0) = myEncoderParame terCompression
    Params.Param(1) = myEncoderParame terColor

    imgSource.Save( "c:\test.ti f", TiffCodecInfo, Params)


    end sub


    Private Function GetEncoderInfo( ByVal format As
    System.Drawing. Imaging.ImageFo rmat) As
    System.Drawing. Imaging.ImageCo decInfo

    Dim index As Integer
    Dim encoders() As System.Drawing. Imaging.ImageCo decInfo
    encoders = System.Drawing. Imaging.ImageCo decInfo.GetImag eEncoders()

    For index = 0 To (encoders.Lengt h - 1)
    If UCase(encoders( index).FormatDe scription) = UCase
    (format.ToStrin g) Then
    Return encoders(index)
    End If
    Next index
    End Function

    -----------------------------------------------------------------



    I can set the colordepth in this part:
    'Colordepth
    Dim myEncoderParame terColor As New
    System.Drawing. Imaging.Encoder Parameter(myenc oder, 24L)


    I can set the compression in this part:
    'Compression
    CompressionEnco der = System.Drawing. Imaging.Encoder .Compression
    Dim myEncoderParame terCompression = New
    System.Drawing. Imaging.Encoder Parameter(Compr essionEncoder, CLng
    (System.Drawing .Imaging.Encode rValue.Compress ionLZW))



    PROBLEM:
    The Tif-source file is a 475kb file 200dpi, black and white. I want to
    save a rotated version of this tif-file, same size, same dpi, same
    colors. I can;t get it done.

    (1) I can't set the colordepth to less then 24L. When I do this I get an
    error in the GDI+. I would like to have a Tif-file with a colordepth
    of 1 bit. Is this possible?

    (2) When setting the compression to CompressionLZW or CompressionNone it
    works fine. But I can;t select the other compressions. When I do so I
    also get an error.



    --
    Met vriendelijke groet / With regards / Saludos,
    Moviat Automatisering


    Maurice Mertens
    mauricem@moviat _KillSpamWordFo rEMail.nl

    tel: +31 162 470 534
    fax: +31 162 470 502
  • smith

    #2
    Re: tiff files, compression, colordepth

    Yeah, 1bpp tiffs are annoying and so far as I've found, the managed way is
    great for slicing out tif frames but doesn't cut it completely on depth
    conversions.

    I got this code from a great newsgroup guy named "BMan" about a year ago. I
    made adjustments so that I could set a threshold and let the users despeckle
    or allow in more "noise" if needed ... at the moment I can't find that
    enhanced code (it was for a previous client). See if the following exact
    conversion code helps and over the weekend I'll see if I can track down the
    other files.

    If you really need CCIT4 compression, as most folks are doing fax image work
    with 1bpp tifs, you can change the LZW to CCTI4 and it still works fine.

    1) make a class, call it Win32API and paste in the following:

    Imports System.Runtime. InteropServices

    Public Class win32api

    <DllImport("KER NEL32.DLL", EntryPoint:="Rt lMoveMemory", _
    SetLastError:=T rue, CharSet:=CharSe t.Auto, _
    ExactSpelling:= True, _
    CallingConventi on:=CallingConv ention.StdCall) > _

    Public Shared Sub CopyArrayTo(<[In](), MarshalAs(Unman agedType.I4)> ByVal
    hpvDest As Int32, <[In](), Out()> ByVal hpvSource() As Byte, ByVal cbCopy As
    Integer)

    ' Leave function empty

    End Sub

    ' GDI32 Constant Definitions

    Public Const BI_RGB = 0&
    Public Const DIB_PAL_COLORS = 1

    ' GDI32 Structure Definitions'

    <StructLayout(L ayoutKind.Seque ntial)> Public Structure GDI32BITMAP
    Public bmType As Integer
    Public bmWidth As Integer
    Public bmHeight As Integer
    Public bmWidthBytes As Integer
    Public bmPlanes As Short
    Public bmBitsPixel As Short
    Public bmBits As Integer
    End Structure

    <StructLayout(L ayoutKind.Seque ntial)> Public Structure GDI32BITMAPINFO HEADER
    Public biSize As Integer
    Public biWidth As Integer
    Public biHeight As Integer
    Public biPlanes As Short
    Public biBitCount As Short
    Public biCompression As Integer
    Public biSizeImage As Integer
    Public biXPelsPerMeter As Integer
    Public biYPelsPerMeter As Integer
    Public biClrUsed As Integer
    Public biClrImportant As Integer
    End Structure

    ' GDI32 DLL Entry Point Declares

    Public Declare Function CreateCompatibl eDC Lib "gdi32" Alias _
    "CreateCompatib leDC" (ByVal hdc As Integer) As Integer

    Public Declare Function SelectObject Lib "gdi32" Alias "SelectObje ct" _
    (ByVal hdc As Integer, ByVal hObject As Integer) As Integer

    Public Declare Function GetObject Lib "gdi32" Alias "GetObjectA " _
    (ByVal hObject As Integer, ByVal nCount As Integer, ByVal lpObject As
    Integer) As Integer

    Public Declare Function CreateDIBSectio n Lib "gdi32" Alias _
    "CreateDIBSecti on" (ByVal hDC As Integer, ByRef pBitmapInfo As _

    GDI32BITMAPINFO HEADER, ByVal un As Integer, ByRef lplpVoid As Integer, _
    ByVal handle As Integer, ByVal dw As Integer) As Integer

    Public Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Integer, _
    ByVal hBitmap As Integer, ByVal nStartScan As Integer, ByVal nNumScans _
    As Integer, ByVal lpBits As Integer, ByRef lpBI As _
    GDI32BITMAPINFO HEADER, ByVal wUsage As Integer) As Integer

    Public Declare Function DeleteObject Lib "gdi32" Alias "DeleteObje ct" _
    (ByVal hObject As Integer) As Integer

    Public Declare Function DeleteDC Lib "gdi32" Alias "DeleteDC" (ByVal hdc As
    Integer) As Integer

    Public Declare Function GdiFlush Lib "gdi32" Alias "GdiFlush" () As Integer

    End Class

    2) make a class, call it TifConverter and paste in this code:

    Imports System.Drawing
    Imports System.Drawing. Imaging
    Imports System.IO
    Imports System.Runtime. InteropServices

    Public Class TiffConverter

    Public Function MakeCCIT4Exact( ByVal value As Image) As Image
    'bman code!
    Dim dotNetBitmap As Bitmap
    Dim XDPI, YDPI As Single
    Dim srcBitmapInfo As win32api.GDI32B ITMAP
    Dim hSrcBitmap As IntPtr = IntPtr.Zero
    Dim pSrcBitmapInfo As IntPtr = IntPtr.Zero
    Dim hDstMemDC As IntPtr = IntPtr.op_Expli cit(win32api.Cr eateCompatibleD C(0))
    Dim DestDIBMIH As win32api.GDI32B ITMAPINFOHEADER
    Dim hDestDIBitmap As IntPtr = IntPtr.Zero
    Dim hDstOldBitmap As IntPtr = IntPtr.Zero
    Dim pDestDIBits As Integer = 0
    Dim RCode As Integer
    Dim UseCompression As Boolean = True

    Try
    ' Load our Image into our GDI+ bitmap object (1BPP)
    dotNetBitmap = CType(value, Bitmap)

    XDPI = dotNetBitmap.Ho rizontalResolut ion
    YDPI = dotNetBitmap.Ve rticalResolutio n

    Dim xrez As Single = 0
    Dim rezratio As Single = 1

    If XDPI = YDPI Then
    xrez = XDPI
    rezratio = 1
    ElseIf XDPI > YDPI Then
    xrez = XDPI
    rezratio = XDPI / YDPI
    Else
    xrez = YDPI
    rezratio = XDPI / YDPI
    End If

    dim b As New Bitmap(dotNetBi tmap, New Size(dotNetBitm ap.Width,
    dotNetBitmap.He ight * rezratio))
    dotNetBitmap = b

    hSrcBitmap = dotNetBitmap.Ge tHbitmap() ' hSrcBitmap is now 32bpp

    ' thanks to GDI+
    ' There most likey should be some protection afforded to the
    ' following()
    ' set of statements to ensure the memory operations don't cause a
    ' GPF in the app

    ' Allocate enough memory to hold a GDI32 structure and use that as a
    ' buffer area for the call to GetObject

    pSrcBitmapInfo = Marshal.AllocCo TaskMem(Marshal .SizeOf(srcBitm apInfo))

    ' Call GetObject and use out buffer we just allocated as to store
    ' the returned struct

    win32api.GetObj ect(hSrcBitmap. ToInt32, Marshal.SizeOf( srcBitmapInfo), _
    pSrcBitmapInfo. ToInt32)

    ' Marshall the data in our buffer back to our GDI32BITMAP structure

    srcBitmapInfo = CType(Marshal.P trToStructure(p SrcBitmapInfo, _
    GetType(win32ap i.GDI32BITMAP)) , win32api.GDI32B ITMAP)

    ' Release the memory we allocated for the buffer to the GetObject
    ' Call

    If IntPtr.op_Inequ ality(pSrcBitma pInfo, IntPtr.Zero) Then _
    Marshal.FreeCoT askMem(pSrcBitm apInfo)

    ' Now we have the dimensions of the HBITMAP underlying our dot net
    ' Bitmap Object and can use them to set up our DIB

    ' BTW, if you don't believe me, look at srcBitmapInfo in the
    ' debugger and you'll see out image is now 32bpp

    With DestDIBMIH
    .biSize = Marshal.SizeOf( DestDIBMIH)
    .biWidth = srcBitmapInfo.b mWidth
    .biHeight = srcBitmapInfo.b mHeight 'CInt(srcBitmap Info.bmHeight * (XDPI /
    YDPI))
    .biPlanes = srcBitmapInfo.b mPlanes
    .biBitCount = srcBitmapInfo.b mPlanes ' 1 bpp * srcBitmapInfo.b mPlanes()
    .biCompression = win32api.BI_RGB
    End With

    ' Create our DIBitmap
    hDestDIBitmap = _
    IntPtr.op_Expli cit(win32api.Cr eateDIBSection( hDstMemDC.ToInt 32, DestDIBMIH,
    0, _
    pDestDIBits, 0, 0))

    ' Now Select our DIBitmap into its DC
    hDstOldBitmap = IntPtr.op_Expli cit(win32api.Se lectObject(hDst MemDC.ToInt32,
    _
    hDestDIBitmap.T oInt32))

    ' Copy the bits from out dotNet Bitmaps objects HBITMAP to out
    ' DIBitmap.

    ' ** IMPORTANT NOTE **
    ' ** THE SOURCE HBITMAP CANNOT BE SELECTED INTO ANY DC
    ' ** I don't check in this, because I know there's no way it
    ' could(be)

    RCode = win32api.GetDIB its(hDstMemDC.T oInt32, hSrcBitmap.ToIn t32, 0, _
    srcBitmapInfo.b mHeight, pDestDIBits, DestDIBMIH, win32api.DIB_PA L_COLORS)

    ' Wait for GDI to finish creating and drawing out DIBitmap
    win32api.GdiFlu sh()

    ' All Done with the conversion, create a new Bitmap using our DIBitmap()
    dotNetBitmap = Bitmap.FromHbit map(hDestDIBitm ap)

    ' Just because I'm being a pain, make the dpi of the new bitmap
    ' This might matter to some image viewers

    dotNetBitmap.Se tResolution(xre z, xrez)

    ' And finally save it before we cleanup and leave. Should be 1Bpp,
    'UseCompression flag determines if compression is to be used

    Dim m As New System.IO.Memor yStream
    If UseCompression Then
    Dim CodecInfo As Imaging.ImageCo decInfo = _
    GetEncoderInfo( "image/tiff")
    Dim ImgEncoder As New Imaging.Encoder (CodecInfo.Clsi d)
    Dim EncParms As New Imaging.Encoder Parameters(1)
    EncParms.Param( 0) = New _
    Imaging.Encoder Parameter(Imagi ng.Encoder.Comp ression, _
    Imaging.Encoder Value.Compressi onLZW)

    dotNetBitmap.Sa ve(m, CodecInfo, EncParms)
    Return Image.FromStrea m(m)
    Else
    dotNetBitmap.Sa ve(m, Imaging.ImageFo rmat.Tiff)
    Return Image.FromStrea m(m)
    End If

    Finally

    ' Clean up GDI resources before leaving

    dotNetBitmap.Di spose()

    If IntPtr.op_Inequ ality(hSrcBitma p, IntPtr.Zero) Then _
    win32api.Delete Object(hSrcBitm ap.ToInt32)

    If IntPtr.op_Inequ ality(hDestDIBi tmap, IntPtr.Zero) Then _
    win32api.Delete Object(win32api .SelectObject(h DstMemDC.ToInt3 2,
    hDstOldBitmap.T oInt32))

    If IntPtr.op_Inequ ality(hDstMemDC , IntPtr.Zero) Then _
    win32api.Delete DC(hDstMemDC.To Int32)

    End Try

    End Function

    Private Function GetEncoderInfo( ByVal mimeType As String) As
    System.Drawing. Imaging.ImageCo decInfo
    Dim j As Integer
    Dim encoders As Drawing.Imaging .ImageCodecInfo ()

    encoders = Drawing.Imaging .ImageCodecInfo .GetImageEncode rs()

    For j = 0 To encoders.Length
    If encoders(j).Mim eType = mimeType Then
    Return encoders(j)
    End If
    Next

    Return Nothing

    End Function

    End Class



    3) make a form, add two buttons and a picturebox. Use one button to load an
    image (a jpg or bmp) into the picturebox. Make the other buttom do this:

    Dim o As New TiffConverter
    Dim i As Image = o.MakeCCIT4Exac t(PictureBox1.I mage)
    i.Save("c:\test area\test.tif")



    Hope it helps

    Robert Smith
    Kirkland, WA








    "Maurice Mertens" <hmoviat@nospam .nospam> wrote in message
    news:Xns95B46E3 994C19mauricemm oviat@194.109.1 33.133...[color=blue]
    > Hello,
    >
    > I'm having troubles with saving a tiff-file with a certain compression
    > and colordepth. This is the code I use:[/color]


    Comment

    Working...