|
thanks a lot.
|
|
|
|
|
I do have a question. If the original image is in CCITT4 compression and 1bpp, is there a way to break the image up without having to do the bi-tonal conversion? Everything I've tried looses the compression and it seems there should be a way to take them apart and recombine without loosing the page parameters.
Edit: I see gcorgnet is having the same issue as me, please let us know if you come up with a solution to this problem. Thank you!
-- modified at 9:35 Tuesday 14th August, 2007
|
|
|
|
|
I found a solution and I wanted to share. Instead of passing in an array of bitmaps, I'm passing in an array of Images. For some reason (that I haven't researched), the Image.Save and Image.SaveAdd manages to keep the compression of the original tif. My guess is when converting from Image to Bitmap the compression is lost.
I'm going to try to share my code, if it's not clear let me know and if you want to add this to your article go ahead, I know I've spent a lot of time trying to figure this out so if this helps someone else I'm glad to be of service.
First you have to break the image up:
private void SplitTiff()<br />
{<br />
imageFile = Image.FromFile("Path to tif here",true);<br />
<br />
frameDimensions = new FrameDimension(imageFile.FrameDimensionsList[0]);<br />
<br />
numberOfImages = imageFile.GetFrameCount(frameDimensions);<br />
<br />
img = new Image[numberOfImages];<br />
<br />
try<br />
{<br />
for (int intFrame = 0;intFrame < numberOfImages;intFrame++)<br />
{<br />
imageFile.SelectActiveFrame(frameDimensions,intFrame);<br />
img[intFrame] = imageFile;<br />
}<br />
}<br />
catch (Exception _err)<br />
{<br />
}<br />
}
Then you call saveMultipageImage passing in the image array, location of the file to be saved, and the type ("TIFF").
public bool saveMultipageImage(Image[] img, string location, string type)<br />
{<br />
if (img != null)<br />
{<br />
try<br />
{<br />
ImageCodecInfo codecInfo = getCodecForstring(type);<br />
<br />
if (img.Length == 1)<br />
{<br />
<br />
EncoderParameters iparams = new EncoderParameters(2);<br />
Encoder iparam = Encoder.SaveFlag;<br />
EncoderParameter iparamPara = new EncoderParameter(iparam,(long)(EncoderValue.MultiFrame));<br />
iparams.Param[0] = iparamPara;<br />
iparam = Encoder.Compression;<br />
iparamPara = new EncoderParameter(iparam, (long)(EncoderValue.CompressionCCITT4));<br />
iparams.Param[1] = iparamPara;<br />
img[0].Save(location, codecInfo, iparams);<br />
}<br />
else if (img.Length > 1)<br />
{<br />
<br />
Encoder saveEncoder;<br />
Encoder compressionEncoder;<br />
EncoderParameter SaveEncodeParam;<br />
EncoderParameter CompressionEncodeParam;<br />
EncoderParameters EncoderParams = new EncoderParameters(2);<br />
<br />
saveEncoder = Encoder.SaveFlag;<br />
compressionEncoder = Encoder.Compression;<br />
<br />
SaveEncodeParam = new EncoderParameter(saveEncoder, (long)EncoderValue.MultiFrame);<br />
CompressionEncodeParam = new EncoderParameter(compressionEncoder, (long)EncoderValue.CompressionCCITT4);<br />
EncoderParams.Param[0] = CompressionEncodeParam;<br />
EncoderParams.Param[1] = SaveEncodeParam;<br />
<br />
File.Delete(location);<br />
img[0].Save(location, codecInfo, EncoderParams);<br />
<br />
<br />
for (int i = 1; i < img.Length; i++)<br />
{<br />
if (img[i] == null)<br />
break;<br />
<br />
SaveEncodeParam = new EncoderParameter(saveEncoder, (long)EncoderValue.FrameDimensionPage);<br />
CompressionEncodeParam = new EncoderParameter(compressionEncoder, (long)EncoderValue.CompressionCCITT4);<br />
EncoderParams.Param[0] = CompressionEncodeParam;<br />
EncoderParams.Param[1] = SaveEncodeParam;<br />
img[0].SaveAdd(img[i], EncoderParams);<br />
<br />
}<br />
<br />
SaveEncodeParam = new EncoderParameter(saveEncoder, (long)EncoderValue.Flush);<br />
EncoderParams.Param[0] = SaveEncodeParam;<br />
img[0].SaveAdd(EncoderParams);<br />
img[0].Dispose();<br />
}<br />
return true;<br />
}<br />
catch (Exception ee)<br />
{<br />
img[0].Dispose();<br />
throw new Exception(ee.Message + " Error in saving as multipage ");<br />
return false;<br />
}<br />
}<br />
else<br />
return false;<br />
}
-- modified at 11:02 Tuesday 14th August, 2007
|
|
|
|
|
I'm having problems disconnecting the image from the FileStream. I can store the tiff frames into a file no problem, but when I load it I have a problem having a "stand-alone" copy of the image.
Here's some code:
FileStream fs = File.Open(path, FileMode.Open);
Image img = Image.FromStream(fs);
pbox.Image = (Image)img.Clone();
//fs.Close();
When I have the above and change the page using img.SelectActiveFrame I have no problem but when I uncomment fs.Close(); I get a GDI+ generic error. This makes me think that the image is still connected to the stream. I tried to avoid this by making a clone of it, but the clone apparently is also attached to the FileStream. Any help would be appreciated.
|
|
|
|
|
hi
i also faced the same problem. The reason is if you close the filestream and then call selectframe you wont be able to iterate through pages of your multipage tiff file which is stored on the file system.So you have to put your filestream object open to perform operations like selectFrame. So if possible call fs.close() at the last once all the operations are done.
second thing if your intention is to append already saved multipage tiff file,pleaserefer my tricky code specifically the function saveToExistingFile.
|
|
|
|
|
You'd probably be ok if you Dispose of your image first then close the Stream. Remember that everything in .NET should be disposed of in a proper sequence, usually in the opposite order of which you've created them.
FileStream fs = File.Open(path, FileMode.Open);
Image img = Image.FromStream(fs);
pbox.Image = (Image)img.Clone();
img.Dispose();
fs.Close();
|
|
|
|
|
Hi,
I have a bunch of System.Drawing.Image objects that are already bitonal, using PixelFormat.Format1bppIndexed and having a resolution of 200dpi (all of them)
I just want to save them into one unique multipage tiff file.
When I try Image.Save(...) I receive a (very nice) exception : A generic error occured in GDI+...
if I create a new System.Drawing.Bitmap object from the image, the saving actually works but the files is too big (several MB). The cause is that the bitmap that has been created has a 32bpp color depth.
I had a look at your code, that actually works with my images, but I am damn sure there must be a way to avoid all that processing on my images that are already bitonal, etc...
Do you have any idea ?
Thanks,
Guillaume
|
|
|
|
|
Good You have explained your problem in a very nice way.I like that.
Now
As you are saying you are sure that all of your images are bitonal(1bppIndexed),it should work properly for Image.Save method.But as your reference variable is Image object, it is likely that it may convert your bitonal images into 32bpp which was the case while i was working on this code.Therefore it is advisable to convert them into bitonal because sometimes when you put bitonal images into Image/Bitmap object .NET converting them into 32bpp images and that's why you are seeing Generic Exception,
so as per my knowledge only way to tackle this problem is to explicitly convert images into Bitonal.
Still i will try my best to give you proper solution but it will take some time,so currently you can continue with this code
Ok Bye
Take Care
|
|
|
|
|
aha..... thanks again, this saved me from yet another hair-pulling session.
|
|
|
|
|
Images are converted into ccitt4 format. but what about color/gray/jpg images ?
I have *.tif and *.jpg files in the same directory. Now i want to make a multifpage tif image with the same compression. for example if *.tiff files compression is ccitt4 and *.jpg is jpeg then the output file.. which would be multipage tiff, should remain the same compression.
Pls help me,
help
help
help
help
thanks
|
|
|
|
|
Great work -
I'm having problem when convert C# code to vb.net 2005. I'm getting "Arithmetic operation result in an overflow" exception? I get the image to load but I keep get the exception error when saving it to multipage tiff. am I doing something wrong??
|
|
|
|
|
can u tell me in which line of code you are having expection ? means either converting image to bitonal image or calling save/save add function or during setting other parameters of image ?
|
|
|
|
|
The problem occur when calling savemultipage(). Thank you
Public Function saveMultipage(ByVal bmp As Image(), ByVal location As String, ByVal type As String) As Boolean
If Not (bmp Is Nothing) Then
Try
Dim codecInfo As ImageCodecInfo = getCodecForstring(type)
Dim i As Integer = 0
While i < bmp.Length
If bmp(i) Is Nothing Then
' break
End If
bmp(i) = CType(ConvertToBitonal(CType(bmp(i), Bitmap)), Image)
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
End While
If bmp.Length = 1 Then
Dim iparams As EncoderParameters = New EncoderParameters(1)
Dim iparam As Encoder = Encoder.Compression
Dim iparamPara As EncoderParameter = New EncoderParameter(iparam, CType((EncoderValue.CompressionCCITT4), Long))
iparams.Param(0) = iparamPara
bmp(0).Save(location, codecInfo, iparams)
Else
If bmp.Length > 1 Then
Dim saveEncoder As Encoder
Dim compressionEncoder As Encoder
Dim SaveEncodeParam As EncoderParameter
Dim CompressionEncodeParam As EncoderParameter
Dim EncoderParams As EncoderParameters = New EncoderParameters(2)
saveEncoder = Encoder.SaveFlag
compressionEncoder = Encoder.Compression
SaveEncodeParam = New EncoderParameter(saveEncoder, CType(EncoderValue.MultiFrame, Long))
CompressionEncodeParam = New EncoderParameter(compressionEncoder, CType(EncoderValue.CompressionCCITT4, Long))
EncoderParams.Param(0) = CompressionEncodeParam
EncoderParams.Param(1) = SaveEncodeParam
File.Delete(location)
bmp(0).Save(location, codecInfo, EncoderParams)
i = 1
While i < bmp.Length
If bmp(i) Is Nothing Then
Exit While
End If
SaveEncodeParam = New EncoderParameter(saveEncoder, CType(EncoderValue.FrameDimensionPage, Long))
CompressionEncodeParam = New EncoderParameter(compressionEncoder, CType(EncoderValue.CompressionCCITT4, Long))
EncoderParams.Param(0) = CompressionEncodeParam
EncoderParams.Param(1) = SaveEncodeParam
bmp(0).SaveAdd(bmp(i), EncoderParams)
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
End While
SaveEncodeParam = New EncoderParameter(saveEncoder, CType(EncoderValue.Flush, Long))
EncoderParams.Param(0) = SaveEncodeParam
bmp(0).SaveAdd(EncoderParams)
End If
End If
Return True
Catch ee As System.Exception
Throw New Exception(ee.Message + " Error in saving as multipage ")
End Try
Else
Return False
End If
End Function
|
|
|
|
|
Naughty, asking in all the forums!
I converted it to vb here:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1360678&SiteID=1&mode=1
The overflow was occurring elsewhere in the autotranslated code, the culprit is fine in the original:
// Compute pixel brightness (i.e. total of Red, Green, and Blue values)
pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3];
in vb you need to cast all the bytes to int first.
|
|
|
|
|
thanks joOls ... i wasnt check on microsoft forums so i didnt know. thanks for translate it to vb for me. that's big help.
|
|
|
|
|
The link to vb.net source is unavailable.
Can you help with that?
Tks
|
|
|
|
|
I have a need to directly capture reports being sent from and AS400 as a PCL. I capture this data with Remote Print Manager Software.
I need to then display this report, Add a digital signature, and then save as a TIFF ?
Mike Dibble
|
|
|
|
|
you are capturing data with Remote Print Manager and data is available in Printer Control language format.
C#.NET has not encoders for PCL format.So we have to manually convert PCL to DIB/Tiff.
So to implement this conversion, you have to study format of PCL and write the code of conversion.
Or there are many controls available in market which converts PCL to DIB/Tiff.You can pick up any convertor which is written in .NET and then using decompiler you can study the logic for conversion.and implement that logic in your own program.
This is one of the shortest way to do..
I hope this might help you.If possible send me more information of PCL if i can do something
Ok
Bye
|
|
|
|
|
Try ghostPCL with the tiffg4 device for black and white or the tiff24nc device for colour.
Thanks,
Troy
modified on Thursday, December 20, 2007 1:49:58 PM
|
|
|
|
|
Why does it convert the images to black and white? Is there a way to do this and preserve the color?
Pablo
Sometimes I think there's no reason to get out of bed . . . then I feel wet, and I realize there is.
|
|
|
|
|
CCITT3 and CCITT4 are both 1-bit compression algorithms. If you want full-color, try using EncoderValue.CompressionLZW instead (and don't convert to bi-tonal). Of course the file size will be bigger as a result, but that is to be expected.
Slainte!
-Mike
Mike Loux
Certified Practicing Geek
mike dot loux at gmail dot com
|
|
|
|
|
Perfect! thanks alot
Pablo
Sometimes I think there's no reason to get out of bed . . . then I feel wet, and I realize there is.
|
|
|
|
|
I tried it, i changed this at 3 places, but all the tiffs are
still ending in black white.
CompressionEncodeParam = new EncoderParameter(compressionEncoder, (long)EncoderValue.CompressionLZW);
is there something else to change?
thanks in advanced
|
|
|
|
|
Dont forget that you need to stop the convert to bi-tonal...
Clickety[^]
Apparently it's not OK to start a bonfire of Microsoft products in the aisles of CompUSA even though the Linuxrulz web site says so
|
|
|
|
|
Here this should work:
Public Shared Function ImageArrayToTiff(ByRef img() As Image, ByVal savePath As String) As Image
Dim codec As ImageCodecInfo = Nothing
For Each c As ImageCodecInfo In ImageCodecInfo.GetImageEncoders
If c.FormatDescription = "TIFF" Then
codec = c
Exit For
End If
Next c
If Not codec Is Nothing Then
If img.Length = 1 Then
Dim iParams As EncoderParameters = New EncoderParameters(1)
iParams.Param(0) = New EncoderParameter(Encoder.Compression, EncoderValue.CompressionLZW)
img(0).Save(savePath, codec, iParams)
Return Image.FromFile(savePath)
ElseIf img.Length > 1 Then
Dim saveEncoder As Encoder = Encoder.SaveFlag
Dim compressionEncoder As Encoder = Encoder.Compression
Dim saveEncodeParam As EncoderParameter = New EncoderParameter(saveEncoder, EncoderValue.MultiFrame)
Dim compressionEncodeParam As EncoderParameter = New EncoderParameter(compressionEncoder, EncoderValue.CompressionLZW)
Dim encoderParams As EncoderParameters = New EncoderParameters(2)
encoderParams.Param(0) = CompressionEncodeParam
encoderParams.Param(1) = saveEncodeParam
File.Delete(savePath)
img(0).Save(savePath, codec, encoderParams)
For Each b As Bitmap In img
saveEncodeParam = New EncoderParameter(saveEncoder, EncoderValue.FrameDimensionPage)
compressionEncodeParam = New EncoderParameter(compressionEncoder, EncoderValue.CompressionLZW)
encoderParams.Param(0) = compressionEncodeParam
encoderParams.Param(1) = saveEncodeParam
img(0).SaveAdd(b, encoderParams)
Next b
saveEncodeParam = New EncoderParameter(saveEncoder, EncoderValue.Flush)
encoderParams.Param(0) = saveEncodeParam
img(0).SaveAdd(encoderParams)
Return Image.FromFile(savePath)
End If
End If
Return Nothing
End Function
Apparently it's not OK to start a bonfire of Microsoft products in the aisles of CompUSA even though the Linuxrulz web site says so
|
|
|
|
|