 |
|
 |
This works great for me with one page documents, but it appears to cut off multiple page TIFF documents to just the first page. Am I doing something wrong or is this not supported?
Thanks
|
|
|
|
 |
|
 |
I didn't really consider multipage TIFF documents when writing this article, but I believe the technique should be adaptable to working with them. I'd recommend opening the source TIFF, iterating each page and making any necessary changes to each page, and then saving the results to a new destination TIFF.
To save a multipage TIFF, you have to do something like this for the first page:
Encoder encoder = Encoder.SaveFlag;
EncoderParameters encoderParameters = new EncoderParameters(1);
EncoderParameter encoderParameter = new EncoderParameter(encoder,(long)EncoderValue.MultiFrame);
encoderParameters.Param[0] = encoderParameter;
currentImage.Save(filename, imageCodecInfo, encoderParameters);
And then do a SaveAdd for subsequent pages, saving each additional bitmap to the file:
encoderParameter = new EncoderParameter(encoder,(long)EncoderValue.FrameDimensionPage);
encoderParameters.Param[0] = encoderParameter;
currentImage.SaveAdd(additionalImage, encoderParameters);
When you're all done writing pages, you close the multipage TIFF like this:
encoderParameter = new EncoderParameter(encoder, (long)EncoderValue.Flush);
encoderParameters.Param[0] = encoderParameter;
currentImage.SaveAdd(encoderParameters);
To determine the number of pages in the source TIFF you use GetFrameCount with a parameter of FrameDimension.Page:
pageCount = bitmap.GetFrameCount(FrameDimension.Page);
To set the active page in the source TIFF you use SelectActiveFrame thusly:
bitmap.SelectActiveFrame(FrameDimension.Page, pageIndex);
This guy has some good tips and code for working with multipage TIFF's
http://www.bobpowell.net/
I hope this helps you out in some way.
|
|
|
|
 |
|
 |
the code works excellent and very fast on files up to a certain image size, after that memory/buffer problems start to show up,
I tested on a 36x48" 200 dpi TIF, that is 9600x7200 pixels (I have to work with engineering drawings, and not letter size sheets) - that size just makes it into reasonable buffer size and processes fine in ~10 secs.
at 400dpi - 36x48" (thats 14400x19200 pixels) the required buffer image size gets so large the byte array fails to initialize, also the graphics, draw image unscaled method fails with out of memory.
The display of these files fails as well, which I dont really care much about, howevere it would be nice to optimize this code so at least the operation can be done in memory - no display required,
here is my suggestions; I hope the author or someone else can optimize the code for this
-check the image size and process the image in chunks, rather then all at once, ( or use multiple buffers if memory permits )
- use bitblt or iterate through the bitmap to draw the original bitmap onto the rgb converted version, because the drawunscaled method inside converttorgb fails with large images
any better tips, lets hear them ?
thanks in advance
|
|
|
|
 |
|
 |
I've been wracking my brain on ways to deal with the issue you mention and think it might be possible to come up with a solution, but it would not be trivial to implement. Assuming you can load the 14400 x 19200 image bitonal image successfully, it should be possible to operate on it in parts. The technique would require writing two additional methods. One method would create an editable, 32 bit RGB bitmap from a portion of the larger image and a separate method would replace that portion of the bitonal image with the modified 32 bit RGB bitmap. Assuming you were not modifying a large section of the image at one time, this should work. If you need to have an editable 32 bit version of the entire image at one time to modify, then I don't know of any alternatives to having enough RAM available to accommodate the huge bitmap (something like 1.1 Gig of RAM in this case).
Would this type of solution work for what you are trying to do?
|
|
|
|
 |
|
 |
thanks for the response, I have worked around my problem successfully, (using the techniques in your article) ultimately what I was after was reading 2 bitonal tif files into memory and creating a third file, this time in colour that has colour pixels set based on the identical or different pixels of the bitonal tif's - and do this all in a reasonable amount of time for a 14400x19200 sized file (if you attempt to use the .net getpixel/setpixel methods you are in for a long wait - it takes forever) - well the memory footprint of a 32bit RGB bitmap is brutal, I didnt need aRGB colour scheme anyways so instead of creating a 32bit GDI+ bitmap I have created an 8bit indexed TIF in a byte array and modified the pixels directly in the byte array (this gives a max of 256 possible colours - choosen from a palette of 24bit) - plenty for what I needed to do. The code after a bit of profiling allows me to compare 2 TIF files in under 10 secs and creates a colour output file at high quality.
I still would like to find a way to buffer a 24bit or 32bit image in parts in memory and be able to work with it, just curiousity and for possible future projects - it certainly is a challenging task
|
|
|
|
 |
|
 |
Dear Cinamon!
I'am sitting at home and trying to do some similar job. My TIFF is a 1pbb Tiff with 50400 x 63157 pixel size. The data i want to integrated into this file are represented within another tiff file, also 1pbb Tiff with 50400 x 63157 pixel size.
In fact i want to load both files and write the "black" pixels of both into a new file. It sounds that you did such a job succesfully - can you please provide me with some further details of your code pimps, so that i can go on with it.
thx a lot in advance
Oliver
|
|
|
|
 |
|
 |
Are you able to even load one of these big boys into a .NET bitmap object? If my calculations are correct, then each of these images will eat up about 380 meg of memory. To do a merge on them would require at least twice that amount of memory. If you can load one of them into memory and have a couple gigs of memory on the machine, then it might be feasible and I could probably offer up some code to make it happen. In this case though, you wouldn't want to convert them to any sort of color representation because that would definitely bring any computer to its knees. You'd want to load each source image into memory and create a method that locks blocks of the image data in each image, gets the data into byte arrays and OR's the data together, then writes the data back out into one of the images.
A different approach might be to try to manipulate the image bytes on disk. If you were able to save the images as uncompressed TIFF's, then the image bytes in the files should be laid out linearly and combining two images of the same size should just be a matter of walking the bytes and OR'ing the image data together. You'd have to be able determine the offset into the TIFF files where the actual image data resides so you don't overwrite the header or any non-image data in the files. This method might be tricky, but it would definitely be more memory friendly and might actually be faster than the first method.
|
|
|
|
 |
|
 |
I Solved like this
After Dispose I called Ojbect.Dispose();
I tested for MutiPageImage contrins 50 frames and we merger 2000 single page tiffs.
|
|
|
|
 |
|
 |
Hi,
I'm trying to load a tif image using Image.FromFile and I am getting an out of memory exception.
An unhandled exception of type 'System.OutOfMemoryException' occurred in system.drawing.dll
Additional information: Out of memory.
I tried loading it using a stream, and I am getting an Invalid parameter exception.
I need to somehow convert thi tif image to a valid jpeg or jpg format.
Has anyone faced this issue before? Can I get some code to solve this problem?
I will be unable to use any libraries that 3rd parties are providing and will have to write my own code.
Thanks in advance.
|
|
|
|
 |
|
 |
There are limits on the size of a bitmap that may be loaded in memory. While some third party products support loading and operating on parts of an image, the .NET framework methods only support loading the entire image into memory. If you are working with large images, particularly color images, then you need to make sure your system can handle it. You can get a rough idea of the memory required to load an image by multiplying the width in pixels by the height in pixels and multiplying the result by one of the following factors to determine the bytes of memory required to load the image:
For 32 bit images -> Memory in bytes = width * height * 4
For 24 bit images -> Memory in bytes = width * height * 3
For 16 bit images -> Memory in bytes = width * height * 2
For 8 bit (256 color/grayscale images) -> Memory in bytes = width * height * 1
For 1 bit (Black and White) images -> Memory in bytes = width * height * 0.125
It seems like you are trying to load an image too large for the available memory in your system. Out of memory conditions can also occur if you are performing multiple operations with bitmaps and don't call Dispose on each bitmap object when you are done with it, so please be mindful of that too. I've had that cause me problems on multiple occasions.
|
|
|
|
 |
|
 |
If I have the 'Out of memory' exception and I want to minimize the possibility of it to happen, what should I do:
a) Add more RAM?
b) Adjust my virtual memory settings?
c) Anything other than above?
Thanks.
|
|
|
|
 |
|
 |
Working with bitmaps is always memory intensive. When I've run into out of memory conditions, most of the time it's been because I processing a bunch of images in a loop of some sort and failed to dispose of each bitmap when I was done with it. Bitmap implement IDisposable, so you should call Dispose on the each bitmap when you are done with it to proactively release the memory it is using.
If you're working with single, extremely large images, then there's no substitute for having lots of RAM. The general formula for figuring out how much RAM you need for a single image is to multiply its width in pixels by its height and then multiply that by the number if bytes per pixel, which is as follows:
Bitonal - 1/8 (0.125) bytes per pixel
16 Color - 1/2 (0.5) bytes per pixel
256 Color - 1 byte per pixel
65k Color - (16 bits / 2 bytes per pixel)
16M Color - 24 bits / 3 bytes per pixel
16M Color with Alpha - 32 bits / 4 bytes per pixel
So, for instance, an 8.5" x 11", 300 DPI bitonal images, works out as follows:
2550 pixels wide * 3300 pixels high * 0.125 bytes per pixel = 1,051,875 bytes (about a meg)
The same image converted to 32 bit color would be
2550 * 3300 * 4 bytes per pixel = 33,660,000 bytes (32 meg!)
So, as you can see, when you start converting bitonal images to color for manipulation, they get much bigger in RAM, so it's very important to release that memory as soon as possible after using the bitmap.
I hope this helps.
|
|
|
|
 |
|
 |
The OutOfMemoryException on Image.FromFile is also thrown if the tiff-image has an invalid pixel-format.
This behavior is quite strange, but we have to live with it.
|
|
|
|
 |
|
 |
Just wondering if ConvertToBitonal should Dispose source when source != original?
i.e. when source is created on line 29:
source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
|
|
|
|
 |
|
 |
Yes, I believe you are correct. Since, in this case, source is created and utilized completely within the context of the procedure, it should be properly disposed of, which the procedure fails to do. Great catch! I will endeavor to update the sample code accordingly.
Michael A. McCloskey
|
|
|
|
 |
|
 |
The example source code has been updated to include the missing Dispose. Thanks for the find and for taking the time to comment!
|
|
|
|
 |
|
 |
Why exactly is the dispose necessary? I mean, the garbage collector will take care of this, no? Or did I miss something?
|
|
|
|
 |
|
 |
Well, yes and no. Many times you can get away without calling Dispose on objects that implement IDisposable, but as a best practice you should call Dispose on these objects as soon as you are done with them. In the case of Bitmaps, the .NET object wraps a Windows GDI bitmap, which is an unmanaged resource that can potentially eat up a lot of memory.
If you don't call Dispose, the object will stick around for at least two garbage collections instead of one. The first garbage collection will detect the unused object and when it sees the object has a finalizer, will put it a queue of objects that require finalization. The next garbage collection will probably actually get rid of it. If you call Dispose, the object can be cleaned up in one collection. The details of this process are available elsewhere, so I don't want to try to dig in too deep here.
My "real world" experience has been that when dealing with a large number of bitmaps, the application can induce a system "out of memory" condition unless Dispose is called proactively. I remember an instance where I was exporting a large number of images from a database in a loop that was reading them from a data reader as byte arrays, creating bitmap objects from the byte arrays, and saving the bitmaps to disk. This application caused the system to run out of memory prior to adding a dispose on each bitmap inside the loop.
|
|
|
|
 |
|
 |
This was exactly what I was looking for and hadn't found anything so straight-forward and easy to implement immediately with successful results!!! Saved me weeks! THANKS.
|
|
|
|
 |
|
 |
I used to do such stuff (converting images etc.)
with Imaging component on VB6, but for .net I preferred to avoid it...
Your code is great, and needless to say, works faster and solves Microsoft bugs
Thanks,
orro
|
|
|
|
 |
|
 |
The code here at Code Project is always just awesome, but this little doo-hickey has got to be the best so far. It was EXACTLY what I needed to "dumb down" those .NET TIFFs to what our system wants. The bitonal TIFFs that come out look just stunning in all of our imaging tools - MS and otherwise. Almost unchanged in size, too, after markup. The code worked great, and even let me run the bitonal conversion on a (Bitmap) cast of an Image, so I didn't have to root up any of my code. What a great finish to the final crux of my tool. I was sweating for a decent workaround until I found this article. Saved my bacon.
I don't know if you drink, but this digital beer is on me. Bartender!
|
|
|
|
 |
|
 |
your work is great!!!Kepp up!
but i think u have miss something!!!i have read the TIFF 6.0 Definetion doc ,and i find that the Tif file create from u is not valid for MS Fax service to send!!!(i have user the CompressionCCITT4 flags),i finally find that u have miss setting the TIFF tags!!!!such as the ImageWidth and XSolution ect.
is it can do by add PropertyItem to the Image tiff we save?
thank u!
and best wishes!
Sorry for my poor english!
|
|
|
|
 |
|
 |
Thank u very much for your greate help!!!!
Yes,what u say that:. " The resolution can be changed prior to saving the bitmap to a TIFF, ..." it work!!!
After i read the RFC2301,RFC2306,TIFF6 Sepection,i use the "bmp.SetPropertyItem(PropertyItem pt);" to
set the TIF Tags after the Converter.ConvertToBitonal(bmp) method by u!
the tags i set are the required fileds in rfc2306,such as
TIFFSetField(image, TIFFTAG_IMAGEWIDTH, 1728);//256
TIFFSetField(image, TIFFTAG_IMAGELENGTH, 144);//257
TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 1);//258
TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, 1);//277
TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, 144);//278
TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);//259,4
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);//262,0
TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);//266,1
TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);//284,1
TIFFSetField(image, TIFFTAG_XRESOLUTION, 200.0);//282
TIFFSetField(image, TIFFTAG_YRESOLUTION, 196.0);//283
TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);//296,2
and it somtings works with Fax service!!!!
we should DO REMEMBER THAT THE G4,G3 FAX used by Fax Service must have a 1728 pix width!!!!!!!
but still i have a problem,the NewSubFileType 0xEF or the SubFileType 0xFF Tag does not effect!!!
i read the tags of the fax received by Fax Servcie,and found that the 0xEF Filed is 3,but the Filed created by .NE FrameWork is always 0??????
it is unbelivebale!!!!!
----------------------------------------
> Date: Wed, 30 Aug 2006 13:02:56 +0000
> From: mmccloskey@speedfactory.net
> To: lingxiaowen@hotmail.com
> Subject: Bitonal Image Converter Reply
>
> Greetings,
> I tried many time to reply to your question on CodeProject.com, but
> their ASP page kept timing out when I tried to post my reply. I
> decided to try to email you directly. Here is my reply:
>
> The tags written into the destination TIFF in this sample are
> controlled by the TIFF encoder in the .NET framework and are not
> something the code has much control over. The Converter class sets the
> destination image size and resolution to that of the source image. The
> resolution can be changed prior to saving the bitmap to a TIFF, by
> using the SetResolution method of the bitmap object as follows:
>
> bitonalBitmap.SetResolution(300.0f, 300.0f);
>
> This will set the DPI of the destination image. If you need an image
> with a different image width or height, then one option would be to
> create a new bitmap of the size you need and then render the original
> image onto it using the drawing functions built into .NET, much as is
> done with the ConvertToBitonal method in the converter class.
>
> I don't know why the MS Fax server doesn't like the image. I don't
> presently have the service set up, so I can't check it out. If you
> have an image that you know does work with the fax service, then I
> would try reading it in and just writing it back out without doing any
> conversions to see if the group IV TIFF's produced by .NET are
> imcompatible with the Fax service.
>
> It could just be that the Fax service requires a standard fax
> resolution (200 dpi ?). If so, then setting the resolution using the
> SetResolution method might solve your problem.
>
> The test image I included with the project was a 96 DPI image. In
> retrospect, I probably should have used a 300 DPI image to better
> represent a typical resolution.
>
> I hope this helps.
>
> ----------------------------------------------------------------
> Speedfactory Web-Mail http://www.speedfactory.net/
>
|
|
|
|
 |
|
 |
I think standard fax resolution is 204x196, not 200x196 or 200dpi.
This is how I save tiff group 4 compression bitonal tiffs, I hope it helps you somehow.
EncoderParameters eps = new EncoderParameters(1);
eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression,
(long)System.Drawing.Imaging.EncoderValue.CompressionCCITT4);
bitonalImage.Save(PathString, GetEncoder(ImageFormat.Tiff), eps);
private static ImageCodecInfo GetEncoder(ImageFormat format) {
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
foreach (ImageCodecInfo codec in codecs) {
if (codec.FormatID == format.Guid) {
return codec;
}
}
return null;
}
|
|
|
|
 |
|
 |
your work is great!!!Kepp up!
but i think u have miss something!!!i have read the TIFF 6.0 Definetion doc ,and i find that the Tif file create from u is not valid for MS Fax service to send!!!(i have user the CompressionCCITT4 flags),i finally find that u have miss setting the TIFF tags!!!!such as the ImageWidth and XSolution ect.
is it can do by add PropertyItem to the Image tiff we save?
thank u!
and best wishes!
Sorry for my poor english!
|
|
|
|
 |