Example #1
0
TImageP TImageReader::load0()
{
	if (!m_reader && !m_vectorReader)
		open();

	if (m_reader) {
		TImageInfo info = m_reader->getImageInfo();
		if (info.m_lx <= 0 || info.m_ly <= 0)
			return TImageP();

		// Initialize raster info
		assert(m_shrink > 0);

		// Build loading rect
		int x0 = 0;
		int x1 = info.m_lx - 1;
		int y0 = 0;
		int y1 = info.m_ly - 1;

		if (!m_region.isEmpty()) {
			// Intersect with the externally specified loading region

			x0 = tmax(x0, m_region.x0);
			y0 = tmax(y0, m_region.y0);
			x1 = tmin(x1, m_region.x1);
			y1 = tmin(y1, m_region.y1);

			if (x0 >= x1 || y0 >= y1)
				return TImageP();
		}

		if (m_shrink > 1) {
			// Crop to shrink multiples
			x1 -= (x1 - x0) % m_shrink;
			y1 -= (y1 - y0) % m_shrink;
		}

		assert(x0 <= x1 && y0 <= y1);

		TDimension imageDimension = TDimension((x1 - x0) / m_shrink + 1, (y1 - y0) / m_shrink + 1);

		if (m_path.getType() == "tzp" || m_path.getType() == "tzu") {
			// Colormap case

			TRasterCM32P ras(imageDimension);
			readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly, m_shrink);

			// Build the savebox
			TRect saveBox(info.m_x0, info.m_y0, info.m_x1, info.m_y1);
			if (!m_region.isEmpty()) {
				// Intersect with the loading rect
				if (m_region.overlaps(saveBox)) {
					saveBox *= m_region;

					int sbx0 = saveBox.x0 - m_region.x0;
					int sby0 = saveBox.y0 - m_region.y0;
					int sbx1 = sbx0 + saveBox.getLx() - 1;
					int sby1 = sby0 + saveBox.getLy() - 1;
					assert(sbx0 >= 0);
					assert(sby0 >= 0);
					assert(sbx1 >= 0);
					assert(sby1 >= 0);

					saveBox = TRect(sbx0, sby0, sbx1, sby1);
				} else
					saveBox = TRect(0, 0, 1, 1);
			}

			if (m_shrink > 1) {
				saveBox.x0 = saveBox.x0 / m_shrink;
				saveBox.y0 = saveBox.y0 / m_shrink;
				saveBox.x1 = saveBox.x1 / m_shrink;
				saveBox.y1 = saveBox.y1 / m_shrink;
			}

			TToonzImageP ti(ras, ras->getBounds() * saveBox);
			ti->setDpi(info.m_dpix, info.m_dpiy);

			return ti;
		} else if (info.m_bitsPerSample >= 8) {
			// Common byte-based rasters (see below, we have black-and-white bit-based images too)

			if (info.m_samplePerPixel == 1 && m_readGreytones) {
				//  Greymap case
				// NOTE: Uses a full 32-bit raster first, and then copies down to the GR8

				// Observe that GR16 file images get immediately down-cast to GR8...
				// Should we implement that too?

				TRasterGR8P ras(imageDimension);
				readRaster_copyLines(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly, m_shrink);

				TRasterImageP ri(ras);
				ri->setDpi(info.m_dpix, info.m_dpiy);

				return ri;
			}

			// assert(info.m_samplePerPixel == 3 || info.m_samplePerPixel == 4);

			TRasterP _ras;
			if (info.m_bitsPerSample == 16) {
				if (m_is64BitEnabled || m_path.getType() != "tif") {
					//  Standard 64-bit case.

					// Also covers down-casting to 32-bit from a 64-bit image file whenever
					// not a tif file (see below).

					TRaster64P ras(imageDimension);
					readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly, m_shrink);

					_ras = ras;
				} else {
					// The Tif reader has got an automatically down-casting readLine(char*, ...)
					// in case the input file is 64-bit. The advantage is that no intermediate
					// 64-bit raster is required in this case.

					TRaster32P ras(imageDimension);
					readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly, m_shrink);

					_ras = ras;
				}
			} else if (info.m_bitsPerSample == 8) {
				//  Standard 32-bit case
				TRaster32P ras(imageDimension);
				readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly, m_shrink);

				_ras = ras;
			} else
				throw TImageException(m_path, "Image format not supported");

			// 64-bit to 32-bit conversions if necessary  (64 bit images not allowed)
			if (!m_is64BitEnabled && (TRaster64P)_ras) {
				TRaster32P raux(_ras->getLx(), _ras->getLy());
				TRop::convert(raux, _ras);
				_ras = raux;
			}

			// Return the image
			TRasterImageP ri(_ras);
			ri->setDpi(info.m_dpix, info.m_dpiy);

			return ri;
		} else if (info.m_samplePerPixel == 1 && info.m_valid == true) {
			//  Previously dubbed as 'Palette cases'. No clue about what is this... :|

			TRaster32P ras(imageDimension);
			readRaster(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly, m_shrink);

			TRasterImageP ri(ras);
			ri->setDpi(info.m_dpix, info.m_dpiy);

			return ri;
		} else if (info.m_samplePerPixel == 1 && m_readGreytones) {
			//  Black-and-White case, I guess. Standard greymaps were considered above...

			TRasterGR8P ras(imageDimension);
			readRaster_copyLines(ras, m_reader, x0, y0, x1, y1, info.m_lx, info.m_ly, m_shrink);

			TRasterImageP ri(ras);
			ri->setDpi(info.m_dpix, info.m_dpiy);

			if (info.m_bitsPerSample == 1) // I suspect this always evaluates true...
				ri->setScanBWFlag(true);

			return ri;
		} else
			return TImageP();
	} else if (m_vectorReader) {
		TVectorImage *vi = m_vectorReader->read();
		return TVectorImageP(vi);
	} else
		return TImageP();
}
Example #2
0
void blend(TToonzImageP ti, TRasterPT<PIXEL> rasOut,
           const std::vector<BlendParam> &params) {
  assert(ti->getRaster()->getSize() == rasOut->getSize());

  // Extract the interesting raster. It should be the savebox of passed cmap,
  // plus - if
  // some param has the 0 index as blending color - the intensity of that blend
  // param.
  unsigned int i, j;
  TRect saveBox(ti->getSavebox());

  int enlargement = 0;
  for (i = 0; i < params.size(); ++i)
    for (j = 0; j < params[i].colorsIndexes.size(); ++j)
      if (params[i].colorsIndexes[j] == 0)
        enlargement = std::max(enlargement, tceil(params[i].intensity));
  saveBox           = saveBox.enlarge(enlargement);

  TRasterCM32P cmIn(ti->getRaster()->extract(saveBox));
  TRasterPT<PIXEL> rasOutExtract = rasOut->extract(saveBox);

  // Ensure that cmIn and rasOut have the same size
  unsigned int lx = cmIn->getLx(), ly = cmIn->getLy();

  // Build the pure colors infos
  SelectionRaster selectionRaster(cmIn);

  // Now, build a little group of BlurPatterns - and for each, one for passed
  // param.
  // A small number of patterns per param is needed to make the pattern look not
  // ever the same.
  const int blurPatternsPerParam = 10;
  std::vector<BlurPatternContainer> blurGroup(params.size());

  for (i = 0; i < params.size(); ++i) {
    BlurPatternContainer &blurContainer = blurGroup[i];
    blurContainer.reserve(blurPatternsPerParam);

    for (j = 0; j < blurPatternsPerParam; ++j)
      blurContainer.push_back(BlurPattern(
          params[i].intensity, params[i].smoothness, params[i].stopAtCountour));
  }

  // Build the palette
  TPalette *palette = ti->getPalette();
  std::vector<TPixel32> paletteColors;
  paletteColors.resize(palette->getStyleCount());
  for (i             = 0; i < paletteColors.size(); ++i)
    paletteColors[i] = premultiply(palette->getStyle(i)->getAverageColor());

  // Build the 4 auxiliary rasters for the blending procedure: they are ink /
  // paint versus input / output in the blend.
  // The output raster is reused to spare some memory - it should be, say, the
  // inkLayer's second at the end of the overall
  // blending procedure. It could be the first, without the necessity of
  // clearing it before blending the layers, but things
  // get more complicated when PIXEL is TPixel64...
  RGBMRasterPair inkLayer, paintLayer;

  TRaster32P rasOut32P_1(lx, ly, lx, (TPixel32 *)rasOut->getRawData(), false);
  inkLayer.first  = (params.size() % 2) ? rasOut32P_1 : TRaster32P(lx, ly);
  inkLayer.second = (params.size() % 2) ? TRaster32P(lx, ly) : rasOut32P_1;

  if (PIXEL::maxChannelValue >= TPixel64::maxChannelValue) {
    TRaster32P rasOut32P_2(lx, ly, lx,
                           ((TPixel32 *)rasOut->getRawData()) + lx * ly, false);
    paintLayer.first  = (params.size() % 2) ? rasOut32P_2 : TRaster32P(lx, ly);
    paintLayer.second = (params.size() % 2) ? TRaster32P(lx, ly) : rasOut32P_2;
  } else {
    paintLayer.first  = TRaster32P(lx, ly);
    paintLayer.second = TRaster32P(lx, ly);
  }

  inkLayer.first->clear();
  inkLayer.second->clear();
  paintLayer.first->clear();
  paintLayer.second->clear();

  // Now, we have to perform the blur of each of the cm's pixels.
  cmIn->lock();
  rasOut->lock();

  inkLayer.first->lock();
  inkLayer.second->lock();
  paintLayer.first->lock();
  paintLayer.second->lock();

  // Convert the initial cmIn to fullcolor ink - paint layers
  buildLayers(cmIn, paletteColors, inkLayer.first, paintLayer.first);

  // Perform the blend on separated ink - paint layers
  for (i = 0; i < params.size(); ++i) {
    if (params[i].colorsIndexes.size() == 0) continue;

    selectionRaster.updateSelection(cmIn, params[i]);
    doBlend(cmIn, inkLayer, paintLayer, selectionRaster, blurGroup[i]);

    tswap(inkLayer.first, inkLayer.second);
    tswap(paintLayer.first, paintLayer.second);
  }

  // Release the unnecessary rasters
  inkLayer.second->unlock();
  paintLayer.second->unlock();
  inkLayer.second   = TRaster32P();
  paintLayer.second = TRaster32P();

  // Clear rasOut - since it was reused to spare space...
  rasOut->clear();

  // Add the ink & paint layers on the output raster
  double PIXELmaxChannelValue = PIXEL::maxChannelValue;
  double toPIXELFactor =
      PIXELmaxChannelValue / (double)TPixel32::maxChannelValue;
  double inkFactor, paintFactor;
  TPoint pos;

  PIXEL *outPix, *outBegin    = (PIXEL *)rasOutExtract->getRawData();
  TPixelCM32 *cmPix, *cmBegin = (TPixelCM32 *)cmIn->getRawData();
  int wrap = rasOutExtract->getWrap();

  TPixel32 *inkPix   = (TPixel32 *)inkLayer.first->getRawData();
  TPixel32 *paintPix = (TPixel32 *)paintLayer.first->getRawData();

  for (i = 0; i < ly; ++i) {
    outPix = outBegin + wrap * i;
    cmPix  = cmBegin + wrap * i;
    for (j = 0; j < lx; ++j, ++outPix, ++cmPix, ++inkPix, ++paintPix) {
      getFactors(cmPix->getTone(), inkFactor, paintFactor);

      outPix->r = tcrop(
          toPIXELFactor * (inkFactor * inkPix->r + paintFactor * paintPix->r),
          0.0, PIXELmaxChannelValue);
      outPix->g = tcrop(
          toPIXELFactor * (inkFactor * inkPix->g + paintFactor * paintPix->g),
          0.0, PIXELmaxChannelValue);
      outPix->b = tcrop(
          toPIXELFactor * (inkFactor * inkPix->b + paintFactor * paintPix->b),
          0.0, PIXELmaxChannelValue);
      outPix->m = tcrop(
          toPIXELFactor * (inkFactor * inkPix->m + paintFactor * paintPix->m),
          0.0, PIXELmaxChannelValue);
    }
  }

  inkLayer.first->unlock();
  paintLayer.first->unlock();

  cmIn->unlock();
  rasOut->unlock();

  // Destroy the auxiliary bitmaps
  selectionRaster.destroy();
}
void AnswerMachineDialog::saveMessage()
{
  char buf[1024];
  unsigned int rec_size = a_msg.getDataSize();
  DBG("recorded data size: %i\n",rec_size);

  int rec_length = a_msg.getLength();
  char rec_len_str[10];
  snprintf(rec_len_str, sizeof(rec_len_str), 
	   "%.2f", float(rec_length)/1000.0);
  string rec_len_s = rec_len_str;

  DBG("recorded file length: %i ms (%s sec)\n",
      rec_length, rec_len_s.c_str());

  email_dict["vmsg_length"] = rec_len_s;

  if(!rec_size){
    unlink(msg_filename.c_str());

    // record in box empty messages as well
    if (AnswerMachineFactory::SaveEmptyMsg &&
	((vm_mode == MODE_BOX) || 
	 (vm_mode == MODE_BOTH))) {
      saveBox(NULL);
    }
  } else {
    try {
      // avoid tmp file to be closed
      // ~AmMail will do that...
      a_msg.setCloseOnDestroy(false);
      a_msg.on_close();

      // copy to tmpfile for box msg
      if ((vm_mode == MODE_BOTH) ||  
	  (vm_mode == MODE_BOX))  {
	DBG("will save to box...\n");
	FILE* m_fp = a_msg.getfp();

	if (vm_mode == MODE_BOTH) {
	  // copy file to new tmpfile
	  m_fp = tmpfile();
	  if(!m_fp){
	    ERROR("could not create temporary file: %s\n",
		  strerror(errno));
	  } else {
	    FILE* fp = a_msg.getfp();
	    rewind(fp);
	    size_t nread;
	    while (!feof(fp)) {
	      nread = fread(buf, 1, 1024, fp);
	      if (fwrite(buf, 1, nread, m_fp) != nread)
		break;
	    }
	  }
	}
	saveBox(m_fp);
      }
	    
      if ((vm_mode == MODE_BOTH) ||
	  (vm_mode == MODE_VOICEMAIL)) { 
	// send mail
	AmMail* mail = new AmMail(tmpl->getEmail(email_dict));
	mail->attachements.push_back(Attachement(a_msg.getfp(),
						 "message."
						 + AnswerMachineFactory::RecFileExt,
						 a_msg.getMimeType()));
	AmMailDeamon::instance()->sendQueued(mail);
      }
    }
    catch(const string& err){
      ERROR("while creating email: %s\n",err.c_str());
    }
  }
}