An argument against Amazon's Kindle

by Kyle Ballard 5/26/2009 3:58:00 PM

I subscribe to a lot of magazines.  I'm kind of a junkie for being able to read a paper copy of materials, and I find my eye strain is a lot lower when reading from print.   As a result, I'm excited about the possibility of owning one of Amazon's Kindle devices and not having to lug 10 magazine issues around with me.   That was until I did some searching and found this.

Print magazines run a lower cost than their electronic counterpart!    How much does it cost to print, distribute, and mail each individual issue?   How much does it cost to electronitcally distribute.

Here is the Amazon listing for the print version of Fortune magazine:



And here is the same magazine in Kindle format:



It is 35 cents more expensive per month ($1.15 vs. $1.50), or roughly $4.50 more per year to get the electronic version than the print version.  

I'm sure there is some reason this is being done, but one thing is for sure, it has nothing to do with the fact that it costs more to distribute electronically, and that irritates the hell out of me.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Becoming a Technical Leader: Book Review

by Kyle Ballard 5/2/2009 2:34:23 PM

0932633021

It's no secret that I am a big fan of Dale Carnegie's - How to Win Friends and Influence People, and this book extends upon the principles in Carnegie's book and applies them directly to any technical job. 

Personally, I would still advise reading Carnegie's book first as a business book, but if you have read that already and are looking to further your development as a leader, this book does a great job at applying a more niche approach to the concept of leadership.  The subtitle of the book is "An Organic Problem-Solving Approach".   I would agree with that assessment.  Gerald Weinberg, the author, does a great job at outlining the differences between a technical leader position, and a traditional management position, and is probably one of the very few books out there who tackle those topics.

 

The book begins by outlining the concept of a leader, what it takes to be a leader, and how leaders develop their character.  He uses several analogies, such as his youthful experiences with a pinball machine, through the ravines and plateaus to which adjustments to his game where made, to outline how his later career as a technical leader would develop. 

The leadership overview segueways into the topics: motivation, innovation, and organization which guide the central theme of the book.  He recommends keeping a daily 5 minute journal (which I have done, and agree is a great idea), notes it is important to recognize that self-confidence is a pre-requisite for success, and he also talks about the trade-offs between technical ability and leadership ability, and how to successfully motivate others.

The final chapters of the book outline the transformative process by which technically able people become leaders.  How to handle other people, who can and will, challenge your leadership, as well as finding time to continually change and improve yourself as a leader to maintain your position.  The ability to lead in the technical field requires continual movement and improvement, without which, one will fall by the wayside.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Code Complete 2: Book Review

by Kyle Ballard 4/29/2009 7:40:00 AM

 

This book is the de-facto standard for best practices as it relates to source code and programming. User ratings and industry leaders will also concur, that this book, now in it's second edition leads the pack as a guide.

The book is a long read, but it is by no means simply a filler to increase the weight of the book. Each chapter is significant and important in it's own way.

Every programmer upon entering the workforce should receive a copy of this book, at a minimum, because it paves the way for your career and sets you on the right path with ideal guidelines for good programming practice. I'm sure others who have read the book feel this strongly about it also. 

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Vacation, Random Thoughts, and Bookmarks

by Kyle Ballard 3/15/2009 1:00:52 PM

Just got back from vacation.  Cubs spring training, city touring in San Francisco, and wine tasting in Sonoma.  It was quite an experience, but I feel at the end of the trip I needed a vacation from my vacation.  Anyone who has been gone for any extended period of time probably knows exactly what I mean.  Danielle and I took some great photos, which I will be posting on my Facebook account shortly.  I was amazed by the weather and feeling of being at the ballpark in Arizona (we even hiked camelback mountain), and also enjoyed my second trip to SF.  Last stop was Sonoma, and I have always been a wine novice, but now feel like I am a wine beginner.  Who knew there was so much science behind the process of making a beverage?

Some changes for me at work, which I haven't had time to write about are that I picked up a Herman Miller Mirra chair, switched Visual Studio into a black background, and have decided to familiarize myself with the DotNetNuke5 project so I can hopefully move my small college alumni project into other universities as well.  We'll see how that goes.

How to Link Facebook to Twitter
I have been putting this off for some time, and once I realized how simple this was I took care of it in 5 minutes.  Great, easy to follow tutorial.
http://www.ajvaynerchuk.com/how-to-link-twitter-to-facebook-a-twitter-tutorial/

We Follow
Simple premise for this site is just an aggregator that lists the most popular twitter uses and categorizes them by tag, # of followers, etc.
http://wefollow.com/

TechCrunch's 60 second "elevator" pitches
Need some inspiration, I find a good amount here watching other's foster their ideas and getting feedback.
http://pitches.techcrunch.com/

Photoshop Phriday
I have always enjoyed the photoshop collections which get posted on digg.com as a way to entertain myself, and a friend pointed me to this site which I have apparently missed under the radar.  A new collection is posted every friday.
http://www.somethingawful.com/d/photoshop-phriday/

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

ItemDataBound in a Nested Repeater

by Kyle Ballard 1/24/2009 7:21:29 PM

Something I struggled with early in my ASP.net development was how to handle ItemDataBound event (or any repeater event) when it was inside another repeater in the code behind logic.  I am presenting my code here so that it may be of use to anyone else having the same problem.

 

Given MyPage.aspx

<asp:Repeater id="rptMyOuterRepeater" runat="server"> 
<HeaderTemplate> 
  <h1>My Repeater</h1> 
</HeaderTemplate> 
<ItemTemplate> 
  <asp:literal id="ltlCategory" runat="server" /> 

  <asp:Repeater ID="rptMyInnerRepeater" runat="server"> 
  <ItemTemplate> 
     <asp:Literal ID="ltlItem" runat="server" /> 
  </ItemTemplate> 
  </asp:Repeater> 

</ItemTemplate> 
</asp:Repeater>

 

Given MyPage.aspx.vb

' **** Please note functions CategoriesDataLayer.GetList() And ItemsDataLayer.GetCategories(CategoryId)
' ****   are used for demonstration only.  You may use any collection of data (datatable, collection, etc)

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    rptMyOuterRepeater.DataSource = CategoriesDataLayer.GetList()
    rptMyOuterRepeater.DataBind()
End Sub

Protected Sub rptMyOuterRepeater_ItemDataBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs) Handles rptMyOuterRepeater.ItemDataBound
    ' Exit function if this is not in ItemTemplate
    If Not e.Item.ItemType = ListItemType.AlternatingItem AndAlso Not e.Item.ItemType = ListItemType.Item Then Exit Sub

    Dim rptMyInnerRepeater As Repeater = e.Item.FindControl("rptMyInnerRepeater")
    rptMyInnerRepeater.DataSource = ItemsDataLayer.GetItemsByCategory(e.Item.DataItem("CategoryId"))
    AddHandler rptMyInnerRepeater.ItemDataBound, AddressOf rptMyInnerRepeater_ItemDataBound
    rptMyInnerRepeater.DataBind()

End Sub

Protected Sub rptMyInnerRepeater_ItemDataBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs)
    ' Exit function if this is not in ItemTemplate
    If Not e.Item.ItemType = ListItemType.AlternatingItem AndAlso Not e.Item.ItemType = ListItemType.Item Then Exit Sub

    CType(e.Item.FindControl("ltlItem"), Literal).Text = e.Item.DataItem("ItemName")
End Sub

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

SQL Server 2005 Database Design & Optimization

by Kyle Ballard 12/27/2008 7:38:16 PM

The following are some basic design guidelines to use when implementing a SQL 2005 database.

1.  Enforce foreign and unique key constraints.

Foreign and unique key constraints will maintain your database integrity.  Think of it as insurance against orphaned records and duplicate data.  If you know a column is to be unique, or a relationship to another table, entering it as a constraint can be one way for your database to police your application and catch errors early on before they become a problem.

 

2.  Identify poorly performing queries and optimize them.

SQL Profiler is a great tool and provides access to meaningful data regarding the execution time and resources required to run each of your queries.  As a general rule, I try to weed out queries which take over 200 milliseconds to execute.  This may seem like a small amount of time, but when you have an large number of visitors (such as after an email blast) this can quickly become a bottleneck.  SQL Profiler can be setup to track all queries executing over X number of milliseconds, X number of reads, and you can target specific databases so it returns only the data you are looking for. 

Performance inefficient statements (LIKE, IN, NOT IN, DISTINCT) can (and probably should if possible) be rewritten using proper join operations, using EXISTS, or using temporary tables in multiple SQL statements.  This will reduce the number of reads and ultimately decrease the time to return the data you are requesting.

 

3.  Use non-clustered indexes.

Using indexes is not an exact science.  It requires a calculated effort to ascertain the advantage of using the index versus the impact which will be incurred when updating, inserting, or deleting records.  A good rule of thumb is to index foreign keys as these columns are often used frequently when performing joins on tables.  Other good candidates for indexes are columns used for data ordering ("order by") and columns used in frequent look-ups (filtering fields).

Additionally, any administrative reports which contain filtering options should be considered candidates for indexes, especially if the table has 500,000 records or more.  Be careful though, to be aware that admin reporting is used exponentially less than the table data on the front-end of the website.  Try to weigh the benefits of each, and never place a filter field for a table that has millions of records without an index.  Scanning every row in a database for a certain value is a performance nightmare.

Lastly, be careful not to cover the entire table with indexes.  Every index added results in an increase of performance when reading data, but every index also carries with a performance hit when updating, deleting, or inserting data

 

4.  Use clustered indexes.

A table is ordered physically (on the file system) by the clustered index.  As a result, it is by far the most optimal way to search for data in the table.  In a common e-commerce example, if you have order headers, shipment recipients, and line items as 3 separate tables, then each may be joined together by the OrderId column.  Making the OrderId column the clustered index, instead of the LineItemId column in the LineItems database table would make sense logically if you were always pulling data from the LineItems table using the OrderId.  Additionally, if you wanted to pull an single record from the LineItems table, if you were to specify the LineItemId in conjunction with the OrderId, your query would execute very fast in that case also since you were aware of the OrderId at the time of the lookup.

 

5.  Avoid using wildcard characters on the left side of an indexed column.

If you have an index on the field "FirstName" but you perform a look-up on that column using wild-card characters on both sides of a lookup value, then you are negating that index (ex: WHERE FirstName LIKE '%yl%' OR FirstName LIKE '%yle').  In this case, you could think of the index like the first few letters of each persons name at the top of the phone book.  If you start at the beginning, then you know to look, but if someone says that this is the middle of the name, or the end, then you won't be able to use that index to lookup the person in the phone book.  The database indexes in a similar fashion, so be aware when using wildcard characters.
(Note:  SQL 2005 may still use an INDEX SEEK, but it is unlikely that will happen when a wildcard appears as the first character in the LIKE clause).

 

6.  Avoid using SELECT * whenever possible.

SQL server database records are logically ordered on the file-system in 8kb chunks.  Any data over that 8kb is stored in what is referred to as an "Overflow page".  At the end of the 8kb page, there is a 16 byte pointer to where the overflow page data is stored (think 'text', varchar(max), etc).  When you use SELECT * to retrieve all columns, the overflow data must also be retrieved as part of the query and as a result, the performance is impacted.

 

7.  Periodically de-fragment your indexes.

Indexes could theoretically be thought of like a fragmented hard drive.  When you create the index the first time, everything is neatly ordered and compact for quick access.  Over time however, indexes become fragmented through deletes, updates, and inserts.  Gaps find their way into the index and the CPU has to work harder to lookup the data being requested.

It is good practice to run DBCC SHOWCONTIG as a command on a recent backup of your database.  When executing this command you will see data returned about the indexes currently active in your database.  As a rule of thumb, look for indexes which have a page count > 10,000 and  (logical scan fragmentation > 20% or avg. page density < 60%).

You have three options available to de-fragment your indexes. 

  • DROP INDEX and CREATE INDEX to re-create indexes
  • DBCC DBREINDEX - Offline operation, table is unavailable when this command is running on it.  Atomic transaction, passes or fails.  Defragments all indexes on a table.
  • DBCC INDEXDEFRAG - Online operation, database can continue to function when running.  Can be stopped at anytime.  Defragments one index at a time.

Provided below is a chart showing the performance of each method.  

http://www.microsoft.com/library/media/1033/technet/images/prodtechnol/sql/2000/maintain/ss2kbp09_big.gif

8.  Use consistent naming conventions.

I don't think there is a universal rule against a certain type of convention (plural vs. singular table names, etc), but maintaining consistency will aid in your development.  Having to keep referring back to your database to see if your column is named Desc, Description, Descrptn, etc. will prolong your develop as will having to check if a table is StoreItem or StoreItems, etc. 

 

9.  Maintain the database.

Writing a simple task (i.e.  SystemMaintenence.exe) which periodically purges old un-useful data, removes leftover image files, and generally tidies up the system is a good process to use to ensure your site is running as efficiently and effectively as possible.   If done properly, you could be removing loads of unused data, which in turn allows your system to operate at an optimal level.  Even moving data out of commonly used tables into 'Archive' tables where it won't be accessed as frequently offers performance gains.

 

10.  Don't abuse the cache.

Some people may disagree with me on this, but I would recommend not using caching at all until after a project has been live for a while and the performance bottlenecks have been identified.  Famous computer scientist Donald Knuth was quoted as saying "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.".  Many developers spend hours and hours pouring over code in a pre-release format looking for ways to optimize the code.  I personally believe that if you do your best to write it well the first time, and take the time to write it properly, then any necessary re-factoring or optimization can be done once the bottleneck is identified.

Additionally, I see many developers who have a tendency to cache as much data as they can without realizing that this cache data has to be stored in the server's physical memory.   If that wasn't bad enough, the system may periodically remove data from the cache if too much data is stored in the cache so that the system can continue operating properly.  Relying on the cache as a crutch for poorly designed queries/code is not a good approach to development.  However, using caching mechanisms properly,  and conservatively, is effective, especially if you are using it to address a performance problem which has presented itself in production code.

 

11.  Use the SqlBulkCopy class.

SqlBulkCopy should (in my opinion) always be used when inserting data over a couple of hundred records.  I have used this class in numerous projects in the past and it can handle tens of thousands of records in just seconds.  It doesn't take long to use, and when reading data from your data source you can perform all your necessary computations before storing it in the in memory table (which will later be sent to the server).  Another method, would be to load everything into a temporary table, and then perform the necessary T-SQL on that temporary table to move the data into your application.  I've used for this moving data from an old system to a new one, reading customer uploaded .csv files before processing them in the system, and taking large files off an FTP account for processing.  I honestly can't think of a good reason to not use this when dealing with any reasonable amount of data.

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

7 Healthy Habits of Highly Effective Web Workers

by Kyle Ballard 12/2/2008 9:24:56 PM

I doubt Steven Covey will ever read my blog post, but I'm glad you found your way here.  Presented below, is my best effort, to provide you with the concepts that have worked for me.  All these suggestions, are merely suggestions, but they have worked well for me, so I am sharing them with you.

1.  Exercise

If it seems obvious, and not a secret, well, that is because it isn't.  If you exercise an hour a day, you will lose weight, have increased energy levels, and a decrease in health problems.  You will be more confident, reduce your daily stress, and find yourself with deeper affection for those friends and family who are around you. 

I understand it can be a challenge to be motivated to exercise when there are a hundred other things on your plate: work, kids, wife, friends.  You might think to yourself, 'Hey! I'm too busy to work out'.  Think of it as insurance on your number one possession: your health.  High blood pressure, high cholesterol, and stress all result in a number of very undesirable effects to your health like heart attack, stroke, diabetes, and on an on.  An hour a day may seem like a lot, but try not to think of it that way.  Think of it as investing an hour in your day to maximize the other 23 hours of your day, and insuring your body against the negative elements so you can live out your golden years writing code, reading books, or spending it with your grand-kids.  Work hard enough at it, and you could even live out your retirement running marathons.

It can be daunting to start an exercise program, and there will be days you don't want to drag yourself out of bed.  Commit yourself to just doing something, anything, when it comes time to your exercise.  If you planned to run for an hour, and you really aren't feeling up to it, commit to just going for a 30 minute walk.  Hey, at least you did something right?  Just committing yourself to living a healthy lifestyle is an important step to your overall health and a determining factor on how effective your efforts are.

Exercise is a great investment in yourself and your number #1 asset: your health.  As an added bonus, you'll have a more productive work day, find yourself feeling more relaxed, and having more energy to get through those marathon coding sessions or play with your kids.

2.  Eat right

I'm from Chicago, and we have more steak houses, fast food establishments (like the infamous Portillo's), and bars than I care to admit.  It can be very, very tempting to eat unhealthy.  You could be nervous about being mocked by your friends and colleagues for eating a salad, have a stressful day and use food to relieve the stress, or you could simply not have any other alternatives around you.

Unfortunately, there are plenty of good reasons why people choose not to eat healthy, however of those good reasons, there are no reasons good enough to justify damaging your health.  Eating large amounts of high calorie, high fat food produces unhealthy blood sugar levels, increases stress, and ultimately results in lower energy levels.  We all know what that post-Thanksgiving food coma feels like. 

Simple strategies like keeping unhealthy food out of your house/apartment, office, and car are a great first step.  Another wonderful strategy is to keep healthy snacks in your desk.  Freeze dried fruit, natural granola, pretzels, and others will help you stave off those desires to gorge yourself on a double cheeseburger and fries because you are so hungry your stomach hurts by the time lunch hour arrives.  Many offices have quick access to stores which sell fresh fruit and vegetables.

It can be hard to go for a long time without eating unhealthy, but you will find that the longer you go eating healthy, the easier it becomes.  It will, as strange as it sounds, actually become easier to eat healthy than to eat unhealthy.  Your body will have a strong reaction (upset stomach, acid-reflux) to unhealthy foods if you go long enough without them and just the thought of going through that will have you wanting to avoid that feeling altogether.

3.  Healthy Sleep

I could say sleep 8 hours, sleep 9 hours, sleep 7 hours, but I think everyone is different.   Work works for you may not work for someone else.  The important thing is to not oversleep and not sleep too little.  Your body simply will not function effectively if you do not get the correct amount of sleep.  You will make more mistakes, become more irritable and find it harder to make the right decisions about your health (drinking too much caffeine to stay awake, making poor food choices).

Just trying to get into a routine, as boring as that sounds, can have you rising with an increased energy level each day.  For me, it's bed at 10 and up at 6.  Does that ever change?  Sure it does.  I go out with friends, hit up a late night movie, but overall I try to stick to that as close as I can.  Nothing really good ever happens after 10pm, and 6 is the perfect time for me to get my workout in before heading to work.

I understand this can be hard with kids, and with those who travel frequently, but the bottom line of it all is getting a good amount of sleep is simply important to your overall health.  You will be more productive, alert, and ready to face the day when you have had the right amount of sleep.

4.  Moderation

All things in moderation.  I'm sure you've heard that before.  Have a drink or two and you'll feel fine at work the next day.  Get sloppy drunk and you will feel miserable, make poor eating choices, skip your exercise, and not get a good nights sleep.   Split a small piece of cheesecake with your friend/significant other on a special occasion and it gives you a reason to celebrate and enjoy a great tasting food item, but have McDonald's for breakfast lunch & dinner and you'll end up feeling like Morgan Spurlock.

Having a glass of really good tasting wine can have you really appreciating the work that went into producing that drink, or having a really good desert item on a rare occasion can have you really have your taste buds savoring that flavor.  Drink every day, watch television for hours, play video games for hours, or doing anything in excess and you will find yourself losing track of what really drew you to that in the first place. It loses it's value and ultimately its enjoyment.

The basic premise is, enjoy the finer things in life, but don't abuse them because then they lose their value.  Addiction isn't something to be taken lightly, and this blog is no substitute for professional medical advice, which I encourage you to seek that advice if you feel you have a problem battling an addiction. 

5.  Spirituality

I'm sure I'll be ostracized to some extend for including this suggestion, however I am very open about my faith.  I'm a Christian, however I am not the same Christian you see on television giving the rest of us a bad name, picketing funerals, and generally acting like someone who just got the wrong information about what it meant to be a Christian.  I encourage others to read the bible, and attend church, but I don't force my beliefs on anyone else.  I don't feel that is the right way to approach life and it certainly gives organized religion a bad name when others act that way.

That being said, I did title this subject 'spirituality' because regardless of your beliefs:  Christian, Catholic, Muslim, Jewish, or simply those who are enlightened spiritually, I find that connecting with those around me, donating my time to a worthy cause, and simply praying all give me piece of mind and put things in perspective for me. 

Going to church puts my life in check, and keeps me on the right track mentally.  Hearing prayer requests for those who are struggling with medical conditions, family problems, or drug addictions helps you become more comfortable with your own mortality, be grateful for what you have in your life instead of focusing on what you don't have, and encourages you to be a better person.  It's enlightening and humbling at the same time. 

6.  No Television

I sometimes struggle with this myself.  I'm a diehard Chicago Cubs fan, and it is hard to not want to tune the game on, but I still feel that television is a waste of the precious (and little) time we have.  I don't suppose it is really the point that television is terrible, rather that television is not a better alternative to reading a book, creative writing, art, photography, computer programming, or any other of a million things which all increase your overall well being.

Find a hobby, follow your dreams.  Don't want to be a programmer?  Hey, it's not for everyone.  Maybe you wanted to be an accountant (hahaha!).  All jokes aside, maybe you wanted to be a chef, artist, or simply just learn about history, lose yourself in a great story perhaps.  Wouldn't that be a more enjoyable way to spend your time instead of watching someone else on t.v. live out your dream?

Think about how much time you have spent watching television in the past year.  Now try to picture how much knowledge, and experience you would possess in regard to any of those aforementioned hobbies, if you had used that same number of hours pursuing that which is important to you.  That statement is reason enough to unplug.

7.  Socialize

Being a programmer, it's really hard for me to sit at a desk, and problem solve all day and then come home and work more.  This happened more in the beginning of my career when I was writing code for about 100% of the day, and it is less now, but it is still important for me to actively keep up friendships, keep up with friends and family, and actively communicate with other developers. 

For some, it can be nerve-wracking, or even anxiety-inducing to be in social situations, but there are plenty of strategies to be a good communicator.  You will find that by actively socializing with others, and keeping a strong social support system, you will have plenty of opportunities to have a good laugh, enjoy life and all it has to offer, get through the hard times in life, and also help others through as well.

Like anything in life, you get out what you put in.  If you put little or no effort into maintaining any level of friendships with anyone, well then you are unfortunately going to be a very lonely person.  If, on the other hand, you actively make it a point to pursue and keep up relations with those close to you, then you will find yourself benefiting from the effort you are putting in as well.

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Remove Surrounding White Space From An Image

by Kyle Ballard 11/22/2008 5:15:02 PM

The following is from my post on StackOverflow.com

I have a block of product images we received from a customer. Each product image is a picture of something and it was taken with a white background. I would like to crop all the surrounding parts of the image but leave only the product in the middle. Is this possible?

As an example: http://www.5dnet.de/media/catalog/product/d/r/dress_shoes_5.jpg

I don't want all white pixels removed, however I do want the image cropped so that the top-most row of pixels contains one non-white pixel, the left-most vertical row of pixels contains one non-white pixel, bottom-most horizontal row of pixels contains one non-white pixel, etc.

Below is the solution to my problem.  It is not the most glamorous approach, but it works.  I could have use Bitmap.Lockbits() to lock the bitmap in memory and do my processing there, but this approach below sufficed my needs.  It is a pixel by pixel scan of the image. 

Some recommended additions/changes if you are feeling inclined:

- Use Bitmap.Lockbits() to improve performance
- Perform image resizing after the trimming is completed.
- Instead of looking for straight white pixels, you could also exclude near-white pixels (for any shadows).

Start.vb

Imports System.Drawing 
Imports System.IO 
Imports System.Configuration.ConfigurationManager 

Module Start 

    Sub Main() 
        Try 
            Console.WriteLine("") 
            Console.WriteLine("Begin:  Crop Images") 
            CropAllImages() 
        Catch e As Exception 
            Console.WriteLine("Error Message: " & e.Message) 
            Console.WriteLine("----------") 
            Console.WriteLine("Error Stack: " & e.StackTrace) 
        End Try 
    End Sub 

    Sub CropAllImages() 
        Dim iTopMostPixel As Integer, iLeftMostPixel As Integer, iRightMostPixel As Integer, iBottomMostPixel As Integer 
        Dim objBmp As Bitmap, objNewBmp As Bitmap 
        Dim rect As Rectangle 
        For Each oFile As FileInfo In New DirectoryInfo(AppSettings("ImagePath")).GetFiles("*.jpg") 
            objBmp = CType(Bitmap.FromFile(AppSettings("ImagePath") & oFile.Name), Image) 

            iTopMostPixel = GetNonWhitePixel(objBmp, 1) + AppSettings("PaddingTop") ' Get the top most pixel and add any optional padding 
            iLeftMostPixel = GetNonWhitePixel(objBmp, 2) + AppSettings("PaddingLeft") ' Get the left most pixel and add any optional padding 
            iBottomMostPixel = GetNonWhitePixel(objBmp, 3) + AppSettings("PaddingBottom") 
            iRightMostPixel = GetNonWhitePixel(objBmp, 4) + AppSettings("PaddingRight") 

            rect = New Rectangle(iLeftMostPixel, iTopMostPixel, iRightMostPixel - iLeftMostPixel, iBottomMostPixel - iTopMostPixel) 
            objNewBmp = objBmp.Clone(rect, objBmp.PixelFormat) 
            objNewBmp.Save(AppSettings("ImagePath") & Replace(oFile.Name, oFile.Extension, "_cropped" & oFile.Extension), Imaging.ImageFormat.Jpeg) 

            Console.WriteLine("Saved: " & AppSettings("ImagePath") & Replace(oFile.Name, oFile.Extension, "_cropped" & oFile.Extension)) 

            objNewBmp.Dispose() 
            objBmp.Dispose() 
        Next 
    End Sub 

    Function GetNonWhitePixel(ByVal objBmp As Bitmap, ByVal iPixelType As Integer) As Integer 
        Dim objColor As Color 

        Select Case iPixelType 
            Case 1 

                ' Top pixel 
                For y = 0 To objBmp.Height - 1 
                    For x = 0 To objBmp.Width - 1 
                        objColor = objBmp.GetPixel(x, y) 
                        If Hex(objColor.R) & Hex(objColor.G) & Hex(objColor.B) <> "FFFFFF" Then Return y 
                    Next 
                Next 

            Case 2 

                ' Left pixel 
                For x = 0 To objBmp.Width - 1 
                    For y = 0 To objBmp.Height - 1 
                        objColor = objBmp.GetPixel(x, y) 
                        If Hex(objColor.R) & Hex(objColor.G) & Hex(objColor.B) <> "FFFFFF" Then Return x 
                    Next 
                Next 

            Case 3 

                ' Bottom pixel 
                For y = objBmp.Height - 1 To 0 Step -1 
                    For x = 0 To objBmp.Width - 1 
                        objColor = objBmp.GetPixel(x, y) 
                        If Hex(objColor.R) & Hex(objColor.G) & Hex(objColor.B) <> "FFFFFF" Then Return y 
                    Next 
                Next 

            Case 4 

                ' Right pixel 
                For x = objBmp.Width - 1 To 0 Step -1 
                    For y = 0 To objBmp.Height - 1 
                        objColor = objBmp.GetPixel(x, y) 
                        If Hex(objColor.R) & Hex(objColor.G) & Hex(objColor.B) <> "FFFFFF" Then Return x 
                    Next 
                Next 

        End Select 

        ' Nothing found 
        Return 0 
    End Function 
End Module

app.config

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <appSettings> 
        <add key="ImagePath" value="C:\Path\To\My\Images\"/> 

        <add key="PaddingLeft" value="10" /> 
        <add key="PaddingRight" value="10" /> 
        <add key="PaddingBottom" value="100" /> 
        <add key="PaddingTop" value="0" /> 
    </appSettings> 
</configuration>

kick it on DotNetKicks.com

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Page_Load executes twice on first request (ASP.net Bug)

by Kyle Ballard 11/13/2008 9:10:00 AM

So I think I found a bug in ASP.net, I confirmed this by creating a page with all other environment variables removed to isolate the problem and my theory held. To further complicate things, this only happens in Firefox.

If I create a blank page and put in an asp:image tag:

<asp:image id="imgMyImage" runat="server" />

And I leave out the ImageUrl piece (or I enter it but leave it as a blank string) then this will post the page twice. I put a break-point on the Response.Write("Here!") inside the Page_Load event to confirm. Fiddler network traffic confirms this also.

The reason I had this blank was because this tag was in a hidden div and it was assigned dynamically for a 'zoom' version of the product image. Once I set this to ImageUrl="/images/spacer.gif" it removed the problem.

Also, I know that asp:image overrides border css styles for the image as well by default. Given that I haven't found a real reason/advantage to use the asp:image control over the server-side img tag (i.e. <img id='imgMyImage' runat='server'>) I may just go forward using the img tag in all cases.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

8 Favorite Developer Tips & Tricks

by Kyle Ballard 11/9/2008 6:02:15 PM

I've been keeping a running collection of tips/tricks that I felt made my life easier as a developer.  I hope this collection has you feeling the same way.  Feel free to post a comment at the bottom if there are others you found useful as well.

 

1.  Visual Studio.  Conditional breakpoints.  Have you ever right clicked a breakpoint when developing in visual studio?  If you have then you would know there are a slew of break options.  You can break when a certain 'Condition' is met (i.e. x = 5), when a certain hit count is reached (i.e. after 5 hits).  This should speed up your debugging.

Breakpoint 

 

2.  Visual Studio.  If you want to comment or un-comment an entire block of code inside visual studio.  Highlight the block of code and select <Ctrl>+<K> and then <Ctrl>+<C> ... if you wish to un-comment a block, then use <Ctrl>+<K> and then <Ctrl>+U.  This works in both Visual Studio as well as SQL Management Studio.

 

3.  Visual Source Safe. When in Visual Source Safe you may use the keyboard shortcut <Ctrl>+<S> to see all files currently checked out, globally, or to a specific user.  Additionally you can search within only the current project, or the entire VSS database.

 

4.  Visual Studio. If you want to see a history of all edits to your file when you are in Visual Studio, you may right click the file in Solution Explorer and select "View History".

 

5.  Javascript.  When including a script file on a site with an SSL certificate, use the html markup <script src=”//www.company.com/scripts/file.js”> approach for preventing the security ('This page contains secure and non-secure items) dialog pop-up.  Notice that the http: portion is gone, but it will render properly regardless of the current protocol.

 

6.  Javascript.  In addition to #3, if you would like to obtain the current protocol which is in use in your Javascript, you may obtain that by issuing the following command:

var prefix = window.parent.document.location.protocol + '//';

 

7.  Javascript.  If you wish to get the object which caused the asynchronous postback on an asp.net ajax enabled page.  You may use the following code:

var ClientId; 
var prm = Sys.WebForms.PageRequestManager.getInstance(); 
prm.add_InitializeRequest(InitHandler); 

function InitHandler(sender, args) { 
  ClientId = args.get_postBackElement().id; 
  alert(ClientId); 
}

 

8.  SQL.  If you need to remove a set of duplicate records, try using the following statements.

SELECT MyDuplicateColumn, MyDuplicateColumn2, Count(*) - 1 As NumToDelete FROM MyTableWithDuplicates GROUP BY MyDuplicateColumn, MyDuplicateColumn2 HAVING COUNT(*) > 1 


Then while looping through the records in the above recordset, issue the following command:

DELETE TOP (NumToDelete) FROM MyTableWithDuplicates WHERE MyDuplicateColumn = 'MyDupeValueFromPreviousQuery' AND MyDuplicateColumn2 = 'MyDupeValueFromPrevousQuery2'
 

kick it on DotNetKicks.com

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Powered by BlogEngine.NET 1.2.0.0
Theme by Mads Kristensen

About the author

My lovely wife and I at a wedding I am a web developer living in the Chicagoland area. I mainly focus on developing e-commerce applications and work with asp.net on a regular basis.


Send mail Facebook Twitter LinkedIn

Calendar

<<  July 2009  >>
MoTuWeThFrSaSu
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar

Recent comments

Categories


    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2009

    Sign in