- scale bilinear (experimental: scaled image is too small by one pixel)
- bug fixes git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5347 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
/*****************************************************************************/
|
||||
// Filter
|
||||
// Written by Michael Pfeiffer
|
||||
//
|
||||
// Filter.cpp
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2003 OpenBeOS Project
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <scheduler.h>
|
||||
#include "Filter.h"
|
||||
#include "Scale.h"
|
||||
|
||||
Filter::Filter(BBitmap* image, BMessenger listener, uint32 what)
|
||||
: fListener(listener)
|
||||
, fWhat(what)
|
||||
, fIsRunning(false)
|
||||
, fWorkerThread(-1)
|
||||
, fSrcImage(image)
|
||||
, fDestImage(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Filter::~Filter()
|
||||
{
|
||||
Stop();
|
||||
delete fDestImage;
|
||||
}
|
||||
|
||||
BBitmap*
|
||||
Filter::GetBitmap()
|
||||
{
|
||||
if (fDestImage == NULL) {
|
||||
fDestImage = CreateDestImage(fSrcImage);
|
||||
}
|
||||
return fDestImage;
|
||||
}
|
||||
|
||||
status_t
|
||||
Filter::worker_thread(void* data)
|
||||
{
|
||||
Filter* filter = (Filter*)data;
|
||||
filter->Run();
|
||||
if (filter->fIsRunning) {
|
||||
filter->fListener.SendMessage(filter->fWhat);
|
||||
filter->fIsRunning = false;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void
|
||||
Filter::Start()
|
||||
{
|
||||
GetBitmap();
|
||||
if (fSrcImage == NULL || fDestImage == NULL) return;
|
||||
fWorkerThread = spawn_thread(worker_thread, "filter", suggest_thread_priority(B_STATUS_RENDERING), this);
|
||||
if (fWorkerThread >= 0) {
|
||||
fIsRunning = true;
|
||||
resume_thread(fWorkerThread);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Filter::Stop()
|
||||
{
|
||||
if (fIsRunning) {
|
||||
fIsRunning = false;
|
||||
status_t st;
|
||||
wait_for_thread(fWorkerThread, &st);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Filter::IsRunning() const
|
||||
{
|
||||
return fIsRunning;
|
||||
}
|
||||
|
||||
BBitmap*
|
||||
Filter::GetSrcImage()
|
||||
{
|
||||
return fSrcImage;
|
||||
}
|
||||
|
||||
BBitmap*
|
||||
Filter::GetDestImage()
|
||||
{
|
||||
return fDestImage;
|
||||
}
|
||||
|
||||
Scaler::Scaler(BBitmap* image, float scale, BMessenger listener, uint32 what)
|
||||
: Filter(image, listener, what)
|
||||
, fScale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
Scaler::~Scaler()
|
||||
{
|
||||
}
|
||||
|
||||
BBitmap*
|
||||
Scaler::CreateDestImage(BBitmap* srcImage)
|
||||
{
|
||||
if (srcImage == NULL || srcImage->ColorSpace() != B_RGB32 && srcImage->ColorSpace() !=B_RGBA32) return NULL;
|
||||
BRect src(srcImage->Bounds());
|
||||
BRect dest(0, 0, (src.Width()+1)*fScale - 1, (src.Height()+1)*fScale - 1);
|
||||
BBitmap* destImage = new BBitmap(dest, srcImage->ColorSpace());
|
||||
return destImage;
|
||||
}
|
||||
|
||||
void
|
||||
Scaler::Run()
|
||||
{
|
||||
scale(GetSrcImage(), GetDestImage(), IsRunningAddr(), fScale, fScale);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*****************************************************************************/
|
||||
// Filter
|
||||
// Written by Michael Pfeiffer
|
||||
//
|
||||
// Filter.h
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2003 OpenBeOS Project
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _Filter_h
|
||||
#define _Filter_h
|
||||
|
||||
#include <OS.h>
|
||||
#include <Bitmap.h>
|
||||
#include <Messenger.h>
|
||||
|
||||
class Filter {
|
||||
public:
|
||||
Filter(BBitmap* image, BMessenger listener, uint32 what);
|
||||
virtual ~Filter();
|
||||
|
||||
BBitmap* GetBitmap();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
bool IsRunning() const;
|
||||
volatile bool *IsRunningAddr() { return &fIsRunning; }
|
||||
|
||||
virtual BBitmap* CreateDestImage(BBitmap* srcImage) = 0;
|
||||
virtual void Run() = 0;
|
||||
|
||||
protected:
|
||||
BBitmap* GetSrcImage();
|
||||
BBitmap* GetDestImage();
|
||||
|
||||
private:
|
||||
BMessenger fListener;
|
||||
uint32 fWhat;
|
||||
static status_t worker_thread(void* data);
|
||||
volatile bool fIsRunning;
|
||||
thread_id fWorkerThread;
|
||||
BBitmap* fSrcImage;
|
||||
BBitmap* fDestImage;
|
||||
};
|
||||
|
||||
class Scaler : public Filter {
|
||||
public:
|
||||
Scaler(BBitmap* image, float scale, BMessenger listener, uint32 what);
|
||||
~Scaler();
|
||||
|
||||
BBitmap* CreateDestImage(BBitmap* srcImage);
|
||||
void Run();
|
||||
float Scale() const { return fScale; }
|
||||
private:
|
||||
float fScale;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,8 @@ App ShowImage : ShowImageApp.cpp
|
||||
ShowImageView.cpp
|
||||
ShowImageWindow.cpp
|
||||
PrintOptionsWindow.cpp
|
||||
Filter.cpp
|
||||
Scale.cpp
|
||||
;
|
||||
|
||||
LinkSharedOSLibs ShowImage : be tracker translation ;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*****************************************************************************/
|
||||
// PrintOptionsWindow
|
||||
// Written by Fernando Francisco de Oliveira, Michael Wilber, Michael Pfeiffer
|
||||
// Written by Michael Pfeiffer
|
||||
//
|
||||
// PrintOptionsWindow.cpp
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*****************************************************************************/
|
||||
// PrintOptionsWindow
|
||||
// Written by Fernando Francisco de Oliveira, Michael Wilber, Michael Pfeiffer
|
||||
// Written by Michael Pfeiffer
|
||||
//
|
||||
// PrintOptionsWindow.h
|
||||
//
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#include "Scale.h"
|
||||
#include <malloc.h>
|
||||
#include <Bitmap.h>
|
||||
|
||||
typedef struct {
|
||||
long x_i;
|
||||
float p;
|
||||
float p1;
|
||||
} row_values;
|
||||
|
||||
static void
|
||||
scale_bilinear_8(const BBitmap *src, BBitmap *dest,
|
||||
const float xFactor, const float yFactor,
|
||||
volatile bool *running)
|
||||
{
|
||||
register long drows, dcols, srows, scols;
|
||||
register unsigned char *spixptr, *dpixptr, *spix1, *spix2, *dpix;
|
||||
register unsigned long slb, dlb;
|
||||
register long i, j;
|
||||
float p, q, p1, q1;
|
||||
float xfac, yfac;
|
||||
float xfac_inv, yfac_inv;
|
||||
float src_y_f;
|
||||
long src_y_i, src_x_i;
|
||||
register unsigned char a, b, c, d;
|
||||
row_values *r, *rptr;
|
||||
float x_f;
|
||||
float result;
|
||||
|
||||
// Get values from image
|
||||
dpix = dpixptr = (unsigned char *)dest->Bits();
|
||||
spixptr = (unsigned char *)src->Bits();
|
||||
srows = src->Bounds().IntegerHeight()+1;
|
||||
scols = src->Bounds().IntegerWidth()+1;
|
||||
drows = dest->Bounds().IntegerHeight()+1;
|
||||
dcols = dest->Bounds().IntegerWidth()+1;
|
||||
slb = src->BytesPerRow();
|
||||
dlb = dest->BytesPerRow();
|
||||
|
||||
// Compute scale factors and inverse scale factors
|
||||
xfac = xFactor;
|
||||
yfac = yFactor;
|
||||
|
||||
if (xfac < 0.0)
|
||||
xfac = (float) dcols / (float) scols;
|
||||
if (yfac < 0.0)
|
||||
yfac = (float) drows / (float) srows;
|
||||
|
||||
xfac_inv = 1.0 / xfac;
|
||||
yfac_inv = 1.0 / yfac;
|
||||
|
||||
|
||||
// Allocate buffer for storing the values of ma and m1
|
||||
rptr = r = (row_values *)malloc (sizeof(row_values) * dcols);
|
||||
|
||||
// Fill up the buffer once, to be used for each row
|
||||
for (i=0; i<dcols; i++)
|
||||
{
|
||||
x_f = i*xfac_inv;
|
||||
rptr->x_i = (long)x_f;
|
||||
rptr->p = x_f - (float) rptr->x_i;
|
||||
rptr->p1 = 1.0 - rptr->p;
|
||||
rptr++;
|
||||
}
|
||||
|
||||
// Perform the scaling by inverse mapping from dest to source
|
||||
// That is, for each point in the destination, find the
|
||||
// corresponding point in the source.
|
||||
for (i=0; *running && i<drows-1; i++)
|
||||
{
|
||||
src_y_f = i * yfac_inv;
|
||||
src_y_i = (long) src_y_f;
|
||||
|
||||
q = src_y_f - (float)src_y_i;
|
||||
q1 = 1.0 - q;
|
||||
spix1 = spixptr + src_y_i*slb;
|
||||
spix2 = spixptr + (src_y_i+1)*slb;
|
||||
rptr = r;
|
||||
|
||||
for (j =0; j<dcols-1; j++,rptr++)
|
||||
{
|
||||
src_x_i = rptr->x_i;
|
||||
p = rptr->p;
|
||||
p1 = rptr->p1;
|
||||
|
||||
// Get the four corner pixels
|
||||
a = *(spix1 + src_x_i);
|
||||
b = *(spix1 + src_x_i + 1);
|
||||
c = *(spix2 + src_x_i);
|
||||
d = *(spix2 + src_x_i + 1);
|
||||
|
||||
// Compute the interpolated pixel value
|
||||
result = (((float)8*p1 + (float)b*p)*q1
|
||||
+ ((float)c*p1 + (float)d*p)*q);
|
||||
|
||||
*dpix++ = (unsigned char) result;
|
||||
}
|
||||
|
||||
// Advance to the next destination line
|
||||
dpix = (dpixptr += dlb);
|
||||
}
|
||||
|
||||
free(r);
|
||||
}
|
||||
|
||||
static void
|
||||
scale_bilinear_32(const BBitmap *src, BBitmap *dest,
|
||||
const float xFactor, const float yFactor,
|
||||
volatile bool *running)
|
||||
{
|
||||
register long drows, dcols, srows, scols;
|
||||
register unsigned long *spixptr, *spix1, *spix2;
|
||||
register unsigned char *dpixptr, *dpix;
|
||||
register unsigned long slb, dlb;
|
||||
register long i, j;
|
||||
float p, q, p1, q1;
|
||||
float xfac = xFactor, yfac = yFactor;
|
||||
float xfac_inv, yfac_inv;
|
||||
float src_y_f;
|
||||
long src_y_i, src_x_i;
|
||||
register unsigned char *a, *b, *c, *d;
|
||||
row_values *r, *rptr;
|
||||
float x_f;
|
||||
float rred, rgreen, rblue;
|
||||
|
||||
srows = src->Bounds().IntegerHeight()+1;
|
||||
scols = src->Bounds().IntegerWidth()+1;
|
||||
drows = dest->Bounds().IntegerHeight()+1;
|
||||
dcols = dest->Bounds().IntegerWidth()+1;
|
||||
|
||||
if (xFactor < 0.0)
|
||||
xfac = (float) dcols / (float) scols;
|
||||
else
|
||||
dcols = (long) ceil(scols * xfac);
|
||||
|
||||
if (yFactor < 0.0)
|
||||
yfac = (float) drows / (float) srows;
|
||||
else
|
||||
drows = (long) ceil(srows * yfac);
|
||||
|
||||
|
||||
|
||||
// Get values from image
|
||||
dpixptr = (unsigned char *)dest->Bits();
|
||||
dpix = (unsigned char *)dpixptr;
|
||||
spixptr = (unsigned long *)src->Bits();
|
||||
slb = src->BytesPerRow()/4;
|
||||
dlb = dest->BytesPerRow();
|
||||
|
||||
|
||||
xfac_inv = 1.0 / xfac;
|
||||
yfac_inv = 1.0 / yfac;
|
||||
|
||||
|
||||
// Allocate buffer for storing the values of ma and m1
|
||||
rptr = r = (row_values *)malloc (sizeof(row_values) * dcols);
|
||||
|
||||
// Fill up the buffer once, to be used for each row
|
||||
for (i=0; i<dcols; i++)
|
||||
{
|
||||
x_f = i*xfac_inv;
|
||||
rptr->x_i = (long)x_f;
|
||||
rptr->p = x_f - (float) rptr->x_i;
|
||||
rptr->p1 = 1.0 - rptr->p;
|
||||
rptr++;
|
||||
}
|
||||
|
||||
// Perform the scaling by inverse mapping from dest to source
|
||||
// That is, for each point in the destination, find the
|
||||
// corresponding point in the source.
|
||||
for (i=0; *running && i<drows-1; i++)
|
||||
{
|
||||
src_y_f = i * yfac_inv;
|
||||
src_y_i = (long) src_y_f;
|
||||
|
||||
q = src_y_f - (float)src_y_i;
|
||||
q1 = 1.0 - q;
|
||||
spix1 = spixptr + src_y_i*slb;
|
||||
spix2 = spixptr + (src_y_i+1)*slb;
|
||||
rptr = r;
|
||||
|
||||
for (j =0; j<dcols-1; j++,rptr++)
|
||||
{
|
||||
src_x_i = rptr->x_i;
|
||||
p = rptr->p;
|
||||
p1 = rptr->p1;
|
||||
|
||||
// Get the four corner pixels
|
||||
a = (unsigned char *)(spix1 + src_x_i);
|
||||
b = (unsigned char *)(spix1 + src_x_i + 1);
|
||||
c = (unsigned char *)(spix2 + src_x_i);
|
||||
d = (unsigned char *)(spix2 + src_x_i + 1);
|
||||
|
||||
// Compute the interpolated pixel value
|
||||
rblue = (((float)a[0]*p1 + (float)b[0]*p)*q1
|
||||
+ ((float)c[0]*p1 + (float)d[0]*p)*q);
|
||||
rgreen = (((float)a[1]*p1 + (float)b[1]*p)*q1
|
||||
+ ((float)c[1]*p1 + (float)d[1]*p)*q);
|
||||
rred = (((float)a[2]*p1 + (float)b[2]*p)*q1
|
||||
+ ((float)c[2]*p1 + (float)d[2]*p)*q);
|
||||
|
||||
dpix[0] = (unsigned char) rblue;
|
||||
dpix[1] = (unsigned char) rgreen;
|
||||
dpix[2] = (unsigned char) rred;
|
||||
dpix += 4;
|
||||
}
|
||||
|
||||
// Advance to the next destination line
|
||||
dpix = (dpixptr += dlb);
|
||||
}
|
||||
|
||||
free(r);
|
||||
}
|
||||
|
||||
status_t scale(const BBitmap *src, BBitmap *dst,
|
||||
volatile bool* running,
|
||||
const float xFactor, const float yFactor,
|
||||
scale_method scmethod)
|
||||
{
|
||||
if (src->ColorSpace() != dst->ColorSpace())
|
||||
return -1;
|
||||
|
||||
|
||||
switch (scmethod)
|
||||
{
|
||||
case IMG_SCALE_BILINEAR:
|
||||
{
|
||||
switch (src->ColorSpace())
|
||||
{
|
||||
case B_COLOR_8_BIT:
|
||||
case B_GRAYSCALE_8_BIT:
|
||||
scale_bilinear_8(src, dst, xFactor, yFactor, running);
|
||||
break;
|
||||
|
||||
case B_RGB32:
|
||||
case B_RGBA32:
|
||||
scale_bilinear_32(src, dst, xFactor, yFactor, running);
|
||||
break;
|
||||
|
||||
default: // color space we can't deal with
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#include <Bitmap.h>
|
||||
|
||||
enum scale_method {
|
||||
IMG_SCALE_BILINEAR = 1
|
||||
};
|
||||
|
||||
class BBitmap;
|
||||
|
||||
// Scale an image. It will work in either direction.
|
||||
// Scaling up or down. Scaling by integer values will be
|
||||
// most optimal.
|
||||
|
||||
status_t scale(const BBitmap *source, BBitmap *dst,
|
||||
volatile bool *running,
|
||||
const float xFactor = -1, const float yFactor = -1,
|
||||
scale_method = IMG_SCALE_BILINEAR);
|
||||
|
||||
@@ -67,6 +67,8 @@ const uint32 MSG_PRINT = 'mPRT';
|
||||
const uint32 MSG_ZOOM_IN = 'mZIN';
|
||||
const uint32 MSG_ZOOM_OUT = 'mZOU';
|
||||
const uint32 MSG_ORIGINAL_SIZE = 'mOSZ';
|
||||
const uint32 MSG_INVALIDATE = 'mIVD';
|
||||
const uint32 MSG_SCALE_BILINEAR = 'mSBL';
|
||||
|
||||
extern const char *APP_SIG;
|
||||
|
||||
|
||||
@@ -167,6 +167,8 @@ ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode,
|
||||
fShowCaption = false;
|
||||
fZoom = 1.0;
|
||||
fMovesImage = false;
|
||||
fScaleBilinear = false;
|
||||
fScaler = NULL;
|
||||
|
||||
SetViewColor(B_TRANSPARENT_COLOR);
|
||||
SetHighColor(kborderColor);
|
||||
@@ -176,8 +178,7 @@ ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode,
|
||||
|
||||
ShowImageView::~ShowImageView()
|
||||
{
|
||||
delete fpBitmap;
|
||||
fpBitmap = NULL;
|
||||
DeleteBitmap();
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -225,10 +226,20 @@ ShowImageView::AddToRecentDocuments()
|
||||
}
|
||||
|
||||
void
|
||||
ShowImageView::SetImage(const entry_ref *pref)
|
||||
ShowImageView::DeleteBitmap()
|
||||
{
|
||||
if (fScaler) {
|
||||
delete fScaler;
|
||||
fScaler = NULL;
|
||||
}
|
||||
delete fpBitmap;
|
||||
fpBitmap = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ShowImageView::SetImage(const entry_ref *pref)
|
||||
{
|
||||
DeleteBitmap();
|
||||
fbHasSelection = false;
|
||||
fMakesSelection = false;
|
||||
|
||||
@@ -355,6 +366,14 @@ ShowImageView::FlushToLeftTop()
|
||||
ScrollTo(p);
|
||||
}
|
||||
|
||||
void
|
||||
ShowImageView::SetScaleBilinear(bool s)
|
||||
{
|
||||
if (fScaleBilinear != s) {
|
||||
fScaleBilinear = s; Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShowImageView::AttachedToWindow()
|
||||
{
|
||||
@@ -362,7 +381,7 @@ ShowImageView::AttachedToWindow()
|
||||
}
|
||||
|
||||
BRect
|
||||
ShowImageView::AlignBitmap() const
|
||||
ShowImageView::AlignBitmap()
|
||||
{
|
||||
BRect rect(fpBitmap->Bounds());
|
||||
float width, height;
|
||||
@@ -374,20 +393,22 @@ ShowImageView::AlignBitmap() const
|
||||
s = width / rect.Width();
|
||||
|
||||
if (s * rect.Height() <= height) {
|
||||
fZoom = s;
|
||||
rect.right = width;
|
||||
rect.bottom = s * rect.Height();
|
||||
// center vertically
|
||||
rect.OffsetBy(0, (height - rect.Height()) / 2);
|
||||
} else {
|
||||
rect.right = height / rect.Height() * rect.Width();
|
||||
fZoom = height / rect.Height();
|
||||
rect.right = fZoom * rect.Width();
|
||||
rect.bottom = height;
|
||||
// center horizontally
|
||||
rect.OffsetBy((width - rect.Width()) / 2, 0);
|
||||
}
|
||||
} else {
|
||||
// zoom image
|
||||
rect.right = (rect.right+1)*fZoom-1;
|
||||
rect.bottom = (rect.bottom+1)*fZoom-1;
|
||||
rect.right = ((int)(rect.right+1)*fZoom)-1;
|
||||
rect.bottom = ((int)(rect.bottom+1)*fZoom)-1;
|
||||
// align
|
||||
switch (fHAlignment) {
|
||||
case B_ALIGN_CENTER:
|
||||
@@ -423,11 +444,8 @@ ShowImageView::Setup(BRect rect)
|
||||
{
|
||||
fLeft = rect.left;
|
||||
fTop = rect.top;
|
||||
fScaleX = rect.Width() / fpBitmap->Bounds().Width();
|
||||
fScaleY = rect.Height() / fpBitmap->Bounds().Height();
|
||||
// XXX Is Width/Height off by one?
|
||||
// fScaleX = (rect.Width()+1) / (fpBitmap->Bounds().Width()+1);
|
||||
// fScaleY = (rect.Width()+1) / (fpBitmap->Bounds().Height()+1);
|
||||
fScaleX = (rect.Width()+1.0) / (fpBitmap->Bounds().Width()+1.0);
|
||||
fScaleY = (rect.Height()+1.0) / (fpBitmap->Bounds().Height()+1.0);
|
||||
}
|
||||
|
||||
BPoint
|
||||
@@ -511,6 +529,32 @@ ShowImageView::DrawCaption()
|
||||
PopState();
|
||||
}
|
||||
|
||||
Scaler*
|
||||
ShowImageView::GetScaler()
|
||||
{
|
||||
if (fScaler == NULL || fScaler->Scale() != fZoom) {
|
||||
delete fScaler;
|
||||
BMessenger msgr(this, Window());
|
||||
fScaler = new Scaler(fpBitmap, fZoom, msgr, MSG_INVALIDATE);
|
||||
fScaler->Start();
|
||||
}
|
||||
return fScaler;
|
||||
}
|
||||
|
||||
void
|
||||
ShowImageView::DrawImage(BRect rect)
|
||||
{
|
||||
if (fScaleBilinear) {
|
||||
Scaler* scaler = GetScaler();
|
||||
if (scaler != NULL && scaler->GetBitmap() != NULL && !scaler->IsRunning()) {
|
||||
BBitmap* bitmap = scaler->GetBitmap();
|
||||
DrawBitmap(bitmap, BPoint(rect.left, rect.top));
|
||||
return;
|
||||
}
|
||||
}
|
||||
DrawBitmap(fpBitmap, fpBitmap->Bounds(), rect);
|
||||
}
|
||||
|
||||
void
|
||||
ShowImageView::Draw(BRect updateRect)
|
||||
{
|
||||
@@ -527,8 +571,8 @@ ShowImageView::Draw(BRect updateRect)
|
||||
// Draw black rectangle around image
|
||||
StrokeRect(border);
|
||||
|
||||
// Draw image
|
||||
DrawBitmap(fpBitmap, fpBitmap->Bounds(), rect);
|
||||
// Draw image
|
||||
DrawImage(rect);
|
||||
|
||||
if (fShowCaption && !fMovesImage) {
|
||||
// to avoid flickering, disabled during moving with mouse
|
||||
@@ -1020,6 +1064,9 @@ ShowImageView::MessageReceived(BMessage *pmsg)
|
||||
case B_MOUSE_WHEEL_CHANGED:
|
||||
MouseWheelChanged(pmsg);
|
||||
break;
|
||||
case MSG_INVALIDATE:
|
||||
Invalidate();
|
||||
break;
|
||||
default:
|
||||
BView::MessageReceived(pmsg);
|
||||
break;
|
||||
@@ -1284,6 +1331,9 @@ ShowImageView::FirstFile()
|
||||
void
|
||||
ShowImageView::SetZoom(float zoom)
|
||||
{
|
||||
if (fScaleBilinear && fZoom != zoom) {
|
||||
delete fScaler; fScaler = NULL;
|
||||
}
|
||||
fZoom = zoom;
|
||||
FixupScrollBars();
|
||||
Invalidate();
|
||||
@@ -1453,7 +1503,8 @@ ShowImageView::DoImageOperation(image_operation op)
|
||||
}
|
||||
|
||||
// set new bitmap
|
||||
delete fpBitmap; fpBitmap = bm;
|
||||
DeleteBitmap();
|
||||
fpBitmap = bm;
|
||||
// remove selection
|
||||
fbHasSelection = false;
|
||||
Notify(NULL);
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include <String.h>
|
||||
#include <TranslatorRoster.h>
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class ShowImageView : public BView {
|
||||
public:
|
||||
ShowImageView(BRect rect, const char *name, uint32 resizingMode,
|
||||
@@ -52,6 +54,8 @@ public:
|
||||
void GetName(BString *name);
|
||||
void GetPath(BString *name);
|
||||
void FlushToLeftTop();
|
||||
void SetScaleBilinear(bool b);
|
||||
bool GetScaleBilinear() { return fScaleBilinear; }
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void Draw(BRect updateRect);
|
||||
@@ -106,11 +110,12 @@ private:
|
||||
void AnimateSelection(bool a);
|
||||
void Notify(const char* status);
|
||||
void AddToRecentDocuments();
|
||||
void DeleteBitmap();
|
||||
int32 BytesPerPixel(color_space cs) const;
|
||||
inline void CopyPixel(uchar* dest, int32 destX, int32 destY, int32 destBPR, uchar* src, int32 x, int32 y, int32 bpr, int32 bpp);
|
||||
inline void InvertPixel(int32 x, int32 y, uchar* dest, int32 destBPR, uchar* src, int32 bpr, int32 bpp);
|
||||
void DoImageOperation(image_operation op);
|
||||
BRect AlignBitmap() const;
|
||||
BRect AlignBitmap();
|
||||
void Setup(BRect r);
|
||||
BPoint ImageToView(BPoint p) const;
|
||||
BPoint ViewToImage(BPoint p) const;
|
||||
@@ -135,6 +140,8 @@ private:
|
||||
void DrawBorder(BRect border);
|
||||
void DrawCaption();
|
||||
void DrawSelectionBox(BRect &rect);
|
||||
Scaler* GetScaler();
|
||||
void DrawImage(BRect rect);
|
||||
float LimitToRange(float v, orientation o, bool absolute);
|
||||
void ScrollRestricted(float x, float y, bool absolute);
|
||||
void ScrollRestrictedTo(float x, float y);
|
||||
@@ -147,6 +154,8 @@ private:
|
||||
int32 fDocumentCount;
|
||||
BBitmap *fpBitmap;
|
||||
float fZoom;
|
||||
bool fScaleBilinear;
|
||||
Scaler* fScaler;
|
||||
bool fResizeToViewBounds;
|
||||
alignment fHAlignment;
|
||||
vertical_alignment fVAlignment;
|
||||
|
||||
@@ -166,12 +166,13 @@ ShowImageWindow::UpdateRecentDocumentsMenu()
|
||||
be_roster->GetRecentDocuments(&list, 20, NULL, APP_SIG);
|
||||
for (int i = 0; list.FindRef("refs", i, &ref) == B_OK; i++) {
|
||||
BEntry entry(&ref);
|
||||
entry.GetName(name);
|
||||
msg = new BMessage(B_REFS_RECEIVED);
|
||||
msg->AddRef("refs", &ref);
|
||||
item = new BMenuItem(name, msg, 0, 0);
|
||||
fpOpenMenu->AddItem(item);
|
||||
item->SetTarget(be_app, NULL);
|
||||
if (entry.GetName(name) == B_OK) {
|
||||
msg = new BMessage(B_REFS_RECEIVED);
|
||||
msg->AddRef("refs", &ref);
|
||||
item = new BMenuItem(name, msg, 0, 0);
|
||||
fpOpenMenu->AddItem(item);
|
||||
item->SetTarget(be_app, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,13 +210,16 @@ ShowImageWindow::BuildViewMenu(BMenu *pmenu)
|
||||
AddItemMenu(pmenu, "Original Size", MSG_ORIGINAL_SIZE, 0, 0, 'W', true);
|
||||
AddItemMenu(pmenu, "Zoom In", MSG_ZOOM_IN, '+', 0, 'W', true);
|
||||
AddItemMenu(pmenu, "Zoom Out", MSG_ZOOM_OUT, '-', 0, 'W', true);
|
||||
AddItemMenu(pmenu, "Scale Bilinear", MSG_SCALE_BILINEAR, 0, 0, 'W', true);
|
||||
pmenu->AddSeparatorItem();
|
||||
AddItemMenu(pmenu, "Fit To Window Size", MSG_FIT_TO_WINDOW_SIZE, 0, 0, 'W', true);
|
||||
AddItemMenu(pmenu, "Full Screen", MSG_FULL_SCREEN, B_ENTER, 0, 'W', true);
|
||||
MarkMenuItem(pmenu, MSG_FULL_SCREEN, fFullScreen);
|
||||
AddItemMenu(pmenu, "Show Caption in Full Screen Mode", MSG_SHOW_CAPTION, 0, 0, 'W', true);
|
||||
MarkMenuItem(pmenu, MSG_SHOW_CAPTION, fShowCaption);
|
||||
|
||||
if (fpImageView) {
|
||||
MarkMenuItem(pmenu, MSG_SCALE_BILINEAR, fpImageView->GetScaleBilinear());
|
||||
bool resize = fpImageView->GetResizeToViewBounds();
|
||||
MarkMenuItem(pmenu, MSG_FIT_TO_WINDOW_SIZE, resize);
|
||||
EnableMenuItem(pmenu, MSG_ORIGINAL_SIZE, !resize);
|
||||
@@ -640,6 +644,9 @@ ShowImageWindow::MessageReceived(BMessage *pmsg)
|
||||
case MSG_ORIGINAL_SIZE:
|
||||
fpImageView->SetZoom(1.0);
|
||||
break;
|
||||
case MSG_SCALE_BILINEAR:
|
||||
fpImageView->SetScaleBilinear(ToggleMenuItem(pmsg->what));
|
||||
break;
|
||||
|
||||
default:
|
||||
BWindow::MessageReceived(pmsg);
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user