Commit 2173c8c5 authored by Patrick Julien's avatar Patrick Julien

- New in-core image format

- Implemented paint-offset
- Implemented real-time zoom
- Made scrolling work with zoom
- Deactivated anything that hasn't been ported yet
- Implemented image builder with ImageMagick.  See "Image/Import Image" or "Layer/Import Image" in menus.

svn path=/trunk/koffice/; revision=179080
parent 7adb0a13
INCLUDES = $(KOFFICE_INCLUDES) -I$(interfacedir) $(all_includes) $(KOPAINTER_INCLUDES)
INCLUDES = $(KOFFICE_INCLUDES) -I$(interfacedir) $(all_includes) $(KOPAINTER_INCLUDES)
## The part
kde_module_LTLIBRARIES = libkritapart.la
libkritapart_la_SOURCES = dummy.cc
libkritapart_la_LDFLAGS = $(KDE_PLUGIN)
libkritapart_la_LIBADD = core/libkiscore.la ui/libkisui.la tools/libkistools.la \
../lib/kofficeui/libkofficeui.la ../lib/kopainter/libkopainter.la
libkritapart_la_LIBADD = core/libkiscore.la core/helper/libkishelper.la core/tiles/libkistile.la \
ui/libkisui.la ../lib/kofficeui/libkofficeui.la ../lib/kopainter/libkopainter.la tools/libkistools.la
METASOURCES = AUTO
## The kdeinit loadable module
......@@ -36,7 +38,7 @@ kdemimedir = $(kde_mimedir)/application
rcdir = $(kde_datadir)/krita
rc_DATA = krita.rc krita_readonly.rc
SUBDIRS = core tools ui . dtd plugins data pics
SUBDIRS = core ui . dtd plugins data pics
messages: rc.cpp
$(XGETTEXT) rc.cpp *.cc */*.cc core/kis_aboutdata.h -o $(podir)/krita.pot
INCLUDES = -I$(srcdir)/../ui -I$(srcdir)/../tools $(KOFFICE_INCLUDES) -I$(interfacedir) \
INCLUDES = -I$(srcdir)/helper/ -I$(srcdir)/tiles/ -I$(srcdir)/../ui -I$(srcdir)/../tools $(KOFFICE_INCLUDES) -I$(interfacedir) \
$(KOPAINTER_INCLUDES) $(LIBMAGICK_CPPFLAGS) $(all_includes)
noinst_LTLIBRARIES = libkiscore.la
libkiscore_la_SOURCES = kis_pixel_packet.cc \
kis_view.cc kis_channel.cc \
kis_layer.cc kis_image.cc \
kis_pluginserver.cc kis_resourceserver.cc \
kis_factory.cc kis_config.cc kis_undo.cc \
kis_doc.cc \
kis_krayon.cc kis_brush.cc kis_pattern.cc kis_gradient.cc \
kis_util.cc kis_tool.cc kis_vec.cc \
kis_cursor.cc kis_timer.cc \
kis_selection.cc kis_framebuffer.cc kis_painter.cc kis_tool_factory.cc \
KRayonViewIface.skel KRayonViewIface.cc kis_tile.cc kis_tiles.cc \
kis_paint_device.cc KIsImageIface.skel KIsImageIface.cc KIsDocIface.skel \
KIsDocIface.cc kis_image_cmd.cc kis_mask.cc kis_color_utils.cc \
kis_magick.cc
libkiscore_la_SOURCES = kis_paint_device.cc kis_layer.cc kis_channel.cc kis_mask.cc kis_image.cc kis_doc.cc\
kis_view.cc kis_tool.cc kis_factory.cc kis_pluginserver.cc kis_resourceserver.cc kis_timer.cc \
kis_brush.cc kis_krayon.cc kis_pattern.cc kis_image_builder.cc kis_util.cc
libkiscore_la_METASOURCES = AUTO
libkiscore_la_LDFLAGS = $(KDE_RPATH) $(LIBMAGICK_RPATH)
libkiscore_la_LIBADD = $(LIBMAGICK_LIBS)
KDE_CXXFLAGS = $(USE_EXCEPTIONS)
SUBDIRS = helper tiles
/*
* kis_channel.cc - part of KImageShop
* copyright (c) 2002 patrick julien <freak@codepimps.org>
*
* Copyright (c) 1999 Andrew Richards <A.Richards@phys.canterbury.ac.nz>
* 1999-2000 Matthias ELter <elter@kde.org>
*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* this program is free software; you can redistribute it and/or modify
* it under the terms of the gnu general public license as published by
* the free software foundation; either version 2 of the license, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* this program is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. see the
* gnu general public license for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* you should have received a copy of the gnu general public license
* along with this program; if not, write to the free software
* foundation, inc., 675 mass ave, cambridge, ma 02139, usa.
*/
#include <qcolor.h>
#include <kdebug.h>
#include "kis_global.h"
#include "kis_types.h"
#include "kis_channel.h"
KisChannel::KisChannel(cId id, const QString& name, uint width, uint height, const QRgb& defaultColor) : super(name, width, height, 4, defaultColor)
{
m_id = id;
m_imgRect = m_tileRect = QRect(0, 0, width, height);
}
KisChannel::~KisChannel()
{
}
uint KisChannel::lastTileOffsetX()
{
uint lastTileXOffset = TILE_SIZE - (m_tileRect.right() - m_imgRect.right());
return ((lastTileXOffset) ? lastTileXOffset : TILE_SIZE);
}
uint KisChannel::lastTileOffsetY()
{
uint lastTileYOffset = TILE_SIZE - (m_tileRect.bottom() - m_imgRect.bottom());
return ((lastTileYOffset) ? lastTileYOffset : TILE_SIZE);
}
QRect KisChannel::tileRect(int tileNo)
{
int xTile = tileNo % xTiles();
int yTile = tileNo / xTiles();
QRect tr(xTile * TILE_SIZE, yTile * TILE_SIZE, TILE_SIZE, TILE_SIZE);
tr.moveBy(m_tileRect.x(), m_tileRect.y());
return(tr);
}
#if 0
void KisChannel::setPixel(uint x, uint y, const uchar *pixel, KisImageCmd *cmd)
{
// TODO : Manipulate pixel value before going upstream
super::setPixel(x, y, pixel, cmd);
}
#endif
/*
* kis_channel.h - part of KImageShop
* copyright (c) 2002 patrick julien <freak@codepimps.org>
*
* Copyright (c) 1999 Andrew Richards <A.Richards@phys.canterbury.ac.nz>
* 1999-2000 Matthias ELter <elter@kde.org>
*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* this program is free software; you can redistribute it and/or modify
* it under the terms of the gnu general public license as published by
* the free software foundation; either version 2 of the license, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* this program is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. see the
* gnu general public license for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* you should have received a copy of the gnu general public license
* along with this program; if not, write to the free software
* foundation, inc., 675 mass ave, cambridge, ma 02139, usa.
*/
#if !defined KIS_CHANNEL_H_
#define KIS_CHANNEL_H_
#ifndef __kis_channel_h__
#define __kis_channel_h__
#include <qrect.h>
#include <qpoint.h>
#include <koStore.h>
#include "kis_global.h"
#include "kis_paint_device.h"
class KisChannel;
class KisImageCmd;
typedef KSharedPtr<KisChannel> KisChannelSP;
typedef QValueVector<KisChannelSP> KisChannelSPLst;
typedef KisChannelSPLst::iterator KisChannelSPLstIterator;
typedef KisChannelSPLst::const_iterator KisChannelSPLstConstIterator;
class KisChannel : public KisPaintDevice {
typedef KisPaintDevice super;
public:
KisChannel(cId id, const QString& name, uint width, uint height, const QRgb& defaultColor);
KisChannel(KisImageSP img, Q_INT32 width, Q_INT32 height, const QString& name, const KoColor& color);
KisChannel(const KisChannel& rhs);
virtual ~KisChannel();
// virtual void setPixel(uint x, uint y, const uchar *pixel, KisImageCmd *cmd);
public:
KisChannel& operator=(const KisChannel& rhs);
public:
// Overide KisPaintDevice
virtual void duplicate(const KisPaintDevice& rhs, bool addAlpha);
public:
QUANTUM opacity() const;
void opacity(QUANTUM val);
KoColor color() const;
void color(KoColor clr);
cId channelId() const { return m_id; }
int width() const { return m_imgRect.width(); }
int height() const { return m_imgRect.height(); }
QRect tileExtents() const { return m_tileRect; };
QRect imageExtents() const { return m_imgRect; };
QPoint offset() const { return m_imgRect.topLeft() - m_tileRect.topLeft(); };
void scale(Q_INT32 width, Q_INT32 height, Q_INT32 interpolationType);
void resize(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h);
void resize(const QRect& rc);
QRect tileRect(int tileNo);
KisChannelSP createMask(Q_INT32 w, Q_INT32 h);
bool boundary(vKisSegments& inside, vKisSegments& outside, const QRect& rc);
bool bounds(QRect& rc);
uint lastTileOffsetX();
uint lastTileOffsetY();
Q_INT32 value(Q_INT32 x, Q_INT32 y);
bool empty();
protected:
cId m_id;
QRect m_imgRect;
QRect m_tileRect;
void feather();
void clear();
void invert();
void border(Q_INT32 xradius, Q_INT32 yradius);
void grow(Q_INT32 xradius, Q_INT32 yradius);
void shrink(Q_INT32 xradius, Q_INT32 yradius);
void translate(Q_INT32 x, Q_INT32 y);
};
#endif // __kis_channel_h__
#endif // KIS_CHANNEL_H_
This diff is collapsed.
/*
* kis_doc.h - part of Krayon
*
* Copyright (c) 1999-2000 Matthias Elter <me@kde.org>
* Copyright (c) 2001 Toshitaka Fujioka <fujioka@kde.org>
* Copyright (c) 2002 Patrick Julien <freak@ideasandassociates.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -18,37 +17,23 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __kis_doc_h__
#define __kis_doc_h__
#include <qstring.h>
#include <qptrlist.h>
#include <qstringlist.h>
#include <kcommand.h>
#include <klocale.h>
#include <ksharedptr.h>
#if !defined KIS_DOC_H_
#define KIS_DOC_H_
#include <koDocument.h>
#include "kis_image.h"
#include "kis_framebuffer.h"
#include "kis_global.h"
#include "kis_selection.h"
#include "kis_view.h"
#include "kis_types.h"
#include "kis_image.h"
class Magick::Image;
class QImage;
class QString;
class DCOPObject;
class KCommand;
class KCommandHistory;
class KisSelection;
class KisView;
/*
* A KisDoc can hold multiple KisImages.
*
* KisDoc -> currentImg() returns a Pointer to the currently active KisImage.
*/
class KisDoc : public KoDocument
{
class KisDoc : public KoDocument {
typedef KoDocument super;
Q_OBJECT
......@@ -56,180 +41,65 @@ public:
KisDoc(QWidget *parentWidget = 0, const char *widgetName = 0, QObject* parent = 0, const char* name = 0, bool singleViewMode = false);
virtual ~KisDoc();
/*
* Reimplemented from KoDocument.
* See koDocument.h.
*/
virtual QCString mimeType() const;
public:
// Overide KoDocument
virtual bool initDoc();
virtual bool loadNativeFormat(const QString& file);
virtual QCString mimeType() const;
virtual QDomDocument saveXML();
virtual bool loadXML(QIODevice *, const QDomDocument& doc);
virtual bool completeLoading(KoStore *store);
virtual bool completeSaving(KoStore*);
virtual DCOPObject* dcopObject();
virtual void paintContent(QPainter& painter, const QRect& rect, bool transparent = false, double zoomX = 1.0, double zoomY = 1.0);
virtual bool isEmpty() const;
void addCommand(KCommand *cmd);
int undoLimit () const;
void setUndoLimit(int limit);
int redoLimit() const;
void setRedoLimit(int limit);
/*
* Use QPainter p to paint a rectangular are of the current image.
*/
void paintPixmap( QPainter* p, QRect area );
public:
KoColor foreground() const;
KoColor background() const;
/*
* Create new KisImage, add it to our KisImage list and make it the current Image.
*/
KisImageSP newImage(const QString& name, int width, int height, cMode cm = cm_RGBA, uchar bitDepth = 8);
void addCommand(KCommand *cmd);
Q_INT32 undoLimit() const;
void setUndoLimit(Q_INT32 limit);
Q_INT32 redoLimit() const;
void setRedoLimit(Q_INT32 limit);
void setUndo(bool undo);
KisImageSP newImage(const QString& name, Q_INT32 width, Q_INT32 height, enumImgType type, Q_INT32 depth);
void addImage(KisImageSP img);
/*
* Remove img from our list and delete it.
*/
void removeImage(KisImageSP img);
/*
* Return apointer to the current view.
*/
KisView* currentView();
const KisView* currentView() const;
/*
* Return apointer to the current image.
*/
KisImageSP currentImg() const;
KisImageSP imageNum( unsigned int _num );
/*
* Return the name of the current image.
*/
KisImageSP imageNum(Q_UINT32 num);
QString currentImgName();
/*
* Make img the current image.
*/
void setCurrentImage(KisImageSP img);
/*
* Unset the current image.
*/
void unsetCurrentImage();
/*
* Does the doc contain any images?
*/
bool isEmpty() const;
/*
* Return a list of image names.
*/
bool empty() const;
QStringList images();
/*
* Rename an image
*/
void renameImage(const QString& oldName, const QString& newName);
/*
* save current image as Qt image (standard image formats)
*/
bool saveAsQtImage(const QString& file, bool wholeImage);
bool MagickImageToLayer(const Magick::Image& img, KisView *view);
/*
* needs to go in kis_framebuffer.cc
*/
bool QtImageToLayer(QImage *qimage, KisView *pView);
/*
* copy rectangular area of layer to Qt Image
*/
bool LayerToQtImage(QImage *qimage, const QRect& clipRect);
/*
* set selection or clip rectangle for the document
*/
bool setClipImage();
/*
* get selection or clip image for the document
*/
QImage *getClipImage() { return m_pClipImage; }
/*
* delete clip image for the document
*/
QImage getClipImage();
void removeClipImage();
/*
* get currrent selection for document
*/
KisSelection *getSelection() { return m_pSelection; }
/*
* set selection for document
*/
KisSelection *getSelection();
void setSelection(const QRect& r);
/*
* clear selection for document -
*/
void clearSelection();
/*
* does the document have a selection ?
*/
bool hasSelection();
/*
* get FrameBuffer
*/
KisFrameBuffer *frameBuffer() { return m_pFrameBuffer; }
QRect getImageRect();
void setImage(const QString& imageName); // for print, save file and load file.
ktvector getTools() const;
void setTools(const ktvector& tools);
inline void setUndo(bool undo);
void setCanvasCursor(const QCursor& cursor);
QString nextImageName() const;
#if 0
/*
* Gradients settings
*/
struct GradientsSettings {
GradientsSettings() {
opacity = 100;
offset = 0;
mode = i18n( "Normal" );
blend = i18n( "FG to BG (RGB)" );
gradient = i18n( "Vertical" );
repeat = i18n( "None" );
}
uint opacity, offset;
QString mode, blend, gradient, repeat;
};
GradientsSettings getGradientsToolSettings() const { return gradientsSettings; }
void setGradientsSettings( GradientsSettings s );
#endif
public slots:
void slotImageUpdated();
void slotImageUpdated(const QRect& rect);
......@@ -242,6 +112,14 @@ public slots:
void slotDocumentRestored();
void slotCommandExecuted();
private slots:
// Slots for KisImage
void slotActiveLayerChanged(KisImageSP img);
void slotAlphaChanged(KisImageSP img);
void slotSelectionChanged(KisImageSP img);
void slotVisibilityChanged(KisImageSP img, CHANNELTYPE ctype);
void slotUpdate(KisImageSP img, Q_UINT32 x, Q_UINT32 y, Q_UINT32 w, Q_UINT32 h);
signals:
void docUpdated();
void docUpdated(const QRect& rect);
......@@ -249,11 +127,10 @@ signals:
void imageListUpdated();
protected:
/* reimplemented from koDocument - a document can have multiple
views of the same data */
// Overide KoDocument
virtual KoView* createViewInstance(QWidget *parent, const char *name);
protected:
QDomElement saveImages(QDomDocument& doc);
QDomElement saveLayers(QDomDocument& doc, KisImageSP img);
QDomElement saveChannels(QDomDocument& doc, KisLayer* lay);
......@@ -267,31 +144,13 @@ protected:
private:
bool m_undo;
/* undo/redo */
KCommandHistory *m_cmdHistory;
/* list of images for the document - each document can have multiple
images and each image must have at least one layer. however, a document
can only have one current image, which is what is loaded and saved -
the permanent data associated with it. This coresponds to an
image, but that image is interchangeable */
KisImageSPLst m_images;
KisView *m_currentView;
vKisImageSP m_images;
KisImageSP m_currentImg;
QImage *m_pClipImage;
KisSelection *m_pSelection;
KisFrameBuffer *m_pFrameBuffer;
ktvector m_tools;
DCOPObject *dcop;
QImage *m_clip;
KisSelection *m_selection;
DCOPObject *m_dcop;
};
void KisDoc::setUndo(bool undo)
{
m_undo = undo;
}
#endif // __kis_doc_h__
#endif // KIS_DOC_H_
......@@ -18,58 +18,121 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined KISGLOBAL_H_
#define KISGLOBAL_H_
#ifndef __kis_global_h__
#define __kis_global_h__
#include <limits.h>
#include <qglobal.h>
#include <qvaluevector.h>
#include <ksharedptr.h>
class KisTool;
/**
* Mime type for this app - not same as file type, but file types
* can be associated with a mime type and are opened with applications
* associated with the same mime type
*/
#define APP_MIMETYPE "application/x-krita"
const int CHANNEL_MIN = 0;
const int CHANNEL_MAX = 255;
const int OPACITY_TRANSPARENT = 0;
const int OPACITY_OPAQUE = 255;
// size for graphic blocks - must be a power of 2
/**
* Default size for a tile, Usually, all
* tiles are sqr(TILE_SIZE). Only tiles
* on the edge of an canvas are exempt from
* this rule.
*/
const int TILE_SIZE = 64;
// maximal number of channels
/*
* This used to mean the maximun number of channel that Krita could
* have... No more, it means the maximum number of color channels in
* a pixel, the number of onscreen channels is limited only by
* memory.
/**
* Default width of a tile.
*/
const int TILE_WIDTH = TILE_SIZE;
/**
* Default height of a tile.
*/
const int MAX_CHANNELS = 4;
const int TILE_HEIGHT = TILE_SIZE;
/**
* Size of a quantum
*/
typedef Q_UINT16 QUANTUM;
const QUANTUM QUANTUM_MAX = USHRT_MAX;
const QUANTUM OPACITY_TRANSPARENT = 0;
const QUANTUM OPACITY_OPAQUE = QUANTUM_MAX;
const QUANTUM MAXCHANNELS = 5;
enum enumComposite {
COMPOSITE_UNDEF,
COMPOSITE_OVER,
COMPOSITE_IN,
COMPOSITE_ATOP,
COMPOSITE_XOR,
COMPOSITE_PLUS,
COMPOSITE_MINUS,
COMPOSITE_ADD,
COMPOSITE_SUBTRACT,
COMPOSITE_DIFF,
COMPOSITE_MULT,
COMPOSITE_BUMPMAP,
COMPOSITE_COPY,
COMPOSITE_COPY_RED,
COMPOSITE_COPY_GREEN,
COMPOSITE_COPY_BLUE,
COMPOSITE_COPY_OPACITY,
COMPOSITE_CLEAR,
COMPOSITE_DISSOLVE,
COMPOSITE_DISPLACE,
COMPOSITE_MODULATE,
COMPOSITE_THRESHOLD
};
enum enumImgType {
IMAGE_TYPE_UNKNOWN,
IMAGE_TYPE_INDEXED,
IMAGE_TYPE_INDEXEDA,
IMAGE_TYPE_GREY,
IMAGE_TYPE_GREYA,
IMAGE_TYPE_RGB,
IMAGE_TYPE_RGBA,
IMAGE_TYPE_CMYK,
IMAGE_TYPE_CMYKA,
IMAGE_TYPE_LAB,
IMAGE_TYPE_LABA,
IMAGE_TYPE_YUV,
IMAGE_TYPE_YUVA };
enum enumUnit {
UNIT_MM,
UNIT_INCH
};
const int PIXEL_GRAY = 0;
const int PIXEL_GRAY_ALPHA = 1;
const int PIXEL_RED = 2;
const int PIXEL_GREEN = 1;
const int PIXEL_BLUE = 0;
const int PIXEL_ALPHA = 3;
const int PIXEL_INDEXED = 0;
const int PIXEL_INDEXED_ALPHA = 1;
typedef Q_UINT8 CHANNELTYPE;
typedef Q_UINT8 PIXELTYPE;
enum ActiveColor { ac_Foreground, ac_Background};
const CHANNELTYPE REDCHANNEL = 0;
const CHANNELTYPE GREENCHANNEL = 1;
const CHANNELTYPE BLUECHANNEL = 2;
const CHANNELTYPE GRAYCHANNEL = 3;
const CHANNELTYPE INDEXEDCHANNEL = 4;
const CHANNELTYPE ALPHACHANNEL = 5;
// color spaces
enum cSpace { cs_Indexed, cs_RGB, cs_HSV, cs_CMYK, cs_Lab };
const PIXELTYPE PIXEL_UNDEF = 255;
const PIXELTYPE PIXEL_GRAY = 0;
const PIXELTYPE PIXEL_GRAY_ALPHA = 1;
const PIXELTYPE PIXEL_RED = 0;
const PIXELTYPE PIXEL_GREEN = 1;
const PIXELTYPE PIXEL_BLUE = 2;
const PIXELTYPE PIXEL_ALPHA = 3;
const PIXELTYPE PIXEL_INDEXED = 0;
const PIXELTYPE PIXEL_INDEXED_ALPHA = 1;
// color modes
enum cMode { cm_Indexed, cm_Greyscale, cm_RGB, cm_RGBA, cm_CMYK, cm_CMYKA, cm_Lab, cm_LabA };
const Q_INT32 IMG_DEFAULT_WIDTH = 512;
const Q_INT32 IMG_DEFAULT_HEIGHT = 512;
const Q_INT32 IMG_DEFAULT_DEPTH = 4;
// channel id's
enum cId { ci_Indexed, ci_Alpha, ci_Red, ci_Green, ci_Blue, ci_Cyan,
ci_Magenta, ci_Yellow, ci_Black, ci_L, ci_a, ci_b };
#define CLAMP(x,l,u) ((x)<(l)?(l):((x)>(u)?(u):(x)))
// background mode
enum bgMode {bm_White, bm_Transparent, bm_BackgroundColor, bm_ForegroundColor };
#define downscale(quantum) ((unsigned char) ((quantum)/257UL))
#define upscale(value) ((QUANTUM) (257UL*(value)))