Table of Contents
BE ENGINEERING INSIGHTS: Getting Your Translator Add-ons to Use the Translation Kit By Jon Watte One of the many good things in BeOS Release 3 was the addition of system-wide translation services through the Translation Kit. While translation between different data formats was previously available in the form of a third-party library named Datatypes, having a Kit in the BeOS makes it easier to use and install, because you can assume it's always there. The Translation Kit will load any old-style Datatypes add-ons, but the interface used by Datatypes is deprecated. The actual work of translating data in the Translation Kit is performed by add-ons known as translators. This article explains what a translator add-on must do to be used by the Translation Kit, and what it can do to be a well-behaved citizen in the world of data format conversions. But first, the code! The archive can be found at: ftp://ftp.be.com/pub/samples/translation_kit/ppm.zip The purpose of our translator is to allow applications to read and write the PPM bitmap file format. I chose PPM because it is a format that is fairly simple to understand, while having enough variation to illustrate how to configure a translator add-on. It is also a fairly popular format for UNIX-style image processing tools. For translation to work, there has to be some common ground between the translators, and the applications using them. For bitmap graphics, this common ground is found in the B_TRANSLATOR_BITMAP format, a format designed to be easily readable and writable to BBitmap system objects. The format of a B_TRANSLATOR_BITMAP formatted file is simple: First, there is the file header, which consists of a struct: struct TranslatorBitmap { uint32 magic; /* B_TRANSLATOR_BITMAP */ BRect bounds; uint32 rowBytes; color_space colors; uint32 dataSize; }; As you can see, all elements of this struct are 32 bytes in size (except for the BRect, but all elements in a BRect are 4 bytes in size) so there should be no alignment problems when reading/writing this struct on different platforms. However, the byte order needs to be well defined, and since Datatypes was around long before the x86 port of BeOS, the well-defined byte order of the TranslatorBitmap struct is big-endian. The "magic" field should be set to the B_TRANSLATOR_BITMAP constant, swapped to big-endian if necessary. The "bounds" field should be set to the For "rowBytes", see below. "colors" is one of the values defined in GraphicsDefs.h
which describe various ways you can interpret the raw pixel
data. In R4, there will be more values defined for a
color_space, although not all values work if you use
"dataSize", lastly, should tell how much pixel data follows the header, but the size of the header (32 bytes) does not count. This should always be set as follows: header.dataSize = (header.bounds.Width()+1)*header.rowBytes Again, be careful about byte-swapping. After this struct the actual data of the bitmap follows directly, from left to right, top to bottom, padded to rowBytes bytes per scanline. rowBytes is typically the smallest multiple of four bytes that will fit the width of the bitmap of whole pixels across. The general rule with regards to byte-swapping is to swap only when you need to read or write data, and keep it in the native format internally. Doing this ensures that you can easily access the values of the header. For instance, if you were to write a BBitmap out in the B_TRANSLATOR_FORMAT format, here's how you could do it: I have sloppily been saying "file format" above; the truth is that any BPositionIO object can be used by a translator, and as long as you canstatus_t WriteBitmap(BBitmap * map, BDataIO * out) { TranslatorBitmap header; /* prepare header */ header.magic = B_TRANSLATOR_BITMAP; header.bounds = map->Bounds(); header.rowBytes = map->BytesPerRow(); header.colors = map->ColorSpace(); header.dataSize = header.rowBytes*(header.bounds.Width()+1); /* swap header */ header.magic = B_HOST_TO_BENDIAN_INT32(header.magic); header.bounds.left = B_HOST_TO_BENDIAN_FLOAT(header.bounds.left); header.bounds.top = B_HOST_TO_BENDIAN_FLOAT(header.bounds.top); header.bounds.right = B_HOST_TO_BENDIAN_FLOAT(header.bounds.right); header.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(header.bounds.bottom); header.rowBytes = B_HOST_TO_BENDIAN_INT32(header.rowBytes); header.colors = (color_space)B_HOST_TO_BENDIAN_INT32(header.colors); header.dataSize = B_HOST_TO_BENDIAN_INT32(header.dataSize); /* write header */ status_t err = out->Write(&header, sizeof(header)); /* write data */ if (err == sizeof(header)) { err = out->Write(map->Bits(), B_BENDIAN_TO_HOST_INT32(header.dataSize)); if (err == B_BENDIAN_TO_HOST_INT32(header.dataSize)) { err = B_OK; } } return (err > B_OK) ? B_IO_ERROR : err; } Seek() and SetSize() and Read() and
Write() it, it needn't be a BFile proper. It can be one of
the system classes BMallocIO or BMemoryIO, or it can be your
own class that knows how to read and write data to some
special storage you're using. This is used by the system
class BBitmapStream, which knows how to present a BBitmap as
a "stream" of data.
Now, your job as a bitmap image translator is to read data
in your "special" file format from the input stream, and
write it to the output stream in the "standard" bitmap
format as explained above. You should also be capable of
doing the reverse: reading data in the "standard" bitmap
format, and writing it out in your special format. This
reading/writing is done in the exported There are standard formats for some other kinds of data
besides bitmap images. You can find them in
<TranslatorFormats.h>, and they are also described in the
Translation Kit chapter of the online Be Book.
There are some things that you need to get the Translation
Kit to the point where it calls your 1) An application that implements an "export" menu item,
such as the Becasso paint program, or the R4 version of
ShowImage, calls on the Translation Kit to list all
available translators, and to select those that say that
they can translate from the B_TRANSLATOR_BITMAP format to
some other format. It then lets the user choose one of these
translators using some UI (a dialog or menu, typically) and
tell the Translation Kit to especially use the translator
selected.
For this to work, your translator needs to tell the world
what formats it can read and write. It does so in the
inputFormats[] and outputFormats[] arrays. These are arrays
of struct translation_format, terminated by a format with
all 0 values. While exporting these arrays is called
"optional" in the documentation, applications that want to
perform an export will not know about your translator unless
it exports these arrays.
Also note that there is no way to specify that only certain
combinations of input and output file formats are good. Once
you declare some input formats and some output formats, any
combination of them may be used by the Translation Kit,
including, in some degenerate cases, translating the SAME
format (i e B_TRANSLATOR_BITMAP to B_TRANSLATOR_BITMAP). You
decide how to best deal with this situation; just copying
>from input to output is acceptable, although if your
translator can also do some other tricks (like the color
space conversion of PPMTranslator) you might want to do that
even on same-format translations.
2) An application that accepts "any file" and then uses the
Translation Kit to figure out what it was will cause your
Because the BPositionIO passed for input may have some
special meaning, such as reading from a network socket, you
should not read more data than you need to make an educated
guess as to the format of data you're passed. Similarly,
calling There are some additional required data items you need to
export from your translator for the Translation Kit to use
it. They tell the world your translator's name, some
information about it, and the version. If there are two
translators with the same name but different versions
installed, the Translation Kit may choose to use only the
latest version, for instance. Thus, you should make sure
that you always bump the version number when releasing a new
version of your translator, and that you never change your
translator's name (as seen in "translatorName[]") once it's
set.
"translatorInfo[]" is your personal soap box, and is a great
place to put shareware notices, copyright information, URLs,
or secret cabal messages. Except that then they wouldn't be
secret anymore.
There are three more optional functions that you may choose
to export, even though your translator will work and be used
by the Translation Kit without them.
" " These two functions together make it possible to create an
application which can present a UI for choosing a
translator, to configure that translator, and later to use
that specific translator/configuration pair to actually
perform a translation. Great for automated batch
conversions, for instance!
For more detailed information on the functions used by the
Translation Kit, look at the Translation Kit chapter of the
Be Book, the section on writing a Translator add-on:
http://www.be.com/documentation/be_book/The%20Translation%20Kit/ The last optional function is " PPMTranslator takes advantage of this schizophrenia to do
something useful when double-clicked -- it runs its own
control panel by calling its own Once your translator is debugged and ready to ship, you only
need to make sure it gets installed where the Translation
Kit will find it. By default, the Translation Kit will look
in the following three places for Translator add-ons:
However, the user can change this behaviour by setting the
environment variable TRANSLATORS. Users who do this are
considered power users, so making sure your translator gets
installed in ~/config/add-ons/Translators/ by default is the
right thing to do.
Before I end this article, I want to explain a few things
about the code included with this article.
First, there is downloading and installing the code. Just
get it from the URL above, put it where you usually put
sample source code, and un-zip it (or let the Expand-o-matic
do it for you). Then, in a Terminal window, "cd" to the
newly un-zipped folder, and type "make install" to build and
install the PPMTranslator and the "translate" command-line
tool. Documentation for the use of "translate" is scarce,
but you have the source, so you should be able to figure it
out from there.
PPMTranslator should be doing most things "right" and thus
be suitable as sample source. If you find something you
don't like or think might be a bug, I'd be interested in
hearing about it, and fixing the archive.
The utilities in colorspace.cpp are intended as a quick way
to get the job done when you need to output data in some
color_space format other than what you have. They are not
intended as a high-quality color convolution or separation
package. Specifically, the conversion to grayscale is sub
par, and the conversion to/from CMY(K), while correct,
assumes that you're using perfect inks on perfect paper. I
wish!
If you read through the sources and conclude that Release 4
will define new values for the color_space enum for color
spaces not previously defined in What are you waiting for? The source is there to explore,
and the world is waiting for your translators! Shoo!
BE ENGINEERING INSIGHTS: How to Avoid Engineering Pitfalls That Defeat Global Sales
By Lynn Fredricks, Proactive International Your programmers work 24-hour days to get your product ready
for domestic sales. But, although 50% or more of your
revenue is on the line, you don't think to ask them to test
the product under the German or Japanese version of the
operating system. It's only after your product starts
appearing on shelves at CompUSA that the Vice President of
Worldwide Sales asks you to demonstrate this hot application
running under the Japanese operating system for a group of
high-ranking executives from Tokyo. After the fourth crash
and reboot, you realize that something isn't right with your
product. Your VP apologizes, then says goodbye to the high-
ranking executives and to 30% of worldwide revenue.
For most development houses with an international presence,
international sales account for upwards of 40% of total
revenue. These revenues, however, can be severely reduced or
eliminated for any software release when products aren't
engineered for sales in international markets. In effect,
your engineering department determines your global sales
strategy, which may well end up defeated by or suffering
from long and expensive localization processes because
software products have been written with only a single
target language in mind.
Before localizing your software, you need to
internationalize it. Internationalization is the process of
creating a single code tree that is easily localized to
multiple languages. Before spec, during development, and
through final code freeze, your engineers should be
well-versed in writing international software. Here are five
of the most common pitfalls that cripple or defeat the
international value of software products.
Language Code Incompatibility
English letters are usually presented as single-byte
characters. Japanese, Chinese, and Korean characters are
double-byte. Some text can be represented vertically. In the
Middle East, some languages flow from right to left. All
platforms have API calls to display all major languages,
including US English. A program can automatically display
date, time, and other culture standards by querying the
operating system. Make sure your programmers learn and use
these APIs wherever characters are displayed.
Third-Party Components
Some components may not be localizable. A third-party vendor
may not license a component for international distribution,
or may demand additional licensing requirements and fees to
localize it for you. Before a component is even tested for
use in a product, require a sign-off for worldwide rights
and compatibility with all international versions of the OS
your company targets.
Hardcoded Resources
Your programmers always keep pieces of text, pictures, and
sounds in a separate, editable resource file, right? If
resources aren't kept separate from the start, your
programmers will either have to re-engineer later, or comb
through your source code every time you localize into
another language. Separate resources are relatively easy to
edit, reducing engineering costs considerably, or allowing
you to outsource localization entirely.
Non-Existent SDKs
Almost every SDK starts as English-only. Even Sun's Java
Development Kit only recently added true international
support. If your product is dependent on a third-party SDK,
ensure that it is either compatible with targeted
international operating systems, or that you are absolutely
sure that international versions will be available by the
time you are ready to localize.
Non-Standard Docs and Help
Tech writers and help authors like to adapt as much as
possible to the platform they are writing for, and add
improvements with incremental releases. Usually, help
systems, as well as electronic documentation systems and
players, do not exist on all platforms and language
versions, increasing development costs for these systems.
Every new or different word in the documentation has to be
translated, copy-edited, and re-published. Therefore, it is
practical and cost-effective to standardize on
cross-platform, open systems, and to enforce a company
policy of standardized product terminology.
International success depends not only on the savvy of your
business development team, but on a cooperative and
proactive understanding of how to create an
internationalized product. Being aware of the pitfalls and
integrating strategies into your product specifications will
allow you to realize your global revenue potential.
About The Author
Lynn Fredricks is the President of Proactive International,
an international business development company that
establishes worldwide distribution networks for software
developers. Proactive International specializes in
high-profile distribution between North America and Japan,
as well as providing product and business analysis for large
international corporations. Additional information can be
found at http://www.proactive-intl.com/.
DEVELOPERS' WORKSHOP: Putting Pen to Paper
Developers' Workshop is a weekly feature that provides
answers to our developers' questions, or topic requests.
To submit a question, visit
http://www.be.com/developers/suggestion_box.html
A while back, Stephen Beaulieu mentioned that DTS has divided
support responsibilities for the various areas which make up
the BeOS, based on familiarity, experience, and preference.
The areas which fell towards me include OpenGL®, POSIX,
Replicants, hardware, and printing. When I think about what
I'd like to write for my Newsletter articles, I look into
the questions which have come my way recently to see what
people are asking about. This article was going to be on
OpenGL®, but people asked about printing last week, so that's
what we'll look at. OpenGL® will have to wait until my next
article!
Printing is a great topic, because it produces a physical
representation of your work. It's very validating. You can
hang your hardcopy on your office wall, show it to your
friends, and just generally impress people with it.
Portable, high-contrast displays are wonderful, but printing
will always be valuable. As I once heard it put so
eloquently, the paperless office is as much a myth as the
paperless bathroom. (There's a very subtle double entendre
in there, "for the connoisseur" as Jean-Louis might say.)
Beno”t Schillings wrote an excellent article...
http://www.be.com/aboutbe/benewsletter/volume_II/Issue18.html
...a short while back which explained how to get up and running
with printing on the BeOS. I want to expand on that article
just a little, showing a couple of techniques which you may
want to incorporate into your own applications. The code
we'll be adding printing to is none-other-than Dynadraw, the
perfect vehicle for showing off printing. You can grab the
source code from:
ftp://ftp.be.com/pub/samples/interface_kit/dynadraw3.zip
In printing out Dynadraw views, it would be nice to have two
modes: one in which one pixel on the screen corresponds to
one typographical point on the page, and another where the
entire view is scaled to fit on a single page.
Correspondingly, under the "Printing" menu, you'll find the
item "Scale to Page" which has a check next to it. The check
implies that we'll scale the view to the page, and the
absence of the check implies that we'll produce "life size"
output.
The DDWindow class manages the printing, and is the target
of the two new messages, PRINT_REQ and SCALE_PAGE.
SCALE_PAGE notifies the FilterView that we're toggling
printing modes. PRINT_REQ calls the imaginatively named
The most important thing to do when creating a print job is
to set the print settings. This is usually done by making a
call to Next we calculate how wide and how long the printout will
be. We do this by taking the ratio of our view width to our
printable rectangle width, and rounding up with the ceiling
function. The total number of sheets, therefore, is
horizontal sheets multiplied by vertical sheets. We then
loop through the pages, offsetting the current page
rectangle to the top of the next page.
With the current page rectangle lined up correctly, we call
The The As you can see, the BPrintJob class and the BView class work
hand-in-hand to allow you to add quick and easy printing to
your applications. Read Beno”t's article, read about
BPrintJob in the Be Book, and try it yourself! Happy
printing!
This is not about making a mˇsalliance of respected
professionals and confidence men in the same column. No,
today's topic is an attempt to balance two opposing views
of an issue. That is, the good and bad sides of a
hypothetical venture fund whose sole purpose would be
investing in Be developers.
Actually, this isn't so hypothetical. This week's choice
of topic was triggered by reactions to a mention on our
site of Marco Bernasconi's BeFund:
Marco, a long-time friend of Be,
is based in Switzerland, and he *is* the fund.
We're all grateful for Marco's role as an "angel" to Be
developers and, as the celestial label implies, this is
not a classical Silicon Valley venture fund. What many
correspondents have asked, however, is whether there
should be a standard venture fund for BeOS-centric
companies. I'll try to reproduce their arguments for and
against, taking full responsibility for whatever
distortions I might introduce in the process.
On the pro side, several readers point to the keiretsu
approach adopted by Kleiner Perkins in convincing other
investors to join them in investments supporting the Go/Eo
platform. More recently, Kleiner Perkins took a similar
course in leading the creation of a Java Fund.
As is now well understood, the reasoning behind this kind
of venture investment is that a new platform needs a
critical mass of symbionts such as software or hardware
developers; the platform support fund provides capital to
these helper companies.
If the platform "ignites," all investors, whether in the
platform company or in third-party companies, are in a
good position to profit handsomely for being in before
success became retroactively obvious. If critical mass
isn't achieved, well, they tried, as manly venture
investors are supposed to do.
Critics of the idea call it "dirigiste" (that is,
interventionist), an affront to the way things are done in
free-market heaven. Essentially, they say, if a start-up
offers a money-making opportunity, it will get financed.
There is so much capital available right now that any good
team with a good business plan will attract funding.
In other words, if the free market doesn't fund BeOS
developers, listen to what investors are saying: the
business plan won't work. Perhaps it's the team, or the
product; more likely there isn't enough confidence that
the platform will reach critical mass and reward investors
accordingly.
Furthermore, opponents of the idea point out, the Go/Eo
keiretsu didn't go anywhere, and there is doubt that Java
will ever ascend to the Windows-killer platform status
originally ordained for it. In other words, the dirigiste
idea doesn't work, critics say, looking at my passport.
Others take a different perspective. They point out that
most large companies now deploy a strategic investment
fund of one kind or another. These days, one of the most
visible examples is Intel, but from Adobe and AT&T to 3Com
and Cisco, "everybody does it." That does not
automatically make it a good idea, but one is tempted to
assume these companies have a different conduit for their
philanthropic activities.
In other words, all these CEOs, and their boards of
directors, believe in the divine intervention of the free
market for most things, but they are collectively willing
to put billions in play when it comes to creating critical
mass, or a self-fulfilling prophecy, rather than letting
nature take its course. If memory serves, in the early
eighties, a rich Apple took a 20% equity position in the
new and, at the time, unproven Adobe. That investment
helped the rise of the Macintosh platform and Apple made a
killing of Microsoft proportions on its Adobe stake.
In fairness, the examples go back and forth, and for every
success story one may find failures of Momenta
proportions. There is no absolute truth in this matter of
platform-support investments. There is only risk taking,
and the small matter of execution.
BeDevTalk is a discussion group that's a forum for the
exchange of technical information, suggestions, questions,
mythology, and suspicions. In this column, we summarize some
of the active threads, listed by their subject lines as they
appear, verbatim, in the group.
To subscribe to BeDevTalk, visit the mailing list page on
our Web site: http://www.be.com/aboutbe/mailinglists.html
Subject: Alternative access to the BeOS API
Is it possible to produce a Be app by cross-compiling on
another platform? The libraries are, as Ernest S. Tomlinson
pointed out, "Portable Executable binaries", so some clever
compiler direction should do the trick. Right?
Fred Fish pointed to a tract in the Microsoft Developer
Network Library called "Learn System-Level Win32 Coding
Techniques by Writing an API Spy program" that shows you
"how to make all client-sharedlib calls go through some
private code you supply." Thomas Hudson nominated Chris
Herborth's port of SWIG
http://www.be.com/beware/Development/SWIG.html
which "analyzes C++ code and
generates an interface to various scripting languages such
as TCL/Tk, Python, Perl..."
There was some shouting from the "feel the pain" crowd (REAL
BeOS developers use MW/BeIDE). And some listeners took the
opportunity to re-open the binary format debate (ELF vs
PEF/PE).
Subject: BHandler destructors not called
Should a BHandler be destroyed when its BLooper is
destroyed? Jesse Hall sees the looper/handler relationship
as similar to that of window/view. And just as dying windows
destroy their views, loopers should clean up after
themselves.
But maybe not: Matt Brubeck thinks unhitching the fate of a
handler from its (current) looper makes message redirection
easier, particularly when the looper is a window.
THE BE LINE: To paraphrase Peter Potrebic, the fact that a
destructed looper doesn't destroy its attached handlers is
not a bug, and won't change. However, the looper should (but
doesn't) remove its handlers while its being destroyed. This
is a bug and will be fixed.
Subject: buggy rint()
Tinic Uro submitted a mathlib mystery spot:
Jens Kilian offered an explanation:
"This is the American way to round a number -- if it's
exactly halfway between integers, it is rounded to the EVEN
one. The German way, which I and (presumably) you were
taught, is to simply take ceil(x + 0.5), always rounding UP
when halfway between numbers."
International relations at stake, a number of listeners
wrote in to suggest using floor() and ceil() (or, for the
latter, floor(x+.5)) instead of rint().
THE BE LINE: (From Mani Varadarajan)
"[rint()'s behavior] is correct. To prevent skewing
rounding errors only one way, it is a well-established rule
that one should always round to the even number if a number
is exactly between an even and odd value (pardon the lack of
precise mathematical terminology).
If the rule were to round always up, the error would be
skewed in one direction. This evens out the error."
Subject: Java tools
What's Be's Java policy? It was announced that Be had been
dealt into Sun's floating crap game, but have they ante'd
up? Is there a JVM on the horizon?
THE BE LINE: Be is NOT an official Java licensee. We'd love
to see a JVM running on the BeOS, but we have no plans to
work on one ourselves.
Subject: Interface paradigm questions
The windows for all instances of a multi-launch app are
listed together in the Deskbar's app window list. How do you
tell which windows belong to which instance of the app?
Suggestions:
Fine suggestions all, each with their own set of advantages
and blemishes. And of the latter for the latter, comes this
from Matt Brubeck:
"I have NetPositive running in workspace three. I want to
open a NetPositive window in workspace one. Ideally, I
should be able to go to workspace one, launch NetPositive,
and have it open a new window. Currently, I have to go to
workspace three, tell NetPositive to open a new window, use
Workspaces to drag the window to workspace one, then go to
workspace one. Bleah."
Subject: printing long longs
Q. How do you
|