Resizing optimized animated GIFs in Photoshop

In a previous post I had some trouble getting Photoshop to save animated GIFs using “combined” frames. This stemmed from wanting to resize some existing GIFs I had made using gifcam. Gifcam can optimize the GIF by making the parts of the images that don’t change transparent and then relying on the combine method for the animation. For whatever reason Photoshop wasn’t automatically using the do not dispose setting for the animation. This means that the partially transparent frames would be shown by themselves and any transparent area would show through to the background. It has sort of a ghosting affect, it looks like this:
gif_non_dispose

Even after figuring out the dispose feature, I ran into another issue. The resampling that Photoshop does during resizing breaks the existing optimization done by Gifcam. Just a tiny change in the edge of the transparent areas used for compression can do this:
resize_no_dispose

Normally you want that kind of resampling as it leads to a nicer looking image. To preserve the optimization we want to use a “rougher” resampling algorithm. If you switch the resampling algorithm to Nearest Neighbor you’ll get a much nicer looking animation:
animation_nearest_neighbor

In the Save For Web dialog the resampling algorithm is labeled as “Quality”.
resampling_quality

You can see the difference if you stack two transparent frames on top of each other. Notice the weird square edge lines that aren’t in the upper (nearest neighbor) image.
resize_compression_compare

You can mess around with this to get some cool glitch effects though.
damaged-cyborg-head_glitch

Saving an animated GIF in Photoshop with “combine” instead of “replace” frames

The GIF format can use two methods to display the frames in an animation. The “replace” method simply replaces the current frame with the next one. The “combine” method merges the next frame onto the current one, so transparent areas will show through. This article has a good explanation of the difference (although it’s for GIMP). I wanted to save a GIF from Photoshop with the combine method, but could not figure out where that setting was.

After some thorough googling I stumbled on this article which explains how to do it. In Photoshop it’s called “dispose” or “do not dispose”. To get to it you need to open the timeline window (Window – Timeline). Then right clicking on any frame brings up a context menu where you can choose between the two methods.

photoshop_timeline_dispose

Mimicking Django Admin Change Form Styling in a Custom Form

I needed to create a custom form in Django admin for batch creating record by uploading a CSV file. The example I use here is upload a CSV of product keys for an existing product in the database. I wanted the custom form styling to match the default Django admin form styling. I’m new to Django so there may be a better way to do it, but this worked for me.

The first thing is to create a custom form class. Mine is pretty simple, a CSV file of product keys and a link to the product. We’re deriving from forms.Form since this is a custom form and it won’t match up to the model fields.

# storefront/products/admin.py

from django import forms
from products.models import Product
from products.models import ProductKey

class ProductKeyUploadForm(forms.Form):
    product = forms.ModelChoiceField(queryset=Product.objects.all())
    file = forms.FileField(label='Product Keys')

The next thing we need to do is add a new URL for this page to our ModelAdmin instance.

# storefront/products/admin.py

from django.contrib import admin

class ProductKeyAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(ProductKeyAdmin, self).get_urls()
        add_urls = [
            url(
                r'^upload/$',
                self.admin_site.admin_view(self.upload),
                name='products_productkey_upload'
            )
        ]
        return add_urls + urls

    def upload(self, request):
        # Coming soon
        pass

admin.site.register(ProductKey, ProductKeyAdmin)

When creating the url it’s important to decorate the view with self.admin_site.admin_view() to incorporate admin permissions. The name= parameters provides a name for linking to the page with the url() function. The Django standard is ‘app_model_action’. We’ll see how to link to this in view template.

Now in the view template file we to extend admin/base_site.html, but use the form styling of admin/change_form.html.

<!-- storefront/products/templates/admin/products/productkey/upload.html -->

{% extends "admin/base_site.html" %}
{% load i18n admin_urls admin_static %}

{% block extrastyle %}
    {{ block.super }}
    <link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}"/>
{% endblock %}

{% block breadcrumbs %}
    <div class="breadcrumbs">
        <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
        &rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst|escape }}</a>
        &rsaquo; {% if has_change_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">
        {{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
        &rsaquo; {% trans 'Upload' %}
    </div>
{% endblock %}

{% block content %}
    <form action="{% url opts|admin_urlname:'upload' %}" method="post" id="productkey_upload_form"
          {% if form.is_multipart %}enctype="multipart/form-data"{% endif %}>
        {% csrf_token %}
        <div>
            {% for fieldset in adminform %}
                {% include "admin/includes/fieldset.html" %}
            {% endfor %}
        </div>
        <div class="submit-row">
            <input type="submit" value="Submit" class="default"/>
        </div>
    </form>
{% endblock %}

This adds the forms CSS that’s used by change_form.html.

{% block extrastyle %}
    {{ block.super }}
    <link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}"/>
{% endblock %}

This block updates the breadcrumbs like change_form.html, but adds ‘Upload’ as the last crumb.

{% block breadcrumbs %}
    <div class="breadcrumbs">
        <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
        &rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst|escape }}</a>
        &rsaquo; {% if has_change_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">
        {{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
        &rsaquo; {% trans 'Upload' %}
    </div>
{% endblock %}

This section adds the form. The ‘admin/includes/fieldset.html’ template outputs the form fields in the same format as admin/change_form.html. Notice the admin_urlname:'upload', that translates into ‘admin:products_productkey_upload’ and matches the url we added. The one thing we are missing is the adminform object. We need to create that in our view method.

{% block content %}
    <form action="{% url opts|admin_urlname:'upload' %}" method="post" id="productkey_upload_form"
          {% if form.is_multipart %}enctype="multipart/form-data"{% endif %}>
        {% csrf_token %}
        <div>
            {% for fieldset in adminform %}
                {% include "admin/includes/fieldset.html" %}
            {% endfor %}
        </div>
        <div class="submit-row">
            <input type="submit" value="Submit" class="default"/>
        </div>
    </form>
{% endblock %}

In our view method we need to mimic the same view context as the change admin requests.

# storefront/products/admin.py

from django.shortcuts import render
from django.contrib.admin import helpers

class ProductKeyAdmin(admin.ModelAdmin):
    def upload(self, request):
        context = {
            'title': 'Upload Product Keys',
            'app_label': self.model._meta.app_label,
            'opts': self.model._meta,
            'has_change_permission': self.has_change_permission(request)
        }

        # Handle form request
        if request.method == 'POST':
            form = ProductKeyUploadForm(request.POST, request.FILES)
            if form.is_valid():
                # Do CSV processing and create ProductKey records
        else:
            form = ProductKeyUploadForm()
        context['form'] = form

        context['adminform'] = helpers.AdminForm(form, list([(None, {'fields': form.base_fields})]),
                                                 self.get_prepopulated_fields(request))

        return render(request, 'admin/products/productkey/upload.html', context)

admin.site.register(ProductKey, ProductKeyAdmin)

We need to populate the view context with some data used by admin/base.html and in our template to create the breadcrumbs.

        context = {
            'title': 'Upload Product Keys',
            'app_label': self.model._meta.app_label,
            'opts': self.model._meta,
            'has_change_permission': self.has_change_permission(request)
        }

The key piece in mimicking the admin/change_form.html is recreating the adminform object. To do that we use the AdminForm helper and pass it a custom fieldset argument. The fieldset is created from our upload form’s fields rather than the default model form. Reference django.contrib.admin.options for how the adminform is normally created.

        context['adminform'] = helpers.AdminForm(form, list([(None, {'fields': form.base_fields})]),
                                                 self.get_prepopulated_fields(request))

With all those pieces put together you’ll end up with a custom form that has styling just like the default change form. Here’s what my example looks like:
Django Admin Custom Form Styling

Installing custom Plex plugins on a Drobo 5N

I recently wanted to install a 3rd party plugin on Plex on my Drobo 5N. I couldn’t find any documentation on how to do this complete process so I thought I’d document it here.

Currently there’s no official plugin for watching twitch.tv via Plex. There is 3rd party plugin someone created available on github, https://github.com/pejoo/Twitch.tv-Plex-Plugin. The instructions say to put this in the Plex Media Server’s plugins folder, but how do we access that when it’s on the Drobo? Here’s the steps I followed to install a custom plugin, specifically the twitch.tv plugin.

First we need to access the drobo apps share which is hidden by default. To find it you need to connect directly to the Drobo file share with the IP address. You can do this on windows with \\ or on Mac with smb://. For more info see this article: http://support.drobo.com/app/answers/detail/a_id/464

Now download the twitch.tv plugin from github: https://github.com/pejoo/Twitch.tv-Plex-Plugin

Extract the zip file and copy the Twitch.tv.bundle folder to DroboApps\plex\Library\Plex Media Server\Plug-ins

You should now see the Twitch.tv channel in Plex.

You may have to install a fix if the Twitch.tv plugin isn’t working, see https://github.com/pencil/Fix-Twitch.tv-Plex-Plugin

Note that you cannot view Twitch.tv streams in the Plex web player due to cross domain issues. You will get the error “Cannot load M3U8: crossdomain access denied”. See https://github.com/pejoo/Twitch.tv-Plex-Plugin/issues/9 for more details.

Bug in CakePHP Containable Behavior, Related Records not Being Returned When Parent Contains a Single Field

I just stumbled on a bug in CakePHP that prevents related child records from being returned when only selecting a single field from the parent. It looks something like this:

$this->Model->find('all', array(
  'contain' => array(
    'Parent' => array(
      'fields' => array('id', 'type'),
      'Child' => array(
        'fields' => array('id', 'type')
      )
    )
  )
);
// Returns as expected
//array(
//  'Model' => array(...),
//  'Parent' => array(
//    'id' => '',
//    'type' => '',
//    'Child' => array(
//      array(
//        'id' => '',
//        'type' => ''
//      ),
//      ...
//    )
//  )
//)

Now if we modify the contain for Parent to only return one field we lose all Child records:

$this->Model->find('all', array(
  'contain' => array(
    'Parent' => array(
      'fields' => array('id'),
      'Child' => array(
        'fields' => array('id', 'type')
      )
    )
  )
);
// Returns no Child records
//array(
//  'Model' => array(...),
//  'Parent' => array(
//    'id' => '',
//    'type' => '',
//  )
//)

This is due to a bug in Model/DataSource/DboSource.php in the _mergeAssociation method. On line 1401 it checks count($merge[0][$association]) > 1 before it will merge the records. Since Parent only has one field, ‘id’, it does not do the merge. This has been corrected in CakePHP 2.4.2 to !empty() instead of count() > 1.

This has been fixed in the CakePHP master branch with this commit: https://github.com/cakephp/cakephp/commit/940a51b5faa0b88fa5334764c19f93fe8364ef30

Logitech mouse freezing USB when switching applications in mac os x

I was having a mysterious problem with my USB inputs freezing on my mac after upgrading to Mavericks. The problem happened intermittently and would freeze all USB inputs for about 10 seconds. The rest of the computer would perform normally. After some troubleshooting I finally traced this down to the Logitech Control Center and application specific configuration for my mouse. It would freeze when switching to the application I had custom settings for, most consistently when using the cmd+tab shortcut. Removing the custom settings would no longer cause USB to stop working when switching to the application.

After some searching I was able to find a post on the Logitech forums about this issue. Other people are having the same issue and it looks like they need to update their drivers for Mavericks. I tried installing the latest version of Control Center (3.8) and the problem still exists.

As an alternative to Control Center you can use USB Overdrive which allows for application specific configuration. Or you can simply remove your application specific settings until Logitech releases a fix for Control Center.

Magento – Link to page through WYSIWYG editor

For Magento 1.4.1.1.

It’s not obvious how to link to a page through the WYSIWYG editor. There doesn’t appear to be any valid documentation on it in the Magento website either. Thankfully I found this post: http://screencastworld.com/2010/03/magento/magento_tips_tricks_and_hacks/magento-tips-tricks-and-hacks-4-how-to-link-pages-using-store-url-short-code

Basically {{store url=”page-slug”}} will be replaced by Magento as if you called $this->getUrl(“page-slug”). It’s easiest to just swap to HTML edit mode and insert that code into the href manually.

Magento – Action elements and helpers in layout

This is relevant for Magento 1.4.1.1.

I have been unable to find any decent documentation on how Magento handles the <action method=”…”> element and helpers within the arguments. After some debugging I found the method responsible for handling these elements. Take a look at app/code/core/Mage/Core/Model/Layout.php on line 289 at the _generateAction method. This method takes the <action> element as $node. It loops through all the child nodes (what would be the method arguments) and turns them into an associative array. If any child node has the “helper” attribute specified it will use that helper to get the value. You can pass arguments to the helper method with further child nodes. This is better illustrated through an example:

<reference name="breadcrumbs">
    <action method="addLink">
        <label>New Link</label>
        <url helper="core/url/getUrl"><page>new-page</page></url>
    </action>
</reference>

This has the effect of making the following calls:

Mage_Page_Block_Html_Breadcrumbs::addLink(
    'Add Link',
    Mage_Core_Helper_Url::getUrl('new-page')
);

The above is merely an example the addLink and getUrl methods do not exist. As far as I’ve found there’s no way to get a generic URL through any helper. In addition the element names for the arguments are only by convention. They are passed in order and the names do not matter.

So in summary:

  • The <action> element calls the “method” attribute on the parent block’s class. Mage_Page_Block_Html_Breadcrumbs::addLink.
  • The child elements are passed as arguments in order. <label> and <url>.
  • Any child elements specifying the “helper” attribute will use that class and method to determine their value. Mage_Core_Helper_Url::getUrl.
  • Any child elements of an element specifying the “helper”attribute will be passed as arguments to the helper method. <page>.

Unfortunately you cannot use helper methods any further down the chain. For example a call to the addCrumb method might look like this:

<reference name="breadcrumbs">
    <action method="addCrumb">
        <crumbName>newlink</crumbName>
        <crumbInfo>
            <label>New Link</label>
            <link>new-link</link>
        </crumbInfo>
    </action>
</reference>

The crumbInfo argument is an associative array. While Magento will construct the array correctly you cannot use a helper on the <link> element where it would be quite useful.

Magento – Add new layout

This is the first in a, hopefully, useful series of quick how-tos for Magento. All of them will be referencing Magento 1.4.1.1.

To add a new layout to Magento that is available in the CMS you’ll need to edit

app/etc/local.xml

To insert the <page> element like:

<config>
    <global>
        <page>
            <layouts>
                <three_box module="page" translate="label">
                    <label>3 box</label>
                    <template>page/3box.phtml</template>
                    <layout_handle>page_three_box</layout_handle>
                </three_box>
            </layouts>
        </page>
    </global>
</config>

To make the layout default you can also add

<is_default>1</is_default>

The layout can now be selected in the CMS as “3 box”. It will use the page/3box.phtml to render in whatever theme you are using. For example:

app/design/frontend/base/default/my_theme/template/page/3box.phtml

To reference the new layout in your layout XML files you use the <layout_handle> value. In our example, <page_three_box>.