Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Can't seem to read image to base64 encoding? 1

Status
Not open for further replies.

1DMF

Programmer
Jan 18, 2005
8,795
GB
hi,

I have this...
Code:
use MIME::Base64 qw( encode_base64 );

# read image file to base64 and set for result
open (my $img, '/images/banners/' . $page . '_' . $banner[0]{'RecID'} . '.' . $banner[0]{'Ext'}) or die $!;
my $raw = do { local $/ = undef; $img; };
$result->{data}->{img} = encode_base64( $raw );

But the base64 encoding for the image data that is created is only
R0xPQigweDU1NWFmZGMp

Which cannot be the entire image encoded and when used via
Code:
<img src="data:image/jpeg;base64,R0xPQigweDU1NWFmZGMp">
I just get an image place holder not the image, so the source must be invalid.

What am I missing?

Thanks,
1DMF



"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Hi

Given that "R0xPQigweDU1NWFmZGMp" means "GLOB(0x555afdc)", is evident that $raw is not really raw data. You forgot to actually read :
Perl:
[b]my[/b] [navy]$raw[/navy] [teal]=[/teal] [b]do[/b] [teal]{[/teal] [b]local[/b] [navy]$/[/navy] [teal]=[/teal] [b]undef[/b][teal];[/teal] [i][COLOR=#009900][highlight]<[/highlight]$img[highlight]>[/highlight][/color][/i][teal];[/teal] [teal]}[/teal][teal];[/teal]

Feherke.
feherke.ga
 
well it seemed my slurp wasn't working so I changed it to a while loop and it worked fine.

Code:
my $raw;
open (my $img, '/images/banners/' . $page . '_' . $banner[0]{'RecID'} . '.' . $banner[0]{'Ext'}) or die $!;
binmode $img;
while (<$img>){$raw .= $_;}

I assumed the slurp syntax was wrong so I looked up slurp and found this works
Code:
local $/=undef; # this is what makes it slurpy by removing EOL char setting!
open (my $img, '/images/banners/' . $page . '_' . $banner[0]{'RecID'} . '.' . $banner[0]{'Ext'}) or die $!;
binmode $img;
my $raw = <$img>;
my $encoded = encode_base64( $raw );

Teach me for cargo-culting from SO junk!

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Hi

Interesting. Your initial slurping code worked for me. ( Of course, after adding the < .. > ) Tested with a couple of PNG files in command line.



Feherke.
feherke.ga
 
that'll learn me, missed your first post. the original SO thread was using nasty bareword file handles, when I refactored to use a proper var, I forgot the angles!

I actually condensed it to
Code:
local $/=undef; # this is what makes it slurpy by removing EOL char setting!
open (my $img, '/images/banners/' . $page . '_' . $banner[0]{'RecID'} . '.' . $banner[0]{'Ext'}) or die $!;
binmode $img;
my $encoded = encode_base64( <$img> ); 
close $img;
Anything you can see wrong with this approach?


"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Hi

Well, the original code used [tt]local[/tt] inside a dedicated block which restricted its effect only to a single reading operation. That way the effect of reseting [tt]$/[/tt] was automatically lost when execution left that block.

Now you reset [tt]$/[/tt] somewhere in a larger code block. So be aware that it affects all the code that follows your quoted fragment, until the end of that block, probably an entire [tt]sub[/tt].


Feherke.
feherke.ga
 
yes, I get that local $/ is localising to the lexical scope of the block, there are no other file reads in the block.

I assume the fact that the code is in not just a 'try/catch' block but also an 'else' clause, it is localised to the else clause?

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Hi

Yes, [tt]else[/tt]'s block is also a block, so it will limit [tt]local[/tt]'s effect.


Feherke.
feherke.ga
 
And the irony in all this is.....

1. Email clients especially Outlook don't allow images embedded with the Data URI Scheme.
2. MIME::Lite doesn't accept pre-encoded data.

I ended up having to just use the raw binary data and pass that to MIME::Lite as
Code:
$msg->attach( 
                    Encoding => 'base64',
                    Type     => 'image/' . $img->{ext},
                    Data     => $img->{img}, # this is raw binary of the image file (not base64 encoded)
                    Id       => $img->{id},
                    Disposition => 'inline'
                    );
Then I could use the CID in the HTML to reference the MIME encoded inline images. :)

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Yes, according to :
Outlook 2003 worked, but 2007+ doesn't , our company runs 2010/2013 with perhaps one user on 2007.

No one is running 2003!

If we were only using 2003 it would be fine, as this email is for internal use only, but it certainly wouldn't be of any use for generic emails due to the poor support, which apparently is due to spammers trying to get round latest image blocking security in emails. Something I wasn't trying to circumvent!

I guess I should have done a little homework before trying to apply the new HTML5 stuff via FileReader and Data URI to my HTML emails.

In terms of the application I'm building, it's neither here nor there how I pass the image data to the email model. What I couldn't do is pass a 'path' or 'filehandle' as the image file is being deleted, but I still wanted to include the embedded image of the banner that was deleted in the 'banner advert removed' email.

Yes, I could send the email with a standard attachment then perform the delete, but I didn't like that, it doesn't feel right sending an email saying something has been performed before the code to actually perform it has ran and is checked for success. So I run the method to remove the record from the DB, as well as delete the physical file on the HD, but I first read the file, so I have it to pass to the email model for inline embedding.

That way I'm sending the email only when the delete process is successful but still able to physically show the image of the advert to make it easy for the recipient to instantly see what was removed, rather than just having a textual description.

I wasn't sure MIME::Lite would accept the raw image via the 'Data' attribute rather than 'Path', but it does :)



"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Hi

Doh, my mistake. I saw there is mentioned "Mozilla Thunderbird 3", then I tested data URI in Thunderbird 31, and as it worked I considered that "3" actually means "since 3". So I supposed the Outlook support also means "since 2003".


Feherke.
feherke.ga
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top