/**
   * Paint the image onto a Graphics object. The painting is performed tile-by-tile, and includes a
   * grey region covering the unused portion of image tiles as well as the general background. At
   * this point the image must be byte data.
   */
  public synchronized void paintComponent(Graphics g) {

    Graphics2D g2D = null;
    if (g instanceof Graphics2D) {
      g2D = (Graphics2D) g;
    } else {
      return;
    }

    // if source is null, it's just a component
    if (source == null) {
      g2D.setColor(getBackground());
      g2D.fillRect(0, 0, componentWidth, componentHeight);
      return;
    }

    int transX = -originX;
    int transY = -originY;

    // Get the clipping rectangle and translate it into image coordinates.
    Rectangle clipBounds = g.getClipBounds();

    if (clipBounds == null) {
      clipBounds = new Rectangle(0, 0, componentWidth, componentHeight);
    }

    // clear the background (clip it) [minimal optimization here]
    if (transX > 0
        || transY > 0
        || transX < (componentWidth - source.getWidth())
        || transY < (componentHeight - source.getHeight())) {
      g2D.setColor(getBackground());
      g2D.fillRect(0, 0, componentWidth, componentHeight);
    }

    clipBounds.translate(-transX, -transY);

    // Determine the extent of the clipping region in tile coordinates.
    int txmin, txmax, tymin, tymax;
    int ti, tj;

    txmin = XtoTileX(clipBounds.x);
    txmin = Math.max(txmin, minTileX);
    txmin = Math.min(txmin, maxTileX);

    txmax = XtoTileX(clipBounds.x + clipBounds.width - 1);
    txmax = Math.max(txmax, minTileX);
    txmax = Math.min(txmax, maxTileX);

    tymin = YtoTileY(clipBounds.y);
    tymin = Math.max(tymin, minTileY);
    tymin = Math.min(tymin, maxTileY);

    tymax = YtoTileY(clipBounds.y + clipBounds.height - 1);
    tymax = Math.max(tymax, minTileY);
    tymax = Math.min(tymax, maxTileY);
    Insets insets = getInsets();

    // Loop over tiles within the clipping region
    for (tj = tymin; tj <= tymax; tj++) {
      for (ti = txmin; ti <= txmax; ti++) {
        int tx = TileXtoX(ti);
        int ty = TileYtoY(tj);

        Raster tile = source.getTile(ti, tj);
        if (tile != null) {
          DataBuffer dataBuffer = tile.getDataBuffer();

          WritableRaster wr = tile.createWritableRaster(sampleModel, dataBuffer, null);

          BufferedImage bi =
              new BufferedImage(colorModel, wr, colorModel.isAlphaPremultiplied(), null);

          // correctly handles band offsets
          if (brightnessEnabled == true) {
            SampleModel sm =
                sampleModel.createCompatibleSampleModel(tile.getWidth(), tile.getHeight());

            WritableRaster raster = RasterFactory.createWritableRaster(sm, null);

            BufferedImage bimg =
                new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);

            // don't move this code
            ByteLookupTable lutTable = new ByteLookupTable(0, lutData);
            LookupOp lookup = new LookupOp(lutTable, null);
            lookup.filter(bi, bimg);

            g2D.drawImage(bimg, biop, tx + transX + insets.left, ty + transY + insets.top);
          } else {
            AffineTransform transform;

            transform =
                AffineTransform.getTranslateInstance(
                    tx + transX + insets.left, ty + transY + insets.top);

            g2D.drawRenderedImage(bi, transform);
          }
        }
      }
    }
  }
    public void paintComponent(Graphics g) {
      Rectangle selection = g.getClipBounds();

      // clear out the image
      Graphics2D g2 = (Graphics2D) g;
      g2.setBackground(backgroundColor);
      g2.clearRect(
          (int) selection.getX(),
          (int) selection.getY(),
          (int) selection.getWidth(),
          (int) selection.getHeight());

      // draw the selection if it exists
      if (selBeginPixel != -1 && selEndPixel != -1) {
        g2.setBackground(selectionColor);
        g2.clearRect(selBeginPixel, 0, selEndPixel - selBeginPixel + 1, this.getHeight());
      }

      if (this.points.size() > 0) {
        g2.setColor(waveColor);
        // draw the lines
        if (this.points.size() > stemThresh) {
          if (points.size() > frameWidth) { // draw contour
            // g2.setStroke(thickerStroke);
            for (int i = 0; i < this.points.size() - 1; i += 4) {
              Point2D.Float pt1 = points.get(i).getDispPoint();
              // Point2D.Float pt2  = new Point2D.Float(pt1.x, pt1.y/2);
              Point2D.Float pt2 = points.get(i + 1).getDispPoint();
              Point2D.Float pt3 = points.get(i + 2).getDispPoint();
              Point2D.Float pt4 = points.get(i + 3).getDispPoint();

              //							//Point2D.Float pt4  = new Point2D.Float(pt2.x, pt2.y/2);
              g2.draw(new Line2D.Float(pt1, pt2));
              // g2.setColor(waveLiteColor);
              g.setColor(waveLiteColor);
              g2.draw(new Line2D.Float(pt2, pt3));
              g2.setColor(waveColor);
              g2.draw(new Line2D.Float(pt3, pt4));
              //							g2.draw(new Line2D.Float(this.points.get(i).getDispPoint(),
              //									this.points.get(i+1).getDispPoint()));
              //							g2.draw(new Line2D.Float(this.points.get(i).getDispPoint(),
              //									this.points.get(i+1).getDispPoint()));
              //							g2.draw(new Line2D.Float(this.points.get(i).getDispPoint(),
              //									this.points.get(i+1).getDispPoint()));
            }

          } else { // draw line
            g2.setStroke(stroke);
            for (int i = 0; i < this.points.size() - 1; i++) {
              g2.draw(
                  new Line2D.Float(
                      this.points.get(i).getDispPoint(), this.points.get(i + 1).getDispPoint()));
            }
          }
        } else { // stem plot
          for (int i = 0; i < this.points.size(); i++) {
            // draw the stem
            SoundSample sample = this.points.get(i);
            g2.setStroke(thickerStroke);
            Point2D.Double base =
                new Point2D.Double(
                    sample.getDispPoint().getX() + 10, Math.floor(this.getHeight()) / 2);
            Point2D.Double pt =
                new Point2D.Double(sample.getDispPoint().getX() + 10, sample.getDispPoint().getY());
            g2.draw(new Line2D.Float(base, pt));

            if (this.points.size() < zoomThresh) {
              // draw the sample value
              float sampleValue = (float) sample.getSampleValue();
              float y = (float) sample.getDispPoint().getY();
              g2.setFont(textFont);
              if (y < Math.floor(this.getHeight()) / 2) y = y - 10;
              else y = y + 10;
              // if (sample.getDispPoint().getX() > 0)
              g2.drawString(formatter.format(sampleValue), (float) sample.getDispPoint().getX(), y);
            }

            // draw the vertical bar in the array
            //						g2.setStroke(thickerStroke);
            //						base = new Point2D.Double(base.getX()-8, this.getHeight() - 10);
            //						pt = new Point2D.Double(base.getX(), this.getHeight() - 50);
            //						g2.draw(new Line2D.Double(base, pt));
            //						g2.drawString(formatter.format(points.get(i).getSampleIndex()),
            // (float)base.getX(), (float)base.getY() - 10 );
          }
          //
          //					g2.setStroke(wideStroke);
          //					//draw the array cells
          //					g2.draw(new Line2D.Double(selection.getX(),
          //							Math.floor(this.getHeight() - 30),
          //							selection.getX()+selection.getWidth()-1,
          //							Math.floor(this.getHeight() - 30)));
          //					//draw the array cells
          //					g2.draw(new Line2D.Double(selection.getX(),
          //							Math.floor(this.getHeight() - 10),
          //							selection.getX()+selection.getWidth()-1,
          //							Math.floor(this.getHeight() - 10)));
        }
      }

      // draw the center line
      g2.setColor(barColor);
      g2.setStroke(new BasicStroke(1));
      g2.draw(
          new Line2D.Double(
              selection.getX(),
              Math.floor(this.getHeight() / 2),
              selection.getX() + selection.getWidth() - 1,
              Math.floor(this.getHeight() / 2)));

      //			//draw the current position
      //			if (selection.getX()<currentPixelPosition &&
      //					currentPixelPosition<(selection.getX()+selection.getWidth()-1))
      //			{
      //				g2.setColor(barColor);
      //				g2.setStroke(new BasicStroke(1));
      //				g2.draw(new Line2D.Double(currentPixelPosition, 0,
      //						currentPixelPosition, frameHeight));
      //			}
    }