Thursday, September 20, 2012

Spriting Images on High DPI ("Retina") Displays

This post assumes you're already familiar with the concept of image spriting, and are just getting into this same concept on high DPI displays, like Apple's Retina® displays.


It's actually very easy to do sprites that can work across both regular and retina displays as long as you follow these basic tips:
  1. Develop your low DPI sprite image first, and don't try to combine your high DPI and low DPI graphics into the same image. Trust me, I've tried and cried.
  2. Blow up your low DPI sprite image to 2x it's normal size, and save this into a new file. (I recommend using "nearest neighbor" rather than any of the other types of the resizing algorithms, so that you get hard edges as it makes the next step easier.)
  3. Generate your high DPI graphics however you intend to do that. Each graphic should be EXACTLY 2x the size of the original low DPI graphic when you're finished with it, even if it means pushing pixels around to get things just right.
  4. In a new layer on top of the original double-sized low DPI graphics, start overlaying your new high DPI graphics so that everything lines up perfectly over the low DPI versions. EXACTLY. When finished, hide your low DPI layer, and save your high DPI image in whatever format you prefer. I follow Apple's iOS convention of using the same file name with @2x appended (before the file extension). So my low DPI might be named sprite.png, and my high DPI will be named sprite@2x.png.
  5. Establish your baseline CSS like this example below. The 50px and 100px shown is the width and height of your image, respectively. NOTE: Your high DPI CSS will inherit this same exact background size. You should NOT double this or change it in any way for high DPI.

    .sprite
    {
        background-image: url(/images/sprite.png);
        background-size: 50px 100px;
    }
  6. For any element you want to be sprited, you'd specify the class you defined above. AND in addition, you would specify a separate class that you can define in CSS to position the background image to fit properly. In the example below, I have a clock icon that is 10px wide and 10px tall, and a stop sign that is 20px wide and 10px tall. In my sprite, my clock is oriented at the top/left of the image, and my stop sign is 10 pixels BELOW it, thus the offset given in the background-position for the stop sign has the X at 0, and the Y down at -10px.

    .clock
    {
        height: 10px;
        width: 10px;
        background-position: 0 0;
    }

    .stopsign
    {
        height: 10px;
        width: 20px;
        background-position: 0 -10px;
    }

  7. Now your table is set. To turn on high DPI support, all you would need to do is specify your new background-image. All the other styles defined above will be inherited, and are exactly the same in high DPI, because the browser treats all of the measurements as virtual pixels, which it will double internally. So my high DPI css for the examples above would be:

    @media
    only screen and (-webkit-min-device-pixel-ratio : 1.5),
    only screen and (min-device-pixel-ratio : 1.5)
    {
        .sprite
        {
            background-image: url(/images/sprite@2x.png);
        }
    }
That's it! If you run into any alignment problems between your low and high DPI views, you probably didn't follow one of the steps above correctly. Make sure your high DPI sprite image is exactly doubled in every way, including the placement of each icon graphic within the sprite. Make sure you have not accidentally changed the background-position, height, width, or background-size in your high DPI css area, as it is not necessary and will instead cause you problems!


Wednesday, June 15, 2011

Official Toyota Extended Warranties

Recently I've been shopping for a new Toyota vehicle. Most dealers now have fleet/internet salesmen that are easy to deal with via e-mail, as the B.S. gets cut out to a large degree since they know you're shopping on the internet and are more up-to-speed on things like invoice pricing, dealer holdbacks, and the rest.

In fact, after filling out the form at cars.overstock.com to receive price quotes from nearby dealers, I was able to easily come to a deal with Derrick B. at Puente Hills Toyota in the City of Industry, CA.

But even if you agree to a specific price, they can still make money off you in other ways... typically with the finance department, which handles financing, as well as things like extended warranties...

I knew to expect this, so I wanted to go in armed with information. Here is some data that I've picked up in my reading that might help you:

  • I have read that the official Toyota extended warranty is a pretty good deal, as long as you don't overpay. You can shop around at different dealerships (more below).
  • Third parties like Fidelity, JM&A, etc. are often pushed by some dealerships, instead of the official Toyota warranties, and have confusingly similar names for their products, e.g. "Platinum" extended warranty, with the same mileage breakouts that Toyota's official extended warranties have. Don't be fooled. The warranty you get should be Toyota ExtraCare, officially branded.
  • You don't need to buy the extended warranty when you buy the vehicle. It's not clear to me how long you have to buy it (some say 30 days, some say 60, some say up until the basic warranty runs out). But it's clear you do NOT need to be pressured into buying it that night (unless you really need to finance it with your vehicle purchase).
  • You can buy the warranty from any dealership, even out of state. One that was recommended frequently online was Toyota of Greenfield, in Massachusetts. Ask for Troy. He appears to be affiliated with this website which has some good information on extended warranties (the official ones, which they sell). For several kinds of Toyotas, I was seeing people quoted in the $600 - $900 range for a $0 deductible platinum 7-year warranty in the 70K to 100K mileage range (from Troy). And many other people were getting charged upwards of $1500-$2500 at their own dealerships, so don't get suckered.

Wednesday, September 15, 2010

Thoughts on iPad Mini

There have been rumors swirling that Apple will release a new version of the iPad in time for the holidays. There have been other rumors that Apple will release an iPad in a smaller form-factor.

In general I subscribe to the philosophy that most rumor-mongers are full of shit.

However, I think these rumors do make sense, and I'll go into why exactly in a minute. But first, my guesses. Everyone likes to make guesses. Here's mine:

Apple will release an "iPad Mini" in November, running iOS 4.2, with a 6" screen at 1024x768 (213dpi), putting it's screen resolution and size on par with the Kindle 3. The smaller form factor (60% reduction in size) would lead to a lighter device. You've now eliminated 2 of the 3 advantages the Kindle has over iPad: higher resolution reading, lighter weight, leaving only one: viewing in direct sunlight.
Will Apple also re-design the screen to work better in sunlight (or at least eliminate the polarity issue that causes the screen to look completely off when wearing sunglasses)? Maybe. I doubt we'll see many advances along that line until next year's release. (I'm lumping "overheating" issues into that third Kindle advantage of viewing in direct sunlight, by the way.)

I think it goes without saying that any new release of iPad will come with a front-facing camera for FaceTime support.

How I came up with the precise specs for my guess above is by looking at what Apple did already with iPhone 4, and how they are trying to inflict minimal pain on iOS developers. iPhone 4 doubled the resolution and kept the screen size the same. This makes it fairly easy for iOS developers to adapt their applications -- double your graphics sizes, and you're done.

What would be even easier? If the resolution increased but the pixel count remained exactly the same. Then developers don't need to do anything! Obviously the screen size is going to have to come down if the resolution increases, which is no surprise if one of the goals is to compete against the Kindle form-factor at six inches diagonal. The 213 dpi I've posited is not "retina" level, per se, though it's still in the range of Kindle 3 DPI. And I think that's where this device is squarely aimed. (Alas, I was not able to find the actual Kindle 3 DPI documented anywhere officially, but it's said to be in the 200s.)

I've read rumors of a 7" iPad Mini, but I would be surprised if Apple went with that size, since it would mean a sub-200 DPI resolution at 183 DPI, and if you think about it, not a whole lot more than the resolution of the iPhone 3, which was 163 DPI. It also would not allow Apple to cut the weight as much as they can with a smaller screen.

Apple wants to have their iPad cake and eat Kindle's, too. What's that, you want a full-sized mobile computing device? Here's the iPad. Oh, you're mainly interested in reading, but wouldn't mind getting these hundreds of thousands of apps that Kindle doesn't offer? Here's iPad Mini.

Apple could release this product in November for the holidays, and developers would have to do nothing at all -- all of their software would run perfectly on this new device because nothing has changed in terms of the pixel count or aspect ratio.

Food for thought... Next Spring... will Apple release iPad 2 with a full retina display increase to ~326dpi, and a doubling of the pixels for the large form-factor (original) iPad line? If so, how long until Apple finally eliminates pixels entirely? Why are developers still using PNGs sprinkled with pixel fairy dust, rather than vector graphics? Will iOS 5 and Mac OS XI eliminate these relics once and for all?

Full disclosure: I am a long-term investor in both Apple and Amazon stock.

Monday, September 13, 2010

Geo::IP built for ActivePerl 5.12

You can find it here.

MSDeploy vs. xcopy network bandwidth throughput

MSDeploy (aka Microsoft Web Deploy) is great for syncing up all kinds of things between two machines. One issue I've noticed recently is, for whatever reason, it doesn't always do well at maxing out your network bandwidth.

We were recently syncing up large SQL Server backups between two boxes connected through a gigabit ethernet switch. I initially decided to use msdeploy.exe, because I wanted it to not only bring over the latest files, but delete the ones on the destination server that no longer exist on the source server. Using -verb=sync and an xml -source:manifest and -dest:manifest file, I ran the test sync from the destination server, and watched the network usage with task manager.

The average throughput was in the 5-15% range on our gigabit connection.

As a test, I ran xcopy /S /D for the same directory tree, and was getting over 90% throughput most of the time, often at 99% throughput!

Unfortunately, xcopy will not truly sync, it's only copying the files over. So now what we do in our .bat file is run the xcopy command first to copy over all the newest data at a high rate of speed, and then we call the same msdeploy command as before, and it deletes any files on destination not found on source. Since all the copying of new data has been done by xcopy, it finishes very quickly and now we're synced up.

I am aware of robocopy's ability to do a lot of this stuff, but it's clear that msdeploy is where Microsoft is putting it's eggs for a lot of the newer syncing technology, so we default to using that first, and now just augment with xcopy when pure throughput is needed.

If anyone knows why msdeploy is so much slower, please comment and I will update this article with any tips to gain performance. My guess is it's due to using the HTTP agent? It just seems weird, because I'm talking about copying of really huge files, so the slowdown is not with hash checking.

Monday, August 16, 2010

Notifying Major Search Engines with sitemap_gen.py

If you're using sitemaps on your website, you can notify the major search engines whenever your sitemap is updated. They usually offer a "ping" URL that you can hit. The ping URLs for the major search engines are below. You would substitute the full URL to your sitemap.xml (or .gz) file, encoded, wherever you see sitemap_url below. And read the note at the bottom of this post for more info on the YahooDemo appid used below:

  • http://www.google.com/webmasters/tools/ping?sitemap=sitemap_url

  • http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=YahooDemo&url=sitemap_url

  • http://www.bing.com/webmaster/ping.aspx?siteMap=sitemap_url

  • http://submissions.ask.com/ping?sitemap=sitemap_url


In addition, if you're using Google's sitemap_gen.py python script for generating your sitemap, they have a hash of tuples for each site you want to notify. Only Google's is included by default. Here is a version of the NOTIFICATION_SITES hash that has Google, Bing, Yahoo, and Ask.com:

NOTIFICATION_SITES = [
('http', 'www.google.com', 'webmasters/tools/ping', {}, '', 'sitemap'),
('http', 'search.yahooapis.com', 'SiteExplorerService/V1/updateNotification', {'appid' : 'YahooDemo'}, '', 'url'),
('http', 'submissions.ask.com', 'ping', {}, '', 'sitemap'),
('http', 'www.bing.com', 'webmaster/ping.aspx', {}, '', 'siteMap')
]


This should work as-is, but if the Yahoo one fails for you, or if you want to follow Yahoo's rules more closely, you should sign up for an official Yahoo Developer appid, and replace "YahooDemo" in the code above with your appid.

Friday, July 23, 2010

Session State not working even though you have enabled it?!

This was a doozie... I was working on a local dev box running Windows Vista and .NET 2.0. I pulled down another developer's web project that uses Session State variables, and when I went to test it, I received this error:

"System.Web.HttpException: Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive..."
I did some sleuthing, and find different recommendations:
  1. Add to your web.config file, within the area.
  2. Add to the same area.
  3. Make sure is in the httpModules area of your root level web.config file (some people said machine.config, not sure which, but I tried both).
  4. Add EnableSessionState="true" to the .aspx @Page directive.
Well, I tried all of these. Yet I still received this error. I opened up IIS Manager and looked at the root level of the site. There's even a configuration panel for "Session State," and "InProc" was already selected. EVERYTHING was turned on, why wasn't it working???

I just figured it out, although I have no idea how or why it was required:
  • In IIS Manager (in IIS7), go to the top level of the website in question.
  • Instead of clicking on the Session State panel, double-click the "Modules" area.
  • Scan that list and see if you have a module for Session State configured (I did not).
  • If not, click the Add Managed Module... button.
  • Type "Session" in the first box (no quotes).
  • In the second box, type "System.Web.SessionState.SessionStateModule" (no quotes)
  • Click the checkbox "invoke only requests to asp.net" (at least, that's what I did)
Now try your application again. If you're lucky like me, it just worked!