struggling to save a tiff as a PNG and keep filesize down

S

sklett

I have a Tiff (fax) with the following properties:
width: 1728
height: 1090
x resolution: 204
y resolution: 98
bit depth: 1

If I open this tiff in Photoshop and change the resolution to 96 and resize
to 816 x 1056, then save as png the size is 3.1Kb (great!)

If I resize the tiff with gdi+ and save as png (same setting as Photoshop)
the filesize is 31Kb (bad!!!)

Here is the code I'm using to resize and save as png:
<code>
Image img = Bitmap.FromFile("../../2109790117_080129_77862164.tif");
if(img.HorizontalResolution != img.VerticalResolution)
{
const float resolution = 96F;

// get the physical dimensions of the document
SizeF size = new SizeF(img.Width / img.HorizontalResolution, img.Height
/ img.VerticalResolution);
Size pixelDimensions = new Size((int)(size.Width * resolution),
(int)(size.Height * resolution));

Bitmap newImage = new Bitmap(pixelDimensions.Width,
pixelDimensions.Height);
newImage.SetResolution(resolution, resolution);
using(Graphics g = Graphics.FromImage(newImage))
{
g.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
g.DrawImage(img, new Rectangle(0, 0, pixelDimensions.Width,
pixelDimensions.Height),
0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
}

img = newImage;
}

string fn = Guid.NewGuid().ToString() + ".png";
img.Save(fn, System.Drawing.Imaging.ImageFormat.Png);
</code>

The image quality of the resize using GDI+ is much better than Photoshops.
I'm using NearestNeighbor in both cases but the results are not the same.

If anyone can shed some light, offer some pointers, whatever I would really
appreciate it. I need to keep the filesize as small as possible.

Thanks,
Steve
 
P

Peter Duniho

I have a Tiff (fax) with the following properties:
width: 1728
height: 1090
x resolution: 204
y resolution: 98
bit depth: 1

If I open this tiff in Photoshop and change the resolution to 96 and
resize
to 816 x 1056, then save as png the size is 3.1Kb (great!)

If I resize the tiff with gdi+ and save as png (same setting as
Photoshop)
the filesize is 31Kb (bad!!!)

The most obvious thing I see is that the image you create isn't a 1 bpp
image as the original is. Perhaps Photoshop is preserving that 1 bpp
color depth, whereas your code is not.

What happens if you create the new image instance as "new
Bitmap(pixelDimensions.Width, pixelDimensions.Height,
PixelFormat.Format1bppIndexed)"?

Pete
 
S

sklett

Peter Duniho said:
The most obvious thing I see is that the image you create isn't a 1 bpp
image as the original is. Perhaps Photoshop is preserving that 1 bpp
color depth, whereas your code is not.

What happens if you create the new image instance as "new
Bitmap(pixelDimensions.Width, pixelDimensions.Height,
PixelFormat.Format1bppIndexed)"?

Hi Peter,

I thought of that as well, but when I try to use a 1bpp image and create a
Graphics instance from it I get the following exception:
"A Graphics object cannot be created from an image that has an indexed pixel
format."

Photoshop is created a 32 BPP image. Very strange.

Thanks for the suggestion though!
-Steve
 
P

Peter Duniho

[...]
What happens if you create the new image instance as "new
Bitmap(pixelDimensions.Width, pixelDimensions.Height,
PixelFormat.Format1bppIndexed)"?

Hi Peter,

I thought of that as well, but when I try to use a 1bpp image and create
a
Graphics instance from it I get the following exception:
"A Graphics object cannot be created from an image that has an indexed
pixel
format."

Ah, right. I forgot about that limitation.

You could resize the image into a 24/32bpp image and then use LockBits()
on that and a 1 bpp image to copy the data directly.
Photoshop is created a 32 BPP image. Very strange.

Are you sure it is? 3K seems awfully small for a file that really was
saved as 32 bpp. At 800 x 1000, you're looking at over 3MB of data for a
32 bpp image. If so, that'd mean that PNG compression is achieving a
1000-to-1 compression ratio when you save from Photoshop.

Even JPEG wouldn't normally be able to save an image of that dimension
without practically destroying the image, and PNG being lossless shouldn't
be able to come anywhere close to that for a full-color image of any
reasonable complexity (even the best-case scenarios that one might
consider are unlikely IMHO and those require careful matching of the input
data to the specific PNG compression algorithm being used).

It's hard to comment precisely without having a copy of the original
bitmap and of the Photoshop-created image. But I still suspect this is a
color depth issue.

Pete
 
S

Steve K.

Peter Duniho said:
[...]
What happens if you create the new image instance as "new
Bitmap(pixelDimensions.Width, pixelDimensions.Height,
PixelFormat.Format1bppIndexed)"?

Hi Peter,

I thought of that as well, but when I try to use a 1bpp image and create
a
Graphics instance from it I get the following exception:
"A Graphics object cannot be created from an image that has an indexed
pixel
format."

Ah, right. I forgot about that limitation.

You could resize the image into a 24/32bpp image and then use LockBits()
on that and a 1 bpp image to copy the data directly.
Photoshop is created a 32 BPP image. Very strange.

Are you sure it is? 3K seems awfully small for a file that really was
saved as 32 bpp. At 800 x 1000, you're looking at over 3MB of data for a
32 bpp image. If so, that'd mean that PNG compression is achieving a
1000-to-1 compression ratio when you save from Photoshop.

I agree, it "smells" a bit. This is not a full color image though, the
source TIFF is a 1BPP image.
I will check this some additional ways and see what I can find out.
Even JPEG wouldn't normally be able to save an image of that dimension
without practically destroying the image, and PNG being lossless shouldn't
be able to come anywhere close to that for a full-color image of any
reasonable complexity (even the best-case scenarios that one might
consider are unlikely IMHO and those require careful matching of the input
data to the specific PNG compression algorithm being used).

It's hard to comment precisely without having a copy of the original
bitmap and of the Photoshop-created image. But I still suspect this is a
color depth issue.

If we can't resolve this through the NG and you would like the images I
would be happy to send to you ;0)

Thanks for your continued efforts to help me!
-Steve
 
P

Peter Duniho

[...]
Are you sure it is? 3K seems awfully small for a file that really was
saved as 32 bpp. At 800 x 1000, you're looking at over 3MB of data for
a
32 bpp image. If so, that'd mean that PNG compression is achieving a
1000-to-1 compression ratio when you save from Photoshop.

I agree, it "smells" a bit. This is not a full color image though, the
source TIFF is a 1BPP image.
I will check this some additional ways and see what I can find out.

It's true, it's possible that with the 32 bpp image only have two colors
PNG is able to compress it dramatically. But you should definitely
confirm that's what's going on, given the disparity from what .NET is
doing.

The only other thing I can think of is that Photoshop is doing a more
elaborate analysis of the data. PNG offers a surprisingly wide variety of
compression options, mainly because how well a particular algorithm will
compress an image depends a lot on the data in the image. Fancier PNG
compression tools (which may include Photoshop) will run multiple
compressions, using varying options, and choose the best-compressing
output.

I doubt that .NET does any sort of comparative compression like this, and
probably just uses some "best average case" options for its compression.
If that's the reason for the difference, then you're out of luck with
respect to using the built-in .NET PNG compression.

Other options would include implementing a PNG compressor yourself
(non-trivial, but not too hard either since the PNG org web site has links
to sample code), or use some third-party library (I know of at least one
command-line utility that will do fancier compression...you could access
the command-line utility from your .NET application to handle the
compression).

But before you do all that, you really should confirm that you're
comparing apples to apples. It would be a shame to do all that work for
nothing.

Finally, another possibility: you mentioned that Photoshop doesn't resize
the image with as high quality as you're getting from .NET. It's possible
that due to the lower quality, the image Photoshop is compressing really
is much more highly compressable than the image .NET is compressing. An
interesting test would be to open the image Photoshop generates (just read
the PNG file in as an Image instance), and then resave that as a new PNG.
That way you know for sure you're compressing the same exact data
Photoshop is.

That would be another "verify apples to apples" check you could make
before pursuing alternatives to using .NET's built-in PNG functionality.
[...]
It's hard to comment precisely without having a copy of the original
bitmap and of the Photoshop-created image. But I still suspect this is
a
color depth issue.

If we can't resolve this through the NG and you would like the images I
would be happy to send to you ;0)

If you want to share the files, I recommend any of several free file
upload sites that you can use. That way you can post the link and easily
share the files with whomever thinks they might be able to help, without
any extra effort on your part and without inefficiently transmitting the
files via email.

Here are three that I think work pretty well:
http://www.filecrunch.com/
http://www.sendspace.com/
http://www.yousendit.com/

They all allow the upload of files for download by others without any
requirement to register or share email addresses (at least one makes it
look like they require an email address, but it's really optional, as with
the others).
Thanks for your continued efforts to help me!

Well, I'm always happy to speculate. I wish I had more specific
information. And sadly, just based on replies I've seen to other posts
regarding PNG questions (of which there haven't been many, granted), I
have some of the most experience with that image file format out of any of
the folks who normally reply. And that's not encouraging news for you, as
I don't really have that much experience with it. :(

Sorry. :) But I'll keep trying to help if I come up with new ideas. :)

Pete
 
N

not_a_commie

Are you sure it is? 3K seems awfully small for a file that really was
saved as 32 bpp. At 800 x 1000, you're looking at over 3MB of data for a
32 bpp image. If so, that'd mean that PNG compression is achieving a
1000-to-1 compression ratio when you save from Photoshop.

Even JPEG wouldn't normally be able to save an image of that dimension
without practically destroying the image, and PNG being lossless shouldn't
be able to come anywhere close to that for a full-color image of any
reasonable complexity (even the best-case scenarios that one might
consider are unlikely IMHO and those require careful matching of the input
data to the specific PNG compression algorithm being used).

Huh? JPEG is for photos and nothing else. Don't try to use that on
your screen shot or your 1bpp image. PNG uses a variety of compression
mechanisms. It chooses the best for your current line in the image. So
if you line is all one color it will use RLE compression. Instead of
being 1728 integers in data it will be two intigers in data: one with
1728 and the next with the color. That's a 1728-to-2 compression with
no hard work at all. And if it can use 16bit values for color and run
length it would be smaller yet, etc.
 
P

Peter Duniho

Huh? JPEG is for photos and nothing else. Don't try to use that on
your screen shot or your 1bpp image.

No one is suggesting that he does.
PNG uses a variety of compression
mechanisms. It chooses the best for your current line in the image. So
if you line is all one color it will use RLE compression. Instead of
being 1728 integers in data it will be two intigers in data: one with
1728 and the next with the color. That's a 1728-to-2 compression with
no hard work at all.

Yes, for a particular kind of data. And PNG supports handling that
compression for horizontal lines or vertical lines (for example).

I already said that for special cases, PNG can compress very well. But
those special cases don't usually hold true. Without knowing anything
else about the image, the fact is that the chances of any random image
being able to be compressed by 1000-to-1 is extremely low.

Pete
 
S

sklett

The only other thing I can think of is that Photoshop is doing a more
elaborate analysis of the data. PNG offers a surprisingly wide variety of
compression options, mainly because how well a particular algorithm will
compress an image depends a lot on the data in the image. Fancier PNG
compression tools (which may include Photoshop) will run multiple
compressions, using varying options, and choose the best-compressing
output.

Hi Peter,

My latest research seems to indicate that the PNG saved from PS is indeed a
1BPP even though Windows reports it's a 32BPP. I checked this by opening
the PNG back into PS and it shows the "Mode" as "Bitmap".

The exact operations that I'm performing on the source TIFF in PS are:
1) open TIFF file
2) resize image to 8.5" x 11" with interpolation mode: Nearest Neighbor
3) Change resolution to 96
4) save as PNG

The resizing is required because the "Pixel Aspect ratio" is not square
because the source TIFF resolution is 204 * 98

The .Net code to mimic what I'm doing with PS is
<code>
Image img = Bitmap.FromFile("../../NA_080129_77887111.tif");
if(img.HorizontalResolution != img.VerticalResolution)
{
const float resolution = 96F;

SizeF size = new SizeF(8.5F, 11.0F);
Size pixelDimensions = new Size((int)(size.Width * resolution),
(int)(size.Height * resolution));

Bitmap newImage = new Bitmap(pixelDimensions.Width,
pixelDimensions.Height);
newImage.SetResolution(resolution, resolution);
using(Graphics g = Graphics.FromImage(newImage))
{
g.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
g.DrawImage(img, new Rectangle(0, 0, pixelDimensions.Width,
pixelDimensions.Height),
0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
}

img = newImage;
}

string fn = "../../" + Guid.NewGuid().ToString() + ".png";
img.Save(fn, System.Drawing.Imaging.ImageFormat.Png);
</code>

I have created a comparison of a specific (zoomed way in) section of the two
png files
http://www.pmddirect.com/temp/gdi+ and PS comparison copy.png

When I open the .net saved PNG in PS, the "Mode" is RGB Color/ 8 Bits

SO! That is a great clue, not sure how I missed this before, apologies if
I've had you barking up the wrong tree.

At this point, I would say my whole problem/challenge is getting .Net to
save a 1BPP png and I bet I would have results on par with that of PS.

I doubt that .NET does any sort of comparative compression like this, and
probably just uses some "best average case" options for its compression.
If that's the reason for the difference, then you're out of luck with
respect to using the built-in .NET PNG compression.

Other options would include implementing a PNG compressor yourself
(non-trivial, but not too hard either since the PNG org web site has links
to sample code), or use some third-party library (I know of at least one
command-line utility that will do fancier compression...you could access
the command-line utility from your .NET application to handle the
compression).

I will look into this, sounds a bit daunting but might be my only option.

But before you do all that, you really should confirm that you're
comparing apples to apples. It would be a shame to do all that work for
nothing.

Finally, another possibility: you mentioned that Photoshop doesn't resize
the image with as high quality as you're getting from .NET. It's possible
that due to the lower quality, the image Photoshop is compressing really
is much more highly compressable than the image .NET is compressing. An
interesting test would be to open the image Photoshop generates (just read
the PNG file in as an Image instance), and then resave that as a new PNG.
That way you know for sure you're compressing the same exact data
Photoshop is.

That would be another "verify apples to apples" check you could make
before pursuing alternatives to using .NET's built-in PNG functionality.
[...]
It's hard to comment precisely without having a copy of the original
bitmap and of the Photoshop-created image. But I still suspect this is
a
color depth issue.

If we can't resolve this through the NG and you would like the images I
would be happy to send to you ;0)

If you want to share the files, I recommend any of several free file
upload sites that you can use. That way you can post the link and easily
share the files with whomever thinks they might be able to help, without
any extra effort on your part and without inefficiently transmitting the
files via email.

Here are three that I think work pretty well:
http://www.filecrunch.com/
http://www.sendspace.com/
http://www.yousendit.com/

They all allow the upload of files for download by others without any
requirement to register or share email addresses (at least one makes it
look like they require an email address, but it's really optional, as with
the others).
Thanks for your continued efforts to help me!

Well, I'm always happy to speculate. I wish I had more specific
information. And sadly, just based on replies I've seen to other posts
regarding PNG questions (of which there haven't been many, granted), I
have some of the most experience with that image file format out of any of
the folks who normally reply. And that's not encouraging news for you, as
I don't really have that much experience with it. :(

Sorry. :) But I'll keep trying to help if I come up with new ideas. :)

Again, thanks for the great help! I really appreciate it. I will do some
research and try to find out if it's possible to save a 1BPP png from code.
I would rather not resort to an external application if I can avoid it.

Gotta run to a meeting, I will update this thread with any additional info I
find in a few hours.

-Steve
 
P

Peter Duniho

[...]
I have created a comparison of a specific (zoomed way in) section of the
two
png files
http://www.pmddirect.com/temp/gdi+ and PS comparison copy.png

When I open the .net saved PNG in PS, the "Mode" is RGB Color/ 8 Bits

Not to mention the doc sizes. Almost 2.5Mb for the one saved from .NET,
and only 100K for the one from Photoshop. :)
SO! That is a great clue, not sure how I missed this before, apologies
if
I've had you barking up the wrong tree.

Not really. I suspected a bit-depth problem all along. :)
At this point, I would say my whole problem/challenge is getting .Net to
save a 1BPP png and I bet I would have results on par with that of PS.

I would hope so. There's no guarantee, I think it's likely.

Of course, all that said, even the 100-to-1 compression you're getting now
isn't too shabby. Obviously, getting the file size down to 3K from 30K
would be great. That 10X savings is definitely significant. But there's
theoretically a lot of information in that 800x1000(-ish) image, and
keeping all that information in just 30K is pretty good.
[...]
Again, thanks for the great help! I really appreciate it. I will do
some
research and try to find out if it's possible to save a 1BPP png from
code.
I would rather not resort to an external application if I can avoid it.

For your first test, you should see if you can load a monochrome image
into .NET and have it preserve the bit depth. If .NET does, rather than
upscaling the color resolution to 24 or 32 bpp, then you have a 1 bpp
image you can test saving. If saving that 1 bpp image works, then you can
spend more time learning how to actually create the necessary 1 bpp image
with Bitmap.LockBits().

Those two tests, you should be able to code in five or ten minutes.
They'll give you good information as to whether it's worth pursuing the
LockBits() solution, which could take longer (I'd guess an hour or two for
someone who's unfamiliar with LockBits() but knows bitmap formats
generally, and perhaps anywhere from two to ten times as long or longer
for someone brand new to the whole topic, depending on their general
abilities).

In particular, if you can create a 1 bpp image in memory with those test,
but saving that image doesn't help, then it won't be worth your effort to
bother figuring out LockBits().

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top