Пример #1
0
static int
bitmap_decode(struct jpeg_decompress_struct *cinfo, Vbitmap *vbitmap,
              YmagineFormatOptions *options)
{
  int nlines = -1;

  cinfo->client_data = (void*) vbitmap;
  
  if (prepareDecompressor(cinfo, options) != YMAGINE_OK) {
    return nlines;
  }

  /* Intercept APP1 markers for PhotoSphere parsing */
  jpeg_set_marker_processor(cinfo, JPEG_APP0 + 1, APP1_handler);
  
  if (startDecompressor(cinfo, VbitmapColormode(vbitmap)) != YMAGINE_OK) {
    return nlines;
  }
  
  YmagineFormatOptions_invokeCallback(options, YMAGINE_IMAGEFORMAT_JPEG,
                                      cinfo->image_width, cinfo->image_height);

#if YMAGINE_DEBUG_JPEG
  ALOGD("bitmap_decode: in=%dx%d bm=%dx%d max=%dx%d",
        cinfo->image_width, cinfo->image_height,
        VbitmapWidth(vbitmap), VbitmapHeight(vbitmap),
        options->maxwidth, options->maxheight);
#endif
  
  nlines = decompress_jpeg(cinfo, NULL, JCOPYOPT_NONE,
                           vbitmap, options);
  
  return nlines;
}
Пример #2
0
static int
VbitmapComputeIntersection(Vbitmap *vbitmap, const Vrect *region, Vrect *output)
{
    Vrect vrect;
    if (output == NULL) return YMAGINE_OK;
    if (vbitmap == NULL) return YMAGINE_ERROR;
    if (region == NULL) {
        output->x = 0;
        output->y = 0;
        output->width = VbitmapWidth(vbitmap);
        output->height = VbitmapHeight(vbitmap);
    }
    // Nothing is NULL
    vrect.x = 0;
    vrect.y = 0;
    vrect.width = VbitmapWidth(vbitmap);
    vrect.height = VbitmapHeight(vbitmap);
    VrectComputeIntersection(&vrect, region, output);

    return YMAGINE_OK;
}
Пример #3
0
int
TransformerSetBitmap(Transformer *transformer, Vbitmap *vbitmap,
                     int offsetx, int offsety)
{
  int rc = YMAGINE_OK;

  if (transformer == NULL) {
    return YMAGINE_ERROR;
  }

  if (transformer->obitmap != NULL) {
    VbitmapUnlock(transformer->obitmap);
  }

  if (vbitmap != NULL) {
    rc = VbitmapLock(vbitmap);
    if (rc != YMAGINE_OK) {
      vbitmap = NULL;
    }
  }

  transformer->obitmap = vbitmap;

  if (vbitmap == NULL) {
    transformer->obitmap = NULL;
    transformer->obuffer = NULL;
    transformer->owidth = 0;
    transformer->oheight = 0;
    transformer->opitch = 0;
    transformer->omode = VBITMAP_COLOR_RGBA;
    transformer->obpp = 0;
    transformer->offsetx = 0;
    transformer->offsety = 0;
  } else {
    transformer->obitmap = vbitmap;
    transformer->obuffer = VbitmapBuffer(vbitmap);
    transformer->owidth = VbitmapWidth(vbitmap);
    transformer->oheight = VbitmapHeight(vbitmap);
    transformer->opitch = VbitmapPitch(vbitmap);
    transformer->omode = VbitmapColormode(vbitmap);
    transformer->obpp = colorBpp(transformer->omode);
    transformer->offsetx = offsetx;
    transformer->offsety = offsety;
  }

  return rc;
}
Пример #4
0
static int
quantizeWithOptions(Vbitmap *vbitmap, int maxcolors,
                    Vcolor *colors, int *scores, int processing)
{
  int i;
  int x, y, c;
  unsigned char *pixels;
  unsigned char *line;
  ColorArea centroid[PALETTESIZE];
  Vcolor current;
  int width, height, pitch;
  uint64_t dist;
  uint64_t refdist;
  int refid;
  int ncolors;
  int maxiters = 100;

  if (maxcolors <= 0 || colors == NULL) {
    return 0;
  }
  if (vbitmap == NULL) {
    return 0;
  }

  if (processing == YMAGINE_THEME_DEFAULT) {
    processing = YMAGINE_THEME_SATURATION;
  }

  if (processing != YMAGINE_THEME_NONE && processing != YMAGINE_THEME_SATURATION) {
    return 0;
  }

  if (VbitmapLock(vbitmap) < 0) {
    return 0;
  }

  pixels = VbitmapBuffer(vbitmap);
  if (pixels == NULL) {
    VbitmapUnlock(vbitmap);
    return 0;
  }

  width = VbitmapWidth(vbitmap);
  height = VbitmapHeight(vbitmap);
  pitch = VbitmapPitch(vbitmap);
  if (width <= 0 || height <= 0 || pitch <= 0) {
    VbitmapUnlock(vbitmap);
    return 0;
  }

  /* Verify that width*height < 1<<24. This quarantee that will be
   no overflow in accumulators */
  if (hasMultiplyOverflow((((uint32_t) 1)<<24), width, height)) {
    VbitmapUnlock(vbitmap);
    return 0;
  }

  /* Initial result, using default palette */
  if (maxcolors > PALETTESIZE) {
    maxcolors = PALETTESIZE;
  }

  for (c = 0; c < maxcolors; c++) {
    centroid[c].color = palette[c];
    centroid[c].count = 0;
  }
#if 0
  for (c = 0; c < maxcolors; c++) {
    fprintf(stderr,
            "Init[%d] = #%02x%02x%02x%02x (%d)\n",
            c,
            centroid[c].color.red,
            centroid[c].color.green,
            centroid[c].color.blue,
            centroid[c].color.alpha,
            centroid[c].count);
  }
#endif

  for (i = 0; i < maxiters; i++) {
    /* Reset accumulators */
    for (c = 0; c < maxcolors; c++) {
      centroid[c].accum_red = 0;
      centroid[c].accum_green = 0;
      centroid[c].accum_blue = 0;
      centroid[c].accum_alpha = 0;
      centroid[c].count = 0;
    }

    /* Assign each pixel to its nearest centroid */
    current.alpha = 0xff;
    for (y = 0; y < height; y++){
      line = pixels + y * pitch;

      for (x = 0; x < width; x++) {
	      /* Current pixel as a Color record */
	      current.red=line[RED_OFFSET];
	      current.green=line[GREEN_OFFSET];
	      current.blue=line[BLUE_OFFSET];
	      current.alpha=line[ALPHA_OFFSET];
	      line+=4;

	      /* Assign to first centroid by default */
	      refdist = norm2(&current, &(centroid[0].color));
	      refid = 0;

	      /* Then try to find a closer one */
	      for (c = 1; c < maxcolors; c++) {
          dist = norm2(&current, &(centroid[c].color));
          if (dist < refdist) {
            refdist = dist;
            refid = c;
          }
	      }

	      /* Assign this pixel to closest centroid */
	      centroid[refid].accum_red += current.red;
	      centroid[refid].accum_green += current.green;
	      centroid[refid].accum_blue += current.blue;
	      centroid[refid].accum_alpha += current.alpha;
	      centroid[refid].count++;
      }
    }

    refdist = 0;
    for (c = 0; c < maxcolors; c++) {
      if (centroid[c].count == 0) {
	      current.red = 0xff;
	      current.green = 0xff;
	      current.blue = 0xff;
	      current.alpha = 0xff;
      } else {
	      current.red = centroid[c].accum_red/centroid[c].count;
	      current.green = centroid[c].accum_green/centroid[c].count;
	      current.blue = centroid[c].accum_blue/centroid[c].count;
	      current.alpha = 0xff;
      }

      dist = norm2(&current, &(centroid[c].color));
      if (dist > refdist) {
	      refdist = dist;
      }
      centroid[c].color = current;
    }

    if (refdist < 1) {
      break;
    }
  }

  VbitmapUnlock(vbitmap);

  /* Saturation */
  if (processing == YMAGINE_THEME_SATURATION) {
    int i;
    uint32_t dwhite;
    uint32_t dblack;
    uint32_t dcrit, dmin;
    Vcolor col;
    col.red = 0x20;
    col.green = 0x20;
    col.blue = 0x20;
    col.alpha = 0xff;
    dcrit = norm2(&col, &black);


    /* Update scores to prefer saturated colors */
    for (i = 0; i < maxcolors; i++) {
      uint32_t coeff;
      col.red = centroid[i].color.red;
      col.green = centroid[i].color.green;
      col.blue = centroid[i].color.blue;
      col.alpha = centroid[i].color.alpha;

      dwhite = norm2(&white, &col);
      dblack = norm2(&black, &col);

      dmin = (dwhite < dblack) ? dwhite : dblack;

      coeff = 256;
      if (dmin < dcrit) {
        coeff = (256 * (dcrit + (dcrit - dmin))) / dcrit;
      }

      centroid[i].count = (centroid[i].count * 256) / coeff;
    }
  }

  /* Sort colors, most dominant one first */
  qsort(centroid, maxcolors, sizeof(centroid[0]), ColorAreaCompare);

  /* Put colors into ARGB format */
  ncolors = 0;
  for (c = 0; c < maxcolors; c++) {
    if (centroid[c].count <= 0) {
      continue;
    }
    colors[c] = centroid[c].color;
    if (scores != NULL) {
      scores[c] = (int) centroid[c].count;
    }
#if 0
    ALOGD("color[%d] = #%02x%02x%02x%02x (%d)",
          c,
          centroid[c].color.red,
          centroid[c].color.green,
          centroid[c].color.blue,
          centroid[c].color.alpha,
          centroid[c].count);
#endif
    ncolors++;
  }

  return ncolors;
}
Пример #5
0
int
encodeWEBP(Vbitmap *vbitmap, Ychannel *channelout, YmagineFormatOptions *options)
{
  int rc = YMAGINE_ERROR;

#if HAVE_WEBP
  WebPConfig config;
  WebPPicture picture;
  WebPPreset preset = WEBP_PRESET_PHOTO; // One of DEFAULT, PICTURE, PHOTO, DRAWING, ICON or TEXT
  int width;
  int height;
  int pitch;
  int quality;
  const unsigned char *pixels;
  int colormode;

  /*
   * List of encoding options for WebP config
   *   int lossless;           // Lossless encoding (0=lossy(default), 1=lossless).
   *   float quality;          // between 0 (smallest file) and 100 (biggest)
   *   int method;             // quality/speed trade-off (0=fast, 6=slower-better)
   *
   *   WebPImageHint image_hint;  // Hint for image type (lossless only for now).
   *
   *   // Parameters related to lossy compression only:
   *   int target_size;        // if non-zero, set the desired target size in bytes.
   *                           // Takes precedence over the 'compression' parameter.
   *   float target_PSNR;      // if non-zero, specifies the minimal distortion to
   *                           // try to achieve. Takes precedence over target_size.
   *   int segments;           // maximum number of segments to use, in [1..4]
   *   int sns_strength;       // Spatial Noise Shaping. 0=off, 100=maximum.
   *   int filter_strength;    // range: [0 = off .. 100 = strongest]
   *   int filter_sharpness;   // range: [0 = off .. 7 = least sharp]
   *   int filter_type;        // filtering type: 0 = simple, 1 = strong (only used
   *                           // if filter_strength > 0 or autofilter > 0)
   *   int autofilter;         // Auto adjust filter's strength [0 = off, 1 = on]
   *   int alpha_compression;  // Algorithm for encoding the alpha plane (0 = none,
   *                           // 1 = compressed with WebP lossless). Default is 1.
   *   int alpha_filtering;    // Predictive filtering method for alpha plane.
   *                           //  0: none, 1: fast, 2: best. Default if 1.
   *   int alpha_quality;      // Between 0 (smallest size) and 100 (lossless).
   *                           // Default is 100.
   *   int pass;               // number of entropy-analysis passes (in [1..10]).
   *
   *   int show_compressed;    // if true, export the compressed picture back.
   *                           // In-loop filtering is not applied.
   *   int preprocessing;      // preprocessing filter (0=none, 1=segment-smooth)
   *   int partitions;         // log2(number of token partitions) in [0..3]
   *                           // Default is set to 0 for easier progressive decoding.
   *   int partition_limit;    // quality degradation allowed to fit the 512k limit on
   *                           // prediction modes coding (0: no degradation,
   *                           // 100: maximum possible degradation).
   */

  colormode = VbitmapColormode(vbitmap);

  if (colormode != VBITMAP_COLOR_RGBA && colormode != VBITMAP_COLOR_RGB) {
    ALOGD("currently only support RGB, RGBA webp encoding");
    return rc;
  }

  quality = YmagineFormatOptions_normalizeQuality(options);

  if (!WebPConfigPreset(&config, preset, (float) quality)) {
    return YMAGINE_ERROR;   // version error
  }

  if (options && options->accuracy >= 0) {
    int method = options->accuracy / 15;
    if (method > 6) {
      method = 6;
    }
    config.method = method;
  }

  if (!WebPValidateConfig(&config)) {
    // parameter ranges verification failed
    return YMAGINE_ERROR;
  }

  rc = VbitmapLock(vbitmap);
  if (rc < 0) {
    ALOGE("AndroidBitmap_lockPixels() failed");
    return YMAGINE_ERROR;
  }

  width = VbitmapWidth(vbitmap);
  height = VbitmapHeight(vbitmap);
  pitch = VbitmapPitch(vbitmap);
  pixels = VbitmapBuffer(vbitmap);

  if (WebPPictureInit(&picture)) {
    picture.use_argb = 1;
    picture.width = width;
    picture.height = height;
    picture.writer = WebPYchannelWrite;
    picture.custom_ptr = channelout;

    if (colormode == VBITMAP_COLOR_RGBA) {
      WebPPictureImportRGBA(&picture, pixels, pitch);
    } else {
      WebPPictureImportRGB(&picture, pixels, pitch);
    }

    WebPEncode(&config, &picture);

    WebPPictureFree(&picture);
  }

  VbitmapUnlock(vbitmap);
  rc = YMAGINE_OK;
#endif

  return rc;
}
Пример #6
0
static int
WEBPDecode(WEBPDec* pSrc, Vbitmap *vbitmap,
           YmagineFormatOptions *options)
{
  int contentSize;
  int origWidth = 0;
  int origHeight = 0;
  int quality;
  unsigned char header[WEBP_HEADER_SIZE + 32];
  int headerlen;
  int toRead;
  unsigned char *input = NULL;
  int inputlen;
  int oformat;
  int opitch;
  unsigned char *odata;
  int rc;
  Vrect srcrect;
  Vrect destrect;
  WebPIDecoder* idec;

  if (options == NULL) {
    /* Options argument is mandatory */
    return 0;
  }

  headerlen = YchannelRead(pSrc->channel, (char *) header, sizeof(header));
  if (headerlen < WEBP_HEADER_SIZE) {
    return 0;
  }

  /* Check WEBP header */
  contentSize = WebpCheckHeader((const char*) header, headerlen);
  if (contentSize <= 0) {
    return 0;
  }

  if (WebPGetInfo(header, headerlen, &origWidth, &origHeight) == 0) {
    ALOGD("invalid VP8 header");
    return 0;
  }

  if (origWidth <= 0 || origHeight <= 0) {
    return 0;
  }

  if (YmagineFormatOptions_invokeCallback(options, YMAGINE_IMAGEFORMAT_WEBP,
                                          origWidth, origHeight) != YMAGINE_OK) {
    return 0;
  }

  if (YmaginePrepareTransform(vbitmap, options,
                              origWidth, origHeight,
                              &srcrect, &destrect) != YMAGINE_OK) {
    return 0;
  }

#if YMAGINE_DEBUG_WEBP
  ALOGD("size: %dx%d req: %dx%d %s -> output: %dx%d",
        origWidth, origHeight,
        destrect.width, destrect.height,
        (options->scalemode == YMAGINE_SCALE_CROP) ? "crop" :
        (options->scalemode == YMAGINE_SCALE_FIT ? "fit" : "letterbox"),
        destrect.width, destrect.height);
#endif

  if (vbitmap != NULL) {
    if (options->resizable) {
      destrect.x = 0;
      destrect.y = 0;
      if (VbitmapResize(vbitmap, destrect.width, destrect.height) != YMAGINE_OK) {
        return 0;
      }
    }
    if (VbitmapType(vbitmap) == VBITMAP_NONE) {
      /* Decode bounds only, return positive number (number of lines) on success */
      return VbitmapHeight(vbitmap);
    }
  }

  pSrc->bitmap = vbitmap;

  inputlen = contentSize;
  toRead = inputlen - headerlen;

  rc = VbitmapLock(vbitmap);
  if (rc != YMAGINE_OK) {
    ALOGE("VbitmapLock() failed (code %d)", rc);
    rc = YMAGINE_ERROR;
  } else {
    odata = VbitmapBuffer(vbitmap);
    opitch = VbitmapPitch(vbitmap);
    oformat = VbitmapColormode(vbitmap);

    pSrc->inwidth = origWidth;
    pSrc->inheight = origHeight;
    pSrc->outwidth = destrect.width;
    pSrc->outheight = destrect.height;

    if (odata == NULL) {
      ALOGD("failed to get reference to pixel buffer");
      rc = YMAGINE_ERROR;
   } else {
      WebPDecoderConfig config;
      int supported = 1;
      int webpcolorspace;

      switch(oformat) {
      case VBITMAP_COLOR_RGBA:
        webpcolorspace = MODE_RGBA;
        break;
      case VBITMAP_COLOR_RGB:
        webpcolorspace = MODE_RGB;
        break;
      case VBITMAP_COLOR_rgbA:
        webpcolorspace = MODE_rgbA;
        break;
      case VBITMAP_COLOR_ARGB:
        webpcolorspace = MODE_ARGB;
        break;
      case VBITMAP_COLOR_Argb:
        webpcolorspace = MODE_Argb;
        break;
      case VBITMAP_COLOR_GRAYSCALE:
      case VBITMAP_COLOR_YUV:
      case VBITMAP_COLOR_CMYK:
      case VBITMAP_COLOR_YCbCr:
      default:
        supported = 0;
        break;
      }

      if (!supported) {
        ALOGD("currently only support RGB, RGBA webp decoding");
        rc = YMAGINE_ERROR;
      } else {
        pSrc->isdirect = 1;
        pSrc->outformat = oformat;
        pSrc->outbpp = VbitmapBpp(vbitmap);
        pSrc->outstride = opitch;
        pSrc->outbuffer = odata + destrect.x * pSrc->outbpp + destrect.y * pSrc->outstride;

        WebPInitDecoderConfig(&config);

        quality = YmagineFormatOptions_normalizeQuality(options);
        if (quality < 90) {
          config.options.no_fancy_upsampling = 1;
        }
        if (quality < 60) {
          config.options.bypass_filtering = 1;
        }
        config.options.use_threads = 1;

        if (srcrect.x != 0 || srcrect.y != 0 || srcrect.width != origWidth || srcrect.height != origHeight) {
          /* Crop on source */
          config.options.use_cropping = 1;
          config.options.crop_left = srcrect.x;
          config.options.crop_top = srcrect.y;
          config.options.crop_width = srcrect.width;
          config.options.crop_height = srcrect.height;
        }
        if (pSrc->outwidth != pSrc->inwidth || pSrc->outheight != pSrc->inheight) {
          config.options.use_scaling = 1;
          config.options.scaled_width = pSrc->outwidth;
          config.options.scaled_height = pSrc->outheight;
        }

        rc = YMAGINE_ERROR;

        // Specify the desired output colorspace:
        config.output.colorspace = webpcolorspace;

        // Have config.output point to an external buffer:
        config.output.u.RGBA.rgba = (uint8_t*) pSrc->outbuffer;
        config.output.u.RGBA.stride = pSrc->outstride;
        config.output.u.RGBA.size = pSrc->outstride * pSrc->outheight;
        config.output.is_external_memory = 1;

        idec = WebPIDecode(NULL, 0, &config);
        if (idec != NULL) {
          VP8StatusCode status;

          status = WebPIAppend(idec, header, headerlen);
          if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) {
            int bytes_remaining = toRead;
            int bytes_read;
            int bytes_req;
            unsigned char rbuf[8192];

            // See WebPIUpdate(idec, buffer, size_of_transmitted_buffer);
            bytes_req = sizeof(rbuf);
            while (bytes_remaining > 0) {
              if (bytes_req > bytes_remaining) {
                bytes_req = bytes_remaining;
              }
              bytes_read = YchannelRead(pSrc->channel, rbuf, bytes_req);
              if (bytes_read <= 0) {
                break;
              }
              status = WebPIAppend(idec, (uint8_t*) rbuf, bytes_read);
              if (status == VP8_STATUS_OK) {
                rc = YMAGINE_OK;
                break;
              } else if (status == VP8_STATUS_SUSPENDED) {
                if (bytes_remaining > 0) {
                  bytes_remaining -= bytes_read;
                }
              } else {
                /* error */
                break;
              }
              // The above call decodes the current available buffer.
              // Part of the image can now be refreshed by calling
              // WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
            }
          }
        }

        // the object doesn't own the image memory, so it can now be deleted.
        WebPIDelete(idec);
        WebPFreeDecBuffer(&config.output);
      }
    }

    VbitmapUnlock(vbitmap);
  }

  if (input) {
    Ymem_free((char*) input);
  }
  if (!pSrc->isdirect) {
    Ymem_free(pSrc->outbuffer);
  }

  if (rc == YMAGINE_OK) {
    return origHeight;
  }

  return 0;
}
Пример #7
0
double
VbitmapComputePSNR(Vbitmap *vbitmap, Vbitmap *reference)
{
  int width;
  int height;
  unsigned char* v1buffer;
  unsigned char* v2buffer;
  int bpp1;
  int bpp2;
  int v1pitch;
  int v2pitch;
  double error = 0.0;
  double psnr = -1.0;

  if (vbitmap == NULL || reference == NULL ||
      VbitmapWidth(vbitmap) != VbitmapWidth(reference) ||
      VbitmapHeight(vbitmap) != VbitmapHeight(reference)) {
    return psnr;
  }

  if (vbitmap == reference) {
    return VBITMAP_MAX_PSNR;
  }

  bpp1 = VbitmapBpp(vbitmap);
  bpp2 = VbitmapBpp(reference);

  if (VbitmapLock(vbitmap) == YMAGINE_OK) {
    if (VbitmapLock(reference) == YMAGINE_OK) {
      v1buffer = VbitmapBuffer(vbitmap);
      v2buffer = VbitmapBuffer(reference);

      if (v1buffer != NULL && v2buffer != NULL) {
        width = VbitmapWidth(vbitmap);
        height = VbitmapHeight(vbitmap);
        v1pitch = VbitmapPitch(vbitmap);
        v2pitch = VbitmapPitch(reference);

        if (bpp1 == 1 && bpp2 == 1) {
          error = calculateError(width, height, v1buffer, v2buffer, 1, 1, v1pitch, v2pitch, 1);
        } else if (bpp1 == 3 && bpp2 == 3) {
          error = calculateError(width, height, v1buffer, v2buffer, 3, 3, v1pitch, v2pitch, 3);
        } else if (bpp1 == 4 && bpp2 == 4) {
          error = calculateError(width, height, v1buffer, v2buffer, 4, 4, v1pitch, v2pitch, 4);
        } else {
          int bpp = MIN(bpp1, bpp2);
          error = calculateError(width, height, v1buffer, v2buffer, bpp1, bpp2, v1pitch, v2pitch, bpp);
        }
      }
      VbitmapUnlock(reference);
    }
    VbitmapUnlock(vbitmap);
  }

  if (error > 1.0e-10) {
    psnr = (10.0 / LOG10) * log((255.0 * 255.0) / error);
    if (psnr > VBITMAP_MAX_PSNR) {
      psnr = VBITMAP_MAX_PSNR;
    }
  } else {
    psnr = VBITMAP_MAX_PSNR;
  }

  return psnr;
}
Пример #8
0
int
Vbitmap_sobel(Vbitmap *outbitmap, Vbitmap *vbitmap)
{
  int width;
  int height;
  int pitch;
  int bpp;
  unsigned char *pixels;

  int owidth;
  int oheight;
  int opitch;
  int obpp;
  unsigned char *opixels;

  int i, j;

  unsigned char *inp;
  unsigned char *outp;

  if (vbitmap == NULL) {
    return YMAGINE_ERROR;
  }

  if (VbitmapLock(vbitmap) >= 0) {
    pixels = VbitmapBuffer(vbitmap);
    width = VbitmapWidth(vbitmap);
    height = VbitmapHeight(vbitmap);
    pitch = VbitmapPitch(vbitmap);
    bpp = colorBpp(VbitmapColormode(vbitmap));

    if (VbitmapLock(outbitmap) >= 0) {
      opixels = VbitmapBuffer(outbitmap);
      owidth = VbitmapWidth(outbitmap);
      oheight = VbitmapHeight(outbitmap);
      opitch = VbitmapPitch(outbitmap);
      obpp = colorBpp(VbitmapColormode(outbitmap));

      if (width != owidth || height != oheight) {
        VbitmapUnlock(outbitmap);
        if (VbitmapResize(outbitmap, width, height) == YMAGINE_OK) {
          if (VbitmapLock(outbitmap) < 0) {
            VbitmapUnlock(vbitmap);
            return YMAGINE_ERROR;
          }

          opixels = VbitmapBuffer(outbitmap);
          owidth = VbitmapWidth(outbitmap);
          oheight = VbitmapHeight(outbitmap);
          opitch = VbitmapPitch(outbitmap);
          obpp = colorBpp(VbitmapColormode(outbitmap));
        }
      }

      if (width == owidth && height == oheight && bpp >= 3) {
        for (j = 0; j < height; j++) {
          inp = pixels + pitch * j;
          outp = opixels + opitch * j;

          outp[0] = EnergySobel(inp, bpp, pitch, 0, j, width, height);
          outp += obpp;
          inp += bpp;

          if (j != 0 && j != height-1) {
            for (i = 1; i < width - 1; i++) {
              outp[0] = EnergySobelFast(inp, bpp, pitch);
              outp += obpp;
              inp += bpp;
            }
          } else {
            for (i = 1; i < width - 1; i++) {
              outp[0] = EnergySobel(inp, bpp, pitch, i, j, width, height);
              outp += obpp;
              inp += bpp;
            }
          }

          outp[0] = EnergySobel(inp, bpp, pitch, width - 1, j, width, height);
        }

        if (obpp >= 3) {
          for (j = 0; j < height; j++) {
            outp = opixels + opitch * j;
            for (i = 0; i < width; i++) {              
              outp[1] = outp[0];
              outp[2] = outp[0];
              if (obpp == 4) {                
                outp[0] = 0xff;
              }

              outp += obpp;
            }
          }
        }
      }

      VbitmapUnlock(outbitmap);
    }

    VbitmapUnlock(vbitmap);
  }

  return YMAGINE_OK;
}
Пример #9
0
static int
tileRender(Vbitmap *canvas, int ntiles, int tileid, Ychannel* channelin, Vbitmap *srcbitmap)
{
  int rc;
  int maxWidth = -1;
  int maxHeight = -1;
  /* scaleMode can be YMAGINE_SCALE_CROP or YMAGINE_SCALE_LETTERBOX */
  int scaleMode = YMAGINE_SCALE_CROP;
  /* Fit mode */
  int adjustMode = YMAGINE_ADJUST_NONE;
  /* metaMode can be one of YMAGINE_METAMODE_ALL, YMAGINE_METAMODE_COMMENTS,
     YMAGINE_METAMODE_NONE or YMAGINE_METAMODE_DEFAULT */
  int metaMode = YMAGINE_METAMODE_DEFAULT;
  int quality = -1;
  int accuracy = -1;
  int subsampling = -1;
  int progressive = -1;
  float sharpen = 0.0f;
  float blur = 0.0f;
  float rotate = 0.0f;
#if YMAGINE_PROFILE
  int profile = 0;
  NSTYPE start = 0;
  NSTYPE end = 0;
  NSTYPE start_decode = 0;
  NSTYPE end_decode = 0;
#endif
  YmagineFormatOptions *options = NULL;
  Vbitmap *vbitmap = NULL;
  int canvasw;
  int canvash;
  int tilex;
  int tiley;
  int tilew;
  int tileh;

#if YMAGINE_PROFILE
  if (profile) {
    start = NSTIME();
  }
#endif

  canvasw = VbitmapWidth(canvas);
  canvash = VbitmapHeight(canvas);

  if (ntiles > 4) {
    ntiles = 4;
  }

  if (tileid < 0 || tileid >= ntiles) {
    return YMAGINE_OK;
  }

  if (ntiles == 1) {
    tilex = 0;
    tiley = 0;
    tilew = canvasw;
    tileh = canvash;
  } else if (ntiles == 2) {
    tilex = cell(canvasw, tileid % 2, 2);
    tiley = cell(canvash, tileid / 2, 1);
    tilew = cell(canvasw, (tileid % 2) + 1, 2) - tilex;
    tileh = cell(canvash, (tileid / 2) + 1, 1) - tiley;
  } else if (ntiles == 3) {
    tilex = cell(canvasw, tileid % 2, 2);
    tiley = cell(canvash, tileid / 2, 2);
    tilew = cell(canvasw, (tileid % 2) + 1, 2) - tilex;
    if (tileid == 0) {
      tilex = 0;
      tiley = 0;
      tilew = cell(canvasw, 1, 2) - tilex;
      tileh = canvash;
    } else {
      tilex = cell(canvasw, 1, 2);
      tiley = cell(canvash, (tileid - 1) % 2, 2);
      tilew = cell(canvasw, 2, 2) - tilex;
      tileh = cell(canvash, ((tileid - 1) % 2) + 1, 2) - tiley;
    }
  } else {
    tilex = cell(canvasw, tileid % 2, 2);
    tiley = cell(canvash, tileid / 2, 2);
    tilew = cell(canvasw, (tileid % 2) + 1, 2) - tilex;
    tileh = cell(canvash, (tileid / 2) + 1, 2) - tiley;
  }

  maxWidth = tilew;
  maxHeight = tileh;

  rc = YMAGINE_ERROR;

  options = YmagineFormatOptions_Create();
  if (options != NULL) {
    YmagineFormatOptions_setResize(options, maxWidth, maxHeight, scaleMode);
    YmagineFormatOptions_setQuality(options, quality);
    YmagineFormatOptions_setAccuracy(options, accuracy);
    YmagineFormatOptions_setMetaMode(options, metaMode);
    if (subsampling >= 0) {
      YmagineFormatOptions_setSubsampling(options, subsampling);
    }
    if (progressive >= 0) {
      YmagineFormatOptions_setProgressive(options, progressive);
    }
    if (sharpen > 0.0f) {
      YmagineFormatOptions_setSharpen(options, sharpen);
    }
    if (blur > 0.0f) {
      YmagineFormatOptions_setBlur(options, blur);
    }
    if (rotate != 0.0f) {
      YmagineFormatOptions_setRotate(options, rotate);
    }
    YmagineFormatOptions_setAdjust(options, adjustMode);

    vbitmap = VbitmapInitMemory(VBITMAP_COLOR_RGBA);
    if (vbitmap != NULL) {
#if YMAGINE_PROFILE
      start_decode = NSTIME();
#endif
      if (channelin != NULL) {
        rc = YmagineDecode(vbitmap, channelin, options);
      } else if (srcbitmap != NULL) {
        rc = YmagineDecodeCopy(vbitmap, srcbitmap, options);
      } else {
        rc = YMAGINE_ERROR;
      }
#if YMAGINE_PROFILE
      end_decode = NSTIME();
      if (profile) {
        ALOGI("Decoded image %dx%d in %.2f ms\n",
              VbitmapWidth(vbitmap), VbitmapHeight(vbitmap),
              ((double) (end_decode - start_decode)) / 1000000.0);
      }
 #endif

      if (rc == YMAGINE_OK) {
        VbitmapRegionSelect(canvas, tilex, tiley, tilew, tileh);
        Ymagine_composeImage(canvas, vbitmap, 0, 0, YMAGINE_COMPOSE_BUMP);
        VbitmapRegionReset(canvas);

#if YMAGINE_PROFILE
        if (profile) {
          end = NSTIME();
          ALOGI("Rendered orb tile %d/%d in %.2f ms\n",
                tileid, ntiles,
          ((double) (end - start)) / 1000000.0);
        }
#endif
      }
      VbitmapRelease(vbitmap);
    }

    YmagineFormatOptions_Release(options);
    options = NULL;
  }

  return rc;
}
Пример #10
0
int
encodeJPEG(Vbitmap *vbitmap, Ychannel *channelout, YmagineFormatOptions *options)
{
  struct jpeg_compress_struct cinfoout;
  struct noop_error_mgr jerr;
  int result = YMAGINE_ERROR;
  int rc;
  int nlines = 0;
  JSAMPROW row_pointer[1];
  unsigned char *pixels;
  int width;
  int height;
  int pitch;
  int colormode;
  int i;

  if (!YchannelWritable(channelout)) {
    return result;
  }

  if (vbitmap == NULL) {
    return result;
  }

  rc = VbitmapLock(vbitmap);
  if (rc != YMAGINE_OK) {
    ALOGE("AndroidBitmap_lockPixels() failed");
    return result;
  }

  memset(&cinfoout, 0, sizeof(struct jpeg_compress_struct));
  cinfoout.err = noop_jpeg_std_error(&jerr.pub);

  if (setjmp(jerr.setjmp_buffer)) {
    /* If we get here, the JPEG code has signaled an error in encoder */
    noop_append_jpeg_message((j_common_ptr) &cinfoout);
  } else {
    /* Equivalent to:
	   jpeg_CreateCompress(&cinfoout, JPEG_LIB_VERSION,
	   (size_t) sizeof(struct jpeg_compress_struct));
     */
    jpeg_create_compress(&cinfoout);

    if (ymaginejpeg_output(&cinfoout, channelout) >= 0) {
      /* Other compression settings */
      int optimize = 0;
      int progressive = 0;
      int grayscale = 0;
      int quality = YmagineFormatOptions_normalizeQuality(options);

      if (quality >= 90) {
        optimize = 1;
      }

      width = VbitmapWidth(vbitmap);
      height = VbitmapHeight(vbitmap);
      pitch = VbitmapPitch(vbitmap);
      colormode = VbitmapColormode(vbitmap);

      cinfoout.image_width = width;
      cinfoout.image_height = height;

      set_colormode(&cinfoout, colormode);

      jpeg_set_defaults(&cinfoout);

      jpeg_set_quality(&cinfoout, quality, FALSE);
      if (grayscale) {
        /* Force a monochrome JPEG file to be generated. */
        jpeg_set_colorspace(&cinfoout, JCS_GRAYSCALE);
      }
      if (optimize) {
        /* Enable entropy parm optimization. */
        cinfoout.optimize_coding = TRUE;
      }
      if (progressive) {
        /* Select simple progressive mode. */
        jpeg_simple_progression(&cinfoout);
      }
      setCompressorOptions(&cinfoout, options);
      jpeg_start_compress(&cinfoout, TRUE);

      pixels = VbitmapBuffer(vbitmap);
      for (i = 0; i < height; i++) {
        row_pointer[0] = pixels + i * pitch;
        jpeg_write_scanlines(&cinfoout, row_pointer, 1);
        nlines++;
      }
      if (nlines > 0) {
        rc = YMAGINE_OK;
      }

      /* Clean up compressor */
      jpeg_finish_compress(&cinfoout);
    }
  }

  jpeg_destroy_compress(&cinfoout);
  VbitmapUnlock(vbitmap);

  return rc;
}
Пример #11
0
static YOPTIMIZE_SPEED int
decompress_jpeg(struct jpeg_decompress_struct *cinfo,
                struct jpeg_compress_struct *cinfoout, JCOPY_OPTION copyoption,
                Vbitmap *vbitmap, YmagineFormatOptions *options)
{
  int scanlines;
  int nlines;
  int totallines;
  int j;
  int scalenum = -1;
  JSAMPARRAY buffer;
  Vrect srcrect;
  Vrect destrect;
  size_t row_stride;
  Transformer *transformer;
  PixelShader *shader = NULL;
  int iwidth, iheight;
  float sharpen = 0.0f;

  if (vbitmap == NULL && cinfoout == NULL) {
    /* No output specified */
    return 0;
  }
  if (options == NULL) {
    /* Options argument is mandatory */
    return 0;
  }

  iwidth = cinfo->image_width;
  iheight = cinfo->image_height;

  if (YmaginePrepareTransform(vbitmap, options,
                              iwidth, iheight,
                              &srcrect, &destrect) != YMAGINE_OK) {
    return 0;
  }

  shader = options->pixelshader;
  sharpen = options->sharpen;

  /* Define if image can be pre-subsampled by a ratio n/8 (n=1..7) */
  scalenum = GetScaleNum(destrect.width, destrect.height,
                         srcrect.width, srcrect.height,
                         options->scalemode);
  if (scalenum > 0 && scalenum < 8) {
    cinfo->scale_num = scalenum;
    cinfo->scale_denom = 8;
  }

  /* Compute actual output dimension for image returned by decoder */
  jpeg_calc_output_dimensions(cinfo);

#if YMAGINE_DEBUG_JPEG
  ALOGD("src=%dx%d@%d,%d dst=%dx%d@%d,%d",
        srcrect.width, srcrect.height, srcrect.x, srcrect.y,
        destrect.width, destrect.height, destrect.x, destrect.y);

  ALOGD("size: %dx%d req: %dx%d %s -> scale: %d/%d output: %dx%d components: %d",
        iwidth, iheight,
        destrect.width, destrect.height,
        Ymagine_scaleModeStr(options->scalemode),
        cinfo->scale_num, cinfo->scale_denom,
        cinfo->output_width, cinfo->output_height,
        cinfo->output_components);
#endif

  /* Scale the crop region to reflect scaling ratio applied by JPEG decoder */
  if (cinfo->image_width != cinfo->output_width) {
    srcrect.x = (srcrect.x * cinfo->output_width) / cinfo->image_width;
    srcrect.width = (srcrect.width * cinfo->output_width) / cinfo->image_width;
  }
  if (cinfo->image_height != cinfo->output_height) {
    srcrect.y = (srcrect.y * cinfo->output_height) / cinfo->image_height;
    srcrect.height = (srcrect.height * cinfo->output_height) / cinfo->image_height;
  }

  /* Number of scan lines to handle per pass. Making it larger actually doesn't help much */
  row_stride = cinfo->output_width * cinfo->output_components;
  scanlines = (32 * 1024) / row_stride;
  if (scanlines < 1) {
    scanlines = 1;
  }
  if (scanlines > cinfo->output_height) {
    scanlines = cinfo->output_height;
  }

#if YMAGINE_DEBUG_JPEG
  ALOGD("BITMAP @(%d,%d) %dx%d bpp=%d -> @(%dx%d) %dx%d (%d lines)",
        srcrect.x, srcrect.y, srcrect.width, srcrect.height, JpegPixelSize(cinfo->out_color_space),
        destrect.x, destrect.y, destrect.width, destrect.height,
        scanlines);
#endif

  /* Resize encoder */
  if (cinfoout != NULL) {
    cinfoout->image_width = destrect.width;
    cinfoout->image_height = destrect.height;
    jpeg_start_compress(cinfoout, TRUE);
    if (copyoption != JCOPYOPT_NONE) {
      /* Copy to the output file any extra markers that we want to preserve */
      jcopy_markers_execute(cinfo, cinfoout, copyoption);
    }
  }

  /* Resize target bitmap */
  if (vbitmap != NULL) {
    if (options->resizable) {
      destrect.x = 0;
      destrect.y = 0;
      if (VbitmapResize(vbitmap, destrect.width, destrect.height) != YMAGINE_OK) {
        return 0;
      }
    }
    if (VbitmapType(vbitmap) == VBITMAP_NONE) {
      /* Decode bounds only, return positive number (number of lines) on success */
      return VbitmapHeight(vbitmap);
    }
  }

  if (!jpeg_start_decompress(cinfo)) {
    if (cinfoout != NULL) {
      jpeg_abort_compress(cinfoout);
    }
    return 0;
  }
  
  buffer = (JSAMPARRAY) (*cinfo->mem->alloc_sarray)((j_common_ptr) cinfo, JPOOL_IMAGE,
                                                    row_stride, scanlines);
  if (buffer == NULL) {
    if (cinfoout != NULL) {
      jpeg_abort_compress(cinfoout);
    }
    jpeg_abort_decompress(cinfo);
    return 0;
  }
  
  totallines = 0;
  
  transformer = TransformerCreate();
  if (transformer != NULL) {
    TransformerSetScale(transformer,
                        cinfo->output_width, cinfo->output_height,
                        destrect.width, destrect.height);
    TransformerSetRegion(transformer,
                         srcrect.x, srcrect.y, srcrect.width, srcrect.height);

    if (vbitmap != NULL) {
      TransformerSetMode(transformer, JpegPixelMode(cinfo->out_color_space), VbitmapColormode(vbitmap));
      TransformerSetBitmap(transformer, vbitmap, destrect.x, destrect.y);
    } else {
      TransformerSetMode(transformer, JpegPixelMode(cinfo->out_color_space),
                         JpegPixelMode(cinfoout->in_color_space));
      TransformerSetWriter(transformer, JpegWriter, cinfoout);
    }
    TransformerSetShader(transformer, shader);
    TransformerSetSharpen(transformer, sharpen);
  }

  while (transformer != NULL && cinfo->output_scanline < cinfo->output_height) {
    nlines = jpeg_read_scanlines(cinfo, buffer, scanlines);
    if (nlines <= 0) {
      /* Decoding error */
      ALOGD("decoding error (nlines=%d)", nlines);
      break;
    }

    for (j = 0; j < nlines; j++) {
      if (TransformerPush(transformer, (const char*) buffer[j]) != YMAGINE_OK) {
        TransformerRelease(transformer);
        transformer = NULL;
        break;
      }
      totallines++;
    }
  }

  /* Clean up */
  if (transformer != NULL) {
    TransformerRelease(transformer);
  }
  if (cinfo->output_scanline > 0 && cinfo->output_scanline == cinfo->output_height) {
    /* Do normal cleanup if whole image has been read and decoded */
    jpeg_finish_decompress(cinfo);
    if (cinfoout != NULL) {
      jpeg_finish_compress(cinfoout);
    }
  }
  else {
    /* else early abort */
    jpeg_abort_decompress(cinfo);
    if (cinfoout != NULL) {
      jpeg_abort_compress(cinfoout);
    }
    totallines = 0;
  }
  
  return totallines;
}
Пример #12
0
int
parseopts_shader(const char* argv[], int argc, int i, PixelShader *shader, int compose)
{
  /* Number of arguments processed */
  int nargs = 0;
  if (argv[i][1] == 's' && strcmp(argv[i], "-saturation") == 0) {
    double saturation = 0.0f;
    if (i+1 >= argc) {
      fprintf(stdout, "missing value after option \"%s\"\n", argv[i]);
      fflush(stdout);
      return -1;
    }
    i++;
    saturation = atof(argv[i]);
    Yshader_PixelShader_saturation(shader, saturation);
    nargs += 2;
  } else if (argv[i][1] == 'e' && strcmp(argv[i], "-exposure") == 0) {
      double exposure = 0.0f;
      if (i+1 >= argc) {
        fprintf(stdout, "missing value after option \"%s\"\n", argv[i]);
        fflush(stdout);
        return -1;
      }
      i++;
      exposure = atof(argv[i]);
      Yshader_PixelShader_exposure(shader, exposure);
      nargs += 2;
  } else if (argv[i][1] == 'c' && strcmp(argv[i], "-contrast") == 0) {
    double contrast = 0.0f;
    if (i+1 >= argc) {
      fprintf(stdout, "missing value after option \"%s\"\n", argv[i]);
      fflush(stdout);
      return -1;
    }
    i++;
    contrast = atof(argv[i]);
    Yshader_PixelShader_contrast(shader, contrast);
    nargs += 2;
  } else if (argv[i][1] == 'b' && strcmp(argv[i], "-brightness") == 0) {
    double brightness = 0.0f;
    if (i+1 >= argc) {
      fprintf(stdout, "missing value after option \"%s\"\n", argv[i]);
      fflush(stdout);
      return -1;
    }
    i++;
    brightness = atof(argv[i]);
    Yshader_PixelShader_brightness(shader, brightness);
    nargs += 2;
  } else if (argv[i][1] == 't' && strcmp(argv[i], "-temperature") == 0) {
    double temperature = 0.0f;
    if (i+1 >= argc) {
      fprintf(stdout, "missing value after option \"%s\"\n", argv[i]);
      fflush(stdout);
      return -1;
    }
    i++;
    temperature = atof(argv[i]);
    Yshader_PixelShader_temperature(shader, temperature);
    nargs += 2;
  } else if (argv[i][1] == 'w' && strcmp(argv[i], "-whitebalance") == 0) {
    double whitebalance = 0.0f;
    if (i+1 >= argc) {
      fprintf(stdout, "missing value after option \"%s\"\n", argv[i]);
      fflush(stdout);
      return -1;
    }
    i++;
    whitebalance = atof(argv[i]);
    Yshader_PixelShader_whitebalance(shader, whitebalance);
    nargs += 2;
  } else if (argv[i][1] == 'v' && strcmp(argv[i], "-vignette") == 0) {
    Vbitmap *vmap;
    const char* shaderfile;
    int fd;
    Ychannel* channel;

    if (i+1 >= argc) {
      fprintf(stdout, "missing value after option \"%s\"\n", argv[i]);
      fflush(stdout);
      return -1;
    }
    i++;

    /* load map for vignette */
    shaderfile = argv[i];
    fd = open(shaderfile, O_RDONLY);
    if (fd < 0) {
      fprintf(stderr, "error loading vignette map \"%s\"\n", shaderfile);
      return -1;
    }

    vmap = VbitmapInitMemory(VBITMAP_COLOR_RGBA);
    channel = YchannelInitFd(fd, 0);
    YmagineDecodeResize(vmap, channel, -1, -1, YMAGINE_SCALE_LETTERBOX);
    YchannelRelease(channel);
    /* Either set auto-release to true, or close the file descriptor Ychannel doesn't own */
    close(fd);
    fprintf(stderr, "Loaded vignette map from '%s' %dx%d\n",
            shaderfile, VbitmapWidth(vmap), VbitmapHeight(vmap));

    /* Append vignette shader to pipeline */
    VbitmapRetain(vmap);
    Yshader_PixelShader_vignette(shader, vmap, compose);
    VbitmapRelease(vmap);

    nargs += 2;
  }

  return nargs;
}