Z Follow-up to Facebook and BlogEngine.NET - Facebook app

by Bobbi Perreault 2. January 2011 18:22
Share on Facebook

 

Happy New Year all.  I was asked if the work I did last year integrating Blogengine.Net comments with Facebook notes comments turned out to be worth the time.  I thought so, at least for one of the blogs hosted at my company.  And so This is a follow-up to those posts, a summary of the benefits I've seen.

If you're interested in knowing the process or in the code, here's a summary link:  http://faxt.com/blog/search.aspx?q=facebook  

I thought it was worth-while to integrate the blog comments with Facebook.  The conversation after a post can reveal as much or more than the actual post, of course Facebook is an island and that is why this plugin was needed.  

As far as I can tell the biggest benefit has been to my Pastor's blog.  With his Facebook notes publicizing every blog post, the congregation on Facebook is able to comment on the Facebook side and that same conversation is then available on the web side.  The Facebook poster is anonymous on the web ( their numerical Facebook id is used to identify them there) 

I think it would be more useful if I took the time to integrate Akismet or some spam filter into his blog.  Because of the amount of spam coming in, I had to shorten the time allowed for comments from the Internet.  So the conversation is only able to be carried on then from the Facebook side.

But we can still at least follow it without being logged in to Facebook.

 

Keeping Image Quality High for your eCommerce Site

by Bobbi Perreault 29. December 2010 18:11
Share on Facebook

When you send an image up to a site hosted here, it will be resized as it’s uploaded to fit it within the boundaries that were defined for it on the item detail page.  Images straight from a digital camera will be very much larger than the space allotted to them.  The resizing process from large to small will result in fuzziness.

To get the crispest display, upload an image that is the same size as it is displayed at on screen.  Size and resolution matter.  Print resolution is totally different than screen resolution.

The second tool discussed here is what I recommend you use for best control. And I think this is more necessary for the images which are sized taller than they are wide. Those seem to be the ones that are most fuzzy when uploaded and resized by the website software. If you have an image taller than it is wide, use the height of the image as your setting.

For the purposes of this discussion, our ideal image size is: 

Max height: 280 pixels

Max width:  370 pixels

For this you will want a program that can edit photographs – Picasa is free and also allows you to view the images on your computer with ease.  You can download it here:

download picasa

A good video for learning how to resize with Picasa:

http://www.youtube.com/watch?v=MPUoV5uzMqY&feature=player_embedded

There’s a problem with resizing in Picasa if your images are not originally sized to a compatible height and width ratio.  Say you are working with an image which is higher than it is wide.  You can only specify width with the Picasa resize, and you won’t know what width you want your image to be if it is more tall than wide.

So, I use Paint.Net.  you can download it for free here: 

Get Paint.NET!

This article has great detailed info on how to resize using Paint.Net

http://www.wikihow.com/Resize-an-Image-With-Paint.Net

Use Paint.NET to Create a Lake

by Bobbi Perreault 16. January 2009 20:05
Share on Facebook

Paint.NET is free software for digital photo editing.  I use it for 85% of my bitmap image processing needs - about the only time I switch to Photoshop is when I need to remove backgrounds because the Polygonal lasso tool makes it so easy. 

I had some fun this morning by putting a lake where none existed.  I started with a picture of FlatIrons that was taken by me when I worked in Longmont. 

I first increased the size of my canvas by adding 120 or so pixels onto the bottom. (Ctrl-R, or Image-Resize)

I used the Rectangle Select tool to select the mountain piece, then Ctrl-C to copy it.  Ctrl-Shift-V pastes my selection into a new layer.

From the Layers menu, select "Flip Vertical" and this will turn it upside down.  Then I type 'M' to get the 'Move Selected Pixels' tool, and move the flipped layer down to the bottom of my canvas.  This lines up the old bottom of the picture with a flipped copy of it's self.

 

 

Keep this layer selected. 

Use the Effects-Noise-Add Noise menu item to litter up the selection with a bunch of white specs.

Use the Effects-Blur-Motion Blur menu item to make the water 'wavy' - Do that by setting the angle to 180 and extending the blur to lengthen the lines.  Keep this selection active.

Once again, copy then paste into a new layer. 

Set the layer properties to Transparency of 70.  (F4 to access, or Layers-Properties)

Keeping this area selected, bump up the contrast to lighten this layer.

 

Move your layer selection back down to the first layer, the original picture - but keep your 'water' selection active.  Copy once again.

Move your layer selection up to the layer that is lightened and made transparent.  Then once again, paste your clipboard into a new layer.

For this third layer - once again set the transparency to 90.  This time use the Contrast tool (Ctrl-Shift-C, or Adjustments-Brightness/Contrast) to Darken the layer.

Now here's the fun piece.  Grab the Lasso select tool and with your mouse down for the whole time - drag your cursor back and forth and back and forth in a wave pattern across the darkened layer you just added.  Keep the lines you're drawing very skinny at the top of your "water" and far apart.  By the time you get to the bottom of your "water" your polygons should be wider - but closer to each other - think wave.

When you've filled the water with your lines, let up the mouse this will select portions of the transparent darker layer.  DELETE your selection.  And magic waves appear.

Here's a link to the final product - I like it for the background of my Twitter page.

NEXT - I'm going to take my waves into Expression Design.  These guys are going to ripple across the screen in the background of my new toy web site, Dont Call Me Late For Supper.

 

ReMix, a new API from Best Buy

by Bobbi Perreault 11. January 2009 13:17
Share on Facebook

When I heard of this API of Best Buy's fom the Minnov8 Gang's podcast,  Mashup Best Buy, I thought I just had to give it a try.  I got an API key at that time, but it took me four long months try it out.  (Let's not talk about time management - not a good subject for me.)

I found it very simple to use, if a bit limited in functionality.  (For example, you can't pull a list of categories from the API, but you can query the products by category once you have that information) 

I wanted to try this in a Silverlight application.  I decided to structure the application so as to keep my API key as part of the server app, so the requests back to the API are done by my web server - not the Silverlight app.

Getting data back from the Best Buy servers is all done with REST requests, like this:

http://api.remix.bestbuy.com/v1/products?sort=name.desc&apiKey=YOURKEYHERE

http://remix.bestbuy.com/docs/types/Products

http://api.remix.bestbuy.com/v1/products(manufacturer='canon'&salePrice%3C33)?apiKey=YOURKEYHERE

http://api.remix.bestbuy.com/v1/products(categoryPath.name='audio'&salePrice%3C33)?apiKey=YOURKEYHERE

http://api.remix.bestbuy.com/v1/products(categoryPath.name=' Blu-ray & DVD Players ')?apiKey=YOURKEYHERE

I couldn't find documentation on what parameters you can pass, but when you send an invalid request ( an incorrect name= value), you receive back all the valid attributes in the error message.  So that was fine.

This silverlight ReMix demo application is written using the Silverlight Islands method of putting together a web app with Silverlight sprinkled through it.  That would be for SEO if this were going to be a real site.  I've written about the Islands method before, you can refer here, and here.

 Source Code (only SL app, not server side.) here   and you need this:  Wrap Panel

Anyway, have fun.  Here's how you can get your own API key to play with this great new source of content for the web.  http://remix.bestbuy.com/

 

Silverlight-Capture and Define Rectangles/Regions and Wire Events on them

by Bobbi Perreault 29. October 2008 12:46
Share on Facebook

This is a piece of an ecommerce tool I built, I call it the Room Builder. It was what I learned Silverlight on - so this project has been brought up from Silverlight 1.1 Alpha version. In other words, you may see some bad practices in there. But it's still useful. Or could be to the right situation.

Specifically today I want to talk about one of the features of the tool, that is the part that allows me to designate a region of a photograph, name it, and wire events to it for use in the application.

There is a link to the finished tool, so you can see what I mean on the left side of this blog, under the section titled "links to some of my silverlight controls".   If you hold your mouse over that link there should be a window pop up with instructions on it's use.

Regions of the photograph are targeted by clicking at key points along the perimeter of a path.  In the case of our Room Builder, it would be the outline of a couch.  After the path is defined, it is finalized with the click of a button.  At that time, the defined region is turned into an object and added to the children of the canvas along with a click event so that object may be selected again.

You can download the source code for this Room Builder application here.  It won't run for you, though, because there is no server side application with the correct web services.  SORRY.  If anyone really needs that piece, I'll be happy to send it.  It's just time I didn't have tonight to spend.  Sorry.

Anyway,

Here's the key points of this region building operation:

Click the Get Started Button, Cursor changes to a pencil.

public void StartMappingClick(object sender, RoutedEventArgs e)
{
//if it's not visible (Opacity), don't execute it.  Stray Clicks.
if ( StartButton.Opacity < 1)
return;
if (_room == null || string.IsNullOrEmpty(_room.ProductID))
{
message.Text = "Please setup your room first.";
return;
}
_gettingRoom = false;
SBHideStartButton.Begin();
SBShowCancelButton.Begin();
SBShowEndButton.Begin();
//for our cursor
ImageMapperCanvas.Cursor = Cursors.None;
LayoutRoot.Cursor = Cursors.None;
///////////////////////
_points = new List();
// Capture mouse and update stat
CaptureMouse();
if (pencil != null)
{
pencil.Visibility = Visibility.Visible;
if (_positionLast != null)
movePencilToCurrentPosition((Point)_positionLast);
}
lastRectangle = "";
_bIn = true;
this.message.Text = "";
}

Click at each turning point of your region

private void HandleMouseLeftButtonDown(object sender, MouseEventArgs e)
{
// Capture mouse and update stat
Point pos = e.GetPosition(this);
if (_bIn)
{
//highlight the point and add it to the list 
registerPoint( pos );
}
_positionLast = pos; //this is so we can track for edits.
}
private void registerPoint(Point pos)
{
//only register the point if it's inside the image.
if (!CheckCollision(pencil, ImageMapperCanvas))
return;
_points.Add(pos);
if (_points.Count == 1)
{
//mark the point
Ellipse el = new Ellipse();
el.SetValue(Canvas.LeftProperty, pos.X+20);
el.SetValue(Canvas.TopProperty, pos.Y+20 );
el.Width=2;
el.Height=2;
el.Stroke = new SolidColorBrush(Color);
el.StrokeThickness = 1;
el.SetValue(Line.NameProperty, lineName(_points.Count));
LayoutRoot.Children.Add(el);
}
else
{
//draw the polyline and add the line to the list.
//string of points
//
// Create new line
var line1 = new Line
{
X1 = _positionLast.Value.X,
Y1 = _positionLast.Value.Y,
X2 = pos.X,
Y2 = pos.Y,
Stroke = new SolidColorBrush(Color),
StrokeThickness = 1
};
line1.SetValue(Line.NameProperty, lineName(_points.Count));
LayoutRoot.Children.Add(line1);
}
}

Click the End Mapping Button

public void EndMappingClick(object sender, RoutedEventArgs e)
{
//if it's not visible (Opacity), don't execute it.  Stray Clicks.
if (this.EndButton.Opacity < 1)
return;
SBHideStartButton.Begin();
SBHideEndButton.Begin();            
SBShowcontrolgrid.Begin();
// Release mouse and update stat
ReleaseMouseCapture();
ImageMapperCanvas.Cursor = Cursors.Stylus;
LayoutRoot.Cursor = Cursors.Arrow;
if (pencil != null)
{
pencil.Visibility = Visibility.Collapsed;
}
if (_bIn)
{
_ictr++;
//we could switch this out based on a selected tool.
// MapItemBO newMapItem = drawRectangle();
MapItemBO newMapItem = drawPolygon();
if (newMapItem != null)
persistMapItem( newMapItem );
_bIn = false;
_points.Clear();
}
this.message.Text = "Search for the outlined item";
}

During this end mapping process, a path object is created, a click event attached, and that object is added to the children of the canvas.

code to get this path added to the canvas, by the way, if you download the sample code, this is line 509 in page.xaml file.

private void createPolygonPath(string dataline, string shapeName, Color border)
{
//to get this I used code from CreateWPFShape.  I also brought up Blend to
//help me with the Xaml for the path, expecially fill and opacity.
//also, in my diagram maker is code which created path geometries programatically
//this came from scribbler.
//
//extract the point array from this dataline. remove markup from the dataline.
dataline = dataline.ToLower();
int ilen = dataline.IndexOf("coords=");
if (ilen < 7)
return; 
dataline = dataline.Substring(ilen + 7);
ilen = dataline.IndexOf("href");
if (ilen < 1)
return;
dataline = dataline.Substring(0,ilen);
dataline = dataline.Replace("\"", "");
//message.Text = dataline;  //for debugging.
string[] pointlist = dataline.Split(','); //split the dataline on commas into an array.
if (pointlist.Count() < 2)
return;
// Create a new geometry.
PathGeometry geometry = new PathGeometry();
// Create a new path figure.
PathFigure figure = new PathFigure();
figure.Segments = new PathSegmentCollection();
// Add figures to the geometry.
for (int i = 0; i < pointlist.Count(); i++)
{
// Determine the starting index and the end index
// into the points array that defines the figure.
int ptx = -1;
int.TryParse( pointlist[i], out ptx);
int pty = -1;
if ( pointlist.Count() > 1 && i != (pointlist.Count() - 1) )
int.TryParse( pointlist[i + 1], out pty);
else
int.TryParse( pointlist[ pointlist.Count()-1 ], out pty);
System.Windows.Point pt = new Point( ptx, pty);
if (i == 0)
figure.StartPoint = pt;
else
{
LineSegment linesegment1 = new LineSegment();
linesegment1.Point = pt;
figure.Segments.Add(linesegment1);
}
i++; //move to the next x
}
if (geometry.Figures == null)
{
PathFigureCollection pathFigures = new PathFigureCollection();
pathFigures.Add(figure);
geometry.Figures = pathFigures;
}
else
{
// Add the new figure to the geometry.
geometry.Figures.Add(figure);
}
// Add the geometry to a new Path and set path properties.
System.Windows.Shapes.Path path = new System.Windows.Shapes.Path();
path.Data = geometry;
path.SetValue(Canvas.NameProperty, shapeName);
SolidColorBrush brw = new SolidColorBrush(Colors.White);           
path.Fill = brw;
path.Opacity = .40;
SolidColorBrush brb = new SolidColorBrush( border ); 
path.Stroke = brb;
path.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(editItemClick);
LayoutRoot.Children.Add(path);
}

Happy SILVERLIGHT! 

Maintaining Browser History in a Silverlight Application

by Bobbi Perreault 10. October 2008 23:37
Share on Facebook

The purpose of maintaining browser history is to give you the ability to enable the browser back button and code for deep linking which improves your discoverability.

This blog post is part four of my four part series on SEO for Silverlight Applications. I put this content together for my talk I gave at the Minnesota Developer's Conference which was last September. Fun Times. ( :-) )

The other posts in this series can be found here: Part I, Menu in Html and Silverlight, this is the Sitemap demo
Part II, Show Multiple Silverlight Controls in the Same Page with jQuery
Part III, service layer communicatioons - the Glue between the Silverlight and the WebApp

Maintaining history and deep linking ability

There are other ways to do this, maintaining browser history for back button and deep linking. In these early days of MVC, though, it’s a little bit to me like the Wild Wild West. What I mean is sometimes it just feels like every man for himself and the man with the biggest gun is the law. So, I brought out the big gun for my browser history and found myself a jquery plugin that is supposed to do the job.

Using this jQuery plugin, jquery.history - I’ve linked to the file menu.js which we’ve looked at before. In the function that sets up all the actions I need to complete when the page loads, ( that’s the $(document).ready function), I've placed a function call that initializes the history object.

 
function pageload(hash) {
// hash doesn't contain the first # character.
if(hash) {
// restore ajax loaded state
$("#load").load(hash + ".html");
} else {
// start page
$("#load").empty();
}
}

Every time a Silverlight object invokes a script that loads a new Island, it also invokes this Function silverlightHistory with the parameter (detailsurl) . This is the script which sets my new url up in the address bar, and adds me to history.

   
// set onlick event for buttons
function silverlightHistory( detailsurl ){
// 
var hash = detailsurl;
hash = hash.replace(/^.*#/, '');
// moves to a new page. 
// pageload is called at once. 
$.historyLoad(hash);
return false;
}
function setProductDetails( detailsurl )
{
//setup for browser history
silverlightHistory( detailsurl );
$('#sl-productListDisplay').html(" ").fadeOut();
//fetch the silverlight product details and plug it in, it's controlid #2
$.get('/Content/sl.htm', function(data){ 
setSilverlight(data, 'ControlId', 2, 'sl-productListDisplay', detailsurl);})
}

 

RSS Feed FriendFeed