Copy icons in OSX

Sometimes I just want to change a default icon (e.g. for a folder) in OSX. So where to do this? First you need a source image to copy. These days (OSX 10.9.4 when I write this) just about every image you can preview can be used, as well as other Application or Document icons. It wasn’t always so.

Say for instance we want to use the Blender icon for the folder it occupies in our Applications folder. The default is the boring blue folder:

Screen Shot 2014-07-13 at 14.00.50

 

 

 

 

 

 

I enter the Blender folder, select the actual Application and choose Command – I to get the Info window:

Screen Shot 2014-07-13 at 14.02.22

 

 

 

 

 

 

 

 

 

 

 

The trick is now to select the small upper icon and Command – C it:

Screen Shot 2014-07-13 at 14.03.27

 

 

 

 

 

 

You can then do the same for the Folder where all the Blender files live in…

Screen Shot 2014-07-13 at 14.04.27

 

 

 

 

 

 

….except this time Command – V the copied image into it:

Screen Shot 2014-07-13 at 14.05.50

 

 

 

 

 

 

 

Voila:

Screen Shot 2014-07-13 at 14.06.52

 

 

 

 

 

 

 

 

Routing audio in max/msp

In something I’m making in max/msp I want to switch the order of a filter and a saturation stage. This seemed easy enough with a a few gate~ objects, but the output was muted all the time when I connected the (inactive) outlet of the gate~ back to the inlet of an object. This is counter intuitive. To explain, this of course works (noise output):

Screen Shot 2014-07-07 at 20.02.18

 

 

 

 

 

 

 

 

But this next situation mutes the instant you connect the closed gate~ outlet back to the dummy +~ object (which is there because max 6 refused to connect that gate~ outlet to a gate~ inlet):

Screen Shot 2014-07-07 at 20.03.18

 

 

 

 

 

 

 

 

 

I guess it all makes sense from a max/msp implementation standpoint and protects us users from stack overflows and such, but how then do we route audio? Using send~ and receive~ it is easy to deceive max/msp, and this works just fine:

Screen Shot 2014-07-07 at 19.55.34

 

 

 

 

 

 

 

 

 

 

 

This way the noise~ output can be routed p gain -> p level -> easydac or p level -> p gain -> easydac. Awesome! Here’s the code:

 

 

----------begin_max5_patcher----------
1447.3oc6Z0sjhpCD9Z8ofhaOytEI.pL2cdN1yTSEgnlcwfUH33rSsyy9I+.
XPIXbKWFOmZpoDgjNjt+R2ecm371zI9KKNfK88dz6adSl71zISTMIaXR8yS7
2hNjliJUh4mVrcKlx8eP2GGefqZeMhP8Pq3Xl2Vr3Zi.qJn7RxOwRg.vuFT2
LsZKgli4pWJnQV15kxmCLEqnh2HWSqKWmVjWvzpMPHrXDIfP.LRdWXRHHLQd
Gbg2S0CYGhmtgPW+LCmx0CbVfZnIgxqfvH4WPwT2NFRlxxJV98uDBLsGJZqx
d7+aFAk6K63WSmJu7vs.EWhWUvv+WAFiiRjCMdtKvXvsEF2hKKQqwmAio4XD
Sn5d.0eP0GwSMBpAC9q6vZav2uUacAng8Bq.6XTTrxIKYlBifJ.CrneLBlLx
XTCJIwH3GHFodShnRWvnE2VLhheQ7ZOChDJGlrG+tWAzJpTRVSES5UgMfqEa
lCTdNvHkaz7vghw.fQAaJwzLSf422tCFfaIQ4SDlX3ZX0tCFYeBvGqOwLXny
9DIioKA3OqKQXfytDKFmj1GdziP2Uw+G5qO5IrBwsMxjSn3zhJJ2jR7NNWtF
bAyhNBtgg8CtyuwooPbF4PJmkaMrJmTJ.15uaUIGbmZ.dADUskpZJrtIVwKc
d1dhoZPA.TekjzOpD429hXHUEbOionk4JaH31Eqogq28B8BuDMzC8eWWTzEe
xvdA2nKGqFUWTX7f0FNJbT67jkXeevbmnPmnAYtgCkM2bJvrZvnFMDCfji2i
YkjBpgBMwGsamQySLFhDB+tlDY1CsMQn5l.sMwv6IMi+nfHlvP4BqrhoUxCK
l4q6TrrMsYnMn.T4TDuPY8yz02jXv0H4zxKR+ANyfmSrjsCSErsLrHaCGwq0
h1tyvqPU47m6egqa+qPoXqCtWndh+ZFIqfJUhNiT1byzI3eUN5xqGMFkDTzt
dFbovNpJWhXRTslp.1zIunHuaWsKjh..DkHXBvbhVYgAsuTx1cLhNuSaaZln
Mkorh77NuJcO66omLwZcJ9ERFeSm7PxdDhS10rD32hQYj03Rd213n0kcaoyI
OX5DZFY2o8Shv0AaMuOagk1yYZeyZJeQ8V1fwMWaWJsvaUmgQWhfxRaZVwbU
GF7aZqJyxbhtDy043QfU7.3Dd.bCNfiAbjKp.+qRh72Mms8HVaTa+R3TJR4m
U4Enyq0v5tb6ATicATmqOzjXMeQ3b6vJvuy667ZKLWDKQ6wYOi3hRDVVwwGu
qz.aM.WIzkWgKVY1sY+lSYdAc8vvbGwK2Tv3Wg7MKNAV5eq.8k8+k4GohNWF
jxKZlUIHTBWRqqVKB5B6cDrRHXI+UMFGcTlVmXyaM7rOR7K2BfEdNkegr+9c
4KKpXoMdp0NAdc8PDbvbBsMM32ZojNQtMjrrtYczD0kR2mr1ZSuX340pwPG0
XvMRi8dZpY8F0QBhYPD30SXva2npBtbUGWQpxdUhAlbaSpn5okn75hCaGaOY
jmdDDuUEYKq7L+93Lypqxdv8d.R9+ZU1gyzVux7CiAsPxmkY+YY128kdVWzI
zsROiGiRO6P40k16udWrtc0HkkPnqnTSm.QflNLbwo7f1NAqgNKlaDV9mZGb
0tMZtu6jcvoxHppob3cjnHSd55gjK3DrPgEI5ivDpbBjmmo8cwMV0zF6XEhQ
2M0z5pFCuaz3nQdeCeVE98PU3zBRI98O1hvq+E.ZJBe1fG08s8G..+yLTZq4
6v+aBC7iNNSW+bzb3w8RDEaYuDlJqRftzkZc+zP3ZK3rPWYHIrcZru4YPqLm
Exdd35YH4sVaBFEsIoyLYgDd7TmHGTmvQSaBcPaVLpZC3RNNAil5.cw0IZ7T
mE2WpCvQO4wgzAdWEWARbTcfii53xZ0I5r65iN80IGkkTUN4HrN43qN+nqrc
rUh44WS+WQk32T.
-----------end_max5_patcher-----------

Controlling TouchOsc via Python and maxmsp

Controlling an OSC client via Python is super easy thanks to the python-osc module. You install it via pip:

 

thingthohmmmmmm:~ henszimmerman$ pip3 install python-osc
Downloading/unpacking python-osc
  Downloading python-osc-1.4.1.tar.gz
  Running setup.py (path:/private/var/folders/wz/7t75jnps3m5dvmrqd4kwpglh0000gn/T/pip_build_henszimmerman/python-osc/setup.py) egg_info for package python-osc
    
Installing collected packages: python-osc
  Running setup.py install for python-osc
    
Successfully installed python-osc
Cleaning up...

With that out of the way, it takes just a few lines of python to control the super great fun TouchOsc iPad app (in this case its monome128 template):

# Python3 on OSX controls OSC UDP iPad client TouchOSC
# with the monome128 template.
# H.Zimmerman, July 4, 2014.

from pythonosc import osc_message_builder
from pythonosc import udp_client

import random
import time

# Hardcoded IP of TouchOSC on my iPad and port 9000.
# TouchOSC has monome 128 template loaded.

client = udp_client.UDPClient('192.168.178.31', 9000)

# Turn on and off 100 times.
# We start with 1, else the TouchOSC LEDs are turned off first
# which suscipiciously looks like it isn't working.

for counter in range(1, 100):

    # Monome128 template has (duh) 128 buttons.

    for buttonIndex in range(128):
        # Build the OSC address of the pushbutton we want to control.
        buttonAdr = '/1/push' + str(buttonIndex)

        # Some console output for our nerdy debugging fun.
        print(buttonAdr)

        # Now construct an OSC message.
        msg = osc_message_builder.OscMessageBuilder(address=buttonAdr)
        msg.add_arg(int(counter % 2))

        # Send it to the iPad.
        client.send(msg.build())

        # Slow down, OSX, else it's over before we know it.
        time.sleep(.1)

I was already having a lot of fun controlling TouchOsc via UDP using max/msp.

Screen Shot 2014-07-04 at 21.34.24

 
 
 
 
 
 
 
 
 
 
 
 
 
 

In case you want this max patch for experimentation fun, here’s the code:

----------begin_max5_patcher----------
1653.3oc4a0saaaCF8ZmmBBgMf01DW9qnztYXXO.6hc4ZQgrEiiZkkDjjyRa
We2GEoUhaijEcMImRZBjULMk8QG+8c99gLe9hEAqJuSzD.9UveCVr3yWrXgZ
ntAVr+4KB1lb257jF0zBVWtcqnnM3R8q0JtqUMdSaYU+fE61lUjKZUWA5gAK
201OJb+nYopqtb06uhh6u9qKKZKR1JTuzuWmkje+qTuYk5xWBOXtMYeRMWD9
9gqRZWeSVwl2UKV2pu+XQQxWFfwpSD7Rl7Ix2Hva6tjubwEcOb4YRCU4Ie77
nAB2wz.jqtysBMrUzzjrQ7HZ.NHGfGjC5YF8PserRnAZP.3sCPOgFPOFSFgx
67ukLPQVlLPtiLn1jLXT3ibP9tIiBw+HQ3i3hZ4Ml.fBoxCl7HTdvkGQxiX.
hOrgSzfbUznb0kG4XPdDYUipX7RbG2wzBNPj9jkYRwFwcUfWWsq4le4MxeRe
0KV9xSP6gYL8MDkgsqeXnhpPXr5DJ7rXrbQ5Q4gpjZIdaE0uSTjrJWbnRrgt
iYRs+gnkPRv32kbl1AiC6u8ruYwU.qH2L18GypJNzH022TB+IYrHFwljAGQT
r.h5N42ceJShhnSfQHiwHqRJ1zoNzedTKFnUsXXZKFnRgfFeVtPikD25bQRM
PphzblYzF61T43jXc1KJxficgdRKX0IPBniZsLj4Ak6.en8LBl5BF4O+q+3J
cZLcgdeoMXmgYFpChvFoTZQPmXqrqnJY8G.YfqOARAerPPRckqyKSFVYgZU4
WDDxTbSj5T34wPiELpQzB9I2UP.0pIxRBoc5KgHlNJslddhwH1M7S7SeFgD6
fJnsCiLhtxlDoXK6DHjyqzFRjc0UzAiHDcsMj3mARuDKK8x2msqMjdmnd45x
1j5OpqX9EcO17KKe4K7VcyDnSBZsuvYBysY7nIueyY47fwtfc5S5I1sjyqQ1
v2a7NtfbA2vTMmJB8TLaGjUijwYpxEbar8Wi1K.wbJwD5.hgyUtQ7nyhXRO.
B2+w+PsucQbj2iU6Z+FWGmzEuwCvgdnrzMqKyKq0WgpkcJek9+59Kd0ilGbv
40AhrBgYStPHRyMbtGwjlROP.TcxMF0TmZTScPdq+XYTydNXT2WwguLpwN0n
1Ekm9ikQM94fQceiEbuQcWSK6V+U3R20gA6JTyWxY8IpRHPWzggcoUxOQQ1s
B.CBgNq9FmjBud0RiicRJ7H3RBeIBGuDeT6ktKXP2Ozi7TNG9y.BzT26uhno
Gkn4GzXXr9YNp8DR8lVUSIdUWWIz+kbnsIMevasnvts+RycTsY.2IaEhlp5r
h1qA6U294zwhXakVTD6fVryP6aiCzINw8x9XtKykAa0kxCGqRyiEpz0hcRik
qSJRK2dhqH9IumIvLGXwPiTlJ7yqgeska1jK9+ZyxfoCpYiNoLmH5xAHLc7u
n9Gsoch79utDfrxNIYzUBGa0zl1SK62nD86DsmllIvfokIfbK70+j0Bhbo9o
KBr7CUofOK5YW+htaoJAGufmFQQJ.EiWhBiVhjVHDDH9zJ9Yf87DyA4.Dg0Y
OFQbQ1iRyoT8lXygayIDwAIUqj1CcSJiYWutr35rMf+EroVTAdSPWoIxS8Cb
0sRPJwg7W2IIFZeVSuABw80zY4JQtQjmaqUAb78Lm8YkX5wpsUAhfNIvu4+U
H06W23eMU0Ttqdc+sx9PafGT8REMsYEIsYkEGLG1WMmaxRSEEGJxjl0zEwPQ
CvA+JyTzHy1Gfl.MccZ3fI4R3vMfbh8F4DZ.ZndCMLpAvA6O1oaKeOMdnyL7
.8Gd59nvS4oS8Kdlje3dCOTSb1CIyK7vla3we1yTizeB8GdHFD6hD4sXWca3
3I4GO5dYh6d2JF5K7X.bh7FZHljFFxe4gQhLIWCjewyTNWTnewCYJm8X+hG5
T1OdDOgyqjwHzYFdLI4PhG0eLIXAk6W7LUxpjP+hmICt6Q6GnI5gj4EdH9CO
3XSKtvOIig4yp1rnRKdxut7W3cLad0KArQgK7n4rQ8RfMyvi+RGCiMIbpGwi
QgSoyK7f8WwW3YVuePFU9kGwiIgKP9K8GT3rJ7ExjvEH+4dgnyK5wD0YOZ7X
h3LxehyH375aKSBc4sDUMJPw2ahg5EqLop5VQcy92SERB1l7d8dxH7R0SyJz
OUs1rA0hay5mudBI0quIqUrtcWsdIVuKJL3htOmubw+AEYN1b
-----------end_max5_patcher-----------

Through the wonders of UDP networking, TouchOsc can easily be bombarded with osc messages from both max/msp and python. Here you can see a silly demonstration of just that:

wxWidgets: drag a file in Windows

sfx

 

 

 

 

 

Disgruntled by the slow and bloated commercial sound effects program we used at work, I decided to write my own blazing fast free light weight version. It is much simpler and uses a flat textfile “database” that’s read straight into RAM. Combined with ISIS network storage, the result is considerably faster and we now solely rely on my program for day to day post production sound effects in every studio and for every audio engineer in our company!

I wrote the program with the fantastic free Code::Blocks C++ IDE and used wxWidgets all the way. You can of course download the full source code and executable on sourceforge.

One thing that took me a while was figuring out how to drag a file from a scrolling list box straight into the Pro Tools timeline (because that’s what we wanna do when we select a sound effect from a list and use it in our sessions).

Let me rephrase that: I have a filename and want the pointed-to file be created in a drag and drop fashion. I’m not coming from an actual file, I’m coming from a filename.

Needless to say, this is just a Windows drag-and-drop, and works just as well for copying a file to a Windows Explorer window or an Avid Media Composer bin. It turns out that you just need a wxFileDataObject object and populate it with the filename via its method AddFile(). Then you create a wxDropSource and populate that with a pointer to the wxFileDataObject using its SetData() method. With the wxDropSource you then do a DoDragDrop():


wxFileDataObject* data = new wxFileDataObject();

wxString fileName = whatever_you_have_to_do_to_get_that_full_filename;

data->AddFile(fileName);

wxDropSource dragSource(this);
dragSource.SetData(*data);

wxDragResult dragResult = dragSource.DoDragDrop();

wxDELETE(data);

// ... assess dragResult, etc.

A good use for Pro Tools’ relative grid option

One of those things in Pro Tools I ignored for years until it dawned on me how handy this could be.

rel

 

 

 

 

 

 

 

Scenario: In a post production timeline (so to be clear: this is not a song) where you work on a timecode grid with frames, some event needs sound effects. This effect happens to be a graphic that ticks away the seconds. You want a beep on every second. Now simply switching to grid mode will not necessarily align the events on the seconds. Place and align the first beep in slip mode, then switch to rel. grid with a seconds grid (see below). You can now alt-drag every next event to the next second. It’s super easy and fast!

rel grid

 

 

 

 

 

 

 

 

 

See the current position in hh:mm:ss in Ableton Live using max-for-live

Display the current position as regular time (HH:MM:SS). Handy if you want to use Live as regular sequencer and need to know the current position in your timeline. Also works as a floating window (many thanks to maxforlive.com user synnack for showing me how to do this!).

position

 

 

 

 

 

 

 

The max-for-live device I built for this purpose is of course hosted on maxforlive.com:

http://www.maxforlive.com/library/device/2376/position

But you can also download it here.

Get the IP address of your machine in max/msp 6 running on OSX

If you have anything to do with OSC in max/msp, you may want to quickly see your machine’s IP address.

Screen Shot 2014-06-29 at 21.28.55

 

 

 

 

 

 

 

 

 

 

Grab the code here:

----------begin_max5_patcher----------
690.3ocyVs0aaBCE9YxuBK+ztjRwDJgr2l1j1EooUooJMskpIC3PbKXirMsY
qq+2muDZoM2nQQUKQwfO9ji+Ne97wgaF3AS4KHRH3MfeB77tYfmm0jwf2x4d
vJ7hrRrz5FLiWUQXJ3P2ZJxBk09GHJfZNATgylSYDvmNEfyyEDoDPYfu9su6
Ok8E7hiqj0fXeje7T1YRxrlRvLtPu96N9r2eJfQTWyEWRYEZ2+HgIA+fp2OQ
ElMD74FcbCmLDDFfh7aQPod2x3MLKLhVZbFmojz+PL1Pg9AKMyZpnrRhxlJn
VeEEol4A24VZQFujKbzBRa1MD3OdxjwHyMiFAN+9XxaTsAsMD0XkgGJ9kfjo
bAZjAGfP2H5DykX8ddWfn4VhjmdwQgvN4ACWYyC3aETbIzrvsCFXFF1yyrzF
khyfaiDbof520DGXgoXVAbCIIZyIIxken.a9EFzNttrDsO4RkthBWPVo9CMI
zGEm3iFm3GFCWWcPz5qCB2DEbe5+fBh.WsP6.pSx0aZZYsPhikPi2JMg1R0P
GZ3wPD0c.b9dv0Lx0Z.rBUKHEjE0ZYMQMU+Q95W3+pW5tSapBKuDtGxvUo+g
O52Fn4S1IMGEzCZN4vp41.2Uxw4Vo0gfg1SM5ntRz3sKQGcXYkModoyx3rYz
BveAEBRMXJzTcouzZ3nqzzi97S+E8T3tdHtep71IcqlPIqm3heVpljyIkkGL
w11JmB2IsLoOOKKpezh8uZ6r+n2Mwt8F6Ojqj7FQVap3Zsne57c.HmHUTFVQ
0MAu2m3G3ybZdNg0sEdNUhSKIVvGr1yrdilQ+WAm3dflnmMzD0Czj7rgFyNg
1AZLMj63T+giqrFWWeEQHWFSKRzh8Kb8tiGZmRYtoV8ptg6UzV+cNfEZUnRK
AaDNIzhjXs.RuO2N3e.EfA7A
-----------end_max5_patcher-----------

TBJPG DLL

A DLL I made for Asymterix ToolBook II Instructor years ago proved to be interesting for lots of people and has been used in TBII for many years by lots of institutions and individuals. Because it was free, I got a lot of thank you notes.

You can still download it here.

The source code (Borland C++Builder) was surprisingly terse:

//---------------------------------------------------------------------------
// Almost no programming at all by Hens Zimmerman
// Borland C++Builder 4 PRO
// 07/07/1999 - freeware
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <jpeg.hpp>
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE, DWORD, PVOID){
    return 1;
}
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) BOOL PASCAL TransferJPEG(
        PCSTR jpegFile,
        PCSTR bmpFile){
    // attempts to xfer jpegFile to destination as a BMP
    TJPEGImage *bmp1 = new TJPEGImage();
    Graphics::TBitmap *bmp2 = new Graphics::TBitmap();
    BOOL bRet = TRUE;
    try{
        bmp1->LoadFromFile(jpegFile);
        bmp2->Assign(bmp1);
        bmp2->SaveToFile(bmpFile);
    }
    catch(...){
        bRet = FALSE;
    }
    delete bmp2;
    delete bmp1;
    return bRet;
}
//---------------------------------------------------------------------------

Here’s my original documentation:

**************************************************************
TBJPG - freeware alternative for ImageStream JPG import filter
**************************************************************

***********
What is it?
***********

If you need to import JPEG-files in an Asymetrix ToolBook II
Instructor application (TBK) at author-level there is no
problem; the ImageStream import-filter takes care of it.
At runtime, there is a problem. As the Instructor 6.5 helpfile
states: "Note: The importGraphic command only supports standard 
Windows bitmap formats (BMP, DIB, and WMF) at runtime, because 
other grapics filters are not redistributable.". This is
probably due to the fact that our good friends at Asymetrix
signed some paper with ImageStream many years ago that binds
them to a silly contract.

The TBJPG.DLL is not really a big effort of mine; it just so
happens that I needed a solution to speed up my app and this 
JPEG-problem started to annoy me. Another development
tool I use from time to time (Borland C++ Builder 4 PRO) has
free JPEG support built right into its core. In just a few 
lines of code, a converter was created. That's right, this is 
just a file-converter. It converts a JPEG to a BMP in a single 
call. As a ToolBook-developer you can add this DLL to your
files and re-distribute it with applications you create.

**
OS
**

The DLL only runs on a Win32 Operating System, such
as Microsoft Windows 95, 98 or NT4.

************
Minimal code
************

Link to the single function inside the DLL like this

linkDLL32 "tbjpg.dll"
  DWORD TransferJPEG(string, string);
end

Make sure TBII is able to find the DLL (see Files, below).

Then simply specify a JPEG to convert into a BMP,
maybe like this:

local string fileName;

-- just some support functions for this example
linkDLL "tbfile32.dll"
  string openFileDlg32(string, string, string, string, int);
  int removeFile32(string);
end

-- do this next line in code (see JPGTEST.TBK)
tempFile of this book = "c:\some.bmp";

-- ask for a file
fileName = openFileDlg32("Pick a JPEG", NULL, NULL, "JPEG,*.jpg", 1);

if(fileName <> NULL)then -- a file was picked
  -- convert it to a BMP
  if(TransferJPEG(fileName, tempFile of this book) <> 0)then
    -- an existing bitmap resource is replaced
    replace resource bitmap "b" with tempFile of this book;
    -- and we remove the BMP afterwards
    get removeFile32(tempFile of this book);
  else
    request "Error converting/loading" && fileName;
  end
end

As you can see, using bitmap resources makes the process
completely transparant. After importing the JPEG, it's just
like using BMP-files, only your app is smaller and faster.

That's right: faster. Usually the time it takes to load
a large BMP file from disk supercedes the time to load 
and decompress the same image as a much smaller JPEG-file
in RAM.

***************************
So how does it work anyway?
***************************

TransferJPEG(jpgFile, bmpFile) takes an existing JPG-file
(the first parameter, a regular TB-string) and creates
the equivalent Windows BMP (bitmap), which is specified in
the second parameter. This, too, is a regular TB-string.

If the BMP exists, it's overwritten.

If the function succeeds, non-zero ('TRUE') is returned.

If the function fails, zero ('FALSE') is returned.
This usually means the JPEG could not be found (did you
forget to specify a path?), the JPEG could not be converted
(there are some strange flavors of JPEG around. Make sure
you are using standard JPEG-files, like produced by Adobe
PhotoShop 5 and up and/or its ProJPEG plugin) or the
BMP could not be written to disk (disk is read-only or full).

The created BMP is not removed by the DLL. You should take 
care of that. Either do this directy after converting a 
JPEG or do it in leaveBook. Whatever sounds best to you.
I'd like my code to be as symmetric as possible, so
I would opt for deleting a file directly after use.
Check JPGTEST.TBK for an example.

*********
Licensing
*********

The product is freeware. You can use it however pleases you.

There is no need to mention me, but I don't mind if you do
anyway. You have the right to use this DLL in a commercial 
application. If it's not too much trouble, mail me 
(hens@gmx.net) if you're using this stuff in a real-world
application. I'd love some feedback.

I include the sourcecode (for what it's worth) so you can
see what's going on. If you've got C++Builder 3 or 4, you
should be able to re-compile and link this into a DLL.
For Builder 3 you'll need tjpeg.zip, which is free from
Borland's website (see links, below).

Don't ask me for new features: there will be none.

If something goes haywire and you think TBJPG.DLL is
causing it, don't bother me. You're using this thing
completely on your own. There are no hidden features inside
the DLL as far as I can tell. It's completley OpenSource.

If you re-distribute this DLL to other ToolBook-developers,
please give them the original ZIP-file with all these files
(sourcecode, examples, signatures, text) in it.

***********************
So what's the drawback?
***********************

There is no drawback whatsoever. The ImageStream-filter
Asymetrix licenses to you when you buy Instructor is so 
unbelievably slow that you can use my DLL to convert a 
JPG to a BMP, import the BMP into your application
and delete it if you want to afterwards. Even this way, 
TBJPG.DLL proved to be at least FOUR TIMES FASTER on 3 
different machines.

The code Borland uses to import a JPEG into a bitmap is highly
standard. In fact, it's the Delphi JPEG Image 
Compression/Decompression Unit (c) 1997, compliant to and
based on the Joint Photographic Experts Group standard
whitepaper also known as IS 10918-1 (ITU-T T.81).

***********
TB-versions 
***********

Asymetrix TBII 5 and up (I only tested this with 6.5, but some 
folks out there use it with TBII 5. You can probably put this
thing to good use in Assistant as well, if you also have
Instructor).

*****
Files
*****

TBJPG.BPR and TBJPG.CPP are the sourcecode to this DLL.
You will only need these files to re-compile or modify
the DLL and you need Borland C++ Builder 3 or 4 or up for that.

TBJPG.DLL is the only file you need to import JPEGs at runtime.
Place it in your TBII runtime directory or in the same directory
as your project's TBK's/SBK's.

JPGTEST.TBK is a simple TBII 6.5 test-application to see this
DLL in action. It's a single graphics button which imports a
JPEG into itself. The OpenScript sourcecode can be found in
this textfile as well. You should be able to import a standard 
JPEG-file when running JPGTEST.TBK from TB runtime (TB60RUN.EXE).

CACHE.EXE is a more complex example of importing JPEGs into
a TBII application. It's a self-extracting archive, which
you should unfold into an empty directory. It will create a
media-subdirectory with some jpeg-files in it.

The OpenScript you'll find in CACHED.TBK has taken me many
hours of work. Feel free to comment or tell me where I go
wrong. If you find a way to optimize speed, I'd be most
interested to know about your changes and findings.

hz37.asc is my PGP public key. You can use it to verify if 
these files are all in perfect health. If you want to d/l 
my PGP public key from a public key server instead, try 
http://www.keyserver.net/en/   and here are my statistics:

Hens Zimmerman  <hens@gmx.net>
PGPKeyID        0xBBC240A7
Fingerprint     EF36 D27A B35F 12E9 3D88 3B34 8A55 8837 BBC2 40A7 
Size            1024
Created         1999/02/15

All the .sig files should have complete validity for the files
they belong to.
   
*****
Links
*****

JPEG-standard:

http://www.jpeg.org/public/jpeghomepage.htm

Borland free download of TJPEG.ZIP for C++Builder 3:

http://www.borland.com/devsupport/bcppbuilder/file_supplements.html

Asymetrix:

http://www.asymetrix.com

PGP:

http://www.pgpi.org/


http://www.nai.com/asp_set/products/tns/intro.asp


http://www.keyserver.net/en/

***************************************
Sample-code from JPGTEST.TBK bookscript
***************************************

to handle enterBook
	forward;
	linkDLL "tbfile32.dll"
		string openFileDlg32(string, string, string, string, int);
		int removeFile32(string);
	end
	linkDLL32 (ExtractFilePath(name of this book) & "tbjpg.dll")
		DWORD TransferJPEG(string, string);
	end
	if("tb60r.sbk" is not in sysBooks)then
		push "tb60r.sbk" onto sysBooks;
	end
	tempFile of this book = ASYM_TempDir();
	if(last char of tempFile of this book <> "\")then
		put "\" after tempFile of this book;
	end
	put "__dummy.bmp" after tempFile of this book
end

to handle sized
	forward;
	send sizeToViewer;
end

to get LastDelimiter string delimiters, string source
	-- returns position of last delimiter in source
	-- or 0 if no delimiter is found
	local long i;
	step i from charCount(source) to 1 by -1
		if(char i of source is in delimiters)then
			return i;
		end
	end
	return 0;
end

to get ExtractFilePath string fileName
	-- extracts filepath of fileName
	local int i;
	i = LastDelimiter("\:", fileName);
	if(i > 0)then
		return chars 1 to i of fileName;
	end
	return NULL;
end

*****************************************
Sample-code from JPGTEST.TBK buttonscript
*****************************************

to handle buttonClick
	local string fileName;
	fileName = openFileDlg32("Pick a JPEG", NULL, NULL, "JPEG,*.jpg", 1);
	if(fileName = NULL)then
		break buttonClick;
	end
	sysCursor = 4;
	if(TransferJPEG(fileName, tempFile of this book) <> 0)then
		replace resource bitmap "b" with tempFile of this book;
		get removeFile32(tempFile of this book);
	else
		sysCursor = 1;
		request "Error loading" && fileName;
	end
	sysCursor = 1;
end



Have fun,



Hens Zimmerman


Groningen

The Netherlands

September 1, 1999.