示例#1
0
Plane * CMRouter::initPlane(bool rotate90) {
	Tile * bufferTile = TiAlloc();
	TiSetType(bufferTile, Tile::BUFFER);
	TiSetBody(bufferTile, NULL);

	QRectF bufferRect(rotate90 ? m_maxRect90 : m_maxRect);

    TileRect br;
    qrectToTile(bufferRect, br);

	bufferRect.adjust(-bufferRect.width(), -bufferRect.height(), bufferRect.width(), bufferRect.height());
    //DebugDialog::debug("max rect", m_maxRect);
    //DebugDialog::debug("max rect 90", m_maxRect90);


    int l = fasterRealToTile(bufferRect.left());
    int t = fasterRealToTile(bufferRect.top());
    int r = fasterRealToTile(bufferRect.right());
    int b = fasterRealToTile(bufferRect.bottom());
    SETLEFT(bufferTile, l);
    SETYMIN(bufferTile, t);		// TILE is Math Y-axis not computer-graphic Y-axis

	Plane * thePlane = TiNewPlane(bufferTile, br.xmini, br.ymini, br.xmaxi, br.ymaxi);

    SETRIGHT(bufferTile, r);
	SETYMAX(bufferTile, b);		// TILE is Math Y-axis not computer-graphic Y-axis

	// do not use InsertTile here
	TiInsertTile(thePlane, &thePlane->maxRect, NULL, Tile::SPACE); 
    //infoTileRect("insert", thePlane->maxRect);

	return thePlane;
}
/**
 * Sets hwc layer rectangles required for hwc composition
 *
 * @param aVisible Input. Layer's unclipped visible rectangle
 *        The origin is the layer's buffer
 * @param aTransform Input. Layer's transformation matrix
 *        It transforms from layer space to screen space
 * @param aClip Input. A clipping rectangle.
 *        The origin is the top-left corner of the screen
 * @param aBufferRect Input. The layer's buffer bounds
 *        The origin is the buffer itself and hence always (0,0)
 * @param aSurceCrop Output. Area of the source to consider,
 *        the origin is the top-left corner of the buffer
 * @param aVisibleRegionScreen Output. Visible region in screen space.
 *        The origin is the top-left corner of the screen
 * @return true if the layer should be rendered.
 *         false if the layer can be skipped
 */
static bool
PrepareLayerRects(nsIntRect aVisible, const gfxMatrix& aTransform,
                  nsIntRect aClip, nsIntRect aBufferRect,
                  hwc_rect_t* aSourceCrop, hwc_rect_t* aVisibleRegionScreen) {

    gfxRect visibleRect(aVisible);
    gfxRect clip(aClip);
    gfxRect visibleRectScreen = aTransform.TransformBounds(visibleRect);
    // |clip| is guaranteed to be integer
    visibleRectScreen.IntersectRect(visibleRectScreen, clip);

    if (visibleRectScreen.IsEmpty()) {
        LOGD("Skip layer");
        return false;
    }

    gfxMatrix inverse(aTransform);
    inverse.Invert();
    gfxRect crop = inverse.TransformBounds(visibleRectScreen);
    // Map to buffer space
    crop -= visibleRect.TopLeft();
    gfxRect bufferRect(aBufferRect);
    //clip to buffer size
    crop.IntersectRect(crop, aBufferRect);
    crop.RoundOut();

    if (crop.IsEmpty()) {
        LOGD("Skip layer");
        return false;
    }


    //propagate buffer clipping back to visible rect
    visibleRectScreen = aTransform.TransformBounds(crop + visibleRect.TopLeft());
    visibleRectScreen.RoundOut();

    aSourceCrop->left = crop.x;
    aSourceCrop->top  = crop.y;
    aSourceCrop->right  = crop.x + crop.width;
    aSourceCrop->bottom = crop.y + crop.height;

    aVisibleRegionScreen->left = visibleRectScreen.x;
    aVisibleRegionScreen->top  = visibleRectScreen.y;
    aVisibleRegionScreen->right  = visibleRectScreen.x + visibleRectScreen.width;
    aVisibleRegionScreen->bottom = visibleRectScreen.y + visibleRectScreen.height;

    return true;
}
示例#3
0
void wxImageBox::OnPaint(wxPaintEvent &event)
{
  wxRect paintRect = getPaintRect();
  if (paintRect.GetRight() >= m_imageWidth)
    paintRect.width = m_imageWidth - paintRect.x;
  if (paintRect.GetBottom() >= m_imageHeight)
    paintRect.height = m_imageHeight - paintRect.y;
  wxRect bufferRect(m_bufferX, m_bufferY,
	m_buffer->GetWidth(), m_buffer->GetHeight());
  if (m_repaint ||
      paintRect.x < bufferRect.x ||
      paintRect.y < bufferRect.y ||
      paintRect.GetRight() > bufferRect.GetRight() ||
      paintRect.GetBottom() > bufferRect.GetBottom())
  {
    Paint(); // update buffer
    m_repaint = false;
    //wxLogMessage("Repaint: %d,%d - %d,%d -> %d,%d - %d,%d",
    // paintRect.x, paintRect.y, paintRect.width, paintRect.height,
    // bufferRect.x, bufferRect.y, bufferRect.width, bufferRect.height);
  }
  wxPaintBox::OnPaint(event);
}
status_t GonkBufferQueueProducer::queueBuffer(int slot,
        const QueueBufferInput &input, QueueBufferOutput *output) {
    ATRACE_CALL();

    int64_t timestamp;
    bool isAutoTimestamp;
    Rect crop;
    int scalingMode;
    uint32_t transform;
    uint32_t stickyTransform;
    bool async;
    sp<Fence> fence;
    input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode, &transform,
            &async, &fence, &stickyTransform);

    if (fence == NULL) {
        ALOGE("queueBuffer: fence is NULL");
        // Temporary workaround for b/17946343: soldier-on instead of returning an error. This
        // prevents the client from dying, at the risk of visible corruption due to hwcomposer
        // reading the buffer before the producer is done rendering it. Unless the buffer is the
        // last frame of an animation, the corruption will be transient.
        fence = Fence::NO_FENCE;
        // return BAD_VALUE;
    }

    switch (scalingMode) {
        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
            break;
        default:
            ALOGE("queueBuffer: unknown scaling mode %d", scalingMode);
            return BAD_VALUE;
    }

    sp<IConsumerListener> listener;
    { // Autolock scope
        Mutex::Autolock lock(mCore->mMutex);

        if (mCore->mIsAbandoned) {
            ALOGE("queueBuffer: GonkBufferQueue has been abandoned");
            return NO_INIT;
        }

        const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
        if (async && mCore->mOverrideMaxBufferCount) {
            // FIXME: Some drivers are manually setting the buffer count
            // (which they shouldn't), so we do this extra test here to
            // handle that case. This is TEMPORARY until we get this fixed.
            if (mCore->mOverrideMaxBufferCount < maxBufferCount) {
                ALOGE("queueBuffer: async mode is invalid with "
                        "buffer count override");
                return BAD_VALUE;
            }
        }

        if (slot < 0 || slot >= maxBufferCount) {
            ALOGE("queueBuffer: slot index %d out of range [0, %d)",
                    slot, maxBufferCount);
            return BAD_VALUE;
        } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) {
            ALOGE("queueBuffer: slot %d is not owned by the producer "
                    "(state = %d)", slot, mSlots[slot].mBufferState);
            return BAD_VALUE;
        } else if (!mSlots[slot].mRequestBufferCalled) {
            ALOGE("queueBuffer: slot %d was queued without requesting "
                    "a buffer", slot);
            return BAD_VALUE;
        }

        ALOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64
                " crop=[%d,%d,%d,%d] transform=%#x scale=%s",
                slot, mCore->mFrameCounter + 1, timestamp,
                crop.left, crop.top, crop.right, crop.bottom,
                transform, GonkBufferItem::scalingModeName(scalingMode));

        const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
        Rect croppedRect;
        crop.intersect(bufferRect, &croppedRect);
        if (croppedRect != crop) {
            ALOGE("queueBuffer: crop rect is not contained within the "
                    "buffer in slot %d", slot);
            return BAD_VALUE;
        }

        mSlots[slot].mFence = fence;
        mSlots[slot].mBufferState = GonkBufferSlot::QUEUED;
        ++mCore->mFrameCounter;
        mSlots[slot].mFrameNumber = mCore->mFrameCounter;

        GonkBufferItem item;
        item.mAcquireCalled = mSlots[slot].mAcquireCalled;
        item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
        item.mCrop = crop;
        item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
        item.mTransformToDisplayInverse =
                bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
        item.mScalingMode = scalingMode;
        item.mTimestamp = timestamp;
        item.mIsAutoTimestamp = isAutoTimestamp;
        item.mFrameNumber = mCore->mFrameCounter;
        item.mSlot = slot;
        item.mFence = fence;
        item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async;

        mStickyTransform = stickyTransform;

        if (mCore->mQueue.empty()) {
            // When the queue is empty, we can ignore mDequeueBufferCannotBlock
            // and simply queue this buffer
            mCore->mQueue.push_back(item);
            listener = mCore->mConsumerListener;
        } else {
            // When the queue is not empty, we need to look at the front buffer
            // state to see if we need to replace it
            GonkBufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
            if (front->mIsDroppable || !mSynchronousMode) {
                // If the front queued buffer is still being tracked, we first
                // mark it as freed
                if (mCore->stillTracking(front)) {
                    mSlots[front->mSlot].mBufferState = GonkBufferSlot::FREE;
                    // Reset the frame number of the freed buffer so that it is
                    // the first in line to be dequeued again
                    mSlots[front->mSlot].mFrameNumber = 0;
                }
                // Overwrite the droppable buffer with the incoming one
                *front = item;
                listener = mCore->mConsumerListener;
            } else {
                mCore->mQueue.push_back(item);
                listener = mCore->mConsumerListener;
            }
        }

        mCore->mBufferHasBeenQueued = true;
        mCore->mDequeueCondition.broadcast();

        output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
                mCore->mTransformHint, mCore->mQueue.size());
    } // Autolock scope

    // Call back without lock held
    if (listener != NULL) {
        listener->onFrameAvailable();
    }

    return NO_ERROR;
}
示例#5
0
status_t BufferQueue::queueBuffer(int buf,
        const QueueBufferInput& input, QueueBufferOutput* output) {
    ATRACE_CALL();
    ATRACE_BUFFER_INDEX(buf);

    Rect crop;
    uint32_t transform;
    int scalingMode;
    int64_t timestamp;

    input.deflate(&timestamp, &crop, &scalingMode, &transform);

    ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
            "scale=%s",
            buf, timestamp, crop.left, crop.top, crop.right, crop.bottom,
            transform, scalingModeName(scalingMode));

    sp<ConsumerListener> listener;

    { // scope for the lock
        Mutex::Autolock lock(mMutex);
        if (mAbandoned) {
            ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
            return NO_INIT;
        }
        if (buf < 0 || buf >= mBufferCount) {
            ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
                    mBufferCount, buf);
            return -EINVAL;
        } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
            ST_LOGE("queueBuffer: slot %d is not owned by the client "
                    "(state=%d)", buf, mSlots[buf].mBufferState);
            return -EINVAL;
        } else if (!mSlots[buf].mRequestBufferCalled) {
            ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
                    "buffer", buf);
            return -EINVAL;
        }

        const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);
        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
        Rect croppedCrop;
        crop.intersect(bufferRect, &croppedCrop);
        if (croppedCrop != crop) {
            ST_LOGE("queueBuffer: crop rect is not contained within the "
                    "buffer in slot %d", buf);
            return -EINVAL;
        }

        if (mSynchronousMode) {
            // In synchronous mode we queue all buffers in a FIFO.
            mQueue.push_back(buf);

            // Synchronous mode always signals that an additional frame should
            // be consumed.
            listener = mConsumerListener;
        } else {
            // In asynchronous mode we only keep the most recent buffer.
            if (mQueue.empty()) {
                mQueue.push_back(buf);

                // Asynchronous mode only signals that a frame should be
                // consumed if no previous frame was pending. If a frame were
                // pending then the consumer would have already been notified.
                listener = mConsumerListener;
            } else {
                Fifo::iterator front(mQueue.begin());
                // buffer currently queued is freed
                mSlots[*front].mBufferState = BufferSlot::FREE;
                // and we record the new buffer index in the queued list
                *front = buf;
            }
        }

        mSlots[buf].mTimestamp = timestamp;
        mSlots[buf].mCrop = crop;
        mSlots[buf].mTransform = transform;

        switch (scalingMode) {
            case NATIVE_WINDOW_SCALING_MODE_FREEZE:
            case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
            case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
                break;
            default:
                ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode);
                scalingMode = mSlots[buf].mScalingMode;
                break;
        }

        mSlots[buf].mBufferState = BufferSlot::QUEUED;
        mSlots[buf].mScalingMode = scalingMode;
        mFrameCounter++;
        mSlots[buf].mFrameNumber = mFrameCounter;

        mBufferHasBeenQueued = true;
        mDequeueCondition.broadcast();

        output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,
                mQueue.size());

        ATRACE_INT(mConsumerName.string(), mQueue.size());
    } // scope for the lock

    // call back without lock held
    if (listener != 0) {
        listener->onFrameAvailable();
    }
    return OK;
}
bool ossimGeneralRasterWriter::writeToBsq()
{
   ossimEndian endian;
   static const char* const MODULE = "ossimGeneralRasterWriter::writeToBsq";

   if (traceDebug()) CLOG << " Entered." << std::endl;

   //***
   // Get an arbitrary tile just to get the size in bytes!
   // This should be changed later... An ossimImageSource should know
   // this.
   //***
   ossimRefPtr<ossimImageData> id;

   // Start the sequence at the first tile.
   theInputConnection->setToStartOfSequence();

   ossim_uint64 bands     = theInputConnection->getNumberOfOutputBands();
   ossim_uint64 tilesWide = theInputConnection->getNumberOfTilesHorizontal();
   ossim_uint64 tilesHigh = theInputConnection->getNumberOfTilesVertical();
   ossim_uint64 tileHeight      = theInputConnection->getTileHeight();
   ossim_uint64 numberOfTiles   = theInputConnection->getNumberOfTiles();
   ossim_uint64 width           = theAreaOfInterest.width();
   ossim_uint64 height          = theAreaOfInterest.height();

   ossim_uint64 bytesInLine     = 0;
   ossim_uint64 buf_band_offset = 0;
   
   // Use the system "streampos" typedef for future 64 bit seeks (long long).
   streampos file_band_offset = 0;
   
   //***
   // Buffer to hold one line x tileHeight
   //***
   ossim_uint64 bufferSizeInBytes = 0;
   unsigned char* buffer = NULL;
      
   theMinPerBand.clear();
   theMaxPerBand.clear();

   ossim_uint64 tileNumber = 0;
   bool wroteSomethingOut = false;
   ossimScalarType scalarType = theInputConnection->getOutputScalarType();
   for(ossim_uint64 i = 0; ((i < tilesHigh)&&(!needsAborting())); ++i)
   {
      if(buffer)
      {
	 // Clear the buffer.
	 memset(buffer, 0, bufferSizeInBytes);
      }
      
      ossimIrect bufferRect(theAreaOfInterest.ul().x,
			    theAreaOfInterest.ul().y + i*tileHeight,
			    theAreaOfInterest.ul().x + (width - 1),
			    theAreaOfInterest.ul().y + i *
                            tileHeight + (tileHeight - 1));
      
      // Tile loop in the sample (width) direction.
      for(ossim_uint64 j = 0; ((j < tilesWide)&&(!needsAborting())); ++j)
      {
         // Get the tile and copy it to the buffer.
         id = theInputConnection->getNextTile();
	 if(id.valid())
         {
            id->computeMinMaxPix(theMinPerBand, theMaxPerBand);
            if(!buffer)
            {
               bytesInLine     = id->getScalarSizeInBytes() * width;
               buf_band_offset = bytesInLine * tileHeight;
               file_band_offset = height * bytesInLine;
               bufferSizeInBytes = bytesInLine * tileHeight * bands;
               buffer = new unsigned char[bufferSizeInBytes];
               memset(buffer, 0, bufferSizeInBytes);
            }
            id->unloadTile(buffer,
                           bufferRect,
                           OSSIM_BSQ);
         }
         ++tileNumber;
      }
      
      // Get the number of lines to write from the buffer.
      ossim_uint64 linesToWrite =
         min(tileHeight,
             static_cast<ossim_uint64>(theAreaOfInterest.lr().y -
                                       bufferRect.ul().y + 1));
      
      // Write the buffer out to disk.  
      ossim_uint64 start_line =
         static_cast<ossim_uint64>(bufferRect.ul().y -
                                   theAreaOfInterest.ul().y);
      for (ossim_uint64 band = 0; ((band < bands)&&(!needsAborting())); ++band)
      {
         ossim_uint8* buf = buffer;
         buf += buf_band_offset * band;
         
         // Put the file pointer in the right spot.
         streampos pos = file_band_offset * band + start_line * bytesInLine;
         theOutputStream->seekp(pos, ios::beg);
         if (theOutputStream->fail())
         {
            ossimNotify(ossimNotifyLevel_FATAL) << MODULE << " ERROR:"
                 << "Error returned seeking to image data position!" << std::endl;
            setErrorStatus();
            return false;
         }
         
         for (ossim_uint64 ii=0; ((ii<linesToWrite)&&(!needsAborting())); ++ii)
         {
            wroteSomethingOut = true;
            if(endian.getSystemEndianType() != theOutputByteOrder)
            {
               endian.swap(scalarType,
                           buf,
                           bytesInLine/ossim::scalarSizeInBytes(scalarType));
            }

            theOutputStream->write((char*)buf, bytesInLine);
            
            if (theOutputStream->fail())
            {
               ossimNotify(ossimNotifyLevel_FATAL) << MODULE << " ERROR:"
                    << "Error returned writing line!" << std::endl;
               setErrorStatus();
               return false;
            }
            
            buf += bytesInLine;
         }
         
      } // End of loop to write lines from buffer to tiff file.
      
      double tile = tileNumber;
      double numTiles = numberOfTiles;
      setPercentComplete(tile / numTiles * 100);

      if(needsAborting())
      {
         setPercentComplete(100.0);
      }
      
   } // End of loop in the line (height) direction.
   
   // Free the memory.
   delete [] buffer;
   
   if (traceDebug()) CLOG << " Exited." << std::endl;
   
   return wroteSomethingOut;
}
bool ossimGeneralRasterWriter::writeToBip()
{
   ossimEndian endian;
   static const char* const MODULE = "ossimGeneralRasterWriter::writeToBip";
   
   if (traceDebug()) CLOG << " Entered." << std::endl;
   
   
   //---
   // Get an arbitrary tile just to get the size in bytes!
   // This should be changed later... An ossimImageSource should know
   // this.
   //---
   ossimRefPtr<ossimImageData> id;
   
   // Start the sequence at the first tile.
   theInputConnection->setToStartOfSequence();
   
   ossim_uint64 bands     = theInputConnection->getNumberOfOutputBands();
   ossim_uint64 tilesWide =  theInputConnection->getNumberOfTilesHorizontal();
   ossim_uint64 tilesHigh     = theInputConnection->getNumberOfTilesVertical();
   ossim_uint64 tileHeight    = theInputConnection->getTileHeight();
   ossim_uint64 numberOfTiles = theInputConnection->getNumberOfTiles();
   ossim_uint64 width         = theAreaOfInterest.width();

   if (traceDebug())
   {
      ossimNotify(ossimNotifyLevel_DEBUG)
         << "\nossimGeneralRasterWriter::writeToBip DEBUG:"
         << "\nbands:          " << bands
         << "\ntilesWide:      " << tilesWide
         << "\ntilesHigh:      " << tilesHigh
         << "\ntileHeight:     " << tileHeight
         << "\nnumberOfTiles:  " << numberOfTiles
         << "\nwidth:          " << width
         << std::endl;
   }
   
   //---
   // Buffer to hold one line x tileHeight
   //---
   ossim_uint64 bufferSizeInBytes = 0;
   ossim_uint64 bytesInLine       = 0;
   unsigned char* buffer = NULL;
   
   theMinPerBand.clear();
   theMaxPerBand.clear();
   ossim_uint64 tileNumber = 0;
   bool wroteSomethingOut = false;
   ossimScalarType scalarType = theInputConnection->getOutputScalarType();
   for(ossim_uint64 i = 0; ((i < tilesHigh)&&(!needsAborting())); ++i)
   {
      // Clear the buffer.
      if(buffer)
      {
	 memset(buffer, 0, bufferSizeInBytes);
      }
      
      ossimIrect bufferRect(theAreaOfInterest.ul().x,
			    theAreaOfInterest.ul().y + i*tileHeight,
			    theAreaOfInterest.ul().x + (width - 1),
			    theAreaOfInterest.ul().y + i*tileHeight + (tileHeight - 1));
      // Tile loop in the sample (width) direction.
      for(ossim_uint64 j = 0; ((j < tilesWide)&&(!needsAborting())); ++j)
      {
         // Get the tile and copy it to the buffer.
         id = theInputConnection->getNextTile();
	 if(id.valid())
         {
            id->computeMinMaxPix(theMinPerBand, theMaxPerBand);
            if(!buffer)
            {
               bytesInLine     = id->getScalarSizeInBytes() * width * bands;
               
               //---
               // Buffer to hold one line x tileHeight
               //---
               bufferSizeInBytes = bytesInLine * tileHeight;
               buffer = new unsigned char[bufferSizeInBytes];
               memset(buffer, 0, bufferSizeInBytes);
            }
            id->unloadTile(buffer,
                           bufferRect,
                           OSSIM_BIP);
         }
         ++tileNumber;
      }
      
      // Get the number of lines to write from the buffer.
      ossim_uint64 linesToWrite =
         min(tileHeight,
             static_cast<ossim_uint64>(theAreaOfInterest.lr().y -
                                       bufferRect.ul().y + 1));
      // Write the buffer out to disk.  
      ossim_uint8* buf = buffer;
      if(buf)
      {
         for (ossim_uint64 ii=0; ((ii<linesToWrite)&&(!needsAborting())); ++ii)
         {
            std::streamsize lineBytes = bytesInLine;
            wroteSomethingOut = true;

            if(endian.getSystemEndianType() != theOutputByteOrder)
            {
               endian.swap(scalarType,
                           buf,
                           lineBytes/ossim::scalarSizeInBytes(scalarType));
            }
            theOutputStream->write((char*)buf, lineBytes);
            if (theOutputStream->fail())
            {
               ossimNotify(ossimNotifyLevel_FATAL)
                  << MODULE << " ERROR:"
                  << "Error returned writing line!" << std::endl;
               setErrorStatus();
               if(buffer)
               {
                  // Free the memory.
                  delete [] buffer;
               }
               return false;
            }
	    
            buf += bytesInLine;
	    
         } // End of loop to write lines from buffer to tiff file.
      }
      double tile = tileNumber;
      double numTiles = numberOfTiles;
      setPercentComplete(tile / numTiles * 100);
      if(needsAborting())
      {
         setPercentComplete(100.0);
      }
      
   } // End of loop in the line (height) direction.
   if(buffer)
   {
      // Free the memory.
      delete [] buffer;
   }
   
   if (traceDebug()) CLOG << " Exited." << std::endl;
   
   return wroteSomethingOut;
}