bash ImageMagick Image Slicer

This is a bash script which accepts an image file, determines the width and height, and creates five vertical segments. It can be used to create a ‘puzzle’, tiles, CAPTCHA sequences and other interesting visual effects.

#!/bin/bash
if [ "$#" -le 2 ]; then
       echo "usage: $0 <base directory> <image file> <segments> [<imagemagick directory>]"
else
BASE_DIR="$1"
ORIGINAL_IMAGE="$2"
SEGMENTS="$3"
if [ "$#" -ge 4 ]; then
        IMAGEMAGICK_DIR="$4"
else
        IMAGEMAGICK_DIR=''
fi
RESIZED_IMAGE="image.jpg"
IMAGE_WIDTH=300
"$IMAGEMAGICK_DIR"convert "$BASE_DIR$ORIGINAL_IMAGE" -resize "$IMAGE_WIDTH"x +repage "$BASE_DIR$RESIZED_IMAGE"
IMAGE_DIMENSIONS=`"$IMAGEMAGICK_DIR"identify "$BASE_DIR$RESIZED_IMAGE" | cut -f 3 -d ' '`
SEGMENT_WIDTH=$((`echo "$IMAGE_DIMENSIONS" | cut -f 1 -d 'x'`/$SEGMENTS))
SEGMENT_HEIGHT=`echo "$IMAGE_DIMENSIONS" | cut -f 2 -d 'x'`
echo '<?php'
echo define\(\'SEGMENTS\',"$SEGMENTS"\)\;
echo define\(\'IMAGE_WIDTH\',"$IMAGE_WIDTH"\)\;
echo define\(\'IMAGE_HEIGHT\',"$SEGMENT_HEIGHT"\)\;
echo define\(\'SEGMENT_WIDTH\',"$SEGMENT_WIDTH"\)\;
echo define\(\'SEGMENT_HEIGHT\',"$SEGMENT_HEIGHT"\)\;
for A in `seq 0 $(($SEGMENTS-1))`
do
       SEGMENT_OFFSET=$(($SEGMENT_WIDTH * $A))
       "$IMAGEMAGICK_DIR"convert "$BASE_DIR$RESIZED_IMAGE" -crop "$SEGMENT_WIDTH"x"$SEGMENT_HEIGHT+$SEGMENT_OFFSET+0" "$BASE_DIR"segments/"$A".jpg
done
"$IMAGEMAGICK_DIR"convert "$BASE_DIR$RESIZED_IMAGE" -colorspace gray -level 0,80%,4.0 "$BASE_DIR"target.jpg
fi

The last convert command creates a a faded version of the image.

Further customization could include segmentation on a different axis, different image file formats, etc.

BlackBerry Web Development - SDK

BlackBerries now have a very cool widget development approach, you can build a web interface, run it through an SDK and it will create the widget or .cod file.

My goal was to learn, to see what it is, what it can do, and decide whether I can use it for some of my projects.

What is it? - I chose to use the command line version of the SDK, because I don’t use Eclipse or Visual Studio (which the SDK can plug into). I had to install some Java DK files as well, you can find references to them in the BlackBerry installation and set up documentation. I didn’t set up a path to the bbwp.exe, I used a relative path to reference it from the widget directories. Worked fine.

What can it do? - I saw the Widget SDK as a tool which would allow me to create cross-platform widgets, where a common core of code could provide key features, and device specific APIs would allow access to device stores such as the call logs, events, phone features, and audio. BlackBerry has an excellent API into those features, and I suspect it will be extended as this approach gains momentum. It’s an excellent balance of proprietary and custom features with a common access method. The two APIs I tested with audio and contact interfaces.

Can I use it? - Yes, but not yet. After I finished, I felt the greatest advantage was that it allows you to create a web application packaged as a widget. Potential issues include ensuring the widget version is updated to stay synchronized with the server, which would not be an issue if the code was delivered directly from a server. It does allow an off-line version. I had a general application in mind, and I think I would wait to see the system mature a little before building.

What I learned

  • It’s Windows based. I may be wrong, but it looks like you need a Microsoft machine for development.
  • It’s new. Everyone is still learning, and I would expect things to change.
  • It works. The process to assemble a widget with the SDK/widget packager does work without any surprises.
  • If it doesn’t work (meaning I made a mistake), it doesn’t work (meaning there aren’t any packaging or run time errors, it just doesn’t work.)
  • The command line packager process was not streamlined. My approach was the following:

    1. Use Windows Explorer to navigate to my widget source code directory
    2. Edit with Notepad
    3. Zip with 7Zip
    4. Navigate to the widget source directory on the command line
    5. Run bbwp.exe using a relative path to the executable
    6. Load the .cod file into the simulator (delete any existing versions first, or reset the simulator)
    7. Test
  • The .jar files referenced must be included in the .zip file prior to packaging. The documentation says to place them under the ext directory, and the ext directory has to be at the same level as the index.html and config.xmlfiles. Be sure to add them into the .zip file
  • A great appreciation for the approach. Although I’m not likely to use it (to me a Smartphone is just a phone, not worthy or in need of nifty software), it is definitely a revolutionary way to allow developers to support multiple devices with a core set of functionality. That said, adoption by other mobile device makers is necessary to make this of value. In all likelihood, there will be some common ground and some custom elements for every device. Innovative package assembly may make it possible to create platform independent applications and widgets. If that is the long range goal, the application architecture must be designed carefully, separating the core functionality from device specific interfaces.
  • Using Eclipse would probably speed the edit/test/revise cycle.
  • If I was a BlackBerry developer, I’d definitely test it out.
  • Audio file delivered through the browser to a BlackBerry are not cached on the device (http://docs.blackberry.com/en/developers/deliverables/5687/BlackBerry_Browser-4.7.0-US.pdf)

    Streamed content is not saved; users cannot replay media unless they download it again.

    This was a side trip.

  • SmartPhones will play an increasingly important role in content and application delivery, web applications should consider providing suitable interfaces for them.

http://www.blackberry.com/developers/docs/widgetapi/
http://docs.blackberry.com/en/developers/subcategories/?userType=21&category=BlackBerry+Widgets&subCategory=BlackBerry+Widget+Sample+Applications

Create Database with MySQL

If you don’t have phpMyAdmin, cPanel, or Plesk, you can SSH into the server and use the following commands:

create user dbuser@localhost identified by 'password';
create database db;
grant all on db.* to dbuser@localhost;

mysql -udbuser db -p

Content Feeds - Facebook and Twitter - Source, Sink or Both?

Facebook and Twitter have become integral parts of web marketing and outreach. Many companies use them in innovative ways to reach people.

Twitter - Twitter is an extremely efficient distribution medium. Tweets are easy to issue from a phone, laptop or desktop. In seconds, you can share a message. The value of the message is directly related to the content. If the message is ‘the service is back up, we’re sorry for the outage’, your clients will be relieved and happy to receive it. An alert that you posted substantial content for review may not be as welcome, unless you are a news service. Take the time to determine where site visitors are coming from for whitepapers and videos to decide whether to post that type of information. This is vital, because diluting a twitter feed with content people aren’t interested in will reduce its effectiveness. Your tweets will be dismissed without even being read. If you aren’t a realtime, high energy organization, twitter may not be a good tool.

Facebook - Facebook is powerful because people can select to receive your posted content, and it allows more content to be posted. Thus, facebook content is distributed within a community that is choosing specifically to follow you. Examining the site stats and facebook participation can help you to decide whether to invest the time in creating and managing a facebook presence or to push content from your site into facebook.

Twitter and Facebook help you reach people, but they also dilute posted content by surrounding it with unrelated material, which may be more interesting than yours.

An excellent approach is to invest in high quality content on your site which engages visitors by assisting them. Do your products and services save people and organizations money? Show them how with a calculator that they can use. The output should be easy to understand, include plenty of explanation, and, if appropriate graph or plot the data for a quick visual assessment. If possible, include comparisons and adjustments to allow further analysis. Explain the services you offer, if you can’t explain them concisely, consider changing them until you can. Educate site visitors with whitepapers, but only if it is informative, not advertising. Posting videos on your site, or sourcing them from YouTube is good, but only if the videos are well done. Well done may mean funny, creative, or entertaining, as well as informative. Video is primarily an entertainment media, many people want to be amused as they receive your message.

The site content will draw visitors from search engines, they will stay on the site if it has value, answering their questions, or entertaining them.

The home page of the site should include a ‘new content’ feed, and the same feed should be filtered out to facebook and twitter if appropriate. Sourcing facebook and twitter content on your home page will filter out unrelated posts, but, once people are on your site - the facebook and twitter content may not justify the page space it consumes. A link so people can connect into those resources is often better.

Word 2007 VBA Macro to Assemble a Manual from Chapters

The following VBA macro allows you to scan a directory for subdirectories and add INCLUDETEXT fields with additional bookmarks to create a master document which can be used to create several different versions of the same content. It will also create stubs for each chapter, based on the admin types.

This is very helpful for manuals.

This macro was used with a master docm file which was supported by a directory called Chapters. The Chapters directory had a numerically named subdirectory for each chapter, and within each chapter there were documents for all the admin types, as well as a Common.docm file which included text for all admin types. The content control is in the admin type file, which can be empty to omit the chapter from the manual, a single INCLUDETEXT of Common.docm to just display the common text, or any other appropriate content.

MasterDocument.docm
Chapters

  • 1

    • Common.docm
    • System.docx
    • Application.docx
    • Editor.docx
    • Guest.docx
  • 2

    • Common.docm
    • System.docx
    • Application.docx
    • Editor.docx
    • Guest.docx

The document needs two fields, AdminType and BaseDir. AdminType must be one of those listed in the AdminTypes array, BaseDir must be set to the base directory for the document. I used ASK fields, but a SET should be fine as well.

The document also needs two bookmarks, “ChapterBlockStart” and “ChapterBlockEnd", which indicate where the chapter includes are to be placed.

Chapter numbering is managed with a SEQ field in the master document. Each chapter’s common.docm has a SEQ reference which increments the chapter number. This ensures the chapter numbers are contiguous even if some chapters are omitted for a specific admin type.

Option Base 1
Option Explicit
Global AdminTypes

Sub Init()
'   Initialize AdminTypes array
    AdminTypes = Array("System", "Application", "Editor", "Guest")
End Sub


Sub FindChapters()

Init

Dim CleanStart, CleanEnd, CleanRange
Dim I, L, T, D, Done
Dim Range
Dim BaseDir, ChapterDir, RootDir
Dim AdminTypeRange, BaseDirRange

' This code removes the old chapters, so you can run the macro on a document to update it if you have
' added more chapters.

CleanStart = ActiveDocument.Bookmarks("ChapterBlockStart").Range.Start
CleanEnd = ActiveDocument.Bookmarks("ChapterBlockEnd").Range.End
Set CleanRange = ActiveDocument.Range(Start:=CleanStart, End:=CleanEnd)
CleanRange.MoveStart wdCharacter, 1
CleanRange.MoveEnd wdCharacter, -1
If CleanRange.Characters.Count > 1 Then CleanRange.Cut

' Position the range at the start of the ChapterBlock
Set Range = ActiveDocument.Bookmarks("ChapterBlockStart").Range

' Get the value of BaseDir.  This is probably terribly inefficient.
I = 1
L = ActiveDocument.Fields.Count()
For I = 1 To L
    T = ActiveDocument.Fields.Item(I).Code.Text
    If (InStr(1, T, "BaseDir", vbTextCompare) <> 0) Then
        BaseDir = ActiveDocument.Fields.Item(I).Result()
    End If
Next

' Loop through all the chapters.  The directory is named 'Chapters'
D = FileSystem.CurDir()
RootDir = BaseDir + "\Chapters\"
I = 1
' This is actually an infinite loop.  It uses On Error to terminate when it runs out of chapters
Done = False
While Not Done
    ' Name the chapter directory
    ChapterDir = RootDir + Trim(Str$(I))
    ' If you can't change into the chapter directory, you're done
    On Error GoTo AllDone
    ' Change into the chapter directory
    FileSystem.ChDir (ChapterDir)
    ' This ensures there is a file for all the admin types for that chapter
    CreateChapter (Trim(Str$(I)))
    ' Each chapter is in a section, on a new page
    Range.Sections.Add Range, wdSectionNewPage

    ' Create the INCLUDETEXT tag
    Range.Fields.Add Range, wdFieldIncludeText, Chr(34) + "BaseDir\\Chapters\\" + Trim(Str$(I)) + "\\AdminType.docx" + Chr(34)

    ' Add in the BaseDir and AdminType fields, so the document is portable and adapts to the admin type
    Set BaseDirRange = Range.Duplicate
    BaseDirRange.Find.MatchCase = True
    BaseDirRange.Find.Text = "BaseDir"
    BaseDirRange.Find.Execute
    BaseDirRange.Fields.Add BaseDirRange, wdFieldEmpty, , False
    Set AdminTypeRange = Range.Duplicate
    AdminTypeRange.Find.Text = "AdminType"
    AdminTypeRange.Find.Execute
    AdminTypeRange.Fields.Add AdminTypeRange, wdFieldEmpty, , False
    AdminTypeRange.Collapse wdCollapseEnd

    ' Advance the range pointer
    Range.MoveEnd wdSection, 1
    Range.Collapse wdCollapseEnd

    ' Increment the chapter counter
    I = I + 1
Wend
AllDone: MsgBox "Found " + Str$(I - 1) + " Chapters"

' Update the fields
ActiveDocument.Fields.Update

End Sub

Sub CreateChapter(C As String)
    Dim I, L
    Dim NewDoc, NewRange, BaseDirRange
    Dim FileName
   
    I = LBound(AdminTypes)
    L = UBound(AdminTypes)
    ' Loop through all the admin types
    For I = 1 To L
        FileName = AdminTypes(I) + ".docx"

        ' If the document doesn't exist
        If (Dir(FileName) = "") Then
            ' Create the document
            Set NewDoc = Documents.Add
            Set NewRange = NewDoc.Range
         
            ' Add an INCLUDETEXT field to include Common.docm which would be the chapter content common
            ' to all admin types.
            NewRange.Fields.Add NewRange, wdFieldIncludeText, Chr(34) + "BaseDir\\Chapters\\" + Trim(Str$(C)) + "\\Common.docm" + Chr(34)
            Set BaseDirRange = NewRange.Duplicate
            BaseDirRange.Find.MatchCase = True
            BaseDirRange.Find.Text = "BaseDir"
            BaseDirRange.Find.Execute
            BaseDirRange.Fields.Add BaseDirRange, wdFieldEmpty, , False
            NewRange.MoveEnd wdSection, 1
            NewRange.Collapse wdCollapseEnd

            ' Save the new file, named by the role and close the window
            NewDoc.SaveAs FileName
            NewDoc.Close
        End If
    Next
End Sub 

Sincere thanks to the referenced link. If you have questions about the field insertion, you will find the answers there.

For the table of contents, I extended the ChapterBlockStart and used it to indicate the content to include. The footer included the page number with a chapter prefix.