Class: Oil::JPEGReader

Inherits:
Object
  • Object
show all
Defined in:
ext/oil/jpeg.c,
ext/oil/jpeg.c

Overview

Read a compressed JPEG image given an IO object.

Instance Method Summary collapse

Constructor Details

#new(io_in[, markers]) ⇒ Object

Creates a new JPEG Reader. io_in must be an IO-like object that responds to read(size).

markers should be an array of valid JPEG header marker symbols. Valid symbols are :APP0 through :APP15 and :COM.

If performance is important, you can avoid reading any header markers by supplying an empty array, [].

When markers are not specified, we read all known JPEG markers.

io = File.open("image.jpg", "r")
reader = Oil::JPEGReader.new(io)

io = File.open("image.jpg", "r")
reader = Oil::JPEGReader.new(io, [:APP1, :APP2])


282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'ext/oil/jpeg.c', line 282

static VALUE initialize(int argc, VALUE *argv, VALUE self)
{
	struct readerdata *reader;
	VALUE io, markers;
	struct jpeg_decompress_struct *dinfo;
	int i, marker_code;

	Data_Get_Struct(self, struct readerdata, reader);
	dinfo = &reader->dinfo;

	/* If source_io has already been set, then this is a re-used jpeg reader
	 * object. This means we need to abort the previous decompress to
	 * prevent memory leaks.
	 */
	if (reader->source_io) {
		jpeg_abort_decompress(dinfo);
	} else {
		jpeg_create_decompress(dinfo);
	}

	dinfo->src = &reader->mgr;

	rb_scan_args(argc, argv, "11", &io, &markers);
	reader->source_io = io;
	reader->mgr.bytes_in_buffer = 0;

	if(!NIL_P(markers)) {
		Check_Type(markers, T_ARRAY);
		for (i=0; i<RARRAY_LEN(markers); i++) {
			if (!SYMBOL_P(RARRAY_PTR(markers)[i])) {
				rb_raise(rb_eTypeError, "Marker code is not a symbol.");
			}
			marker_code = sym_to_marker_code(RARRAY_PTR(markers)[i]);
			jpeg_save_markers(dinfo, marker_code, 0xFFFF);
		}
	}

	/* Be warned that this can raise a ruby exception and longjmp away. */
	jpeg_read_header(dinfo, TRUE);

	jpeg_calc_output_dimensions(dinfo);

	return self;
}

Instance Method Details

#each(opts, &block) ⇒ self

Yields a series of binary strings that make up the output JPEG image.

Options is a hash which may have the following symbols:

:quality - JPEG quality setting. Betweein 0 and 100. :markers - Custom markers to include in the output JPEG. Must be a hash where

the keys are :APP[0-15] or :COM and the values are arrays of strings that
will be inserted into the markers.

Returns:

  • (self)


833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
# File 'ext/oil/jpeg.c', line 833

static VALUE each(int argc, VALUE *argv, VALUE self)
{
	struct readerdata *reader;
	struct writerdata writer;
	int cmp, state;
	struct write_jpeg_args args;
	unsigned char *inwidthbuf, *outwidthbuf;
	struct yscaler ys;
	VALUE opts;

	rb_scan_args(argc, argv, "01", &opts);

	Data_Get_Struct(self, struct readerdata, reader);

	if (!reader->scale_width) {
		reader->scale_width = reader->dinfo.output_width;
	}
	if (!reader->scale_height) {
		reader->scale_height = reader->dinfo.output_height;
	}

	writer.cinfo.err = &reader->jerr;
	jpeg_create_compress(&writer.cinfo);

	cmp = reader->dinfo.output_components;
	inwidthbuf = malloc(reader->dinfo.output_width * cmp);
	outwidthbuf = malloc(reader->scale_width * cmp);
	yscaler_init(&ys, reader->dinfo.output_height, reader->scale_height,
		reader->scale_width * cmp);

	args.reader = reader;
	args.opts = opts;
	args.writer = &writer;
	args.inwidthbuf = inwidthbuf;
	args.outwidthbuf = outwidthbuf;
	args.ys = &ys;
	reader->locked = 1;
	rb_protect((VALUE(*)(VALUE))each2, (VALUE)&args, &state);

	yscaler_free(&ys);
	free(inwidthbuf);
	free(outwidthbuf);
	jpeg_destroy_compress(&writer.cinfo);

	if (state) {
		rb_jump_tag(state);
	}

	return self;
}

#image_heightNumeric

The height of the image as indicated by the header.

This may differ from the height of the image that will be returned by the decompressor if we request DCT scaling.

Returns:

  • (Numeric)


469
470
471
472
473
474
# File 'ext/oil/jpeg.c', line 469

static VALUE image_height(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->image_height);
}

#image_widthNumeric

The width of the of the image as indicated by the header.

This may differ from the width of the image that will be returned by the decompressor if we request DCT scaling.

Returns:

  • (Numeric)


452
453
454
455
456
457
# File 'ext/oil/jpeg.c', line 452

static VALUE image_width(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->image_width);
}

#jpeg_color_spaceObject

Returns a symbol representing the color model in which the JPEG is stored, as indicated by the image header.

Possible color models are: :GRAYSCALE, :RGB, :YCbCr, :CMYK, and :YCCK. This method will return :UNKNOWN if the color model is not recognized.

This may differ from the color space that will be returned by the decompressor if we ask for a color space transformation.



393
394
395
396
397
398
399
400
401
402
# File 'ext/oil/jpeg.c', line 393

static VALUE jpeg_color_space(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	ID id;

	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	id = j_color_space_to_id(dinfo->jpeg_color_space);

	return ID2SYM(id);
}

#markersHash

Get a hash of raw marker data from the JPEG.

The keys in the hash are the marker codes as symbols. The values are arrays.

Arrays since there may be multiple instances of a single marker in a JPEG marker.

Returns:

  • (Hash)


516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# File 'ext/oil/jpeg.c', line 516

static VALUE markers(VALUE self)
{
	struct jpeg_decompress_struct *dinfo;
	jpeg_saved_marker_ptr marker;
	VALUE hash, ary, key, val;

	hash = rb_hash_new();

	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);

	for (marker=dinfo->marker_list; marker; marker=marker->next) {
		key = marker_code_to_sym(marker->marker);
		ary = rb_hash_aref(hash, key);
		if (NIL_P(ary)) {
			ary = rb_ary_new();
			rb_hash_aset(hash, key, ary);
		}
		val = rb_str_new((char *)marker->data, marker->data_length);
		rb_ary_push(ary, val);
	}

	return hash;
}

#num_componentsNumeric

Retrieve the number of components per pixel as indicated by the image header.

This may differ from the number of components that will be returned by the decompressor if we ask for a color space transformation.

Returns:

  • (Numeric)


338
339
340
341
342
343
# File 'ext/oil/jpeg.c', line 338

static VALUE num_components(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->num_components);
}

#out_color_componentsNumeric

Retrieve the number of components in the output color space.

Some color spaces have padding, so this may not accurately represent the size of output pixels.

Returns:

  • (Numeric)


372
373
374
375
376
377
# File 'ext/oil/jpeg.c', line 372

static VALUE out_color_components(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->out_color_components);
}

#out_color_spaceObject

Returns a symbol representing the color model to which the image will be converted on decompress.



412
413
414
415
416
417
418
419
420
421
# File 'ext/oil/jpeg.c', line 412

static VALUE out_color_space(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	ID id;

	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	id = j_color_space_to_id(dinfo->out_color_space);

	return ID2SYM(id);
}

#out_color_space=(symbol) ⇒ Object

Set the color model to which the image will be converted on decompress.



430
431
432
433
434
435
436
437
438
439
440
# File 'ext/oil/jpeg.c', line 430

static VALUE set_out_color_space(VALUE self, VALUE cs)
{
	struct readerdata *reader;

	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);

	reader->dinfo.out_color_space = sym_to_j_color_space(cs);
	jpeg_calc_output_dimensions(&reader->dinfo);
	return cs;
}

#output_componentsNumeric

Retrieve the number of bytes per pixel that will be in the output image.

Not all bytes will necessarily have data, since some color spaces have padding.

Returns:

  • (Numeric)


355
356
357
358
359
360
# File 'ext/oil/jpeg.c', line 355

static VALUE output_components(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->output_components);
}

#image_heightNumeric

The height of the image that will be output by the decompressor.

Returns:

  • (Numeric)


497
498
499
500
501
502
# File 'ext/oil/jpeg.c', line 497

static VALUE output_height(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->output_height);
}

#output_widthNumeric

The width of the of the image that will be output by the decompressor.

Returns:

  • (Numeric)


483
484
485
486
487
488
# File 'ext/oil/jpeg.c', line 483

static VALUE output_width(VALUE self)
{
	struct jpeg_decompress_struct * dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->output_width);
}

#scale_denomNumeric

Retrieve the denominator of the fraction by which the JPEG will be scaled as it is read. This is 1, 2, 4, or 8 for libjpeg version 6b. In version 8b this is always the source DCT size, which is 8 for baseline JPEG.

Returns:

  • (Numeric)


586
587
588
589
590
591
# File 'ext/oil/jpeg.c', line 586

static VALUE scale_denom(VALUE self)
{
	struct jpeg_decompress_struct *dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->scale_denom);
}

#scale_denom=(number) ⇒ Object

Set the denominator of the fraction by which the JPEG will be scaled as it is read. This can be set to 1, 2, 4, or 8 for libjpeg version 6b. In version 8b this must always be the source DCT size, which is 8 for baseline JPEG.

Prior to version 1.2, libjpeg-turbo will not scale down images on decompression, and this option will do nothing.



605
606
607
608
609
610
611
612
613
614
615
# File 'ext/oil/jpeg.c', line 605

static VALUE set_scale_denom(VALUE self, VALUE scale_denom)
{
	struct readerdata *reader;

	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);

	reader->dinfo.scale_denom = NUM2INT(scale_denom);
	jpeg_calc_output_dimensions(&reader->dinfo);
	return scale_denom;
}

#scale_heightNumeric

Retrieve the height to which the image will be resized after decompression. A height of 0 means the image will remain at original height.

Returns:

  • (Numeric)


657
658
659
660
661
662
# File 'ext/oil/jpeg.c', line 657

static VALUE scale_height(VALUE self)
{
	struct readerdata *reader;
	Data_Get_Struct(self, struct readerdata, reader);
	return INT2FIX(reader->scale_height);
}

#scale_height=(number) ⇒ Object

Set the height to which the image will be resized after decompression. A height of 0 means the image will remain at original height.



672
673
674
675
676
677
678
679
# File 'ext/oil/jpeg.c', line 672

static VALUE set_scale_height(VALUE self, VALUE scale_height)
{
	struct readerdata *reader;
	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);
	reader->scale_height = NUM2INT(scale_height);
	return scale_height;
}

#scale_numNumeric

Retrieve the numerator of the fraction by which the JPEG will be scaled as it is read. This is always 1 for libjpeg version 6b. In version 8b this can be 1 to 16.

Returns:

  • (Numeric)


549
550
551
552
553
554
# File 'ext/oil/jpeg.c', line 549

static VALUE scale_num(VALUE self)
{
	struct jpeg_decompress_struct *dinfo;
	Data_Get_Struct(self, struct jpeg_decompress_struct, dinfo);
	return INT2FIX(dinfo->scale_num);
}

#scale_num=(number) ⇒ Object

Set the numerator of the fraction by which the JPEG will be scaled as it is read. This must always be 1 for libjpeg version 6b. In version 8b this can be set to 1 through 16.



565
566
567
568
569
570
571
572
573
574
575
# File 'ext/oil/jpeg.c', line 565

static VALUE set_scale_num(VALUE self, VALUE scale_num)
{
	struct readerdata *reader;

	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);

	reader->dinfo.scale_num = NUM2INT(scale_num);
	jpeg_calc_output_dimensions(&reader->dinfo);
	return scale_num;
}

#scale_widthNumeric

Retrieve the width to which the image will be resized after decompression. A width of 0 means the image will remain at original width.

Returns:

  • (Numeric)


625
626
627
628
629
630
# File 'ext/oil/jpeg.c', line 625

static VALUE scale_width(VALUE self)
{
	struct readerdata *reader;
	Data_Get_Struct(self, struct readerdata, reader);
	return INT2FIX(reader->scale_width);
}

#scale_width=(number) ⇒ Object

Set the width to which the image will be resized after decompression. A width of 0 means the image will remain at original width.



640
641
642
643
644
645
646
647
# File 'ext/oil/jpeg.c', line 640

static VALUE set_scale_width(VALUE self, VALUE scale_width)
{
	struct readerdata *reader;
	Data_Get_Struct(self, struct readerdata, reader);
	raise_if_locked(reader);
	reader->scale_width = NUM2INT(scale_width);
	return scale_width;
}