Encoding/decoding a image as Base64 (fails under Ruby1.9 but works under Ruby1.8)

  • Follow


Hi, the folowing code encodes and decodes a image file as Base64:

=2D Encode "icon.png" in Base64 as "base64.txt":
=2D-------------------------------------
  File.open("base64.txt","w") do |file|
    file.write [open("icon.png").read].pack("m")
  end
=2D-------------------------------------

=2D Decode "base64.txt" as a PNG "new_icon.png" file:
=2D-------------------------------------
  File.open('new_icon.png', 'wb') do |file|
    file << (IO.readlines('base64.txt').to_s.unpack('m')).first
  end
=2D-------------------------------------


It works perfectly under Ruby1.8 (after encoding and decoding "icon.png" is=
=20
exatcly the same as "new_icon.png", the same binay file).

However running under Ruby1.9 the result is different since "new_icon.png" =
is=20
a corrupted image file. When I try to open it with a image viewer I get thi=
s=20
error (under Linux):

  libpng warning: gAMA: CRC error
  libpng error: PNG unsigned integer out of range.


Which is the difference when using Ruby1.9? how to solve it?
Thanks a lot.


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply ibc (607) 12/3/2009 12:22:55 AM

El Jueves, 3 de Diciembre de 2009, I=C3=B1aki Baz Castillo escribi=C3=B3:
> Hi, the folowing code encodes and decodes a image file as Base64:
>=20
> - Encode "icon.png" in Base64 as "base64.txt":
> --------------------------------------
>   File.open("base64.txt","w") do |file|
>     file.write [open("icon.png").read].pack("m")
>   end
> --------------------------------------
>=20
> - Decode "base64.txt" as a PNG "new_icon.png" file:
> --------------------------------------
>   File.open('new_icon.png', 'wb') do |file|
>     file << (IO.readlines('base64.txt').to_s.unpack('m')).first
>   end
> --------------------------------------
>=20
>=20
> It works perfectly under Ruby1.8 (after encoding and decoding "icon.png" =
is
> exatcly the same as "new_icon.png", the same binay file).
>=20
> However running under Ruby1.9 the result is different since "new_icon.png"
>  is a corrupted image file. When I try to open it with a image viewer I g=
et
>  this error (under Linux):
>=20
>   libpng warning: gAMA: CRC error
>   libpng error: PNG unsigned integer out of range.
>=20
>=20
> Which is the difference when using Ruby1.9? how to solve it?
> Thanks a lot.

The difference is in the second step, the decoding process, since "base64.t=
xt"=20
file is the same using Ruby1.8 or 1.9.




=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/3/2009 12:24:55 AM


El Jueves, 3 de Diciembre de 2009, I=C3=B1aki Baz Castillo escribi=C3=B3:

> The difference is in the second step, the decoding process, since
>  "base64.txt" file is the same using Ruby1.8 or 1.9.

Ok, the issue is fixed by uing "IO.read" rather than "IO.readlines":

=2D Decode "base64.txt" as a PNG "new_icon.png" file:
=2D-------------------------------------
   File.open('new_icon.png', 'wb') do |file|
     file << (IO.read('base64.txt').to_s.unpack('m')).first
   end
=2D-------------------------------------=20


=2D-=20
I=C3=B1aki Baz Castillo <ibc@aliax.net>

0
Reply utf 12/3/2009 12:27:30 AM

On Thu, Dec 3, 2009 at 1:22 AM, I=F1aki Baz Castillo <ibc@aliax.net> wrote:
> =A0File.open("base64.txt","w") do |file|
> =A0 =A0file.write [open("icon.png").read].pack("m")
> =A0end
>
> =A0File.open('new_icon.png', 'wb') do |file|
> =A0 =A0file << (IO.readlines('base64.txt').to_s.unpack('m')).first
> =A0end
>
> Which is the difference when using Ruby1.9? how to solve it?
> Thanks a lot.

In Ruby 1.9, Array#to_s is an alias for Array#inspect.

In Ruby 1.8, Array#to_s worked like Array#join with no arguments.

Try this:
   IO.read "base64.txt"

0
Reply Lars 12/3/2009 8:04:01 AM

2009/12/3 I=F1aki Baz Castillo <ibc@aliax.net>:
> Hi, the folowing code encodes and decodes a image file as Base64:
>
> - Encode "icon.png" in Base64 as "base64.txt":
> --------------------------------------
> =A0File.open("base64.txt","w") do |file|
> =A0 =A0file.write [open("icon.png").read].pack("m")
> =A0end
> --------------------------------------
>
> - Decode "base64.txt" as a PNG "new_icon.png" file:
> --------------------------------------
> =A0File.open('new_icon.png', 'wb') do |file|
> =A0 =A0file << (IO.readlines('base64.txt').to_s.unpack('m')).first
> =A0end
> --------------------------------------
>
>
> It works perfectly under Ruby1.8 (after encoding and decoding "icon.png" =
is
> exatcly the same as "new_icon.png", the same binay file).
>
> However running under Ruby1.9 the result is different since "new_icon.png=
" is
> a corrupted image file. When I try to open it with a image viewer I get t=
his
> error (under Linux):
>
> =A0libpng warning: gAMA: CRC error
> =A0libpng error: PNG unsigned integer out of range.
>
>
> Which is the difference when using Ruby1.9? how to solve it?
> Thanks a lot.

One thing strikes odd: you are not reading the file in binary mode.
It may be that 1.9 punishes you for that.  You probably rather want

File.open("base64.txt","w") do |file|
  file.write [File.open("icon.png", "rb") {|io| io.read}].pack("m")
end

You can simplify decoding as

File.open('new_icon.png', 'wb') do |file|
   file.write(File.read('base64.txt').unpack('m').first)
end

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

0
Reply Robert 12/3/2009 8:17:58 AM

El Jueves, 3 de Diciembre de 2009, Robert Klemme escribi=F3:
> 2009/12/3 I=F1aki Baz Castillo <ibc@aliax.net>:
> > Hi, the folowing code encodes and decodes a image file as Base64:
> >
> > - Encode "icon.png" in Base64 as "base64.txt":
> > --------------------------------------
> >  File.open("base64.txt","w") do |file|
> >    file.write [open("icon.png").read].pack("m")
> >  end
> > --------------------------------------
> >
> > - Decode "base64.txt" as a PNG "new_icon.png" file:
> > --------------------------------------
> >  File.open('new_icon.png', 'wb') do |file|
> >    file << (IO.readlines('base64.txt').to_s.unpack('m')).first
> >  end
> > --------------------------------------
> >
> >
> > It works perfectly under Ruby1.8 (after encoding and decoding "icon.png"
> > is exatcly the same as "new_icon.png", the same binay file).
> >
> > However running under Ruby1.9 the result is different since
> > "new_icon.png" is a corrupted image file. When I try to open it with a
> > image viewer I get this error (under Linux):
> >
> >  libpng warning: gAMA: CRC error
> >  libpng error: PNG unsigned integer out of range.
> >
> >
> > Which is the difference when using Ruby1.9? how to solve it?
> > Thanks a lot.
>=20
> One thing strikes odd: you are not reading the file in binary mode.
> It may be that 1.9 punishes you for that.  You probably rather want
>=20
> File.open("base64.txt","w") do |file|
>   file.write [File.open("icon.png", "rb") {|io| io.read}].pack("m")
> end
>=20
> You can simplify decoding as
>=20
> File.open('new_icon.png', 'wb') do |file|
>    file.write(File.read('base64.txt').unpack('m').first)
> end


That makes lot of sense!
Thanks.

=2D-=20
I=F1aki Baz Castillo <ibc@aliax.net>

0
Reply iso 12/3/2009 9:43:52 AM

El Jueves, 3 de Diciembre de 2009, Lars Christensen escribi=F3:
> On Thu, Dec 3, 2009 at 1:22 AM, I=F1aki Baz Castillo <ibc@aliax.net> wrot=
e:
> >  File.open("base64.txt","w") do |file|
> >    file.write [open("icon.png").read].pack("m")
> >  end
> >
> >  File.open('new_icon.png', 'wb') do |file|
> >    file << (IO.readlines('base64.txt').to_s.unpack('m')).first
> >  end
> >
> > Which is the difference when using Ruby1.9? how to solve it?
> > Thanks a lot.
>=20
> In Ruby 1.9, Array#to_s is an alias for Array#inspect.
>=20
> In Ruby 1.8, Array#to_s worked like Array#join with no arguments.
>=20
> Try this:
>    IO.read "base64.txt"

Yes. It seems that usng "to_s" could be a bit problematic under Ruby1.9 due=
 to=20
the new behaviour...
Thanks.


=2D-=20
I=F1aki Baz Castillo <ibc@aliax.net>

0
Reply iso 12/3/2009 10:01:21 AM

On Thu, Dec 3, 2009 at 5:01 AM, I=F1aki Baz Castillo <ibc@aliax.net> wrote:
> El Jueves, 3 de Diciembre de 2009, Lars Christensen escribi=F3:
>> On Thu, Dec 3, 2009 at 1:22 AM, I=F1aki Baz Castillo <ibc@aliax.net> wro=
te:
>> In Ruby 1.9, Array#to_s is an alias for Array#inspect.
>>
>> In Ruby 1.8, Array#to_s worked like Array#join with no arguments.
>>
> Yes. It seems that usng "to_s" could be a bit problematic under Ruby1.9 d=
ue to
> the new behaviour...

http://talklikeaduck.denhaven2.com/2009/10/27/its-the-little-things



--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

0
Reply Rick 12/3/2009 12:12:49 PM

7 Replies
143 Views

(page loaded in 0.076 seconds)


Reply: