コード例 #1
0
/**
 * Expand the colormap from RGB to Packed ARGB as needed by Cairo.
 * And apply any LCMS transformation.
 */
static void ConvertColormap(PRUint32 *aColormap, PRUint32 aColors)
{
    // Apply CMS transformation if enabled and available
    if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
        qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
        if (transform)
            qcms_transform_data(transform, aColormap, aColormap, aColors);
    }
    // Convert from the GIF's RGB format to the Cairo format.
    // Work from end to begin, because of the in-place expansion
    PRUint8 *from = ((PRUint8 *)aColormap) + 3 * aColors;
    PRUint32 *to = aColormap + aColors;

    // Convert color entries to Cairo format

    // set up for loops below
    if (!aColors) return;
    PRUint32 c = aColors;

    // copy as bytes until source pointer is 32-bit-aligned
    // NB: can't use 32-bit reads, they might read off the end of the buffer
    for (; (NS_PTR_TO_UINT32(from) & 0x3) && c; --c) {
        from -= 3;
        *--to = GFX_PACKED_PIXEL(0xFF, from[0], from[1], from[2]);
    }

    // bulk copy of pixels.
    while (c >= 4) {
        from -= 12;
        to   -=  4;
        c    -=  4;
        GFX_BLOCK_RGB_TO_FRGB(from,to);
    }

    // copy remaining pixel(s)
    // NB: can't use 32-bit reads, they might read off the end of the buffer
    while (c--) {
        from -= 3;
        *--to = GFX_PACKED_PIXEL(0xFF, from[0], from[1], from[2]);
    }
}
コード例 #2
0
void
nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
                           png_uint_32 row_num, int pass)
{
  /* libpng comments:
   *
   * this function is called for every row in the image.  If the
   * image is interlacing, and you turned on the interlace handler,
   * this function will be called for every row in every pass.
   * Some of these rows will not be changed from the previous pass.
   * When the row is not changed, the new_row variable will be NULL.
   * The rows and passes are called in order, so you don't really
   * need the row_num and pass, but I'm supplying them because it
   * may make your life easier.
   *
   * For the non-NULL rows of interlaced images, you must call
   * png_progressive_combine_row() passing in the row and the
   * old row.  You can call this function for NULL rows (it will
   * just return) and for non-interlaced images (it just does the
   * memcpy for you) if it will make the code easier.  Thus, you
   * can just do this for all cases:
   *
   *    png_progressive_combine_row(png_ptr, old_row, new_row);
   *
   * where old_row is what was displayed for previous rows.  Note
   * that the first pass (pass == 0 really) will completely cover
   * the old row, so the rows do not have to be initialized.  After
   * the first pass (and only for interlaced images), you will have
   * to pass the current row, and the function will combine the
   * old row and the new row.
   */
  nsPNGDecoder *decoder =
               static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));

  // skip this frame
  if (decoder->mFrameIsHidden)
    return;

  if (row_num >= (png_uint_32) decoder->mFrameRect.height)
    return;

  if (new_row) {
    PRInt32 width = decoder->mFrameRect.width;
    PRUint32 iwidth = decoder->mFrameRect.width;

    png_bytep line = new_row;
    if (decoder->interlacebuf) {
      line = decoder->interlacebuf + (row_num * decoder->mChannels * width);
      png_progressive_combine_row(png_ptr, line, new_row);
    }

    PRUint32 bpr = width * sizeof(PRUint32);
    PRUint32 *cptr32 = (PRUint32*)(decoder->mImageData + (row_num*bpr));
    bool rowHasNoAlpha = true;

    if (decoder->mTransform) {
      if (decoder->mCMSLine) {
        qcms_transform_data(decoder->mTransform, line, decoder->mCMSLine,
                            iwidth);
        /* copy alpha over */
        PRUint32 channels = decoder->mChannels;
        if (channels == 2 || channels == 4) {
          for (PRUint32 i = 0; i < iwidth; i++)
            decoder->mCMSLine[4 * i + 3] = line[channels * i + channels - 1];
        }
        line = decoder->mCMSLine;
      } else {
        qcms_transform_data(decoder->mTransform, line, line, iwidth);
       }
     }

    switch (decoder->format) {
      case gfxASurface::ImageFormatRGB24:
      {
        // counter for while() loops below
        PRUint32 idx = iwidth;

        // copy as bytes until source pointer is 32-bit-aligned
        for (; (NS_PTR_TO_UINT32(line) & 0x3) && idx; --idx) {
          *cptr32++ = GFX_PACKED_PIXEL(0xFF, line[0], line[1], line[2]);
          line += 3;
        }

        // copy pixels in blocks of 4
        while (idx >= 4) {
          GFX_BLOCK_RGB_TO_FRGB(line, cptr32);
          idx    -=  4;
          line   += 12;
          cptr32 +=  4;
        }

        // copy remaining pixel(s)
        while (idx--) {
          // 32-bit read of final pixel will exceed buffer, so read bytes
          *cptr32++ = GFX_PACKED_PIXEL(0xFF, line[0], line[1], line[2]);
          line += 3;
        }
      }
      break;
      case gfxASurface::ImageFormatARGB32:
      {
        if (!decoder->mDisablePremultipliedAlpha) {
          for (PRUint32 x=width; x>0; --x) {
            *cptr32++ = GFX_PACKED_PIXEL(line[3], line[0], line[1], line[2]);
            if (line[3] != 0xff)
              rowHasNoAlpha = PR_FALSE;
            line += 4;
          }
        } else {
          for (PRUint32 x=width; x>0; --x) {
            *cptr32++ = GFX_PACKED_PIXEL_NO_PREMULTIPLY(line[3], line[0], line[1], line[2]);
            if (line[3] != 0xff)
              rowHasNoAlpha = PR_FALSE;
            line += 4;
          }
        }
      }
      break;
      default:
        longjmp(png_jmpbuf(decoder->mPNG), 1);
    }

    if (!rowHasNoAlpha)
      decoder->mFrameHasNoAlpha = PR_FALSE;

    PRUint32 numFrames = decoder->mImage->GetNumFrames();
    if (numFrames <= 1) {
      // Only do incremental image display for the first frame
      // XXXbholley - this check should be handled in the superclass
      nsIntRect r(0, row_num, width, 1);
      decoder->PostInvalidation(r);
    }
  }
}
コード例 #3
0
void
nsJPEGDecoder::OutputScanlines(bool* suspend)
{
  *suspend = false;

  const uint32_t top = mInfo.output_scanline;

  while ((mInfo.output_scanline < mInfo.output_height)) {
      /* Use the Cairo image buffer as scanline buffer */
      uint32_t *imageRow = ((uint32_t*)mImageData) +
                           (mInfo.output_scanline * mInfo.output_width);

      if (mInfo.cconvert->color_convert == ycc_rgb_convert_argb) {
        /* Special case: scanline will be directly converted into packed ARGB */
        if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) {
          *suspend = true; /* suspend */
          break;
        }
        continue; /* all done for this row! */
      }

      JSAMPROW sampleRow = (JSAMPROW)imageRow;
      if (mInfo.output_components == 3) {
        /* Put the pixels at end of row to enable in-place expansion */
        sampleRow += mInfo.output_width;
      }

      /* Request one scanline.  Returns 0 or 1 scanlines. */    
      if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) {
        *suspend = true; /* suspend */
        break;
      }

      if (mTransform) {
        JSAMPROW source = sampleRow;
        if (mInfo.out_color_space == JCS_GRAYSCALE) {
          /* Convert from the 1byte grey pixels at begin of row 
             to the 3byte RGB byte pixels at 'end' of row */
          sampleRow += mInfo.output_width;
        }
        qcms_transform_data(mTransform, source, sampleRow, mInfo.output_width);
        /* Move 3byte RGB data to end of row */
        if (mInfo.out_color_space == JCS_CMYK) {
          memmove(sampleRow + mInfo.output_width,
                  sampleRow,
                  3 * mInfo.output_width);
          sampleRow += mInfo.output_width;
        }
      } else {
        if (mInfo.out_color_space == JCS_CMYK) {
          /* Convert from CMYK to RGB */
          /* We cannot convert directly to Cairo, as the CMSRGBTransform may wants to do a RGB transform... */
          /* Would be better to have platform CMSenabled transformation from CMYK to (A)RGB... */
          cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width);
          sampleRow += mInfo.output_width;
        }
        if (mCMSMode == eCMSMode_All) {
          /* No embedded ICC profile - treat as sRGB */
          qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
          if (transform) {
            qcms_transform_data(transform, sampleRow, sampleRow, mInfo.output_width);
          }
        }
      }

      // counter for while() loops below
      uint32_t idx = mInfo.output_width;

      // copy as bytes until source pointer is 32-bit-aligned
      for (; (NS_PTR_TO_UINT32(sampleRow) & 0x3) && idx; --idx) {
        *imageRow++ = GFX_PACKED_PIXEL(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
        sampleRow += 3;
      }

      // copy pixels in blocks of 4
      while (idx >= 4) {
        GFX_BLOCK_RGB_TO_FRGB(sampleRow, imageRow);
        idx       -=  4;
        sampleRow += 12;
        imageRow  +=  4;
      }

      // copy remaining pixel(s)
      while (idx--) {
        // 32-bit read of final pixel will exceed buffer, so read bytes
        *imageRow++ = GFX_PACKED_PIXEL(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
        sampleRow += 3;
      }
  }

  if (top != mInfo.output_scanline) {
      nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
      PostInvalidation(r);
  }

}