sfftools/sffview/tags/REL0_5_0/sffdoc.cpp

419 lines
10 KiB
C++

//
// This file is part of sffview, a program to view structured fax files (sff)
//
// Copyright (C) 1998-2012 Peter Schaefer-Hutter and contributors ("THE AUTHORS")
//
// Permission to use, copy, modify, distribute, and sell this software and
// its documentation for any purpose is hereby granted without fee.
//
// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL,
// INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
// THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
// OR PERFORMANCE OF THIS SOFTWARE.
//
// Contributor(s):
// None
//
// You can contact the original author by email at peter.schaefer@gmx.de.
//
// I'm always pleased to hear that somebody is actually using my software.
// If you can manage it, e-mail me a quick notice. Thanks!
//
/*-RCS-Info----------------------------------------------------
$Id: sffdoc.cpp,v 1.4 2011/10/18 19:39:38 pschaefer Exp $
---RCS-Info--------------------------------------------------*/
#include <wx/wx.h>
#if !wxUSE_DOC_VIEW_ARCHITECTURE
#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
#endif
#include "sfftypes.h"
#include "common.h"
#include "codes.h"
#include "decoder.h"
#include "sfffile.h"
#include "sffdoc.h"
#include "sffview.h"
#include <iostream>
using namespace std;
// ---------------------------------------------------------------------
CBitmapDecoder::CBitmapDecoder(wxUint32 aWidth, wxUint32 aHeight) :
m_pBitmap(0),
m_Width(aWidth),
m_Height(aHeight),
m_Scanline(0),
m_sink(m_abBuffer, sizeof(m_abBuffer))
{
m_WidthInBytes = aWidth>>3;
m_Width = aWidth;
m_Height = aHeight;
m_pBitmap = new wxUint8[m_WidthInBytes*aHeight];
memset(m_pBitmap, 0x00, m_WidthInBytes*aHeight);
Reset();
}
CBitmapDecoder::~CBitmapDecoder()
{
if (m_pBitmap) delete m_pBitmap;
}
void CBitmapDecoder::Reset()
{
m_Scanline = 0;
m_sink.Reset();
}
void CBitmapDecoder::BlankLine()
{
::memset(m_abBuffer, 0x00, sizeof(m_abBuffer));
}
CBitSink& CBitmapDecoder::GetBitSink()
{
m_sink.Reset();
return m_sink;
}
void CBitmapDecoder::WriteLine()
{
if (m_Scanline < m_Height) {
memcpy(m_pBitmap+(m_WidthInBytes*m_Scanline), m_abBuffer, m_WidthInBytes);
++m_Scanline;
}
}
const wxUint8 *CBitmapDecoder::GetBitmap()
{
return m_pBitmap;
}
// ---------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(SffDocument, wxDocument)
SffDocument::SffDocument(void) :
m_pSffFile(NULL),
m_pDecoder(NULL),
m_pPageBmp(NULL),
m_nPageIdx(0)
{
}
SffDocument::~SffDocument(void)
{
if (m_pSffFile) {
delete m_pSffFile;
}
if (m_pPageBmp) {
delete m_pPageBmp;
}
if (m_pDecoder) {
delete m_pDecoder;
}
}
bool SffDocument::OnOpenDocument(const wxString& filename)
{
bool rc = false;
try {
wxBusyCursor wait;
m_nPageIdx = 0;
std::string strFN(filename.ToStdString());
m_pSffFile = new CSffFile(strFN);
m_pDecoder = new CBitmapDecoder(GetWidth(), GetHeight());
SetFilename(filename, TRUE);
Modify(FALSE);
CreatePageBitmap();
rc = true;
}
catch (const CSimpleException& e) {
wxLogError( (wxChar *) e.what().c_str() );
}
return rc;
}
int SffDocument::GetPageCount()
{
wxASSERT(m_pSffFile != NULL);
return (m_pSffFile != NULL) ? m_pSffFile->GetPageCount() : 0;
}
int SffDocument::GetCurrentPageIdx()
{
wxASSERT(m_pSffFile != NULL);
return m_nPageIdx;
}
void SffDocument::CreatePageBitmap()
{
int i;
int lines, cols;
bool bLowRes;
if (m_pSffFile == NULL)
return;
try
{
TSFFRecord rec;
// CDCFile outfile;
m_pSffFile->SeekPage(m_nPageIdx);
bLowRes = m_pSffFile->IsLowRes(m_nPageIdx);
lines = GetHeight();
cols = GetWidth();
// Decode SFF Records ...
m_pDecoder->Reset();
while ((lines > 0) && m_pSffFile->GetRecord(rec)) {
switch(rec.type) {
case NORMAL :
m_pDecoder->BlankLine();
m_pSffFile->DecodeRecord(rec, m_pDecoder->GetBitSink());
m_pDecoder->WriteLine(); --lines;
if (bLowRes) { // double line if low-res
m_pDecoder->WriteLine(); --lines;
}
if (rec.pData != 0) free(rec.pData);
break;
case USERINFO :
// not supported
if (rec.pData != 0) free(rec.pData);
break;
case BADLINE :
case WHITESKIP :
// a white skip is, ah, skipped ;)
m_pDecoder->BlankLine();
for (i=0; i < rec.cb; ++i) {
m_pDecoder->WriteLine(); --lines;
if (bLowRes) { // double line if low-res
m_pDecoder->WriteLine(); --lines;
}
}
break;
default :
break;
}
}
wxBitmap *pOld = m_pPageBmp;
m_pPageBmp = new wxBitmap((const char*)m_pDecoder->GetBitmap(),
GetWidth(), GetHeight());
UpdateAllViews();
if (pOld) {
delete pOld;
}
}
catch (CSimpleException e) {
wxLogError( (wxChar *)e.what().c_str() );
}
}
wxBitmap *SffDocument::GetPageBitmap(int nPage)
{
int i;
int lines, cols;
bool bLowRes;
if (m_pSffFile == NULL)
return NULL;
wxBitmap *pBmp = NULL;
try
{
TSFFRecord rec;
// CDCFile outfile;
m_pSffFile->SeekPage(nPage-1);
bLowRes = m_pSffFile->IsLowRes(nPage-1);
lines = GetHeight();
cols = GetWidth();
// Decode SFF Records ...
m_pDecoder->Reset();
while ((lines > 0) && m_pSffFile->GetRecord(rec)) {
switch(rec.type) {
case NORMAL :
m_pDecoder->BlankLine();
m_pSffFile->DecodeRecord(rec, m_pDecoder->GetBitSink());
m_pDecoder->WriteLine(); --lines;
if (bLowRes) { // double line if low-res
m_pDecoder->WriteLine(); --lines;
}
if (rec.pData != 0) free(rec.pData);
break;
case USERINFO :
// not supported
if (rec.pData != 0) free(rec.pData);
break;
case BADLINE :
case WHITESKIP :
// a white skip is, ah, skipped ;)
m_pDecoder->BlankLine();
for (i=0; i < rec.cb; ++i) {
m_pDecoder->WriteLine(); --lines;
if (bLowRes) { // double line if low-res
m_pDecoder->WriteLine(); --lines;
}
}
break;
default :
break;
}
}
pBmp = new wxBitmap((const char*)m_pDecoder->GetBitmap(),
GetWidth(), GetHeight());
}
catch (CSimpleException e) {
wxLogError( (wxChar *)e.what().c_str() );
}
return pBmp;
}
wxUint32 SffDocument::GetHeight()
{
wxASSERT(m_pSffFile != NULL);
if (m_pSffFile != NULL) {
wxUint32 h = m_pSffFile->GetPageHeight(m_nPageIdx);
return m_pSffFile->IsLowRes(m_nPageIdx) ? h * 2 : h;
}
return 0;
}
wxUint32 SffDocument::GetWidth()
{
wxASSERT(m_pSffFile != NULL);
if (m_pSffFile != NULL) {
return m_pSffFile->GetPageWidth(m_nPageIdx);
}
return 0;
}
void SffDocument::NextPage()
{
wxASSERT(m_pSffFile != NULL);
if (m_pSffFile != NULL) {
if (m_nPageIdx < m_pSffFile->GetPageCount()) {
++m_nPageIdx;
CreatePageBitmap();
}
}
}
void SffDocument::PrevPage()
{
wxASSERT(m_pSffFile != NULL);
if (m_nPageIdx >= 1) {
--m_nPageIdx;
CreatePageBitmap();
}
}
/*
void SffDocument::PreparePage(int nPage)
{
wxASSERT(m_pSffFile != NULL);
if (m_nPageIdx >= 1) {
--m_nPageIdx;
CreatePageBitmap();
}
}
*/
// ---------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(SffPrintout, wxPrintout)
SffPrintout::SffPrintout(SffDocument *doc) :
wxPrintout()
{
m_Doc = doc;
m_nPageCount = doc->GetPageCount();
};
bool SffPrintout::OnPrintPage(int page)
{
wxBitmap *pBmp = m_Doc->GetPageBitmap(page);
int nBitmapHeight = pBmp->GetHeight();
int nBitmapWidth = pBmp->GetWidth();
wxDC *dc = GetDC();
wxMemoryDC mem_dc;
mem_dc.SelectObject(*pBmp);
// Get the logical pixels per inch of screen and printer
int ppiScreenX, ppiScreenY;
GetPPIScreen(&ppiScreenX, &ppiScreenY);
wxUnusedVar(ppiScreenY);
int ppiPrinterX, ppiPrinterY;
GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
wxUnusedVar(ppiPrinterY);
// This scales the DC so that the printout roughly represents the
// the screen scaling. The text point size _should_ be the right size
// but in fact is too small for some reason. This is a detail that will
// need to be addressed at some point but can be fudged for the
// moment.
float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
// Now we have to check in case our real page size is reduced
// (e.g. because we're drawing to a print preview memory DC)
int pageWidth, pageHeight;
int w, h;
dc->GetSize(&w, &h);
GetPageSizePixels(&pageWidth, &pageHeight);
wxUnusedVar(pageHeight);
// If printer pageWidth == current DC width, then this doesn't
// change. But we might be the preview bitmap width, so scale down.
float overallScale = scale * (float)(w/(float)pageWidth);
float zoomW = w; zoomW = zoomW/(nBitmapWidth*overallScale);
float zoomH = h; zoomH = zoomH/(nBitmapHeight*overallScale);
dc->SetUserScale(overallScale * zoomW, overallScale * zoomH);
dc->SetBackground(*wxWHITE_BRUSH);
#if defined(__WXGTK__) && !wxCHECK_VERSION(2,8,0)
if (pageWidth != w) {
// Strange misbehaviour of older wxGTK -> if we blit zoomed, the colours
// get inversed ??!? Workaround: wxSRC_INVERT
dc->Blit(0,0,nBitmapWidth,nBitmapHeight,&mem_dc,0,0,wxSRC_INVERT);
} else {
dc->Blit(0,0,nBitmapWidth,nBitmapHeight,&mem_dc,0,0,wxCOPY);
}
#else
dc->Blit(0,0,nBitmapWidth,nBitmapHeight,&mem_dc,0,0,wxCOPY);
#endif
return TRUE;
}
bool SffPrintout::HasPage(int pageNum)
{
return (pageNum <= m_nPageCount);
}
bool SffPrintout::OnBeginDocument(int startPage, int endPage)
{
if (!wxPrintout::OnBeginDocument(startPage, endPage))
return FALSE;
return TRUE;
}
void SffPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
{
*minPage = 1;
*maxPage = m_nPageCount;
*selPageFrom = 1;
*selPageTo = 1;
}