Group 4 compression tif

dgorka

Well-known member
Joined
Dec 27, 2006
Messages
88
Programming Experience
5-10
I"m having a similar problem.

I'm bringing in tiff images and adding a watermark to them, then saving them back out as tiffs. The problem I'm having is that I can't get them to save as a Group 4 compression tif. Any ideas? Here is my save code:

VB.NET:
tempBM.Save(tiffFileName, ImageFormat.Tiff)

Thanks in advance.
 
JohnH,

I have that same code in there, the problem I'm getting is that I'm loading the image into a bitmap, writing a string onto the bitmap, then saving it back out as a tif. When I run it with that save line from what you linked, it gives me an error saying "Parameter is not valid". My coworker thinks it's because i'm trying to go from a bitmap to the tif so in that conversion it's screwing something up. Since there isn't much code for the app I'll post all of it so you can get a better idea of what I mean. Thank you.

VB.NET:
Imports System.Drawing.Imaging
Imports System.IO

Class Form1
    Private tiff As Image
    Private enParams As New EncoderParameters(1)
    Private tifCodec As ImageCodecInfo = ImageCodecInfo.GetImageEncoders(3)
    Private root As New DirectoryInfo("C:\Documents and Settings\gorkad\My Documents\testing")
    Private newDir As String = "\results12"

    Private displayFontFam As New FontFamily("Verdana")
    Private displayFont As New Font(displayFontFam, 36, FontStyle.Bold, GraphicsUnit.Point)

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        enParams.Param(0) = New EncoderParameter(Encoder.Compression, EncoderValue.CompressionCCITT4)

        If Not Directory.Exists(root.FullName & newDir) Then Directory.CreateDirectory(root.FullName & newDir)
        For Each tiffFile As FileInfo In root.GetFiles("*.tif")
            tiff = Image.FromFile(tiffFile.FullName)
            Dim tempBM As New Bitmap(tiff.Width, tiff.Height, PixelFormat.Format32bppArgb)
            tempBM.SetResolution(tiff.HorizontalResolution, tiff.VerticalResolution)
            Dim g As Graphics = Graphics.FromImage(tempBM)
            g.DrawImageUnscaled(tiff, New Point(0, 0))
            g.DrawString("test string", displayFont, Brushes.Blue, tiff.Width / 2 - 24, tiff.Height / 2 - 24)

            tempBM.Save(tiffFile.FullName.Replace("testing", "testing" & newDir), tifCodec, enParams)
        Next
        MsgBox("Done!")
    End Sub
End Class
 
I get the same error on my system with all compression options except None and CompressionLZW. Maybe one need to have special compression codecs or Tiff codecs installed for the others to work?

edit: scratch that, from this page it looks as the other compression types only works for blackwhite images.
 
Last edited:
After doing some hunting online I found an app here that does what we need. It's in C# and my coworker translated it to VB and it works great. Thanks for your help!

A note for those looking to use this code, its in the module called "Converter.cs" and the sub is ConvertToBitonal.

I suppose I can give the translated code as well. So here it is in VB:

VB.NET:
Private Function convertToG4tiff(ByVal original As Bitmap) As Image
        Dim source As Bitmap
        'If original bitmap is not already in 32 BPP, ARGB format, then convert
        If Not original.PixelFormat = PixelFormat.Format32bppArgb Then
            source = New Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb)
            source.SetResolution(original.HorizontalResolution, original.VerticalResolution)
            Using g As Graphics = Graphics.FromImage(source)
                g.DrawImageUnscaled(original, 0, 0)
            End Using
        Else
            source = original
        End If
        ' Lock source bitmap in memory
        Dim sourceData As BitmapData = source.LockBits(New Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
        ' Copy image data to binary array
        Dim imageSize As Integer = sourceData.Stride * sourceData.Height
        Dim sourceBuffer(imageSize) As Byte
        Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize)
        ' Unlock source bitmap
        source.UnlockBits(sourceData)
        ' Create destination bitmap
        Dim destination As Bitmap = New Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed)
        ' Lock destination bitmap in memory
        Dim destinationData As BitmapData = destination.LockBits(New Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed)
        ' Create destination buffer
        imageSize = destinationData.Stride * destinationData.Height
        Dim destinationBuffer(imageSize) As Byte
        Dim sourceIndex As Integer = 0
        Dim destinationIndex As Integer = 0
        Dim pixelTotal As Integer = 0
        Dim destinationValue As Byte = 0
        Dim pixelValue As Integer = 128
        Dim Height As Integer = source.Height
        Dim Width As Integer = source.Width
        Dim threshold As Integer = 500
        ' Iterate lines
        For y As Integer = 0 To Height - 1
            sourceIndex = y * sourceData.Stride
            destinationIndex = y * destinationData.Stride
            destinationValue = 0
            pixelValue = 128
            ' Iterate pixels
            For x As Integer = 0 To Width - 1
                ' Compute pixel brightness (i.e. total of Red, Green, and Blue values)
                pixelTotal = CInt(sourceBuffer(sourceIndex + 1)) + CInt(sourceBuffer(sourceIndex + 2)) + CInt(sourceBuffer(sourceIndex + 3))
                If pixelTotal > threshold Then destinationValue += CByte(pixelValue) '(byte)pixelValue
                If pixelValue = 1 Then
                    destinationBuffer(destinationIndex) = destinationValue
                    destinationIndex += 1
                    destinationValue = 0
                    pixelValue = 128
                Else
                    pixelValue = pixelValue >> 1
                End If
                sourceIndex += 4
            Next x
            If Not pixelValue = 128 Then destinationBuffer(destinationIndex) = destinationValue
        Next y
        ' Copy binary image data to destination bitmap
        Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize)
        ' Unlock destination bitmap
        destination.UnlockBits(destinationData)
        ' Dispose of source if not originally supplied bitmap
        If Not source Is original Then source.Dispose()
        ' Return
        Return destination
    End Function

So enjoy and I hope this can help anyone else who stumbles upon this problem!
 
This routine, returns 96 dpi image when a 200 dpi image is passed in. Anyone know why? I'm not really grokking what's going on.
 
Use the Bitmap.SetResolution method. Properties VerticalResolution and HorizontalResolution can be used to get the values. I think 96 value you get is your current screen DPI and is used as default for Bitmap constructor.
 
Uh, thanks.

You know, I only post here after I've tried all the obvious stuff and Googled around and checked my books, yadda, yadda. It seems like my questions should require esoteric answers, not poke-you-in-the-eye obvious ones. ;-)
 
be careful on the c to VB translations

Dim sourceBuffer(imageSize) As Byte
should be
Dim sourceBuffer(imageSize-1) As Byte

vb creates an array of 0 to imageSize in your example.. so the last byte will eb a null byte and could cause problems peopending on that application that uses the data

I know this because this little error (of my own creation.. NOT copying your code) brought dowm my application.. took about a week to find it.. evidentally most components ignor the null byte, fill it in with 0, or at least respond gracefully .. others do not..

but thanks for all the hard work.. !!!

jd
 
Back
Top